@@ -25,15 +25,66 @@ import 'package:test/test.dart';
2525
2626typedef DiagnosticMatcher = bool Function (Diagnostic diagnostic);
2727
28+ /// A description of a message that is expected to be reported with an error.
29+ class ExpectedContextMessage {
30+ /// The path of the file with which the message is associated.
31+ final File file;
32+
33+ /// The offset of the beginning of the error's region.
34+ final int offset;
35+
36+ /// The offset of the beginning of the error's region.
37+ final int length;
38+
39+ /// The message text for the error.
40+ final String ? text;
41+
42+ /// A list of patterns that should be contained in the message test; empty if
43+ /// the message contents should not be checked.
44+ final List <Pattern > textContains;
45+
46+ ExpectedContextMessage (
47+ this .file,
48+ this .offset,
49+ this .length, {
50+ this .text,
51+ this .textContains = const [],
52+ });
53+
54+ /// Return `true` if the [message] matches this description of what it's
55+ /// expected to be.
56+ bool matches (DiagnosticMessage message) {
57+ if (message.filePath != file.path) {
58+ return false ;
59+ }
60+ if (message.offset != offset) {
61+ return false ;
62+ }
63+ if (message.length != length) {
64+ return false ;
65+ }
66+ var messageText = message.messageText (includeUrl: true );
67+ if (text != null && messageText != text) {
68+ return false ;
69+ }
70+ for (var pattern in textContains) {
71+ if (! messageText.contains (pattern)) {
72+ return false ;
73+ }
74+ }
75+ return true ;
76+ }
77+ }
78+
2879/// A description of a diagnostic that is expected to be reported.
2980class ExpectedDiagnostic {
30- final DiagnosticMatcher _diagnosticMatcher ;
81+ final DiagnosticMatcher diagnosticMatcher ;
3182
3283 /// The offset of the beginning of the diagnostic's region.
33- final int _offset ;
84+ final int offset ;
3485
3586 /// The length of the diagnostic's region.
36- final int _length ;
87+ final int length ;
3788
3889 /// A pattern that should be contained in the diagnostic message or `null` if
3990 /// the message contents should not be checked.
@@ -43,20 +94,26 @@ class ExpectedDiagnostic {
4394 /// `null` if the correction message contents should not be checked.
4495 final Pattern ? _correctionContains;
4596
97+ /// The list of context messages that are expected to be associated with the
98+ /// error, or `null` if the context messages should not be checked.
99+ final List <ExpectedContextMessage >? _contextMessages;
100+
46101 ExpectedDiagnostic (
47- this ._diagnosticMatcher ,
48- this ._offset ,
49- this ._length , {
102+ this .diagnosticMatcher ,
103+ this .offset ,
104+ this .length , {
50105 Pattern ? messageContains,
51106 Pattern ? correctionContains,
52- }) : _messageContains = messageContains,
107+ List <ExpectedContextMessage >? contextMessages,
108+ }) : _contextMessages = contextMessages,
109+ _messageContains = messageContains,
53110 _correctionContains = correctionContains;
54111
55112 /// Whether the [diagnostic] matches this description of what it's expected to be.
56113 bool matches (Diagnostic diagnostic) {
57- if (! _diagnosticMatcher (diagnostic)) return false ;
58- if (diagnostic.offset != _offset ) return false ;
59- if (diagnostic.length != _length ) return false ;
114+ if (! diagnosticMatcher (diagnostic)) return false ;
115+ if (diagnostic.offset != offset ) return false ;
116+ if (diagnostic.length != length ) return false ;
60117 if (_messageContains != null &&
61118 ! diagnostic.message.contains (_messageContains)) {
62119 return false ;
@@ -68,6 +125,17 @@ class ExpectedDiagnostic {
68125 return false ;
69126 }
70127 }
128+ if (_contextMessages != null ) {
129+ var actualContextMessages = diagnostic.contextMessages.toList ();
130+ if (actualContextMessages.length != _contextMessages.length) {
131+ return false ;
132+ }
133+ for (int i = 0 ; i < _contextMessages.length; i++ ) {
134+ if (! _contextMessages[i].matches (actualContextMessages[i])) {
135+ return false ;
136+ }
137+ }
138+ }
71139
72140 return true ;
73141 }
@@ -77,13 +145,18 @@ class ExpectedDiagnostic {
77145final class ExpectedError extends ExpectedDiagnostic {
78146 final DiagnosticCode _code;
79147
80- ExpectedError (this ._code, int offset, int length, {Pattern ? messageContains})
81- : super (
82- (error) => error.diagnosticCode == _code,
83- offset,
84- length,
85- messageContains: messageContains,
86- );
148+ ExpectedError (
149+ this ._code,
150+ int offset,
151+ int length, {
152+ super .messageContains,
153+ super .correctionContains,
154+ super .contextMessages,
155+ }) : super (
156+ (diagnostic) => diagnostic.diagnosticCode == _code,
157+ offset,
158+ length,
159+ );
87160}
88161
89162/// A description of an expected lint rule violation.
@@ -96,7 +169,12 @@ final class ExpectedLint extends ExpectedDiagnostic {
96169 int length, {
97170 super .messageContains,
98171 super .correctionContains,
99- }) : super ((error) => error.diagnosticCode.name == _lintName, offset, length);
172+ super .contextMessages,
173+ }) : super (
174+ (diagnostic) => diagnostic.diagnosticCode.name == _lintName,
175+ offset,
176+ length,
177+ );
100178}
101179
102180class PubPackageResolutionTest with MockPackagesMixin , ResourceProviderMixin {
@@ -111,6 +189,9 @@ class PubPackageResolutionTest with MockPackagesMixin, ResourceProviderMixin {
111189
112190 AnalysisContextCollectionImpl ? _analysisContextCollection;
113191
192+ /// The test file being analyzed.
193+ late File testFile = newFile (_testFilePath, '' );
194+
114195 /// The analysis result that is used in various `assertDiagnostics` methods.
115196 late ResolvedUnitResult result;
116197
@@ -331,7 +412,18 @@ class PubPackageResolutionTest with MockPackagesMixin, ResourceProviderMixin {
331412 } else {
332413 buffer.write (' error(${actual .diagnosticCode }, ' );
333414 }
334- buffer.write ('${actual .offset }, ${actual .length }),' );
415+ buffer.write ('${actual .offset }, ${actual .length },' );
416+ if (actual.contextMessages.isNotEmpty) {
417+ buffer.write (' contextMessages: [' );
418+ for (var contextMessage in actual.contextMessages) {
419+ buffer.write ('contextMessage(' );
420+ buffer.write ("newFile('${contextMessage .filePath }'), " );
421+ buffer.write ('${contextMessage .offset }, ${contextMessage .length },' );
422+ buffer.write ('), ' );
423+ }
424+ buffer.write ('],' );
425+ }
426+ buffer.write ('),' );
335427 }
336428
337429 return buffer.toString ();
@@ -351,8 +443,8 @@ class PubPackageResolutionTest with MockPackagesMixin, ResourceProviderMixin {
351443 if (expected is ExpectedLint ) {
352444 buffer.write (expected._lintName);
353445 }
354- buffer.write (' [${expected ._offset }, ' );
355- buffer.write (expected._length );
446+ buffer.write (' [${expected .offset }, ' );
447+ buffer.write (expected.length );
356448 if (expected._messageContains case Pattern messageContains) {
357449 buffer.write (', messageContains: ' );
358450 buffer.write (json.encode (messageContains.toString ()));
@@ -484,7 +576,7 @@ class PubPackageResolutionTest with MockPackagesMixin, ResourceProviderMixin {
484576 }
485577
486578 void _addTestFile (String content) {
487- newFile (_testFilePath, content);
579+ testFile. writeAsStringSync ( content);
488580 }
489581
490582 DriverBasedAnalysisContext _contextFor (String path) {
0 commit comments