Skip to content

Commit

Permalink
Extend golden tests to optionally cover augmentations.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmorgan committed Sep 10, 2024
1 parent 0c22dbf commit c04ed1d
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 56 deletions.
20 changes: 20 additions & 0 deletions goldens/README.md
Original file line number Diff line number Diff line change
@@ -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.
File renamed without changes.
5 changes: 5 additions & 0 deletions goldens/foo/lib/declare_x.analyzer.augmentations
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
part of 'package:foo/declare_x.dart';

augment class Foo {
int get x => 3;
}
5 changes: 5 additions & 0 deletions goldens/foo/lib/declare_x.cfe.augmentations
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
augment library 'package:foo/declare_x.dart';

augment class Foo {
int get x => 3;
}
8 changes: 8 additions & 0 deletions goldens/foo/lib/declare_x.dart
Original file line number Diff line number Diff line change
@@ -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 {}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
99 changes: 72 additions & 27 deletions pkgs/_analyzer_macros/test/golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -41,23 +41,56 @@ void main() {
final path = file.path;
final relativePath = p.relative(path, from: directory.path);

late File goldenFile;
late Map<String, Object?> golden;
Map<String, Object?>? macroOutput;
File? introspectionGoldenFile;
Map<String, Object?>? introspectionGolden;
Map<String, Object?>? 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<String, Object?>;
introspectionGoldenFile = File(p.setExtension(path, '.analyzer.json'));
if (introspectionGoldenFile!.existsSync()) {
introspectionGolden =
json.decode(introspectionGoldenFile!.readAsStringSync())
as Map<String, Object?>;
} 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!);
}
}
});
Expand All @@ -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<String, Object?>);
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<String, Object?>);
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');
}
});
}
});
Expand Down
100 changes: 72 additions & 28 deletions pkgs/_cfe_macros/test/golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -49,23 +49,56 @@ void main() {
final path = file.path;
final relativePath = p.relative(path, from: directory.path);

late File goldenFile;
late Map<String, Object?> golden;
Map<String, Object?>? macroOutput;
File? introspectionGoldenFile;
Map<String, Object?>? introspectionGolden;
Map<String, Object?>? 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<String, Object?>;
introspectionGoldenFile = File(p.setExtension(path, '.cfe.json'));
if (introspectionGoldenFile!.existsSync()) {
introspectionGolden =
json.decode(introspectionGoldenFile!.readAsStringSync())
as Map<String, Object?>;
} 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!);
}
}
});
Expand Down Expand Up @@ -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<String, Object?>);
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<String, Object?>);
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');
}
});
}
});
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c04ed1d

Please sign in to comment.