blob: 7af168de55a07c57388f0aa3bff920e210f7a582 [file]
// 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');
''');
}
}