| // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:analyzer_testing/package_config_file_builder.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../dart/resolution/context_collection_resolution.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(InvalidWidgetPreviewApplicationTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class InvalidWidgetPreviewApplicationTest extends PubPackageResolutionTest { |
| @override |
| void setUp() { |
| super.setUp(); |
| writeTestPackageConfig(PackageConfigFileBuilder(), flutter: true); |
| } |
| |
| // @Preview cannot be applied to constructors of abstract classes. |
| test_invalidAbstractClassConstructors() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| abstract class B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| B(); |
| } |
| '''); |
| } |
| |
| // @Preview application must invoke the `Preview` constructor. |
| test_invalidAnnotationApplication() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview |
| //^^^^^^^^ |
| // [diag.noAnnotationConstructorArguments] Annotation creation must have arguments. |
| B(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to external constructors. |
| test_invalidExternalConstructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| external B(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to external functions. |
| test_invalidExternalStaticFunction() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| external static Widget foo(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to external top-level functions. |
| test_invalidExternalTopLevelFunction() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| @Preview() |
| // [diag.invalidWidgetPreviewApplication][column 2][length 7] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| external Widget foo(); |
| '''); |
| } |
| |
| // @Preview cannot be applied to instance members of classes. |
| test_invalidInstanceMethod() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| Widget foo() { |
| return Text('Foo'); |
| } |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to nested functions. |
| test_invalidNestedFunction() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| Widget foo() { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| Widget nested() { |
| return Text('Foo'); |
| } |
| return nested(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to enum members. |
| test_invalidParentContext_enumMember() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widget_previews.dart'; |
| |
| enum B { |
| a, |
| b, |
| c; |
| |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| const B(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to extension methods. |
| test_invalidParentContext_extensionMethod() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class Foo extends StatelessWidget { |
| } |
| |
| extension E on Foo { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| Widget invalidExtensionPreview() => Text('Invalid'); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to extension type members. |
| test_invalidParentContext_extensionTypeMember() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class Foo extends StatelessWidget { |
| @override |
| Widget build(BuildContext context) => Text('Foo'); |
| } |
| |
| extension type FooExtensionType(Foo foo) { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| Widget invalidExtensionTypePreview() => Text('Invalid'); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to extension type members. |
| test_invalidParentContext_mixinMember() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class Foo extends StatelessWidget { |
| @override |
| Widget build(BuildContext context) => Text('Foo'); |
| } |
| |
| mixin PreviewMixin { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| Widget invalidMixinPreview() => Text('Invalid'); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to constructors of private classes. |
| test_invalidPrivateClass_constructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class _B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| _B(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to factory constructors of private classes. |
| test_invalidPrivateClass_factoryConstructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class _B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| factory _B.foo() => throw ''; |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to instance members of private classes. |
| test_invalidPrivateClass_instanceMember() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class _B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| static Widget bar() => Text('Bar'); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to private static functions. |
| test_invalidPrivateClassStatic() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| static Widget _foo() { |
| // ^^^^ |
| // [diag.unusedElement] The declaration '_foo' isn't referenced. |
| return Text('Foo'); |
| } |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to private factory constructors. |
| test_invalidPrivateConstructor_factory() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| factory B._foo() => B(); |
| |
| B(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to private generative constructors. |
| test_invalidPrivateConstructor_generative() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| B._(); |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to private primary constructors. |
| test_invalidPrivateConstructor_primary() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B._() extends StatelessWidget { |
| @Preview() |
| // ^^^^^^^ |
| // [diag.invalidWidgetPreviewApplication] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| this; |
| } |
| '''); |
| } |
| |
| // @Preview cannot be applied to private top-level functions. |
| test_invalidPrivateTopLevel() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| // ignore_for_file: unused_element |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| @Preview() |
| // [diag.invalidWidgetPreviewApplication][column 2][length 7] The '@Preview(...)' annotation can only be applied to public, statically accessible constructors and functions. |
| Widget _foo() { |
| return Text('Foo'); |
| } |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to public factory constructors of |
| // abstract Widget subtypes. |
| test_validAbstractClassFactoryConstructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| abstract class B extends StatelessWidget { |
| @Preview() |
| factory B() => C(); |
| |
| @Preview() |
| factory B.named() => C.named(); |
| |
| B._(); |
| } |
| |
| class C extends B { |
| C() : super._(); |
| factory C.named() => C(); |
| } |
| '''); |
| } |
| |
| // Ensure that constant instances of @Preview(...) can be applied. |
| test_validAnnotationConstant() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widget_previews.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| const myPreview = Preview(name: 'Testing'); |
| |
| @myPreview |
| Widget bar() => Text('Bar'); |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to public factory constructors of |
| // Widget subtypes, including those with optional parameters. |
| test_validClassFactoryConstructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| factory B.foo({Key? key}) => B._(key: key); |
| |
| @Preview() |
| factory B.bar() => B._(); |
| |
| B._({super.key}); |
| } |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to public constructors of Widget |
| // subtypes, including those with optional parameters. |
| test_validClassGenerativeConstructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| const B({super.key}); |
| |
| @Preview() |
| B.foo([String? _]); |
| } |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to public primary constructors of |
| // Widget subtypes, including those with optional parameters. |
| test_validClassPrimaryConstructor() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B({super.key}) extends StatelessWidget { |
| @Preview() |
| this; |
| } |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to public static functions that are |
| // defined in public classes and that return Widget or WidgetBuilder. |
| test_validClassStatic() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/widget_previews.dart'; |
| |
| class B extends StatelessWidget { |
| @Preview() |
| static Widget foo() { |
| return Text('Foo'); |
| } |
| |
| @Preview() |
| static WidgetBuilder bar() { |
| return (BuildContext context) { |
| return Text('Bar'); |
| }; |
| } |
| } |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to public top-level functions that |
| // return a Widget or WidgetBuilder. |
| test_validTopLevel() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widget_previews.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| @Preview(name: 'Widget') |
| Widget foo() => Text('Foo'); |
| |
| @Preview(name: 'WidgetBuilder') |
| WidgetBuilder bar() { |
| return (BuildContext context) { |
| return Text('Bar'); |
| }; |
| } |
| '''); |
| } |
| |
| // Ensure that @Preview can be applied to functions that explicitly return a |
| // subtype of Widget. |
| test_validTopLevel_widgetSubtype() async { |
| await resolveTestCodeWithDiagnostics(r''' |
| import 'package:flutter/widget_previews.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| typedef MyWidget = Widget; |
| |
| @Preview(name: 'Testing') |
| Text foo() => Text('Foo'); |
| |
| @Preview(name: 'Testing') |
| MyWidget bar() => Text('Bar'); |
| '''); |
| } |
| } |