1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file is run as part of a reduced test set in CI on Mac and Windows
6// machines.
7@Tags(<String>['reduced-test-set'])
8library;
9
10import 'package:flutter/material.dart';
11import 'package:flutter_test/flutter_test.dart';
12
13void main() {
14 group('Container control tests:', () {
15 final Container container = Container(
16 alignment: Alignment.bottomRight,
17 padding: const EdgeInsets.all(7.0),
18 // uses color, not decoration:
19 color: const Color(0xFF00FF00),
20 foregroundDecoration: const BoxDecoration(color: Color(0x7F0000FF)),
21 width: 53.0,
22 height: 76.0,
23 constraints: const BoxConstraints(
24 minWidth: 50.0,
25 maxWidth: 55.0,
26 minHeight: 78.0,
27 maxHeight: 82.0,
28 ),
29 margin: const EdgeInsets.all(5.0),
30 child: const SizedBox(
31 width: 25.0,
32 height: 33.0,
33 child: DecoratedBox(
34 // uses decoration, not color:
35 decoration: BoxDecoration(color: Color(0xFFFFFF00)),
36 ),
37 ),
38 );
39
40 testWidgets('paints as expected', (WidgetTester tester) async {
41 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
42
43 final RenderBox box = tester.renderObject(find.byType(Container));
44 expect(box, isNotNull);
45
46 expect(
47 box,
48 paints
49 ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0xFF00FF00))
50 ..rect(rect: const Rect.fromLTWH(26.0, 43.0, 25.0, 33.0), color: const Color(0xFFFFFF00))
51 ..rect(rect: const Rect.fromLTWH(5.0, 5.0, 53.0, 78.0), color: const Color(0x7F0000FF)),
52 );
53 });
54
55 group('diagnostics', () {
56 testWidgets('has reasonable default diagnostics', (WidgetTester tester) async {
57 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
58
59 final RenderBox box = tester.renderObject(find.byType(Container));
60
61 expect(container, hasOneLineDescription);
62 expect(box, hasAGoodToStringDeep);
63 });
64
65 testWidgets('has expected info diagnostics', (WidgetTester tester) async {
66 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
67
68 final RenderBox box = tester.renderObject(find.byType(Container));
69
70 expect(
71 box.toStringDeep(minLevel: DiagnosticLevel.info, wrapWidth: 640),
72 equalsIgnoringHashCodes(
73 'RenderPadding#00000 relayoutBoundary=up1\n'
74 ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
75 ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
76 ' │ size: Size(63.0, 88.0)\n'
77 ' │ padding: EdgeInsets.all(5.0)\n'
78 ' │\n'
79 ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n'
80 ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n'
81 ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
82 ' │ size: Size(53.0, 78.0)\n'
83 ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n'
84 ' │\n'
85 ' └─child: RenderDecoratedBox#00000\n'
86 ' │ parentData: <none> (can use size)\n'
87 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
88 ' │ size: Size(53.0, 78.0)\n'
89 ' │ decoration: BoxDecoration:\n'
90 ' │ color: ${const Color(0x7f0000ff)}\n'
91 ' │ configuration: ImageConfiguration(bundle: PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform: android)\n'
92 ' │\n'
93 ' └─child: _RenderColoredBox#00000\n'
94 ' │ parentData: <none> (can use size)\n'
95 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
96 ' │ size: Size(53.0, 78.0)\n'
97 ' │ behavior: opaque\n'
98 ' │\n'
99 ' └─child: RenderPadding#00000\n'
100 ' │ parentData: <none> (can use size)\n'
101 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
102 ' │ size: Size(53.0, 78.0)\n'
103 ' │ padding: EdgeInsets.all(7.0)\n'
104 ' │\n'
105 ' └─child: RenderPositionedBox#00000\n'
106 ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
107 ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
108 ' │ size: Size(39.0, 64.0)\n'
109 ' │ alignment: Alignment.bottomRight\n'
110 ' │ widthFactor: expand\n'
111 ' │ heightFactor: expand\n'
112 ' │\n'
113 ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n'
114 ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n'
115 ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n'
116 ' │ size: Size(25.0, 33.0)\n'
117 ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n'
118 ' │\n'
119 ' └─child: RenderDecoratedBox#00000\n'
120 ' parentData: <none> (can use size)\n'
121 ' constraints: BoxConstraints(w=25.0, h=33.0)\n'
122 ' size: Size(25.0, 33.0)\n'
123 ' decoration: BoxDecoration:\n'
124 ' color: ${const Color(0xffffff00)}\n'
125 ' configuration: ImageConfiguration(bundle: PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform: android)\n',
126 ),
127 );
128 });
129
130 testWidgets('has expected debug diagnostics', (WidgetTester tester) async {
131 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
132
133 final RenderBox box = tester.renderObject(find.byType(Container));
134
135 expect(
136 // Using the redundant value to ensure the test is explicitly for
137 // debug diagnostics, regardless of any changes to the default value.
138 // ignore: avoid_redundant_argument_values
139 box.toStringDeep(minLevel: DiagnosticLevel.debug, wrapWidth: 600),
140 equalsIgnoringHashCodes(
141 'RenderPadding#0f959 relayoutBoundary=up1\n'
142 ' │ creator: Padding ← Container ← Align ← _FocusInheritedScope ← '
143 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
144 'FocusTraversalGroup ← MediaQuery ← _MediaQueryFromView ← '
145 '_PipelineOwnerScope ← _ViewScope ← ⋯\n'
146 ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
147 ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
148 ' │ size: Size(63.0, 88.0)\n'
149 ' │ padding: EdgeInsets.all(5.0)\n'
150 ' │\n'
151 ' └─child: RenderConstrainedBox#df6d6 relayoutBoundary=up2\n'
152 ' │ creator: ConstrainedBox ← Padding ← Container ← Align ← '
153 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
154 '_FocusInheritedScope ← Focus ← FocusTraversalGroup ← MediaQuery ← '
155 '_MediaQueryFromView ← _PipelineOwnerScope ← ⋯\n'
156 ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n'
157 ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
158 ' │ size: Size(53.0, 78.0)\n'
159 ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n'
160 ' │\n'
161 ' └─child: RenderDecoratedBox#7b39b\n'
162 ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← '
163 'Container ← Align ← _FocusInheritedScope ← '
164 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
165 'FocusTraversalGroup ← MediaQuery ← _MediaQueryFromView ← ⋯\n'
166 ' │ parentData: <none> (can use size)\n'
167 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
168 ' │ size: Size(53.0, 78.0)\n'
169 ' │ decoration: BoxDecoration:\n'
170 ' │ color: ${const Color(0x7f0000ff)}\n'
171 ' │ configuration: ImageConfiguration(bundle: '
172 'PlatformAssetBundle#fe53b(), devicePixelRatio: 3.0, platform: '
173 'android)\n'
174 ' │\n'
175 ' └─child: _RenderColoredBox#6bd0d\n'
176 ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← '
177 'Padding ← Container ← Align ← _FocusInheritedScope ← '
178 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
179 'FocusTraversalGroup ← MediaQuery ← ⋯\n'
180 ' │ parentData: <none> (can use size)\n'
181 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
182 ' │ size: Size(53.0, 78.0)\n'
183 ' │ behavior: opaque\n'
184 ' │\n'
185 ' └─child: RenderPadding#d92f7\n'
186 ' │ creator: Padding ← ColoredBox ← DecoratedBox ← '
187 'ConstrainedBox ← Padding ← Container ← Align ← '
188 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
189 '_FocusInheritedScope ← Focus ← FocusTraversalGroup ← ⋯\n'
190 ' │ parentData: <none> (can use size)\n'
191 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
192 ' │ size: Size(53.0, 78.0)\n'
193 ' │ padding: EdgeInsets.all(7.0)\n'
194 ' │\n'
195 ' └─child: RenderPositionedBox#aaa32\n'
196 ' │ creator: Align ← Padding ← ColoredBox ← '
197 'DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ← '
198 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
199 '_FocusInheritedScope ← Focus ← ⋯\n'
200 ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
201 ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
202 ' │ size: Size(39.0, 64.0)\n'
203 ' │ alignment: Alignment.bottomRight\n'
204 ' │ widthFactor: expand\n'
205 ' │ heightFactor: expand\n'
206 ' │\n'
207 ' └─child: RenderConstrainedBox#49805 relayoutBoundary=up1\n'
208 ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← '
209 'DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ← '
210 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
211 '_FocusInheritedScope ← ⋯\n'
212 ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n'
213 ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n'
214 ' │ size: Size(25.0, 33.0)\n'
215 ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n'
216 ' │\n'
217 ' └─child: RenderDecoratedBox#7843f\n'
218 ' creator: DecoratedBox ← SizedBox ← Align ← '
219 'Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ← '
220 'Container ← Align ← _FocusInheritedScope ← '
221 '_FocusScopeWithExternalFocusNode ← ⋯\n'
222 ' parentData: <none> (can use size)\n'
223 ' constraints: BoxConstraints(w=25.0, h=33.0)\n'
224 ' size: Size(25.0, 33.0)\n'
225 ' decoration: BoxDecoration:\n'
226 ' color: ${const Color(0xffffff00)}\n'
227 ' configuration: ImageConfiguration(bundle: '
228 'PlatformAssetBundle#fe53b(), devicePixelRatio: 3.0, platform: '
229 'android)\n',
230 ),
231 );
232 });
233
234 testWidgets('has expected fine diagnostics', (WidgetTester tester) async {
235 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
236
237 final RenderBox box = tester.renderObject(find.byType(Container));
238
239 expect(
240 box.toStringDeep(minLevel: DiagnosticLevel.fine, wrapWidth: 600),
241 equalsIgnoringHashCodes(
242 'RenderPadding#68510 relayoutBoundary=up1\n'
243 ' │ creator: Padding ← Container ← Align ← _FocusInheritedScope ← '
244 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
245 'FocusTraversalGroup ← MediaQuery ← _MediaQueryFromView ← '
246 '_PipelineOwnerScope ← _ViewScope ← ⋯\n'
247 ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
248 ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
249 ' │ layer: null\n'
250 ' │ semantics node: null\n'
251 ' │ size: Size(63.0, 88.0)\n'
252 ' │ padding: EdgeInsets.all(5.0)\n'
253 ' │ textDirection: null\n'
254 ' │\n'
255 ' └─child: RenderConstrainedBox#69988 relayoutBoundary=up2\n'
256 ' │ creator: ConstrainedBox ← Padding ← Container ← Align ← '
257 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
258 '_FocusInheritedScope ← Focus ← FocusTraversalGroup ← MediaQuery ← '
259 '_MediaQueryFromView ← _PipelineOwnerScope ← ⋯\n'
260 ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n'
261 ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
262 ' │ layer: null\n'
263 ' │ semantics node: null\n'
264 ' │ size: Size(53.0, 78.0)\n'
265 ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n'
266 ' │\n'
267 ' └─child: RenderDecoratedBox#c7049\n'
268 ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← '
269 'Container ← Align ← _FocusInheritedScope ← '
270 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
271 'FocusTraversalGroup ← MediaQuery ← _MediaQueryFromView ← ⋯\n'
272 ' │ parentData: <none> (can use size)\n'
273 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
274 ' │ layer: null\n'
275 ' │ semantics node: null\n'
276 ' │ size: Size(53.0, 78.0)\n'
277 ' │ decoration: BoxDecoration:\n'
278 ' │ color: ${const Color(0x7f0000ff)}\n'
279 ' │ image: null\n'
280 ' │ border: null\n'
281 ' │ borderRadius: null\n'
282 ' │ boxShadow: null\n'
283 ' │ gradient: null\n'
284 ' │ shape: rectangle\n'
285 ' │ configuration: ImageConfiguration(bundle: '
286 'PlatformAssetBundle#23b2a(), devicePixelRatio: 3.0, platform: android)\n'
287 ' │\n'
288 ' └─child: _RenderColoredBox#c8805\n'
289 ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← '
290 'Padding ← Container ← Align ← _FocusInheritedScope ← '
291 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
292 'FocusTraversalGroup ← MediaQuery ← ⋯\n'
293 ' │ parentData: <none> (can use size)\n'
294 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
295 ' │ layer: null\n'
296 ' │ semantics node: null\n'
297 ' │ size: Size(53.0, 78.0)\n'
298 ' │ behavior: opaque\n'
299 ' │\n'
300 ' └─child: RenderPadding#0fab7\n'
301 ' │ creator: Padding ← ColoredBox ← DecoratedBox ← '
302 'ConstrainedBox ← Padding ← Container ← Align ← '
303 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
304 '_FocusInheritedScope ← Focus ← FocusTraversalGroup ← ⋯\n'
305 ' │ parentData: <none> (can use size)\n'
306 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
307 ' │ layer: null\n'
308 ' │ semantics node: null\n'
309 ' │ size: Size(53.0, 78.0)\n'
310 ' │ padding: EdgeInsets.all(7.0)\n'
311 ' │ textDirection: null\n'
312 ' │\n'
313 ' └─child: RenderPositionedBox#458fb\n'
314 ' │ creator: Align ← Padding ← ColoredBox ← '
315 'DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ← '
316 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
317 '_FocusInheritedScope ← Focus ← ⋯\n'
318 ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
319 ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
320 ' │ layer: null\n'
321 ' │ semantics node: null\n'
322 ' │ size: Size(39.0, 64.0)\n'
323 ' │ alignment: Alignment.bottomRight\n'
324 ' │ textDirection: null\n'
325 ' │ widthFactor: expand\n'
326 ' │ heightFactor: expand\n'
327 ' │\n'
328 ' └─child: RenderConstrainedBox#16613 relayoutBoundary=up1\n'
329 ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← '
330 'DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ← '
331 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
332 '_FocusInheritedScope ← ⋯\n'
333 ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n'
334 ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n'
335 ' │ layer: null\n'
336 ' │ semantics node: null\n'
337 ' │ size: Size(25.0, 33.0)\n'
338 ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n'
339 ' │\n'
340 ' └─child: RenderDecoratedBox#52bc3\n'
341 ' creator: DecoratedBox ← SizedBox ← Align ← '
342 'Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ← '
343 'Container ← Align ← _FocusInheritedScope ← '
344 '_FocusScopeWithExternalFocusNode ← ⋯\n'
345 ' parentData: <none> (can use size)\n'
346 ' constraints: BoxConstraints(w=25.0, h=33.0)\n'
347 ' layer: null\n'
348 ' semantics node: null\n'
349 ' size: Size(25.0, 33.0)\n'
350 ' decoration: BoxDecoration:\n'
351 ' color: ${const Color(0xffffff00)}\n'
352 ' image: null\n'
353 ' border: null\n'
354 ' borderRadius: null\n'
355 ' boxShadow: null\n'
356 ' gradient: null\n'
357 ' shape: rectangle\n'
358 ' configuration: ImageConfiguration(bundle: '
359 'PlatformAssetBundle#23b2a(), devicePixelRatio: 3.0, platform: android)\n',
360 ),
361 );
362 });
363
364 testWidgets('has expected hidden diagnostics', (WidgetTester tester) async {
365 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
366
367 final RenderBox box = tester.renderObject(find.byType(Container));
368
369 expect(
370 box.toStringDeep(minLevel: DiagnosticLevel.hidden, wrapWidth: 600),
371 equalsIgnoringHashCodes(
372 'RenderPadding#4a353 relayoutBoundary=up1\n'
373 ' │ needsCompositing: false\n'
374 ' │ creator: Padding ← Container ← Align ← _FocusInheritedScope ← '
375 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
376 'FocusTraversalGroup ← MediaQuery ← _MediaQueryFromView ← '
377 '_PipelineOwnerScope ← _ViewScope ← ⋯\n'
378 ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n'
379 ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n'
380 ' │ layer: null\n'
381 ' │ semantics node: null\n'
382 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
383 ' │ isSemanticBoundary: false\n'
384 ' │ size: Size(63.0, 88.0)\n'
385 ' │ padding: EdgeInsets.all(5.0)\n'
386 ' │ textDirection: null\n'
387 ' │\n'
388 ' └─child: RenderConstrainedBox#e3b23 relayoutBoundary=up2\n'
389 ' │ needsCompositing: false\n'
390 ' │ creator: ConstrainedBox ← Padding ← Container ← Align ← '
391 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
392 '_FocusInheritedScope ← Focus ← FocusTraversalGroup ← MediaQuery ← '
393 '_MediaQueryFromView ← _PipelineOwnerScope ← ⋯\n'
394 ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n'
395 ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n'
396 ' │ layer: null\n'
397 ' │ semantics node: null\n'
398 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
399 ' │ isSemanticBoundary: false\n'
400 ' │ size: Size(53.0, 78.0)\n'
401 ' │ additionalConstraints: BoxConstraints(w=53.0, h=78.0)\n'
402 ' │\n'
403 ' └─child: RenderDecoratedBox#1ca6c\n'
404 ' │ needsCompositing: false\n'
405 ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← '
406 'Container ← Align ← _FocusInheritedScope ← '
407 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
408 'FocusTraversalGroup ← MediaQuery ← _MediaQueryFromView ← ⋯\n'
409 ' │ parentData: <none> (can use size)\n'
410 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
411 ' │ layer: null\n'
412 ' │ semantics node: null\n'
413 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
414 ' │ isSemanticBoundary: false\n'
415 ' │ size: Size(53.0, 78.0)\n'
416 ' │ decoration: BoxDecoration:\n'
417 ' │ color: ${const Color(0x7f0000ff)}\n'
418 ' │ image: null\n'
419 ' │ border: null\n'
420 ' │ borderRadius: null\n'
421 ' │ boxShadow: null\n'
422 ' │ gradient: null\n'
423 ' │ shape: rectangle\n'
424 ' │ configuration: ImageConfiguration(bundle: '
425 'PlatformAssetBundle#fe2c8(), devicePixelRatio: 3.0, platform: '
426 'android)\n'
427 ' │\n'
428 ' └─child: _RenderColoredBox#cff14\n'
429 ' │ needsCompositing: false\n'
430 ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← '
431 'Padding ← Container ← Align ← _FocusInheritedScope ← '
432 '_FocusScopeWithExternalFocusNode ← _FocusInheritedScope ← Focus ← '
433 'FocusTraversalGroup ← MediaQuery ← ⋯\n'
434 ' │ parentData: <none> (can use size)\n'
435 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
436 ' │ layer: null\n'
437 ' │ semantics node: null\n'
438 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
439 ' │ isSemanticBoundary: false\n'
440 ' │ size: Size(53.0, 78.0)\n'
441 ' │ behavior: opaque\n'
442 ' │\n'
443 ' └─child: RenderPadding#f6d0f\n'
444 ' │ needsCompositing: false\n'
445 ' │ creator: Padding ← ColoredBox ← DecoratedBox ← '
446 'ConstrainedBox ← Padding ← Container ← Align ← '
447 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
448 '_FocusInheritedScope ← Focus ← FocusTraversalGroup ← ⋯\n'
449 ' │ parentData: <none> (can use size)\n'
450 ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n'
451 ' │ layer: null\n'
452 ' │ semantics node: null\n'
453 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
454 ' │ isSemanticBoundary: false\n'
455 ' │ size: Size(53.0, 78.0)\n'
456 ' │ padding: EdgeInsets.all(7.0)\n'
457 ' │ textDirection: null\n'
458 ' │\n'
459 ' └─child: RenderPositionedBox#4f7d2\n'
460 ' │ needsCompositing: false\n'
461 ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox '
462 '← ConstrainedBox ← Padding ← Container ← Align ← '
463 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
464 '_FocusInheritedScope ← Focus ← ⋯\n'
465 ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
466 ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
467 ' │ layer: null\n'
468 ' │ semantics node: null\n'
469 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
470 ' │ isSemanticBoundary: false\n'
471 ' │ size: Size(39.0, 64.0)\n'
472 ' │ alignment: Alignment.bottomRight\n'
473 ' │ textDirection: null\n'
474 ' │ widthFactor: expand\n'
475 ' │ heightFactor: expand\n'
476 ' │\n'
477 ' └─child: RenderConstrainedBox#81408 relayoutBoundary=up1\n'
478 ' │ needsCompositing: false\n'
479 ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← '
480 'DecoratedBox ← ConstrainedBox ← Padding ← Container ← Align ← '
481 '_FocusInheritedScope ← _FocusScopeWithExternalFocusNode ← '
482 '_FocusInheritedScope ← ⋯\n'
483 ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n'
484 ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n'
485 ' │ layer: null\n'
486 ' │ semantics node: null\n'
487 ' │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
488 ' │ isSemanticBoundary: false\n'
489 ' │ size: Size(25.0, 33.0)\n'
490 ' │ additionalConstraints: BoxConstraints(w=25.0, h=33.0)\n'
491 ' │\n'
492 ' └─child: RenderDecoratedBox#b5693\n'
493 ' needsCompositing: false\n'
494 ' creator: DecoratedBox ← SizedBox ← Align ← '
495 'Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ← '
496 'Container ← Align ← _FocusInheritedScope ← '
497 '_FocusScopeWithExternalFocusNode ← ⋯\n'
498 ' parentData: <none> (can use size)\n'
499 ' constraints: BoxConstraints(w=25.0, h=33.0)\n'
500 ' layer: null\n'
501 ' semantics node: null\n'
502 ' isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
503 ' isSemanticBoundary: false\n'
504 ' size: Size(25.0, 33.0)\n'
505 ' decoration: BoxDecoration:\n'
506 ' color: ${const Color(0xffffff00)}\n'
507 ' image: null\n'
508 ' border: null\n'
509 ' borderRadius: null\n'
510 ' boxShadow: null\n'
511 ' gradient: null\n'
512 ' shape: rectangle\n'
513 ' configuration: ImageConfiguration(bundle: '
514 'PlatformAssetBundle#fe2c8(), devicePixelRatio: 3.0, platform: android)\n',
515 ),
516 );
517 });
518
519 testWidgets('painting error has expected diagnostics', (WidgetTester tester) async {
520 await tester.pumpWidget(Align(alignment: Alignment.topLeft, child: container));
521
522 final RenderBox decoratedBox = tester.renderObject(find.byType(DecoratedBox).last);
523 final PaintingContext context = _MockPaintingContext();
524 late FlutterError error;
525 try {
526 decoratedBox.paint(context, Offset.zero);
527 } on FlutterError catch (e) {
528 error = e;
529 }
530 expect(error, isNotNull);
531 expect(
532 error.toStringDeep(wrapWidth: 600),
533 'FlutterError\n'
534 ' BoxDecoration painter had mismatching save and restore calls.\n'
535 ' Before painting the decoration, the canvas save count was 0. '
536 'After painting it, the canvas save count was 2. Every call to '
537 'save() or saveLayer() must be matched by a call to restore().\n'
538 ' The decoration was:\n'
539 ' BoxDecoration(color: ${const Color(0xffffff00)})\n'
540 ' The painter was:\n'
541 ' BoxPainter for BoxDecoration(color: '
542 '${const Color(0xffffff00)})\n',
543 );
544 });
545 });
546 });
547
548 testWidgets('Can be placed in an infinite box', (WidgetTester tester) async {
549 await tester.pumpWidget(
550 Directionality(
551 textDirection: TextDirection.ltr,
552 child: ListView(children: <Widget>[Container()]),
553 ),
554 );
555 });
556
557 testWidgets('Container transformAlignment', (WidgetTester tester) async {
558 final Key key = UniqueKey();
559
560 await tester.pumpWidget(
561 Directionality(
562 textDirection: TextDirection.ltr,
563 child: Stack(
564 children: <Widget>[
565 Positioned(
566 top: 100.0,
567 left: 100.0,
568 child: Container(width: 100.0, height: 100.0, color: const Color(0xFF0000FF)),
569 ),
570 Positioned(
571 top: 100.0,
572 left: 100.0,
573 child: Container(
574 width: 100.0,
575 height: 100.0,
576 key: key,
577 transform: Matrix4.diagonal3Values(0.5, 0.5, 1.0),
578 transformAlignment: Alignment.centerRight,
579 child: Container(color: const Color(0xFF00FFFF)),
580 ),
581 ),
582 ],
583 ),
584 ),
585 );
586
587 final Finder finder = find.byKey(key);
588
589 expect(tester.getSize(finder), equals(const Size(100, 100)));
590
591 expect(tester.getTopLeft(finder), equals(const Offset(100, 100)));
592 expect(tester.getTopRight(finder), equals(const Offset(200, 100)));
593
594 expect(tester.getBottomLeft(finder), equals(const Offset(100, 200)));
595 expect(tester.getBottomRight(finder), equals(const Offset(200, 200)));
596 });
597
598 testWidgets('giving clipBehaviour Clip.None, will not add a ClipPath to the tree', (
599 WidgetTester tester,
600 ) async {
601 await tester.pumpWidget(
602 Container(
603 decoration: const BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(1))),
604 child: const SizedBox(),
605 ),
606 );
607
608 expect(find.byType(ClipPath), findsNothing);
609 });
610
611 testWidgets('giving clipBehaviour not a Clip.None, will add a ClipPath to the tree', (
612 WidgetTester tester,
613 ) async {
614 final Container container = Container(
615 clipBehavior: Clip.hardEdge,
616 decoration: const BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(1))),
617 child: const SizedBox(),
618 );
619
620 await tester.pumpWidget(container);
621
622 expect(find.byType(ClipPath), findsOneWidget);
623 });
624
625 testWidgets('getClipPath() works for lots of kinds of decorations', (WidgetTester tester) async {
626 Future<void> test(Decoration decoration) async {
627 await tester.pumpWidget(
628 Directionality(
629 textDirection: TextDirection.rtl,
630 child: Center(
631 child: SizedBox(
632 width: 100.0,
633 height: 100.0,
634 child: RepaintBoundary(
635 child: Container(
636 clipBehavior: Clip.hardEdge,
637 decoration: decoration,
638 child: ColoredBox(color: Colors.yellow.withOpacity(0.5)),
639 ),
640 ),
641 ),
642 ),
643 ),
644 );
645 await expectLater(
646 find.byType(Container),
647 matchesGoldenFile('container_test.getClipPath.${decoration.runtimeType}.png'),
648 );
649 }
650
651 await test(const BoxDecoration());
652 await test(const UnderlineTabIndicator());
653 await test(const ShapeDecoration(shape: StadiumBorder()));
654 await test(const FlutterLogoDecoration());
655 });
656
657 testWidgets('Container is hittable only when having decorations', (WidgetTester tester) async {
658 bool tapped = false;
659 await tester.pumpWidget(
660 GestureDetector(
661 onTap: () {
662 tapped = true;
663 },
664 child: Container(decoration: const BoxDecoration(color: Colors.black)),
665 ),
666 );
667
668 await tester.tap(find.byType(Container));
669 expect(tapped, true);
670 tapped = false;
671
672 await tester.pumpWidget(
673 GestureDetector(
674 onTap: () {
675 tapped = true;
676 },
677 child: Container(foregroundDecoration: const BoxDecoration(color: Colors.black)),
678 ),
679 );
680
681 await tester.tap(find.byType(Container));
682 expect(tapped, true);
683 tapped = false;
684
685 await tester.pumpWidget(
686 GestureDetector(
687 onTap: () {
688 tapped = true;
689 },
690 child: Container(color: Colors.black),
691 ),
692 );
693
694 await tester.tap(find.byType(Container));
695 expect(tapped, true);
696 tapped = false;
697
698 // Everything but color or decorations
699 await tester.pumpWidget(
700 GestureDetector(
701 onTap: () {
702 tapped = true;
703 },
704 child: Center(
705 child: Container(
706 alignment: Alignment.bottomRight,
707 padding: const EdgeInsets.all(2),
708 width: 50,
709 height: 50,
710 margin: const EdgeInsets.all(2),
711 transform: Matrix4.rotationZ(1),
712 ),
713 ),
714 ),
715 );
716
717 await tester.tap(find.byType(Container), warnIfMissed: false);
718 expect(tapped, false);
719 });
720
721 testWidgets(
722 'Container discards alignment when the child parameter is null and constraints is not Tight',
723 (WidgetTester tester) async {
724 await tester.pumpWidget(
725 Container(
726 decoration: const BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(1))),
727 alignment: Alignment.centerLeft,
728 ),
729 );
730
731 expect(find.byType(Align), findsNothing);
732 },
733 );
734
735 testWidgets(
736 'Container with BorderRadiusDirectional and no Directionality throws a detailed error',
737 (WidgetTester tester) async {
738 await tester.pumpWidget(
739 Container(
740 decoration: BoxDecoration(
741 border: Border.all(),
742 borderRadius: const BorderRadiusDirectional.all(Radius.circular(1.0)),
743 ),
744 ),
745 );
746
747 expect(
748 tester.takeException(),
749 isFlutterError.having(
750 (FlutterError e) => e.message,
751 'message',
752 allOf(contains('No TextDirection found.'), contains('without a Directionality ancestor')),
753 ),
754 );
755 },
756 );
757
758 testWidgets('using clipBehaviour and shadow, should not clip the shadow', (
759 WidgetTester tester,
760 ) async {
761 final Container container = Container(
762 clipBehavior: Clip.hardEdge,
763 decoration: const BoxDecoration(
764 borderRadius: BorderRadius.all(Radius.circular(30)),
765 color: Colors.red,
766 boxShadow: <BoxShadow>[BoxShadow(color: Colors.blue, spreadRadius: 10, blurRadius: 20.0)],
767 ),
768 child: const SizedBox(width: 50, height: 50),
769 );
770
771 await tester.pumpWidget(
772 RepaintBoundary(
773 child: Padding(padding: const EdgeInsets.all(30.0), child: container),
774 ),
775 );
776
777 await expectLater(
778 find.byType(RepaintBoundary),
779 matchesGoldenFile('container.clipBehaviour.with.shadow.png'),
780 );
781 });
782}
783
784class _MockPaintingContext extends Fake implements PaintingContext {
785 @override
786 final Canvas canvas = _MockCanvas();
787}
788
789class _MockCanvas extends Fake implements Canvas {
790 int saveCount = 0;
791
792 @override
793 int getSaveCount() {
794 return saveCount++;
795 }
796
797 @override
798 void drawRect(Rect rect, Paint paint) {}
799}
800