| Index: packages/analyzer/test/src/task/driver_test.dart
|
| diff --git a/packages/analyzer/test/src/task/driver_test.dart b/packages/analyzer/test/src/task/driver_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aed091c873488384ba1d5f1b20261a6dc9e21124
|
| --- /dev/null
|
| +++ b/packages/analyzer/test/src/task/driver_test.dart
|
| @@ -0,0 +1,793 @@
|
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library test.src.task.driver_test;
|
| +
|
| +import 'package:analyzer/src/context/cache.dart';
|
| +import 'package:analyzer/src/generated/engine.dart'
|
| + hide
|
| + AnalysisCache,
|
| + AnalysisContextImpl,
|
| + AnalysisTask,
|
| + UniversalCachePartition,
|
| + WorkManager;
|
| +import 'package:analyzer/src/generated/java_engine.dart';
|
| +import 'package:analyzer/src/task/driver.dart';
|
| +import 'package:analyzer/src/task/inputs.dart';
|
| +import 'package:analyzer/src/task/manager.dart';
|
| +import 'package:analyzer/task/model.dart';
|
| +import 'package:typed_mock/typed_mock.dart';
|
| +import 'package:unittest/unittest.dart';
|
| +
|
| +import '../../generated/test_support.dart';
|
| +import '../../reflective_tests.dart';
|
| +import '../../utils.dart';
|
| +import 'test_support.dart';
|
| +
|
| +main() {
|
| + initializeTestEnvironment();
|
| + runReflectiveTests(AnalysisDriverTest);
|
| + runReflectiveTests(CycleAwareDependencyWalkerTest);
|
| + runReflectiveTests(WorkItemTest);
|
| + runReflectiveTests(WorkOrderTest);
|
| +}
|
| +
|
| +class AbstractDriverTest {
|
| + TaskManager taskManager = new TaskManager();
|
| + List<WorkManager> workManagers = <WorkManager>[];
|
| + InternalAnalysisContext context = new _InternalAnalysisContextMock();
|
| + AnalysisDriver analysisDriver;
|
| +
|
| + void setUp() {
|
| + context = new _InternalAnalysisContextMock();
|
| + analysisDriver = new AnalysisDriver(taskManager, workManagers, context);
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class AnalysisDriverTest extends AbstractDriverTest {
|
| + WorkManager workManager1 = new _WorkManagerMock();
|
| + WorkManager workManager2 = new _WorkManagerMock();
|
| +
|
| + AnalysisTarget target1 = new TestSource('/1.dart');
|
| + AnalysisTarget target2 = new TestSource('/2.dart');
|
| +
|
| + ResultDescriptor result1 = new ResultDescriptor('result1', -1);
|
| + ResultDescriptor result2 = new ResultDescriptor('result2', -2);
|
| +
|
| + TaskDescriptor descriptor1;
|
| + TaskDescriptor descriptor2;
|
| +
|
| + void setUp() {
|
| + super.setUp();
|
| + when(workManager1.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.NONE);
|
| + when(workManager2.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.NONE);
|
| +
|
| + workManagers.add(workManager1);
|
| + workManagers.add(workManager2);
|
| + }
|
| +
|
| + test_computeResult() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + TestAnalysisTask task;
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', (context, target) => task, (target) => {}, [result]);
|
| + task = new TestAnalysisTask(context, target, descriptor: descriptor);
|
| + taskManager.addTaskDescriptor(descriptor);
|
| +
|
| + analysisDriver.computeResult(target, result);
|
| + expect(context.getCacheEntry(target).getValue(result), 1);
|
| + }
|
| +
|
| + test_create() {
|
| + expect(analysisDriver, isNotNull);
|
| + expect(analysisDriver.context, context);
|
| + expect(analysisDriver.currentWorkOrder, isNull);
|
| + expect(analysisDriver.taskManager, taskManager);
|
| + }
|
| +
|
| + test_createNextWorkOrder_highLow() {
|
| + _configureDescriptors12();
|
| + when(workManager1.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.PRIORITY);
|
| + when(workManager2.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.NORMAL);
|
| + when(workManager1.getNextResult())
|
| + .thenReturn(new TargetedResult(target1, result1));
|
| + WorkOrder workOrder = analysisDriver.createNextWorkOrder();
|
| + expect(workOrder, isNotNull);
|
| + expect(workOrder.moveNext(), true);
|
| + expect(workOrder.current.target, target1);
|
| + expect(workOrder.current.descriptor, descriptor1);
|
| + }
|
| +
|
| + test_createNextWorkOrder_lowHigh() {
|
| + _configureDescriptors12();
|
| + when(workManager1.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.NORMAL);
|
| + when(workManager2.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.PRIORITY);
|
| + when(workManager2.getNextResult())
|
| + .thenReturn(new TargetedResult(target1, result1));
|
| + WorkOrder workOrder = analysisDriver.createNextWorkOrder();
|
| + expect(workOrder, isNotNull);
|
| + expect(workOrder.moveNext(), true);
|
| + expect(workOrder.current.target, target1);
|
| + expect(workOrder.current.descriptor, descriptor1);
|
| + }
|
| +
|
| + test_createNextWorkOrder_none() {
|
| + _configureDescriptors12();
|
| + when(workManager1.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.NONE);
|
| + when(workManager2.getNextResultPriority())
|
| + .thenReturn(WorkOrderPriority.NONE);
|
| + expect(analysisDriver.createNextWorkOrder(), isNull);
|
| + }
|
| +
|
| + test_createWorkOrderForResult_error() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + CaughtException exception = new CaughtException(null, null);
|
| + context
|
| + .getCacheEntry(target)
|
| + .setErrorState(exception, <ResultDescriptor>[result]);
|
| +
|
| + expect(analysisDriver.createWorkOrderForResult(target, result), isNull);
|
| + }
|
| +
|
| + test_createWorkOrderForResult_inProcess() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + context.getCacheEntry(target).setState(result, CacheState.IN_PROCESS);
|
| +
|
| + expect(analysisDriver.createWorkOrderForResult(target, result), isNull);
|
| + }
|
| +
|
| + test_createWorkOrderForResult_invalid() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {},
|
| + [result]);
|
| + taskManager.addTaskDescriptor(descriptor);
|
| + context.getCacheEntry(target).setState(result, CacheState.INVALID);
|
| +
|
| + WorkOrder workOrder =
|
| + analysisDriver.createWorkOrderForResult(target, result);
|
| + expect(workOrder, isNotNull);
|
| + }
|
| +
|
| + test_createWorkOrderForResult_valid() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + context
|
| + .getCacheEntry(target)
|
| + .setValue(result, '', TargetedResult.EMPTY_LIST);
|
| +
|
| + expect(analysisDriver.createWorkOrderForResult(target, result), isNull);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_complete_generalTarget_generalResult() {
|
| + _createWorkOrderForTarget(true, false, false);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_complete_generalTarget_priorityResult() {
|
| + _createWorkOrderForTarget(true, false, true);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_complete_priorityTarget_generalResult() {
|
| + _createWorkOrderForTarget(true, true, false);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_complete_priorityTarget_priorityResult() {
|
| + _createWorkOrderForTarget(true, true, true);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_incomplete_generalTarget_generalResult() {
|
| + _createWorkOrderForTarget(false, false, false);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_incomplete_generalTarget_priorityResult() {
|
| + _createWorkOrderForTarget(false, false, true);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_incomplete_priorityTarget_generalResult() {
|
| + _createWorkOrderForTarget(false, true, false);
|
| + }
|
| +
|
| + test_createWorkOrderForTarget_incomplete_priorityTarget_priorityResult() {
|
| + _createWorkOrderForTarget(false, true, true);
|
| + }
|
| +
|
| + test_performAnalysisTask() {
|
| + _configureDescriptors12();
|
| + when(workManager1.getNextResultPriority()).thenReturnList(
|
| + <WorkOrderPriority>[WorkOrderPriority.NORMAL, WorkOrderPriority.NONE]);
|
| + when(workManager1.getNextResult())
|
| + .thenReturn(new TargetedResult(target1, result1));
|
| +
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + expect(analysisDriver.performAnalysisTask(), false);
|
| + }
|
| +
|
| + test_performAnalysisTask_infiniteLoop_handled() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor resultA = new ResultDescriptor('resultA', -1);
|
| + ResultDescriptor resultB = new ResultDescriptor('resultB', -2);
|
| + // configure tasks
|
| + TestAnalysisTask task1;
|
| + TestAnalysisTask task2;
|
| + TaskDescriptor descriptor1 = new TaskDescriptor(
|
| + 'task1',
|
| + (context, target) => task1,
|
| + (target) => {'inputB': new SimpleTaskInput<int>(target, resultB)},
|
| + [resultA]);
|
| + TaskDescriptor descriptor2 = new TaskDescriptor(
|
| + 'task2',
|
| + (context, target) => task2,
|
| + (target) => {'inputA': new SimpleTaskInput<int>(target, resultA)},
|
| + [resultB]);
|
| + task1 = new TestAnalysisTask(context, target,
|
| + descriptor: descriptor1,
|
| + results: [resultA],
|
| + value: 10,
|
| + handlesDependencyCycles: true);
|
| + task2 = new TestAnalysisTask(context, target,
|
| + descriptor: descriptor2,
|
| + results: [resultB],
|
| + value: 20,
|
| + handlesDependencyCycles: true);
|
| + taskManager.addTaskDescriptor(descriptor1);
|
| + taskManager.addTaskDescriptor(descriptor2);
|
| + // configure WorkManager
|
| + when(workManager1.getNextResultPriority()).thenReturnList(
|
| + <WorkOrderPriority>[WorkOrderPriority.NORMAL, WorkOrderPriority.NONE]);
|
| + when(workManager1.getNextResult())
|
| + .thenReturn(new TargetedResult(target, resultB));
|
| + // prepare work order
|
| + while (analysisDriver.performAnalysisTask()) {}
|
| + Set<TaskDescriptor> expectedCycle = [descriptor1, descriptor2].toSet();
|
| + expect(task1.dependencyCycle, isNotNull);
|
| + expect(task1.dependencyCycle.map((workItem) => workItem.descriptor).toSet(),
|
| + expectedCycle);
|
| + expect(task2.dependencyCycle, isNotNull);
|
| + expect(task2.dependencyCycle.map((workItem) => workItem.descriptor).toSet(),
|
| + expectedCycle);
|
| + CaughtException exception = context.getCacheEntry(target).exception;
|
| + expect(exception, isNull);
|
| + expect(context.getCacheEntry(target).getValue(resultA), 10);
|
| + expect(context.getCacheEntry(target).getValue(resultB), 20);
|
| + }
|
| +
|
| + test_performAnalysisTask_infiniteLoop_unhandled() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor resultA = new ResultDescriptor('resultA', -1);
|
| + ResultDescriptor resultB = new ResultDescriptor('resultB', -2);
|
| + // configure tasks
|
| + TestAnalysisTask task1;
|
| + TestAnalysisTask task2;
|
| + TaskDescriptor descriptor1 = new TaskDescriptor(
|
| + 'task1',
|
| + (context, target) => task1,
|
| + (target) => {'inputB': new SimpleTaskInput<int>(target, resultB)},
|
| + [resultA]);
|
| + TaskDescriptor descriptor2 = new TaskDescriptor(
|
| + 'task2',
|
| + (context, target) => task2,
|
| + (target) => {'inputA': new SimpleTaskInput<int>(target, resultA)},
|
| + [resultB]);
|
| + task1 = new TestAnalysisTask(context, target, descriptor: descriptor1);
|
| + task2 = new TestAnalysisTask(context, target, descriptor: descriptor2);
|
| + taskManager.addTaskDescriptor(descriptor1);
|
| + taskManager.addTaskDescriptor(descriptor2);
|
| + // configure WorkManager
|
| + when(workManager1.getNextResultPriority()).thenReturnList(
|
| + <WorkOrderPriority>[WorkOrderPriority.NORMAL, WorkOrderPriority.NONE]);
|
| + when(workManager1.getNextResult())
|
| + .thenReturn(new TargetedResult(target, resultB));
|
| + // prepare work order
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + CaughtException exception = context.getCacheEntry(target).exception;
|
| + expect(exception, isNotNull);
|
| + expect(exception.exception, new isInstanceOf<InfiniteTaskLoopException>());
|
| + }
|
| +
|
| + test_performAnalysisTask_inputsFirst() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor resultA = new ResultDescriptor('resultA', -1);
|
| + ResultDescriptor resultB = new ResultDescriptor('resultB', -2);
|
| + // configure tasks
|
| + TestAnalysisTask task1;
|
| + TestAnalysisTask task2;
|
| + TaskDescriptor descriptor1 = new TaskDescriptor(
|
| + 'task1', (context, target) => task1, (target) => {}, [resultA]);
|
| + TaskDescriptor descriptor2 = new TaskDescriptor(
|
| + 'task2',
|
| + (context, target) => task2,
|
| + (target) => {'inputA': new SimpleTaskInput<int>(target, resultA)},
|
| + [resultB]);
|
| + task1 = new TestAnalysisTask(context, target,
|
| + descriptor: descriptor1, results: [resultA], value: 10);
|
| + task2 = new TestAnalysisTask(context, target,
|
| + descriptor: descriptor2, value: 20);
|
| + taskManager.addTaskDescriptor(descriptor1);
|
| + taskManager.addTaskDescriptor(descriptor2);
|
| + // configure WorkManager
|
| + when(workManager1.getNextResultPriority()).thenReturnList(
|
| + <WorkOrderPriority>[WorkOrderPriority.NORMAL, WorkOrderPriority.NONE]);
|
| + when(workManager1.getNextResult())
|
| + .thenReturn(new TargetedResult(target, resultB));
|
| + // prepare work order
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + expect(context.getCacheEntry(target).getValue(resultA), -1);
|
| + expect(context.getCacheEntry(target).getValue(resultB), -2);
|
| + // compute resultA
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + expect(context.getCacheEntry(target).getValue(resultA), 10);
|
| + expect(context.getCacheEntry(target).getValue(resultB), -2);
|
| + // compute resultB
|
| + expect(analysisDriver.performAnalysisTask(), true);
|
| + expect(context.getCacheEntry(target).getValue(resultA), 10);
|
| + expect(context.getCacheEntry(target).getValue(resultB), 20);
|
| + // done
|
| + expect(analysisDriver.performAnalysisTask(), false);
|
| + }
|
| +
|
| + test_performAnalysisTask_onResultComputed() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + TestAnalysisTask task;
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', (context, target) => task, (target) => {}, [result]);
|
| + task = new TestAnalysisTask(context, target,
|
| + descriptor: descriptor, value: 42);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| +
|
| + bool streamNotified = false;
|
| + analysisDriver.onResultComputed(result).listen((event) {
|
| + streamNotified = true;
|
| + expect(event.context, same(context));
|
| + expect(event.target, same(target));
|
| + expect(event.descriptor, same(result));
|
| + expect(event.value, 42);
|
| + });
|
| + analysisDriver.performWorkItem(item);
|
| + expect(streamNotified, isTrue);
|
| + }
|
| +
|
| + test_performWorkItem_exceptionInTask() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + CaughtException exception =
|
| + new CaughtException(new AnalysisException(), null);
|
| + TestAnalysisTask task;
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', (context, target) => task, (target) => {}, [result]);
|
| + task = new TestAnalysisTask(context, target,
|
| + descriptor: descriptor, exception: exception);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| +
|
| + analysisDriver.performWorkItem(item);
|
| + CacheEntry targetEntry = context.getCacheEntry(item.target);
|
| + expect(targetEntry.exception, exception);
|
| + expect(targetEntry.getState(result), CacheState.ERROR);
|
| + }
|
| +
|
| + test_performWorkItem_noException() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + TestAnalysisTask task;
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', (context, target) => task, (target) => {}, [result]);
|
| + task = new TestAnalysisTask(context, target, descriptor: descriptor);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| +
|
| + analysisDriver.performWorkItem(item);
|
| + CacheEntry targetEntry = context.getCacheEntry(item.target);
|
| + expect(targetEntry.exception, isNull);
|
| + expect(targetEntry.getState(result), CacheState.VALID);
|
| + }
|
| +
|
| + test_performWorkItem_preExistingException() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {},
|
| + [result]);
|
| + CaughtException exception =
|
| + new CaughtException(new AnalysisException(), null);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| + item.exception = exception;
|
| +
|
| + analysisDriver.performWorkItem(item);
|
| + CacheEntry targetEntry = context.getCacheEntry(item.target);
|
| + expect(targetEntry.exception, exception);
|
| + expect(targetEntry.getState(result), CacheState.ERROR);
|
| + }
|
| +
|
| + test_reset() {
|
| + ResultDescriptor inputResult = new ResultDescriptor('input', null);
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {'one': inputResult.of(target)},
|
| + [new ResultDescriptor('output', null)]);
|
| + analysisDriver.currentWorkOrder =
|
| + new WorkOrder(taskManager, new WorkItem(null, null, descriptor, null));
|
| +
|
| + analysisDriver.reset();
|
| + expect(analysisDriver.currentWorkOrder, isNull);
|
| + }
|
| +
|
| + void _configureDescriptors12() {
|
| + descriptor1 = new TaskDescriptor(
|
| + 'task1',
|
| + (context, target) =>
|
| + new TestAnalysisTask(context, target, descriptor: descriptor1),
|
| + (target) => {},
|
| + [result1]);
|
| + taskManager.addTaskDescriptor(descriptor1);
|
| +
|
| + descriptor2 = new TaskDescriptor(
|
| + 'task2',
|
| + (context, target) =>
|
| + new TestAnalysisTask(context, target, descriptor: descriptor1),
|
| + (target) => {},
|
| + [result2]);
|
| + taskManager.addTaskDescriptor(descriptor2);
|
| + }
|
| +
|
| + /**
|
| + * [complete] is `true` if the value of the result has already been computed.
|
| + * [priorityTarget] is `true` if the target is in the list of priority
|
| + * targets.
|
| + * [priorityResult] is `true` if the result should only be computed for
|
| + * priority targets.
|
| + */
|
| + _createWorkOrderForTarget(
|
| + bool complete, bool priorityTarget, bool priorityResult) {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor result = new ResultDescriptor('result', null);
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {},
|
| + [result]);
|
| + if (priorityResult) {
|
| + taskManager.addPriorityResult(result);
|
| + } else {
|
| + taskManager.addGeneralResult(result);
|
| + }
|
| + taskManager.addTaskDescriptor(descriptor);
|
| + if (priorityTarget) {
|
| + context.priorityTargets.add(target);
|
| + } else {
|
| + context.explicitTargets.add(target);
|
| + }
|
| + if (complete) {
|
| + context
|
| + .getCacheEntry(target)
|
| + .setValue(result, '', TargetedResult.EMPTY_LIST);
|
| + } else {
|
| + context.getCacheEntry(target).setState(result, CacheState.INVALID);
|
| + }
|
| +
|
| + WorkOrder workOrder =
|
| + analysisDriver.createWorkOrderForTarget(target, priorityTarget);
|
| + if (complete) {
|
| + expect(workOrder, isNull);
|
| + } else if (priorityResult) {
|
| + expect(workOrder, priorityTarget ? isNotNull : isNull);
|
| + } else {
|
| + expect(workOrder, isNotNull);
|
| + }
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class CycleAwareDependencyWalkerTest {
|
| + void checkGraph(Map<int, List<int>> graph, int startingNode,
|
| + List<StronglyConnectedComponent<int>> expectedResults) {
|
| + List<Set<int>> expectedResultsDisregardingOrder =
|
| + expectedResults.map((component) => component.nodes.toSet()).toList();
|
| + List<bool> expectedCycleIndicators =
|
| + expectedResults.map((component) => component.containsCycle).toList();
|
| + List<Set<int>> results = <Set<int>>[];
|
| + List<bool> cycleIndicators = <bool>[];
|
| + _TestCycleAwareDependencyWalker walker =
|
| + new _TestCycleAwareDependencyWalker(graph, startingNode);
|
| + while (true) {
|
| + StronglyConnectedComponent<int> nextStronglyConnectedComponent =
|
| + walker.getNextStronglyConnectedComponent();
|
| + if (nextStronglyConnectedComponent == null) {
|
| + break;
|
| + }
|
| + results.add(nextStronglyConnectedComponent.nodes.toSet());
|
| + cycleIndicators.add(nextStronglyConnectedComponent.containsCycle);
|
| + walker.evaluatedNodes.addAll(nextStronglyConnectedComponent.nodes);
|
| + }
|
| + expect(results, expectedResultsDisregardingOrder);
|
| + expect(cycleIndicators, expectedCycleIndicators);
|
| + }
|
| +
|
| + StronglyConnectedComponent<int> cycle(List<int> nodes) =>
|
| + new StronglyConnectedComponent(nodes, true);
|
| +
|
| + StronglyConnectedComponent<int> singleton(int node) =>
|
| + new StronglyConnectedComponent(<int>[node], false);
|
| +
|
| + void test_complex_graph() {
|
| + checkGraph(
|
| + {
|
| + 1: [2, 3],
|
| + 2: [3, 4],
|
| + 3: [],
|
| + 4: [3, 5],
|
| + 5: [2, 6],
|
| + 6: [3, 4]
|
| + },
|
| + 1,
|
| + [
|
| + singleton(3),
|
| + cycle([2, 4, 5, 6]),
|
| + singleton(1)
|
| + ]);
|
| + }
|
| +
|
| + void test_cycle_depends_on_other_nodes() {
|
| + checkGraph(
|
| + {
|
| + 1: [2, 3],
|
| + 2: [4, 1],
|
| + 3: [],
|
| + 4: []
|
| + },
|
| + 1,
|
| + [
|
| + singleton(4),
|
| + singleton(3),
|
| + cycle([1, 2])
|
| + ]);
|
| + }
|
| +
|
| + void test_initial_node_depends_on_cycle() {
|
| + checkGraph(
|
| + {
|
| + 1: [2],
|
| + 2: [3],
|
| + 3: [2]
|
| + },
|
| + 1,
|
| + [
|
| + cycle([2, 3]),
|
| + singleton(1)
|
| + ]);
|
| + }
|
| +
|
| + void test_simple_cycle() {
|
| + checkGraph(
|
| + {
|
| + 1: [2],
|
| + 2: [1]
|
| + },
|
| + 1,
|
| + [
|
| + cycle([1, 2])
|
| + ]);
|
| + }
|
| +
|
| + void test_simple_dependency_chain() {
|
| + checkGraph(
|
| + {
|
| + 1: [2],
|
| + 2: []
|
| + },
|
| + 1,
|
| + [singleton(2), singleton(1)]);
|
| + }
|
| +
|
| + void test_single_node() {
|
| + checkGraph({1: []}, 1, [singleton(1)]);
|
| + }
|
| +
|
| + void test_single_node_cycle() {
|
| + checkGraph(
|
| + {
|
| + 1: [1]
|
| + },
|
| + 1,
|
| + [
|
| + cycle([1])
|
| + ]);
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class WorkItemTest extends AbstractDriverTest {
|
| + test_buildTask_complete() {
|
| + AnalysisTarget target = new TestSource();
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {},
|
| + [new ResultDescriptor('output', null)]);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| + AnalysisTask task = item.buildTask();
|
| + expect(task, isNotNull);
|
| + }
|
| +
|
| + test_buildTask_incomplete() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor inputResult = new ResultDescriptor('input', null);
|
| + List<ResultDescriptor> outputResults = <ResultDescriptor>[
|
| + new ResultDescriptor('output', null)
|
| + ];
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) =>
|
| + new TestAnalysisTask(context, target, results: outputResults),
|
| + (target) => {'one': inputResult.of(target)},
|
| + outputResults);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| + expect(() => item.buildTask(), throwsStateError);
|
| + }
|
| +
|
| + test_create() {
|
| + AnalysisTarget target = new TestSource();
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', null, (target) => {}, [new ResultDescriptor('result', null)]);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| + expect(item, isNotNull);
|
| + expect(item.context, context);
|
| + expect(item.descriptor, descriptor);
|
| + expect(item.target, target);
|
| + }
|
| +
|
| + test_gatherInputs_complete() {
|
| + AnalysisTarget target = new TestSource();
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {},
|
| + [new ResultDescriptor('output', null)]);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| + WorkItem result = item.gatherInputs(taskManager, []);
|
| + expect(result, isNull);
|
| + expect(item.exception, isNull);
|
| + }
|
| +
|
| + test_gatherInputs_incomplete() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor resultA = new ResultDescriptor('resultA', null);
|
| + ResultDescriptor resultB = new ResultDescriptor('resultB', null);
|
| + // prepare tasks
|
| + TaskDescriptor task1 = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) =>
|
| + new TestAnalysisTask(context, target, results: [resultA]),
|
| + (target) => {},
|
| + [resultA]);
|
| + TaskDescriptor task2 = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {'one': resultA.of(target)},
|
| + [resultB]);
|
| + taskManager.addTaskDescriptor(task1);
|
| + taskManager.addTaskDescriptor(task2);
|
| + // gather inputs
|
| + WorkItem item = new WorkItem(context, target, task2, null);
|
| + WorkItem inputItem = item.gatherInputs(taskManager, []);
|
| + expect(inputItem, isNotNull);
|
| + }
|
| +
|
| + test_gatherInputs_invalid() {
|
| + AnalysisTarget target = new TestSource();
|
| + ResultDescriptor inputResult = new ResultDescriptor('input', null);
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task',
|
| + (context, target) => new TestAnalysisTask(context, target),
|
| + (target) => {'one': inputResult.of(target)},
|
| + [new ResultDescriptor('output', null)]);
|
| + WorkItem item = new WorkItem(context, target, descriptor, null);
|
| + WorkItem result = item.gatherInputs(taskManager, []);
|
| + expect(result, isNull);
|
| + expect(item.exception, isNotNull);
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class WorkOrderTest extends EngineTestCase {
|
| + test_create() {
|
| + TaskManager manager = new TaskManager();
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', null, (_) => {}, [new ResultDescriptor('result', null)]);
|
| + WorkOrder order =
|
| + new WorkOrder(manager, new WorkItem(null, null, descriptor, null));
|
| + expect(order, isNotNull);
|
| + expect(order.currentItems, isNull);
|
| + expect(order.current, isNull);
|
| + }
|
| +
|
| + test_moveNext() {
|
| + TaskManager manager = new TaskManager();
|
| + TaskDescriptor descriptor = new TaskDescriptor(
|
| + 'task', null, (_) => {}, [new ResultDescriptor('result', null)]);
|
| + WorkItem workItem = new WorkItem(null, null, descriptor, null);
|
| + WorkOrder order = new WorkOrder(manager, workItem);
|
| + // "item" has no child items
|
| + expect(order.moveNext(), isTrue);
|
| + expect(order.current, workItem);
|
| + // done
|
| + expect(order.moveNext(), isFalse);
|
| + expect(order.current, isNull);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * A dummy [InternalAnalysisContext] that does not use [AnalysisDriver] itself,
|
| + * but provides enough implementation for it to function.
|
| + */
|
| +class _InternalAnalysisContextMock extends TypedMock
|
| + implements InternalAnalysisContext {
|
| + AnalysisCache analysisCache;
|
| +
|
| + @override
|
| + List<AnalysisTarget> explicitTargets = <AnalysisTarget>[];
|
| +
|
| + @override
|
| + List<AnalysisTarget> priorityTargets = <AnalysisTarget>[];
|
| +
|
| + _InternalAnalysisContextMock() {
|
| + analysisCache = new AnalysisCache([new UniversalCachePartition(this)]);
|
| + }
|
| +
|
| + @override
|
| + CacheEntry getCacheEntry(AnalysisTarget target) {
|
| + CacheEntry entry = analysisCache.get(target);
|
| + if (entry == null) {
|
| + entry = new CacheEntry(target);
|
| + analysisCache.put(entry);
|
| + }
|
| + return entry;
|
| + }
|
| +
|
| + noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
| +}
|
| +
|
| +/**
|
| + * Concrete class for testing [CycleAwareDependencyWalker] behavior.
|
| + */
|
| +class _TestCycleAwareDependencyWalker extends CycleAwareDependencyWalker<int> {
|
| + final Map<int, List<int>> graph;
|
| +
|
| + Set<int> evaluatedNodes = new Set<int>();
|
| +
|
| + _TestCycleAwareDependencyWalker(this.graph, int startingNode)
|
| + : super(startingNode);
|
| +
|
| + @override
|
| + int getNextInput(int node, List<int> skipInputs) {
|
| + for (int dependency in graph[node]) {
|
| + if (!skipInputs.contains(dependency) &&
|
| + !evaluatedNodes.contains(dependency)) {
|
| + return dependency;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +class _WorkManagerMock extends TypedMock implements WorkManager {
|
| + noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
| +}
|
|
|