Allow integration test helpers to work on substrings instead of whole strings (#160437)

The integration test framework that waits for transitions and
(optionally) takes actions on transitions allows to match patterns.

If one uses a RegExp pattern than the framework only checks whether a
line contains the given RegExp pattern.

If one uses a String pattern it matches it exactly.

=> We add a `Barrier.contains()` and `Multiple.contains()` that allow
matching a line with if it contains the String (just like in RegExp)

=> This makes tests simpler as they don't have to know about the exact
padding of progres bar etc. Those may be irrelevant for the purpose of
the integration test and only complicate it.
This commit is contained in:
Martin Kustermann 2024-12-20 18:27:33 +01:00 committed by GitHub
parent 188d1e1999
commit a44f745180
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 23 deletions

View File

@ -72,7 +72,7 @@ void main() {
<String>['run', '-d$device', '--$buildMode'],
exampleDirectory.path,
<Transition>[
Multiple(
Multiple.contains(
<Pattern>['Flutter run key commands.'],
handler: (String line) {
if (buildMode == 'debug') {
@ -85,7 +85,7 @@ void main() {
},
),
if (buildMode == 'debug') ...<Transition>[
Barrier('Performing hot reload...'.padRight(progressMessageWidth), logging: true),
Barrier.contains('Performing hot reload...', logging: true),
Multiple(
<Pattern>[RegExp('Reloaded .*')],
handler: (String line) {
@ -93,7 +93,7 @@ void main() {
return 'R';
},
),
Barrier('Performing hot restart...'.padRight(progressMessageWidth)),
Barrier.contains('Performing hot restart...'),
Multiple(
<Pattern>[RegExp('Restarted application .*')],
handler: (String line) {
@ -101,7 +101,7 @@ void main() {
return 'r';
},
),
Barrier('Performing hot reload...'.padRight(progressMessageWidth), logging: true),
Barrier.contains('Performing hot reload...', logging: true),
Multiple(
<Pattern>[RegExp('Reloaded .*')],
handler: (String line) {
@ -109,7 +109,7 @@ void main() {
},
),
],
const Barrier('Application finished.'),
Barrier.contains('Application finished.'),
],
logging: false,
);

View File

@ -56,7 +56,7 @@ void main() {
return 'q';
},
),
const Barrier('Application finished.'),
Barrier('Application finished.'),
],
);
expect(existsDuringTest, isNot(isNull));
@ -136,7 +136,7 @@ void main() {
return 'q';
},
),
const Barrier('Application finished.'),
Barrier('Application finished.'),
],
logging:
false, // we ignore leading log lines to avoid making this test sensitive to e.g. the help message text
@ -232,7 +232,7 @@ void main() {
return 'q';
},
),
const Barrier('Application finished.'),
Barrier('Application finished.'),
],
logging:
false, // we ignore leading log lines to avoid making this test sensitive to e.g. the help message text
@ -391,7 +391,7 @@ void main() {
return 'q';
},
),
const Barrier('Application finished.'),
Barrier('Application finished.'),
],
);
expect(result.exitCode, 0);

View File

@ -43,48 +43,56 @@ abstract class Transition {
bool matches(String line);
@protected
bool lineMatchesPattern(String line, Pattern pattern) {
if (pattern is String) {
return line == pattern;
bool lineMatchesPattern(String line, Pattern pattern, bool contains) {
if (pattern is RegExp) {
// Ideally this would also distinguish between "contains" and "equals"
// operation.
return line.contains(pattern);
}
return line.contains(pattern);
return contains ? line.contains(pattern) : line == pattern;
}
@protected
String describe(Pattern pattern) {
if (pattern is String) {
return '"$pattern"';
}
String describe(Pattern pattern, bool contains) {
if (pattern is RegExp) {
return '/${pattern.pattern}/';
}
return '$pattern';
return contains ? '"...$pattern..."' : '"$pattern"';
}
}
class Barrier extends Transition {
const Barrier(this.pattern, {super.handler, super.logging});
Barrier(this.pattern, {super.handler, super.logging}) : contains = false;
Barrier.contains(this.pattern, {super.handler, super.logging}) : contains = true;
final Pattern pattern;
final bool contains;
@override
bool matches(String line) => lineMatchesPattern(line, pattern);
bool matches(String line) => lineMatchesPattern(line, pattern, contains);
@override
String toString() => describe(pattern);
String toString() => describe(pattern, contains);
}
class Multiple extends Transition {
Multiple(List<Pattern> patterns, {super.handler, super.logging})
: _originalPatterns = patterns,
patterns = patterns.toList();
patterns = patterns.toList(),
contains = false;
Multiple.contains(List<Pattern> patterns, {super.handler, super.logging})
: _originalPatterns = patterns,
patterns = patterns.toList(),
contains = true;
final List<Pattern> _originalPatterns;
final List<Pattern> patterns;
final bool contains;
@override
bool matches(String line) {
for (int index = 0; index < patterns.length; index += 1) {
if (lineMatchesPattern(line, patterns[index])) {
if (lineMatchesPattern(line, patterns[index], contains)) {
patterns.removeAt(index);
break;
}
@ -94,6 +102,7 @@ class Multiple extends Transition {
@override
String toString() {
String describe(Pattern pattern) => super.describe(pattern, contains);
if (patterns.isEmpty) {
return '${_originalPatterns.map(describe).join(', ')} (all matched)';
}