Skip to content

Commit b0efb37

Browse files
bwilkersoncommit-bot@chromium.org
authored andcommitted
Add enhanced testing support for dart fix
Change-Id: I8cf49b85142c242597542eae9306eb09be5e4149 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175920 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent dd8401a commit b0efb37

File tree

2 files changed

+185
-28
lines changed

2 files changed

+185
-28
lines changed

pkg/dartdev/lib/src/commands/fix.dart

+95-20
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ To use the tool, run either ['dart fix --dry-run'] for a preview of the proposed
8888
if (!dir.existsSync()) {
8989
usageException("Directory doesn't exist: ${dir.path}");
9090
}
91+
dir = io.Directory(path.canonicalize(path.normalize(dir.absolute.path)));
92+
var dirPath = dir.path;
9193

9294
var modeText = dryRun ? ' (dry run)' : '';
9395

94-
final projectName = path.basename(path.canonicalize(dir.path));
96+
final projectName = path.basename(dirPath);
9597
var progress = log.progress(
9698
'Computing fixes in ${log.ansi.emphasized(projectName)}$modeText');
9799

@@ -111,24 +113,24 @@ To use the tool, run either ['dart fix --dry-run'] for a preview of the proposed
111113
}
112114
});
113115

114-
fixes = await server.requestBulkFixes(dir.absolute.path);
116+
fixes = await server.requestBulkFixes(dirPath);
115117
final List<SourceFileEdit> edits = fixes.edits;
116118

117119
await server.shutdown();
118120

119121
progress.finish(showTiming: true);
120122

121123
if (testMode) {
122-
if (_compareFixes(edits)) {
123-
return 1;
124-
}
124+
var result = _compareFixesInDirectory(dir, edits);
125+
log.stdout('Passed: ${result.passCount}, Failed: ${result.failCount}');
126+
return result.failCount > 0 ? 1 : 0;
125127
} else if (edits.isEmpty) {
126128
log.stdout('Nothing to fix!');
127129
} else {
128130
var details = fixes.details;
129131
details.sort((f1, f2) => path
130-
.relative(f1.path, from: dir.path)
131-
.compareTo(path.relative(f2.path, from: dir.path)));
132+
.relative(f1.path, from: dirPath)
133+
.compareTo(path.relative(f2.path, from: dirPath)));
132134

133135
var fileCount = 0;
134136
var fixCount = 0;
@@ -170,32 +172,83 @@ To use the tool, run either ['dart fix --dry-run'] for a preview of the proposed
170172

171173
/// Return `true` if any of the fixes fail to create the same content as is
172174
/// found in the golden file.
173-
bool _compareFixes(List<SourceFileEdit> edits) {
174-
var passCount = 0;
175-
var failCount = 0;
175+
_TestResult _compareFixesInDirectory(
176+
io.Directory directory, List<SourceFileEdit> edits) {
177+
var result = _TestResult();
178+
//
179+
// Gather the files of interest in this directory and process
180+
// subdirectories.
181+
//
182+
var dartFiles = <io.File>[];
183+
var expectFileMap = <String, io.File>{};
184+
for (var child in directory.listSync()) {
185+
if (child is io.Directory) {
186+
var childResult = _compareFixesInDirectory(child, edits);
187+
result.passCount += childResult.passCount;
188+
result.failCount += childResult.failCount;
189+
} else if (child is io.File) {
190+
var name = child.name;
191+
if (name.endsWith('.dart')) {
192+
dartFiles.add(child);
193+
} else if (name.endsWith('.expect')) {
194+
expectFileMap[child.path] = child;
195+
}
196+
}
197+
}
198+
var editMap = <String, SourceFileEdit>{};
176199
for (var edit in edits) {
177-
var filePath = edit.file;
200+
editMap[edit.file] = edit;
201+
}
202+
for (var originalFile in dartFiles) {
203+
var filePath = originalFile.path;
178204
var baseName = path.basename(filePath);
179205
var expectFileName = baseName + '.expect';
180206
var expectFilePath = path.join(path.dirname(filePath), expectFileName);
207+
var expectFile = expectFileMap.remove(expectFilePath);
208+
if (expectFile == null) {
209+
result.failCount++;
210+
log.stdout(
211+
'No corresponding expect file for the Dart file at "$filePath".');
212+
continue;
213+
}
214+
var edit = editMap[filePath];
181215
try {
182-
var originalCode = io.File(filePath).readAsStringSync();
183-
var expectedCode = io.File(expectFilePath).readAsStringSync();
184-
var actualCode = SourceEdit.applySequence(originalCode, edit.edits);
185-
if (actualCode != expectedCode) {
186-
failCount++;
216+
var originalCode = originalFile.readAsStringSync();
217+
var expectedCode = expectFile.readAsStringSync();
218+
var actualCode = edit == null
219+
? originalCode
220+
: SourceEdit.applySequence(originalCode, edit.edits);
221+
// Use a whitespace insensitive comparison.
222+
if (_compressWhitespace(actualCode) !=
223+
_compressWhitespace(expectedCode)) {
224+
result.failCount++;
187225
_reportFailure(filePath, actualCode, expectedCode);
226+
_printEdits(edits);
188227
} else {
189-
passCount++;
228+
result.passCount++;
190229
}
191230
} on io.FileSystemException {
192-
// Ignored for now.
231+
result.failCount++;
232+
log.stdout('Failed to process "$filePath".');
233+
log.stdout(
234+
' Ensure that the file and its expect file are both readable.');
193235
}
194236
}
195-
log.stdout('Passed: $passCount, Failed: $failCount');
196-
return failCount > 0;
237+
//
238+
// Report any `.expect` files that have no corresponding `.dart` file.
239+
//
240+
for (var unmatchedExpectPath in expectFileMap.keys) {
241+
result.failCount++;
242+
log.stdout(
243+
'No corresponding Dart file for the expect file at "$unmatchedExpectPath".');
244+
}
245+
return result;
197246
}
198247

248+
/// Compress sequences of whitespace characters into a single space.
249+
String _compressWhitespace(String code) =>
250+
code.replaceAll(RegExp(r'\s*'), ' ');
251+
199252
String _pluralFix(int count) => count == 1 ? 'fix' : 'fixes';
200253

201254
void _printDetails(List<BulkFix> details, io.Directory workingDir) {
@@ -215,6 +268,16 @@ To use the tool, run either ['dart fix --dry-run'] for a preview of the proposed
215268
}
216269
}
217270

271+
void _printEdits(List<SourceFileEdit> edits) {
272+
log.stdout('Edits returned from server:');
273+
for (var fileEdit in edits) {
274+
log.stdout(' ${fileEdit.file}');
275+
for (var edit in fileEdit.edits) {
276+
log.stdout(" ${edit.offset} - ${edit.end}, '${edit.replacement}'");
277+
}
278+
}
279+
}
280+
218281
/// Report that the [actualCode] produced by applying fixes to the content of
219282
/// [filePath] did not match the [expectedCode].
220283
void _reportFailure(String filePath, String actualCode, String expectedCode) {
@@ -228,3 +291,15 @@ To use the tool, run either ['dart fix --dry-run'] for a preview of the proposed
228291

229292
static String _format(int value) => _numberFormat.format(value);
230293
}
294+
295+
/// The result of running tests in a given directory.
296+
class _TestResult {
297+
/// The number of tests that passed.
298+
int passCount = 0;
299+
300+
/// The number of tests that failed.
301+
int failCount = 0;
302+
303+
/// Initialize a newly created result object.
304+
_TestResult();
305+
}

pkg/dartdev/test/commands/fix_test.dart

+90-8
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,38 @@ const runFromSource = false;
2121
void defineFix() {
2222
TestProject p;
2323

24+
ProcessResult result;
25+
2426
final bullet = Logger.standard().ansi.bullet;
2527

2628
setUp(() => p = null);
2729

2830
tearDown(() => p?.dispose());
2931

32+
void assertResult({int exitCode = 0}) {
33+
String message;
34+
if (result.exitCode != exitCode) {
35+
if (result.stderr.isNotEmpty) {
36+
message = 'Error code was ${result.exitCode} and stderr was not empty';
37+
} else {
38+
message = 'Error code was ${result.exitCode}';
39+
}
40+
} else if (result.stderr.isNotEmpty) {
41+
message = 'stderr was not empty';
42+
} else {
43+
return;
44+
}
45+
fail('''
46+
$message
47+
48+
stdout:
49+
${result.stdout}
50+
51+
stderr:
52+
${result.stderr}
53+
''');
54+
}
55+
3056
ProcessResult runFix(List<String> args, {String workingDir}) {
3157
if (runFromSource) {
3258
var binary = path.join(Directory.current.path, 'bin', 'dartdev.dart');
@@ -188,7 +214,7 @@ linter:
188214
});
189215

190216
group('compare-to-golden', () {
191-
test('different', () {
217+
test('applied fixes do not match expected', () {
192218
p = project(
193219
mainSrc: '''
194220
class A {
@@ -215,12 +241,11 @@ class B extends A {
215241
String a() => '';
216242
}
217243
''');
218-
var result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
219-
expect(result.exitCode, 1);
220-
expect(result.stderr, isEmpty);
244+
result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
245+
assertResult(exitCode: 1);
221246
});
222247

223-
test('same', () {
248+
test('applied fixes match expected', () {
224249
p = project(
225250
mainSrc: '''
226251
class A {
@@ -248,9 +273,66 @@ class B extends A {
248273
String a() => '';
249274
}
250275
''');
251-
var result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
252-
expect(result.exitCode, 0);
253-
expect(result.stderr, isEmpty);
276+
result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
277+
assertResult();
278+
});
279+
280+
test('missing expect', () {
281+
p = project(
282+
mainSrc: '''
283+
class A {
284+
String a() => "";
285+
}
286+
287+
class B extends A {
288+
String a() => "";
289+
}
290+
''',
291+
analysisOptions: '''
292+
linter:
293+
rules:
294+
- annotate_overrides
295+
- prefer_single_quotes
296+
''',
297+
);
298+
result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
299+
assertResult(exitCode: 1);
300+
});
301+
302+
test('missing original', () {
303+
p = project(mainSrc: '''
304+
class C {}
305+
''');
306+
p.file('lib/main.dart.expect', '''
307+
class C {}
308+
''');
309+
p.file('lib/secondary.dart.expect', '''
310+
class A {}
311+
''');
312+
result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
313+
assertResult(exitCode: 1);
314+
});
315+
316+
test('no fixes to apply does not match expected', () {
317+
p = project(
318+
mainSrc: '''
319+
class A {
320+
String a() => "";
321+
}
322+
''',
323+
analysisOptions: '''
324+
linter:
325+
rules:
326+
- annotate_overrides
327+
''',
328+
);
329+
p.file('lib/main.dart.expect', '''
330+
class A {
331+
String a() => '';
332+
}
333+
''');
334+
result = runFix(['--compare-to-golden', '.'], workingDir: p.dirPath);
335+
assertResult(exitCode: 1);
254336
});
255337
});
256338
}

0 commit comments

Comments
 (0)