flutter/packages/flutter_tools/test/general.shard/base/context_test.dart
Michael Goderbauer 5491c8c146
Auto-format Framework (#160545)
This auto-formats all *.dart files in the repository outside of the
`engine` subdirectory and enforces that these files stay formatted with
a presubmit check.

**Reviewers:** Please carefully review all the commits except for the
one titled "formatted". The "formatted" commit was auto-generated by
running `dev/tools/format.sh -a -f`. The other commits were hand-crafted
to prepare the repo for the formatting change. I recommend reviewing the
commits one-by-one via the "Commits" tab and avoiding Github's "Files
changed" tab as it will likely slow down your browser because of the
size of this PR.

---------

Co-authored-by: Kate Lovett <katelovett@google.com>
Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
2024-12-19 20:06:21 +00:00

293 lines
8.8 KiB
Dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_tools/src/base/context.dart';
import '../../src/common.dart';
void main() {
group('AppContext', () {
group('global getter', () {
late bool called;
setUp(() {
called = false;
});
test('returns non-null context in the root zone', () {
expect(context, isNotNull);
});
test('returns root context in child of root zone if zone was manually created', () {
final Zone rootZone = Zone.current;
final AppContext rootContext = context;
runZoned<void>(() {
expect(Zone.current, isNot(rootZone));
expect(Zone.current.parent, rootZone);
expect(context, rootContext);
called = true;
});
expect(called, isTrue);
});
test('returns child context after run', () async {
final AppContext rootContext = context;
await rootContext.run<void>(
name: 'child',
body: () {
expect(context, isNot(rootContext));
expect(context.name, 'child');
called = true;
},
);
expect(called, isTrue);
});
test('returns grandchild context after nested run', () async {
final AppContext rootContext = context;
await rootContext.run<void>(
name: 'child',
body: () async {
final AppContext childContext = context;
await childContext.run<void>(
name: 'grandchild',
body: () {
expect(context, isNot(rootContext));
expect(context, isNot(childContext));
expect(context.name, 'grandchild');
called = true;
},
);
},
);
expect(called, isTrue);
});
test('scans up zone hierarchy for first context', () async {
final AppContext rootContext = context;
await rootContext.run<void>(
name: 'child',
body: () {
final AppContext childContext = context;
runZoned<void>(() {
expect(context, isNot(rootContext));
expect(context, same(childContext));
expect(context.name, 'child');
called = true;
});
},
);
expect(called, isTrue);
});
});
group('operator[]', () {
test('still finds values if async code runs after body has finished', () async {
final Completer<void> outer = Completer<void>();
final Completer<void> inner = Completer<void>();
String? value;
await context.run<void>(
body: () {
outer.future.then<void>((_) {
value = context.get<String>();
inner.complete();
});
},
fallbacks: <Type, Generator>{String: () => 'value'},
);
expect(value, isNull);
outer.complete();
await inner.future;
expect(value, 'value');
});
test('caches generated override values', () async {
int consultationCount = 0;
String? value;
await context.run<void>(
body: () async {
final StringBuffer buf = StringBuffer(context.get<String>()!);
buf.write(context.get<String>());
await context.run<void>(
body: () {
buf.write(context.get<String>());
},
);
value = buf.toString();
},
overrides: <Type, Generator>{
String: () {
consultationCount++;
return 'v';
},
},
);
expect(value, 'vvv');
expect(consultationCount, 1);
});
test('caches generated fallback values', () async {
int consultationCount = 0;
String? value;
await context.run(
body: () async {
final StringBuffer buf = StringBuffer(context.get<String>()!);
buf.write(context.get<String>());
await context.run<void>(
body: () {
buf.write(context.get<String>());
},
);
value = buf.toString();
},
fallbacks: <Type, Generator>{
String: () {
consultationCount++;
return 'v';
},
},
);
expect(value, 'vvv');
expect(consultationCount, 1);
});
test('returns null if generated value is null', () async {
final String? value = await context.run<String?>(
body: () => context.get<String>(),
overrides: <Type, Generator>{String: () => null},
);
expect(value, isNull);
});
test('throws if generator has dependency cycle', () async {
final Future<String?> value = context.run<String?>(
body: () async {
return context.get<String>();
},
fallbacks: <Type, Generator>{
int: () => int.parse(context.get<String>() ?? ''),
String: () => '${context.get<double>()}',
double: () => context.get<int>()! * 1.0,
},
);
expect(
() => value,
throwsA(
isA<ContextDependencyCycleException>()
.having((ContextDependencyCycleException error) => error.cycle, 'cycle', <Type>[
String,
double,
int,
])
.having(
(ContextDependencyCycleException error) => error.toString(),
'toString()',
'Dependency cycle detected: String -> double -> int',
),
),
);
});
});
group('run', () {
test('returns the value returned by body', () async {
expect(await context.run<int>(body: () => 123), 123);
expect(await context.run<String>(body: () => 'value'), 'value');
expect(await context.run<int>(body: () async => 456), 456);
});
test('passes name to child context', () async {
await context.run<void>(
name: 'child',
body: () {
expect(context.name, 'child');
},
);
});
group('fallbacks', () {
late bool called;
setUp(() {
called = false;
});
test('are applied after parent context is consulted', () async {
final String? value = await context.run<String?>(
body: () {
return context.run<String?>(
body: () {
called = true;
return context.get<String>();
},
fallbacks: <Type, Generator>{String: () => 'child'},
);
},
);
expect(called, isTrue);
expect(value, 'child');
});
test('are not applied if parent context supplies value', () async {
bool childConsulted = false;
final String? value = await context.run<String?>(
body: () {
return context.run<String?>(
body: () {
called = true;
return context.get<String>();
},
fallbacks: <Type, Generator>{
String: () {
childConsulted = true;
return 'child';
},
},
);
},
fallbacks: <Type, Generator>{String: () => 'parent'},
);
expect(called, isTrue);
expect(value, 'parent');
expect(childConsulted, isFalse);
});
test('may depend on one another', () async {
final String? value = await context.run<String?>(
body: () {
return context.get<String>();
},
fallbacks: <Type, Generator>{int: () => 123, String: () => '-${context.get<int>()}-'},
);
expect(value, '-123-');
});
});
group('overrides', () {
test('intercept consultation of parent context', () async {
bool parentConsulted = false;
final String? value = await context.run<String?>(
body: () {
return context.run<String?>(
body: () => context.get<String>(),
overrides: <Type, Generator>{String: () => 'child'},
);
},
fallbacks: <Type, Generator>{
String: () {
parentConsulted = true;
return 'parent';
},
},
);
expect(value, 'child');
expect(parentConsulted, isFalse);
});
});
});
});
}