2019-11-27 23:04:02 +00:00
|
|
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
2016-01-28 06:38:57 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:flutter_tools/src/base/context.dart';
|
2018-08-15 03:33:58 +00:00
|
|
|
|
2019-07-13 18:51:44 +00:00
|
|
|
import '../../src/common.dart';
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2016-03-10 01:43:14 +00:00
|
|
|
void main() {
|
2016-12-08 17:39:32 +00:00
|
|
|
group('AppContext', () {
|
2018-03-28 17:58:28 +00:00
|
|
|
group('global getter', () {
|
|
|
|
bool called;
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
setUp(() {
|
|
|
|
called = false;
|
2016-02-07 03:19:50 +00:00
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
test('returns non-null context in the root zone', () {
|
|
|
|
expect(context, isNotNull);
|
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
test('returns root context in child of root zone if zone was manually created', () {
|
|
|
|
final Zone rootZone = Zone.current;
|
|
|
|
final AppContext rootContext = context;
|
2018-10-01 19:29:08 +00:00
|
|
|
runZoned<void>(() {
|
2018-03-28 17:58:28 +00:00
|
|
|
expect(Zone.current, isNot(rootZone));
|
|
|
|
expect(Zone.current.parent, rootZone);
|
|
|
|
expect(context, rootContext);
|
|
|
|
called = true;
|
|
|
|
});
|
|
|
|
expect(called, isTrue);
|
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('returns child context after run', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
final AppContext rootContext = context;
|
2018-03-28 22:17:29 +00:00
|
|
|
await rootContext.run<void>(name: 'child', body: () {
|
2018-03-28 17:58:28 +00:00
|
|
|
expect(context, isNot(rootContext));
|
|
|
|
expect(context.name, 'child');
|
|
|
|
called = true;
|
|
|
|
});
|
|
|
|
expect(called, isTrue);
|
2016-02-07 03:19:50 +00:00
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('returns grandchild context after nested run', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
final AppContext rootContext = context;
|
2018-03-28 22:17:29 +00:00
|
|
|
await rootContext.run<void>(name: 'child', body: () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
final AppContext childContext = context;
|
2018-03-28 22:17:29 +00:00
|
|
|
await childContext.run<void>(name: 'grandchild', body: () {
|
2018-03-28 17:58:28 +00:00
|
|
|
expect(context, isNot(rootContext));
|
|
|
|
expect(context, isNot(childContext));
|
|
|
|
expect(context.name, 'grandchild');
|
|
|
|
called = true;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
expect(called, isTrue);
|
|
|
|
});
|
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('scans up zone hierarchy for first context', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
final AppContext rootContext = context;
|
2018-03-28 22:17:29 +00:00
|
|
|
await rootContext.run<void>(name: 'child', body: () {
|
2018-03-28 17:58:28 +00:00
|
|
|
final AppContext childContext = context;
|
2018-10-01 19:29:08 +00:00
|
|
|
runZoned<void>(() {
|
2018-03-28 17:58:28 +00:00
|
|
|
expect(context, isNot(rootContext));
|
|
|
|
expect(context, same(childContext));
|
|
|
|
expect(context.name, 'child');
|
|
|
|
called = true;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
expect(called, isTrue);
|
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
});
|
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
group('operator[]', () {
|
|
|
|
test('still finds values if async code runs after body has finished', () async {
|
2018-09-12 06:29:29 +00:00
|
|
|
final Completer<void> outer = Completer<void>();
|
|
|
|
final Completer<void> inner = Completer<void>();
|
2018-03-28 17:58:28 +00:00
|
|
|
String value;
|
2018-03-28 22:17:29 +00:00
|
|
|
await context.run<void>(
|
2018-03-28 17:58:28 +00:00
|
|
|
body: () {
|
2018-10-01 19:29:08 +00:00
|
|
|
outer.future.then<void>((_) {
|
2019-04-25 22:51:08 +00:00
|
|
|
value = context.get<String>();
|
2018-03-28 17:58:28 +00:00
|
|
|
inner.complete();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
String: () => 'value',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(value, isNull);
|
|
|
|
outer.complete();
|
|
|
|
await inner.future;
|
|
|
|
expect(value, 'value');
|
|
|
|
});
|
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('caches generated override values', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
int consultationCount = 0;
|
|
|
|
String value;
|
2018-03-28 22:17:29 +00:00
|
|
|
await context.run<void>(
|
|
|
|
body: () async {
|
2019-04-25 22:51:08 +00:00
|
|
|
final StringBuffer buf = StringBuffer(context.get<String>());
|
|
|
|
buf.write(context.get<String>());
|
2018-03-28 22:17:29 +00:00
|
|
|
await context.run<void>(body: () {
|
2019-04-25 22:51:08 +00:00
|
|
|
buf.write(context.get<String>());
|
2018-03-28 17:58:28 +00:00
|
|
|
});
|
|
|
|
value = buf.toString();
|
|
|
|
},
|
|
|
|
overrides: <Type, Generator>{
|
|
|
|
String: () {
|
|
|
|
consultationCount++;
|
|
|
|
return 'v';
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(value, 'vvv');
|
|
|
|
expect(consultationCount, 1);
|
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('caches generated fallback values', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
int consultationCount = 0;
|
|
|
|
String value;
|
2018-03-28 22:17:29 +00:00
|
|
|
await context.run(
|
|
|
|
body: () async {
|
2019-04-25 22:51:08 +00:00
|
|
|
final StringBuffer buf = StringBuffer(context.get<String>());
|
|
|
|
buf.write(context.get<String>());
|
2018-03-28 22:17:29 +00:00
|
|
|
await context.run<void>(body: () {
|
2019-04-25 22:51:08 +00:00
|
|
|
buf.write(context.get<String>());
|
2018-03-28 17:58:28 +00:00
|
|
|
});
|
|
|
|
value = buf.toString();
|
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
String: () {
|
|
|
|
consultationCount++;
|
|
|
|
return 'v';
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(value, 'vvv');
|
|
|
|
expect(consultationCount, 1);
|
2016-02-07 03:19:50 +00:00
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('returns null if generated value is null', () async {
|
|
|
|
final String value = await context.run<String>(
|
2019-04-25 22:51:08 +00:00
|
|
|
body: () => context.get<String>(),
|
2018-03-28 17:58:28 +00:00
|
|
|
overrides: <Type, Generator>{
|
|
|
|
String: () => null,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(value, isNull);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('throws if generator has dependency cycle', () async {
|
2018-03-28 22:17:29 +00:00
|
|
|
final Future<String> value = context.run<String>(
|
2018-03-28 17:58:28 +00:00
|
|
|
body: () async {
|
2019-04-25 22:51:08 +00:00
|
|
|
return context.get<String>();
|
2018-03-28 17:58:28 +00:00
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
2019-04-25 22:51:08 +00:00
|
|
|
int: () => int.parse(context.get<String>()),
|
|
|
|
String: () => '${context.get<double>()}',
|
|
|
|
double: () => context.get<int>() * 1.0,
|
2018-03-28 17:58:28 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
try {
|
|
|
|
await value;
|
|
|
|
fail('ContextDependencyCycleException expected but not thrown.');
|
|
|
|
} on ContextDependencyCycleException catch (e) {
|
|
|
|
expect(e.cycle, <Type>[String, double, int]);
|
|
|
|
expect(e.toString(), 'Dependency cycle detected: String -> double -> int');
|
|
|
|
}
|
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
});
|
2016-12-08 17:39:32 +00:00
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
group('run', () {
|
|
|
|
test('returns the value returned by body', () async {
|
2018-03-28 22:17:29 +00:00
|
|
|
expect(await context.run<int>(body: () => 123), 123);
|
|
|
|
expect(await context.run<String>(body: () => 'value'), 'value');
|
2018-04-09 19:43:31 +00:00
|
|
|
expect(await context.run<int>(body: () async => 456), 456);
|
2018-03-28 17:58:28 +00:00
|
|
|
});
|
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('passes name to child context', () async {
|
|
|
|
await context.run<void>(name: 'child', body: () {
|
2018-03-28 17:58:28 +00:00
|
|
|
expect(context.name, 'child');
|
2016-12-08 17:39:32 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
group('fallbacks', () {
|
|
|
|
bool called;
|
|
|
|
|
|
|
|
setUp(() {
|
|
|
|
called = false;
|
|
|
|
});
|
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('are applied after parent context is consulted', () async {
|
|
|
|
final String value = await context.run<String>(
|
2018-03-28 17:58:28 +00:00
|
|
|
body: () {
|
|
|
|
return context.run<String>(
|
|
|
|
body: () {
|
|
|
|
called = true;
|
2019-04-25 22:51:08 +00:00
|
|
|
return context.get<String>();
|
2018-03-28 17:58:28 +00:00
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
String: () => 'child',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(called, isTrue);
|
|
|
|
expect(value, 'child');
|
|
|
|
});
|
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('are not applied if parent context supplies value', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
bool childConsulted = false;
|
2018-03-28 22:17:29 +00:00
|
|
|
final String value = await context.run<String>(
|
2018-03-28 17:58:28 +00:00
|
|
|
body: () {
|
|
|
|
return context.run<String>(
|
|
|
|
body: () {
|
|
|
|
called = true;
|
2019-04-25 22:51:08 +00:00
|
|
|
return context.get<String>();
|
2018-03-28 17:58:28 +00:00
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
String: () {
|
|
|
|
childConsulted = true;
|
|
|
|
return 'child';
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
String: () => 'parent',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(called, isTrue);
|
|
|
|
expect(value, 'parent');
|
|
|
|
expect(childConsulted, isFalse);
|
|
|
|
});
|
|
|
|
|
2018-03-28 22:17:29 +00:00
|
|
|
test('may depend on one another', () async {
|
|
|
|
final String value = await context.run<String>(
|
2018-03-28 17:58:28 +00:00
|
|
|
body: () {
|
2019-04-25 22:51:08 +00:00
|
|
|
return context.get<String>();
|
2018-03-28 17:58:28 +00:00
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
int: () => 123,
|
2019-04-25 22:51:08 +00:00
|
|
|
String: () => '-${context.get<int>()}-',
|
2018-03-28 17:58:28 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(value, '-123-');
|
2016-12-08 17:39:32 +00:00
|
|
|
});
|
|
|
|
});
|
2017-01-12 17:31:27 +00:00
|
|
|
|
2018-03-28 17:58:28 +00:00
|
|
|
group('overrides', () {
|
2018-03-28 22:17:29 +00:00
|
|
|
test('intercept consultation of parent context', () async {
|
2018-03-28 17:58:28 +00:00
|
|
|
bool parentConsulted = false;
|
2018-03-28 22:17:29 +00:00
|
|
|
final String value = await context.run<String>(
|
2018-03-28 17:58:28 +00:00
|
|
|
body: () {
|
|
|
|
return context.run<String>(
|
2019-04-25 22:51:08 +00:00
|
|
|
body: () => context.get<String>(),
|
2018-03-28 17:58:28 +00:00
|
|
|
overrides: <Type, Generator>{
|
|
|
|
String: () => 'child',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
},
|
|
|
|
fallbacks: <Type, Generator>{
|
|
|
|
String: () {
|
|
|
|
parentConsulted = true;
|
|
|
|
return 'parent';
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expect(value, 'child');
|
|
|
|
expect(parentConsulted, isFalse);
|
2017-01-12 17:31:27 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2016-01-28 06:38:57 +00:00
|
|
|
});
|
|
|
|
}
|