From c04ed1da0a9f6c3c6179e5bf7f1b91e988965982 Mon Sep 17 00:00:00 2001 From: David Morgan Date: Tue, 10 Sep 2024 14:28:50 +0200 Subject: [PATCH] Extend golden tests to optionally cover augmentations. --- goldens/README.md | 20 ++++ .../foo/analysis_options.yaml | 0 .../foo/lib/declare_x.analyzer.augmentations | 5 + goldens/foo/lib/declare_x.cfe.augmentations | 5 + goldens/foo/lib/declare_x.dart | 8 ++ .../foo/lib/foo.analyzer.json | 0 .../foo/lib/foo.cfe.json | 0 .../foo/lib/foo.dart | 0 .../foo/pubspec.yaml | 0 pkgs/_analyzer_macros/test/golden_test.dart | 99 ++++++++++++----- pkgs/_cfe_macros/test/golden_test.dart | 100 +++++++++++++----- pubspec.yaml | 2 +- 12 files changed, 183 insertions(+), 56 deletions(-) create mode 100644 goldens/README.md rename {introspection_goldens => goldens}/foo/analysis_options.yaml (100%) create mode 100644 goldens/foo/lib/declare_x.analyzer.augmentations create mode 100644 goldens/foo/lib/declare_x.cfe.augmentations create mode 100644 goldens/foo/lib/declare_x.dart rename {introspection_goldens => goldens}/foo/lib/foo.analyzer.json (100%) rename {introspection_goldens => goldens}/foo/lib/foo.cfe.json (100%) rename {introspection_goldens => goldens}/foo/lib/foo.dart (100%) rename {introspection_goldens => goldens}/foo/pubspec.yaml (100%) diff --git a/goldens/README.md b/goldens/README.md new file mode 100644 index 00000000..fa185850 --- /dev/null +++ b/goldens/README.md @@ -0,0 +1,20 @@ +# Golden Tests + +Each `.dart` file under this path creates a test case in +`pkgs/_analyzer_macros/test/golden_test.dart` and +`pkgs/_cfe_macros/test/golden_test.dart`. + +The test case looks for golden files next to the `.dart` file and asserts +that they match. + +## Introspection + +To test introspection, add `.analyzer.json` and/or `.cfe.json` golden files. +The JSON in the golden file is compared with the query output on the `.dart` +file, which must be tagged with the `QueryClass` macro. + +## Application + +To test macro application, add `.analyzer.augmentations` and/or +`.cfe.augmentations` golden files. These are compared with the full +macro augmentation output of the corresponding `.dart` file. diff --git a/introspection_goldens/foo/analysis_options.yaml b/goldens/foo/analysis_options.yaml similarity index 100% rename from introspection_goldens/foo/analysis_options.yaml rename to goldens/foo/analysis_options.yaml diff --git a/goldens/foo/lib/declare_x.analyzer.augmentations b/goldens/foo/lib/declare_x.analyzer.augmentations new file mode 100644 index 00000000..1ba54394 --- /dev/null +++ b/goldens/foo/lib/declare_x.analyzer.augmentations @@ -0,0 +1,5 @@ +part of 'package:foo/declare_x.dart'; + +augment class Foo { +int get x => 3; +} diff --git a/goldens/foo/lib/declare_x.cfe.augmentations b/goldens/foo/lib/declare_x.cfe.augmentations new file mode 100644 index 00000000..0502e29f --- /dev/null +++ b/goldens/foo/lib/declare_x.cfe.augmentations @@ -0,0 +1,5 @@ +augment library 'package:foo/declare_x.dart'; + +augment class Foo { +int get x => 3; +} diff --git a/goldens/foo/lib/declare_x.dart b/goldens/foo/lib/declare_x.dart new file mode 100644 index 00000000..8056403d --- /dev/null +++ b/goldens/foo/lib/declare_x.dart @@ -0,0 +1,8 @@ +// Copyright (c) 2024, 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:_test_macros/declare_x_macro.dart'; + +@DeclareX() +class Foo {} diff --git a/introspection_goldens/foo/lib/foo.analyzer.json b/goldens/foo/lib/foo.analyzer.json similarity index 100% rename from introspection_goldens/foo/lib/foo.analyzer.json rename to goldens/foo/lib/foo.analyzer.json diff --git a/introspection_goldens/foo/lib/foo.cfe.json b/goldens/foo/lib/foo.cfe.json similarity index 100% rename from introspection_goldens/foo/lib/foo.cfe.json rename to goldens/foo/lib/foo.cfe.json diff --git a/introspection_goldens/foo/lib/foo.dart b/goldens/foo/lib/foo.dart similarity index 100% rename from introspection_goldens/foo/lib/foo.dart rename to goldens/foo/lib/foo.dart diff --git a/introspection_goldens/foo/pubspec.yaml b/goldens/foo/pubspec.yaml similarity index 100% rename from introspection_goldens/foo/pubspec.yaml rename to goldens/foo/pubspec.yaml diff --git a/pkgs/_analyzer_macros/test/golden_test.dart b/pkgs/_analyzer_macros/test/golden_test.dart index 361af6cc..de074cb4 100644 --- a/pkgs/_analyzer_macros/test/golden_test.dart +++ b/pkgs/_analyzer_macros/test/golden_test.dart @@ -21,7 +21,7 @@ void main() { group('analyzer with injected macro impl query result matches golden', () { final directory = Directory( Isolate.resolvePackageUriSync(Uri.parse('package:foo/foo.dart'))! - .resolve('../../../introspection_goldens') + .resolve('../../../goldens') .toFilePath()); setUp(() async { @@ -41,23 +41,56 @@ void main() { final path = file.path; final relativePath = p.relative(path, from: directory.path); - late File goldenFile; - late Map golden; - Map? macroOutput; + File? introspectionGoldenFile; + Map? introspectionGolden; + Map? introspectionMacroOutput; + + File? applicationGoldenFile; + String? applicationGolden; + String? applicationMacroOutput; + final updateGoldens = Platform.environment['UPDATE_GOLDENS'] == 'yes'; setUp(() { - goldenFile = File(p.setExtension(path, '.analyzer.json')); - golden = - json.decode(goldenFile.readAsStringSync()) as Map; + introspectionGoldenFile = File(p.setExtension(path, '.analyzer.json')); + if (introspectionGoldenFile!.existsSync()) { + introspectionGolden = + json.decode(introspectionGoldenFile!.readAsStringSync()) + as Map; + } else { + introspectionGoldenFile = null; + } + + applicationGoldenFile = + File(p.setExtension(path, '.analyzer.augmentations')); + if (applicationGoldenFile!.existsSync()) { + applicationGolden = applicationGoldenFile!.readAsStringSync(); + } else { + applicationGoldenFile = null; + } + + if (introspectionGoldenFile == null && applicationGoldenFile == null) { + throw StateError('Setup failed, no goldens for $path'); + } }); + if (updateGoldens) { tearDown(() { - if (macroOutput != null) { - final string = - (const JsonEncoder.withIndent(' ')).convert(macroOutput); - if (goldenFile.readAsStringSync() != string) { - print('Updating mismatched golden: ${goldenFile.path}'); - goldenFile.writeAsStringSync(string); + if (introspectionGoldenFile != null && + introspectionMacroOutput != null) { + final string = (const JsonEncoder.withIndent(' ')) + .convert(introspectionMacroOutput); + if (introspectionGoldenFile!.readAsStringSync() != string) { + print('Updating mismatched golden: ' + '${introspectionGoldenFile!.path}'); + introspectionGoldenFile!.writeAsStringSync(string); + } + } + if (applicationGoldenFile != null && applicationMacroOutput != null) { + if (applicationGoldenFile!.readAsStringSync() != + applicationMacroOutput) { + print( + 'Updating mismatched golden: ${applicationGoldenFile!.path}'); + applicationGoldenFile!.writeAsStringSync(applicationMacroOutput!); } } }); @@ -69,20 +102,32 @@ void main() { final augmentationUnit = resolvedLibrary.units.singleWhere((u) => u.isMacroAugmentation); - // Each `QueryClass` outputs its query result as a comment in an - // augmentation. Collect them and merge them to compare with the - // golden. - final macroOutputs = augmentationUnit.content - .split('\n') - .where((l) => l.startsWith('// ')) - .map((l) => - json.decode(l.substring('// '.length)) as Map); - macroOutput = _merge(macroOutputs); - - expect(macroOutput, golden, - reason: updateGoldens - ? null - : '\n--> To update goldens, run: UPDATE_GOLDENS=yes dart test'); + if (introspectionGolden != null) { + // Each `QueryClass` outputs its query result as a comment in an + // augmentation. Collect them and merge them to compare with the + // golden. + final macroOutputs = augmentationUnit.content + .split('\n') + .where((l) => l.startsWith('// ')) + .map((l) => json.decode(l.substring('// '.length)) + as Map); + introspectionMacroOutput = _merge(macroOutputs); + + expect(introspectionMacroOutput, introspectionGolden, + reason: updateGoldens + ? null + : '\n--> To update goldens, run: ' + 'UPDATE_GOLDENS=yes dart test'); + } + + if (applicationGolden != null) { + applicationMacroOutput = augmentationUnit.content; + expect(applicationMacroOutput, applicationGolden, + reason: updateGoldens + ? null + : '\n--> To update goldens, run: ' + 'UPDATE_GOLDENS=yes dart test'); + } }); } }); diff --git a/pkgs/_cfe_macros/test/golden_test.dart b/pkgs/_cfe_macros/test/golden_test.dart index 14746386..a586af80 100644 --- a/pkgs/_cfe_macros/test/golden_test.dart +++ b/pkgs/_cfe_macros/test/golden_test.dart @@ -20,7 +20,7 @@ void main() { final directory = Directory( Isolate.resolvePackageUriSync(Uri.parse('package:foo/foo.dart'))! - .resolve('../../../introspection_goldens') + .resolve('../../../goldens') .toFilePath()); setUp(() async { @@ -49,23 +49,56 @@ void main() { final path = file.path; final relativePath = p.relative(path, from: directory.path); - late File goldenFile; - late Map golden; - Map? macroOutput; + File? introspectionGoldenFile; + Map? introspectionGolden; + Map? introspectionMacroOutput; + + File? applicationGoldenFile; + String? applicationGolden; + String? applicationMacroOutput; + final updateGoldens = Platform.environment['UPDATE_GOLDENS'] == 'yes'; + setUp(() { - goldenFile = File(p.setExtension(path, '.cfe.json')); - golden = - json.decode(goldenFile.readAsStringSync()) as Map; + introspectionGoldenFile = File(p.setExtension(path, '.cfe.json')); + if (introspectionGoldenFile!.existsSync()) { + introspectionGolden = + json.decode(introspectionGoldenFile!.readAsStringSync()) + as Map; + } else { + introspectionGoldenFile = null; + } + + applicationGoldenFile = + File(p.setExtension(path, '.cfe.augmentations')); + if (applicationGoldenFile!.existsSync()) { + applicationGolden = applicationGoldenFile!.readAsStringSync(); + } else { + applicationGoldenFile = null; + } + + if (introspectionGoldenFile == null && applicationGoldenFile == null) { + throw StateError('Setup failed, no goldens for $path'); + } }); if (updateGoldens) { tearDown(() { - if (macroOutput != null) { - final string = - (const JsonEncoder.withIndent(' ')).convert(macroOutput); - if (goldenFile.readAsStringSync() != string) { - print('Updating mismatched golden: ${goldenFile.path}'); - goldenFile.writeAsStringSync(string); + if (introspectionGoldenFile != null && + introspectionMacroOutput != null) { + final string = (const JsonEncoder.withIndent(' ')) + .convert(introspectionMacroOutput); + if (introspectionGoldenFile!.readAsStringSync() != string) { + print('Updating mismatched golden: ' + '${introspectionGoldenFile!.path}'); + introspectionGoldenFile!.writeAsStringSync(string); + } + } + if (applicationGoldenFile != null && applicationMacroOutput != null) { + if (applicationGoldenFile!.readAsStringSync() != + applicationMacroOutput) { + print( + 'Updating mismatched golden: ${applicationGoldenFile!.path}'); + applicationGoldenFile!.writeAsStringSync(applicationMacroOutput!); } } }); @@ -94,25 +127,36 @@ void main() { final sources = computeKernelResult .previousState!.incrementalCompiler!.context.uriToSource; - final macroSource = sources.entries + applicationMacroOutput = sources.entries .singleWhere((e) => e.key.scheme == 'dart-macro+file') .value .text; - // Each `QueryClass` outputs its query result as a comment in an - // augmentation. Collect them and merge them to compare with the - // golden. - final macroOutputs = macroSource - .split('\n') - .where((l) => l.startsWith('// ')) - .map((l) => - json.decode(l.substring('// '.length)) as Map); - macroOutput = _merge(macroOutputs); - - expect(macroOutput, golden, - reason: updateGoldens - ? null - : '\n--> To update goldens, run: UPDATE_GOLDENS=yes dart test'); + if (introspectionGolden != null) { + // Each `QueryClass` outputs its query result as a comment in an + // augmentation. Collect them and merge them to compare with the + // golden. + final macroOutputs = applicationMacroOutput! + .split('\n') + .where((l) => l.startsWith('// ')) + .map((l) => json.decode(l.substring('// '.length)) + as Map); + introspectionMacroOutput = _merge(macroOutputs); + + expect(introspectionMacroOutput, introspectionGolden, + reason: updateGoldens + ? null + : '\n--> To update goldens, run: ' + 'UPDATE_GOLDENS=yes dart test'); + } + + if (applicationGolden != null) { + expect(applicationMacroOutput, applicationGolden, + reason: updateGoldens + ? null + : '\n--> To update goldens, run: ' + 'UPDATE_GOLDENS=yes dart test'); + } }); } }); diff --git a/pubspec.yaml b/pubspec.yaml index 84f0e096..87a49db6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ dev_dependencies: dart_flutter_team_lints: ^3.1.0 publish_to: none workspace: - - introspection_goldens/foo + - goldens/foo - pkgs/_analyzer_macros - pkgs/_analyzer_macros/test/package_under_test - pkgs/_cfe_macros