Skip to content

Commit e8ec471

Browse files
Migrate builder test to functional test, refactor gold source file location
1 parent bdc6cb0 commit e8ec471

38 files changed

Lines changed: 284 additions & 38 deletions
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// Copyright 2020 Workiva Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
@TestOn('vm')
16+
import 'dart:io';
17+
18+
import 'package:path/path.dart' as p;
19+
import 'package:test/test.dart';
20+
21+
main() {
22+
group('overReactBuilder', () {
23+
const testPackagePath = 'test_fixtures/test_packages/builder';
24+
late String testPackageName;
25+
26+
late String outputDirectory;
27+
28+
setUpAll(() {
29+
Process.runSync('dart', ['pub', 'get'], workingDirectory: testPackagePath);
30+
testPackageName =
31+
RegExp('name: (.+)').firstMatch(File(p.join(testPackagePath, 'pubspec.yaml')).readAsStringSync())!.group(1)!;
32+
outputDirectory = Directory.systemTemp.createTempSync().path;
33+
34+
// Clean previous build
35+
Process.runSync('dart', ['run', 'build_runner', 'clean'], workingDirectory: testPackagePath);
36+
});
37+
38+
/// Runs build_runner for a specific file, cleaning first.
39+
ProcessResult buildFile(String sourceFilePath) {
40+
// Build with filter for the specific file
41+
return Process.runSync(
42+
'dart',
43+
[
44+
'run',
45+
'build_runner',
46+
'build',
47+
'--verbose',
48+
'--build-filter=lib/${sourceFilePath.replaceAll('.dart', '*.g.dart')}',
49+
'--output=$outputDirectory'
50+
],
51+
workingDirectory: testPackagePath);
52+
}
53+
54+
String generatedOutputPath(String sourceFilePath) {
55+
return p.join(
56+
outputDirectory,
57+
'packages',
58+
testPackageName,
59+
sourceFilePath.replaceAll('.dart', '.over_react.g.dart'),
60+
);
61+
}
62+
63+
/// Runs build_runner for a specific file and verifies the generated output matches the gold file.
64+
Future<void> checkBuildForFile(String sourceFilePath, String pathToGoldFile) async {
65+
final build = buildFile(sourceFilePath);
66+
67+
expect(build.exitCode, 0,
68+
reason: 'build should have succeeded.'
69+
'\nstdout: ${build.stdout}'
70+
'\nstderr: ${build.stderr}');
71+
72+
// Read generated file
73+
final expectedGeneratedFile = File(generatedOutputPath(sourceFilePath));
74+
expect(expectedGeneratedFile.existsSync(), isTrue,
75+
reason:
76+
'File should have been generated: ${expectedGeneratedFile.path}.\n\nBuild output:\n${build.stdout}\n${build.stderr}');
77+
78+
// Compare with gold file
79+
final expectedContent = File(pathToGoldFile).readAsStringSync();
80+
final actualContent = expectedGeneratedFile.readAsStringSync();
81+
82+
expect(actualContent, expectedContent, reason: 'Generated file should match gold file');
83+
}
84+
85+
/// Runs build_runner for a specific file and verifies no output is generated.
86+
Future<void> checkNoOutputForFile(String sourceFilePath) async {
87+
final build = buildFile(sourceFilePath);
88+
89+
expect(build.exitCode, 0,
90+
reason: 'build should have succeeded.'
91+
'\nstdout: ${build.stdout}'
92+
'\nstderr: ${build.stderr}');
93+
94+
// Verify no generated file exists
95+
final expectedGeneratedFile = File(generatedOutputPath(sourceFilePath));
96+
expect(expectedGeneratedFile.existsSync(), isFalse,
97+
reason: 'File should not have been generated: ${expectedGeneratedFile.path}');
98+
}
99+
100+
/// Runs build_runner for a specific file and verifies a warning appears in the output.
101+
Future<void> checkWarningForFile(String sourceFilePath, String expectedWarning) async {
102+
final build = buildFile(sourceFilePath);
103+
104+
// Check for expected warning in output
105+
expect('${build.stdout}${build.stderr}', contains(expectedWarning),
106+
reason: 'Expected warning not found in build output');
107+
108+
expect(build.exitCode, 0,
109+
reason: 'build should have succeeded.'
110+
'\nstdout: ${build.stdout}'
111+
'\nstderr: ${build.stderr}');
112+
}
113+
114+
/// Runs build_runner for a specific file and verifies a severe error appears in the output.
115+
Future<void> checkSevereErrorForFile(String sourceFilePath, String expectedError) async {
116+
final build = buildFile(sourceFilePath);
117+
118+
// Check for expected error in output
119+
expect('${build.stdout}${build.stderr}', contains(expectedError),
120+
reason: 'Expected error not found in build output');
121+
122+
expect(build.exitCode, 1,
123+
reason: 'build should have failed.'
124+
'\nstdout: ${build.stdout}'
125+
'\nstderr: ${build.stderr}');
126+
}
127+
128+
test('does not produce a build output for a file with no over_react annotations', () async {
129+
await checkNoOutputForFile('no_annotations.dart');
130+
});
131+
132+
test(
133+
'warns if .over_react.g.dart part directive is present and no declarations are present, but no code is generated',
134+
() async {
135+
await checkWarningForFile('has_part_directive_missing_gen/no_declarations.dart',
136+
'An over_react part directive was found in lib/has_part_directive_missing_gen/no_declarations.dart, but no code was generated.');
137+
});
138+
139+
test('warns if .over_react.g.dart part directive is present and declarations are present, but no code is generated',
140+
() async {
141+
await checkWarningForFile('has_part_directive_missing_gen/with_declarations.dart',
142+
'An over_react part directive was found in lib/has_part_directive_missing_gen/with_declarations.dart, but no code was generated.');
143+
});
144+
145+
group('for backwards compatible boilerplate:', () {
146+
test('builds from basic component file', () async {
147+
await checkBuildForFile('backwards_compatible/basic.dart',
148+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/backwards_compatible/basic.over_react.g.dart.goldFile');
149+
});
150+
151+
test('builds from basic multi-part library', () async {
152+
await checkBuildForFile('backwards_compatible/basic_library.dart',
153+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/backwards_compatible/basic_library.over_react.g.dart.goldFile');
154+
});
155+
156+
test('builds for props mixins', () async {
157+
await checkBuildForFile('backwards_compatible/props_mixin.dart',
158+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/backwards_compatible/props_mixin.over_react.g.dart.goldFile');
159+
});
160+
161+
test('builds for state mixins', () async {
162+
await checkBuildForFile('backwards_compatible/state_mixin.dart',
163+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/backwards_compatible/state_mixin.over_react.g.dart.goldFile');
164+
});
165+
166+
test('does not produce a build output for just a part file', () async {
167+
await checkNoOutputForFile('backwards_compatible/part_of_basic_library.dart');
168+
});
169+
});
170+
171+
group('for Dart 2 only compatible boilerplate:', () {
172+
test('builds from basic component file', () async {
173+
await checkBuildForFile('dart2_only/basic.dart',
174+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/dart2_only/basic.over_react.g.dart.goldFile');
175+
});
176+
177+
test('builds from basic multi-part library', () async {
178+
await checkBuildForFile('dart2_only/basic_library.dart',
179+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/dart2_only/basic_library.over_react.g.dart.goldFile');
180+
});
181+
182+
test('builds for props mixins', () async {
183+
await checkBuildForFile('dart2_only/props_mixin.dart',
184+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/dart2_only/props_mixin.over_react.g.dart.goldFile');
185+
});
186+
187+
test('builds for state mixins', () async {
188+
await checkBuildForFile('dart2_only/state_mixin.dart',
189+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/dart2_only/state_mixin.over_react.g.dart.goldFile');
190+
});
191+
192+
test('does not produce a build output for just a part file', () async {
193+
await checkNoOutputForFile('dart2_only/part_of_basic_library.dart');
194+
});
195+
196+
test('fails if the .over_react.g.dart part directive is missing', () async {
197+
await checkSevereErrorForFile(
198+
'dart2_only/missing_over_react_g_part/library.dart', 'Missing "part \'library.over_react.g.dart\';".');
199+
});
200+
201+
group('for Component2:', () {
202+
test('builds from basic component file', () async {
203+
await checkBuildForFile('dart2_only/component2/basic.dart',
204+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/dart2_only/component2/basic.over_react.g.dart.goldFile');
205+
});
206+
207+
test('builds from basic multi-part library', () async {
208+
await checkBuildForFile('dart2_only/component2/basic_library.dart',
209+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/dart2_only/component2/basic_library.over_react.g.dart.goldFile');
210+
});
211+
});
212+
});
213+
214+
group('for mixin based boilerplate:', () {
215+
test('builds from basic component file', () async {
216+
await checkBuildForFile('mixin_based/basic.dart',
217+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/mixin_based/basic.over_react.g.dart.goldFile');
218+
});
219+
220+
test('builds from basic component file using Dart >=2.9.0 syntax', () async {
221+
await checkBuildForFile('mixin_based/basic_two_nine.dart',
222+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/mixin_based/basic_two_nine.over_react.g.dart.goldFile');
223+
});
224+
225+
test('builds from basic multi-part library', () async {
226+
await checkBuildForFile('mixin_based/basic_library.dart',
227+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/mixin_based/basic_library.over_react.g.dart.goldFile');
228+
});
229+
230+
test('builds when props mixins and classes have type parameters', () async {
231+
await checkBuildForFile('mixin_based/type_parameters.dart',
232+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/mixin_based/type_parameters.over_react.g.dart.goldFile');
233+
});
234+
235+
test('builds for props mixins', () async {
236+
await checkBuildForFile('mixin_based/props_mixin.dart',
237+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/mixin_based/props_mixin.over_react.g.dart.goldFile');
238+
});
239+
240+
test('builds for state mixins', () async {
241+
await checkBuildForFile('mixin_based/state_mixin.dart',
242+
'${p.absolute(p.current)}/test_fixtures/gold_output_files/mixin_based/state_mixin.over_react.g.dart.goldFile');
243+
});
244+
245+
test('does not produce a build output for just a part file', () async {
246+
await checkNoOutputForFile('mixin_based/part_of_basic_library.dart');
247+
});
248+
249+
test('fails if the .over_react.g.dart part directive is missing', () async {
250+
await checkSevereErrorForFile(
251+
'mixin_based/missing_over_react_g_part/library.dart', 'Missing "part \'library.over_react.g.dart\';".');
252+
});
253+
});
254+
});
255+
}

test_fixtures/gold_output_files/README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,3 @@ To re-generate the gold files in this directory using the over_react builder, ru
44
```sh
55
dart tool/update_gold_output_files.dart
66
```
7-
8-
If that deletes other generated files throughout over_react (which usually only happens after it prompts you about conflicting outputs), you can restore them by running a build:
9-
```sh
10-
dart run build_runner build
11-
```

test_fixtures/test_packages/builder/analysis_options.yaml

Whitespace-only changes.

test_fixtures/source_files/backwards_compatible/basic.dart renamed to test_fixtures/test_packages/builder/lib/backwards_compatible/basic.dart

File renamed without changes.

test_fixtures/source_files/backwards_compatible/basic_library.dart renamed to test_fixtures/test_packages/builder/lib/backwards_compatible/basic_library.dart

File renamed without changes.

test_fixtures/source_files/backwards_compatible/part_of_basic_library.dart renamed to test_fixtures/test_packages/builder/lib/backwards_compatible/part_of_basic_library.dart

File renamed without changes.

test_fixtures/source_files/backwards_compatible/part_of_basic_library_2.dart renamed to test_fixtures/test_packages/builder/lib/backwards_compatible/part_of_basic_library_2.dart

File renamed without changes.

test_fixtures/source_files/backwards_compatible/props_mixin.dart renamed to test_fixtures/test_packages/builder/lib/backwards_compatible/props_mixin.dart

File renamed without changes.

test_fixtures/source_files/backwards_compatible/state_mixin.dart renamed to test_fixtures/test_packages/builder/lib/backwards_compatible/state_mixin.dart

File renamed without changes.

test_fixtures/source_files/dart2_only/basic.dart renamed to test_fixtures/test_packages/builder/lib/dart2_only/basic.dart

File renamed without changes.

0 commit comments

Comments
 (0)