Fix many minor performance problems in tests and main code (#1828)

diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart
index c4d6e9a..03ef2ad 100644
--- a/lib/src/dartdoc_options.dart
+++ b/lib/src/dartdoc_options.dart
@@ -806,14 +806,21 @@
     return _valueAtFromFiles(dir) ?? defaultsTo;
   }
 
+  Map<String, T> __valueAtFromFiles = new Map();
+  // The value of this option from files will not change unless files are
+  // modified during execution (not allowed in Dartdoc).
   T _valueAtFromFiles(Directory dir) {
-    _OptionValueWithContext valueWithContext;
-    if (parentDirOverridesChild) {
-      valueWithContext = _valueAtFromFilesLastFound(dir);
-    } else {
-      valueWithContext = _valueAtFromFilesFirstFound(dir);
+    String key = pathLib.canonicalize(dir.path);
+    if (!__valueAtFromFiles.containsKey(key)) {
+      _OptionValueWithContext valueWithContext;
+      if (parentDirOverridesChild) {
+        valueWithContext = _valueAtFromFilesLastFound(dir);
+      } else {
+        valueWithContext = _valueAtFromFilesFirstFound(dir);
+      }
+      __valueAtFromFiles[key] = _handlePathsInContext(valueWithContext);
     }
-    return _handlePathsInContext(valueWithContext);
+    return __valueAtFromFiles[key];
   }
 
   /// Searches all dartdoc_options files through parent directories,
diff --git a/lib/src/tool_runner.dart b/lib/src/tool_runner.dart
index c55ff4a..e919c8e 100644
--- a/lib/src/tool_runner.dart
+++ b/lib/src/tool_runner.dart
@@ -20,15 +20,20 @@
   /// Takes a [toolConfiguration] that describes all of the available tools.
   /// An optional `errorCallback` will be called for each error message
   /// generated by the tool.
-  ToolRunner(this.toolConfiguration, [this._errorCallback])
-      : temporaryDirectory =
-            Directory.systemTemp.createTempSync('dartdoc_tools_');
+  ToolRunner(this.toolConfiguration, [this._errorCallback]);
 
   final ToolConfiguration toolConfiguration;
-  final Directory temporaryDirectory;
   final ToolErrorCallback _errorCallback;
   int _temporaryFileCount = 0;
 
+  Directory _temporaryDirectory;
+  Directory get temporaryDirectory {
+    if (_temporaryDirectory == null) {
+      _temporaryDirectory = Directory.systemTemp.createTempSync('dartdoc_tools_');
+    }
+    return _temporaryDirectory;
+  }
+
   void _error(String message) {
     if (_errorCallback != null) {
       _errorCallback(message);
@@ -47,7 +52,7 @@
   ///
   /// This will remove any temporary files created by the tool runner.
   void dispose() {
-    if (temporaryDirectory.existsSync())
+    if (_temporaryDirectory != null && temporaryDirectory.existsSync())
       temporaryDirectory.deleteSync(recursive: true);
   }
 
diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart
index f47bb2b..370c9c7 100644
--- a/test/dartdoc_test.dart
+++ b/test/dartdoc_test.dart
@@ -20,12 +20,12 @@
   group('dartdoc with generators', () {
     Directory tempDir;
     List<String> outputParam;
-    setUp(() {
+    setUpAll(() {
       tempDir = Directory.systemTemp.createTempSync('dartdoc.test.');
       outputParam = ['--output', tempDir.path];
     });
 
-    tearDown(() {
+    tearDownAll(() {
       delete(tempDir);
     });
 
@@ -40,7 +40,7 @@
       DartdocResults results;
       PackageGraph p;
 
-      setUp(() async {
+      setUpAll(() async {
         dartdoc = await buildDartdoc([], testPackageOptions);
         results = await dartdoc.generateDocsBase();
         p = results.packageGraph;
@@ -73,23 +73,23 @@
         expect(Something.isPublic, isTrue);
         expect(Something.displayedCategories, isNotEmpty);
       });
+    });
 
-      test('errors generate errors even when warnings are off', () async {
-        Dartdoc dartdoc = await buildDartdoc([], testPackageToolError);
-        DartdocResults results = await dartdoc.generateDocsBase();
-        PackageGraph p = results.packageGraph;
-        Iterable<String> unresolvedToolErrors = p
-            .packageWarningCounter.countedWarnings.values
-            .expand<String>((Set<Tuple2<PackageWarning, String>> s) => s
-                .where((Tuple2<PackageWarning, String> t) =>
-                    t.item1 == PackageWarning.toolError)
-                .map<String>((Tuple2<PackageWarning, String> t) => t.item2));
+    test('errors generate errors even when warnings are off', () async {
+      Dartdoc dartdoc = await buildDartdoc([], testPackageToolError);
+      DartdocResults results = await dartdoc.generateDocsBase();
+      PackageGraph p = results.packageGraph;
+      Iterable<String> unresolvedToolErrors = p
+          .packageWarningCounter.countedWarnings.values
+          .expand<String>((Set<Tuple2<PackageWarning, String>> s) => s
+          .where((Tuple2<PackageWarning, String> t) =>
+      t.item1 == PackageWarning.toolError)
+          .map<String>((Tuple2<PackageWarning, String> t) => t.item2));
 
-        expect(p.packageWarningCounter.errorCount, equals(1));
-        expect(unresolvedToolErrors.length, equals(1));
-        expect(unresolvedToolErrors.first,
-            contains('Tool "drill" returned non-zero exit code'));
-      });
+      expect(p.packageWarningCounter.errorCount, equals(1));
+      expect(unresolvedToolErrors.length, equals(1));
+      expect(unresolvedToolErrors.first,
+          contains('Tool "drill" returned non-zero exit code'));
     });
 
     group('Invoking command-line dartdoc', () {
@@ -118,7 +118,7 @@
       DartdocResults results;
       Package testPackageOptions;
 
-      setUp(() async {
+      setUpAll(() async {
         results = await (await buildDartdoc(
                 ['--link-to-remote'], testPackageOptionsImporter))
             .generateDocsBase();
diff --git a/test/model_test.dart b/test/model_test.dart
index 01be3ef..cb69b0d 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -184,12 +184,11 @@
     Class htmlInjection;
     Method injectSimpleHtml;
 
-    setUp(() {
+    setUpAll(() {
       htmlInjection =
           exLibrary.classes.firstWhere((c) => c.name == 'HtmlInjection');
       injectSimpleHtml = htmlInjection.allInstanceMethods
           .firstWhere((m) => m.name == 'injectSimpleHtml');
-      packageGraph.allLocalModelElements.forEach((m) => m.documentation);
     });
     test("doesn't inject HTML if --inject-html option is not present", () {
       expect(
@@ -552,7 +551,7 @@
         reexportTwoLib;
     Class SomeClass, SomeOtherClass, YetAnotherClass, AUnicornClass;
 
-    setUp(() {
+    setUpAll(() {
       dartAsyncLib = utils.testPackageGraphSdk.libraries
           .firstWhere((l) => l.name == 'dart:async');
 
@@ -699,7 +698,7 @@
     Method withMacro, withMacro2, withPrivateMacro, withUndefinedMacro;
     EnumField macroReferencedHere;
 
-    setUp(() {
+    setUpAll(() {
       dog = exLibrary.classes.firstWhere((c) => c.name == 'Dog');
       withMacro =
           dog.allInstanceMethods.firstWhere((m) => m.name == 'withMacro');
@@ -751,7 +750,7 @@
     Method withAnimationBadHeight;
     Method withAnimationUnknownArg;
 
-    setUp(() {
+    setUpAll(() {
       documentationErrors = errorLibrary.classes
           .firstWhere((c) => c.name == 'DocumentationErrors');
       withInvalidNamedAnimation = documentationErrors.allInstanceMethods
@@ -768,7 +767,6 @@
           .firstWhere((m) => m.name == 'withAnimationBadHeight');
       withAnimationUnknownArg = documentationErrors.allInstanceMethods
           .firstWhere((m) => m.name == 'withAnimationUnknownArg');
-      packageGraphErrors.allLocalModelElements.forEach((m) => m.documentation);
     });
 
     test("warns with invalidly-named animation within the method documentation",
@@ -850,7 +848,7 @@
     Method withAnimationInline;
     Method withAnimationOutOfOrder;
 
-    setUp(() {
+    setUpAll(() {
       dog = exLibrary.classes.firstWhere((c) => c.name == 'Dog');
       withAnimation =
           dog.allInstanceMethods.firstWhere((m) => m.name == 'withAnimation');
@@ -866,7 +864,6 @@
           .firstWhere((m) => m.name == 'withAnimationInline');
       withAnimationOutOfOrder = dog.allInstanceMethods
           .firstWhere((m) => m.name == 'withAnimationOutOfOrder');
-      packageGraph.allLocalModelElements.forEach((m) => m.documentation);
     });
 
     test("renders an unnamed animation within the method documentation", () {
@@ -920,7 +917,7 @@
     Field aImplementingThingy;
     Accessor aImplementingThingyAccessor;
 
-    setUp(() {
+    setUpAll(() {
       BaseThingy =
           fakeLibrary.classes.firstWhere((c) => c.name == 'BaseThingy');
       BaseThingy2 =
@@ -966,7 +963,7 @@
 
     ModelFunction short;
 
-    setUp(() {
+    setUpAll(() {
       incorrectDocReferenceFromEx = exLibrary.constants
           .firstWhere((c) => c.name == 'incorrectDocReferenceFromEx');
       B = exLibrary.classes.firstWhere((c) => c.name == 'B');
@@ -1003,7 +1000,7 @@
       Class DocumentWithATable;
       String docsAsHtml;
 
-      setUp(() {
+      setUpAll(() {
         DocumentWithATable = fakeLibrary.classes
             .firstWhere((cls) => cls.name == 'DocumentWithATable');
         docsAsHtml = DocumentWithATable.documentationAsHtml;
@@ -1032,7 +1029,7 @@
     group('doc references', () {
       String docsAsHtml;
 
-      setUp(() {
+      setUpAll(() {
         docsAsHtml = doAwesomeStuff.documentationAsHtml;
       });
 
@@ -1358,7 +1355,7 @@
         overrideByBoth,
         overrideByModifierClass;
 
-    setUp(() {
+    setUpAll(() {
       Iterable<Class> classes = fakeLibrary.publicClasses;
       GenericClass = classes.firstWhere((c) => c.name == 'GenericClass');
       ModifierClass = classes.firstWhere((c) => c.name == 'ModifierClass');
@@ -1487,7 +1484,7 @@
     Class Apple, B, Cat, Cool, Dog, F, Dep, SpecialList;
     Class ExtendingClass, CatString;
 
-    setUp(() {
+    setUpAll(() {
       classes = exLibrary.publicClasses.toList();
       Apple = classes.firstWhere((c) => c.name == 'Apple');
       B = classes.firstWhere((c) => c.name == 'B');
@@ -1741,7 +1738,7 @@
   group('Enum', () {
     Enum animal;
 
-    setUp(() {
+    setUpAll(() {
       animal = exLibrary.enums.firstWhere((e) => e.name == 'Animal');
 
       /// Trigger code reference resolution
@@ -1809,7 +1806,7 @@
     ModelFunction topLevelFunction;
     ModelFunction typeParamOfFutureOr;
 
-    setUp(() {
+    setUpAll(() {
       f1 = exLibrary.functions.first;
       genericFunction =
           exLibrary.functions.firstWhere((f) => f.name == 'genericFunction');
@@ -1947,7 +1944,7 @@
   group('Type expansion', () {
     Class TemplatedInterface, ClassWithUnusualProperties;
 
-    setUp(() {
+    setUpAll(() {
       TemplatedInterface =
           exLibrary.classes.singleWhere((c) => c.name == 'TemplatedInterface');
       ClassWithUnusualProperties = fakeLibrary.classes
@@ -2116,7 +2113,7 @@
     Method inheritedClear, testGeneric, testGenericMethod;
     Method getAFunctionReturningVoid, getAFunctionReturningBool;
 
-    setUp(() {
+    setUpAll(() {
       klass = exLibrary.classes.singleWhere((c) => c.name == 'Klass');
       classB = exLibrary.classes.singleWhere((c) => c.name == 'B');
       HasGenerics =
@@ -2282,7 +2279,7 @@
     Class specializedDuration;
     Operator plus, equalsOverride;
 
-    setUp(() {
+    setUpAll(() {
       specializedDuration =
           exLibrary.classes.firstWhere((c) => c.name == 'SpecializedDuration');
       plus = specializedDuration.allOperators
@@ -2342,7 +2339,7 @@
     Field aProperty;
     Field covariantField, covariantSetter;
 
-    setUp(() {
+    setUpAll(() {
       c = exLibrary.classes.firstWhere((c) => c.name == 'Apple');
       f1 = c.staticProperties[0]; // n
       f2 = c.instanceProperties[0];
@@ -2655,7 +2652,7 @@
 
     Class classB;
 
-    setUp(() {
+    setUpAll(() {
       TopLevelVariable justGetter =
           fakeLibrary.properties.firstWhere((p) => p.name == 'justGetter');
       onlyGetterGetter = justGetter.getter;
@@ -2704,7 +2701,7 @@
     TopLevelVariable complicatedReturn;
     TopLevelVariable importantComputations;
 
-    setUp(() {
+    setUpAll(() {
       v = exLibrary.properties.firstWhere((p) => p.name == 'number');
       v3 = exLibrary.properties.firstWhere((p) => p.name == 'y');
       importantComputations = fakeLibrary.properties
@@ -2839,7 +2836,7 @@
 
     Field aStaticConstField, aName;
 
-    setUp(() {
+    setUpAll(() {
       greenConstant =
           exLibrary.constants.firstWhere((c) => c.name == 'COLOR_GREEN');
       orangeConstant =
@@ -2914,7 +2911,7 @@
     Constructor appleConstructorFromString;
     Constructor constructorTesterDefault, constructorTesterFromSomething;
     Class apple, constCat, constructorTester;
-    setUp(() {
+    setUpAll(() {
       apple = exLibrary.classes.firstWhere((c) => c.name == 'Apple');
       constCat = exLibrary.classes.firstWhere((c) => c.name == 'ConstantCat');
       constructorTester =
@@ -2973,7 +2970,7 @@
     ModelFunction returningFutureVoid, aVoidParameter;
     Class ExtendsFutureVoid, ImplementsFutureVoid, ATypeTakingClassMixedIn;
 
-    setUp(() {
+    setUpAll(() {
       returningFutureVoid = fakeLibrary.functions
           .firstWhere((f) => f.name == 'returningFutureVoid');
       aVoidParameter =
@@ -3043,7 +3040,7 @@
   group('ModelType', () {
     Field fList;
 
-    setUp(() {
+    setUpAll(() {
       fList = exLibrary.classes
           .firstWhere((c) => c.name == 'B')
           .instanceProperties
@@ -3061,7 +3058,7 @@
     Typedef aComplexTypedef;
     Class TypedefUsingClass;
 
-    setUp(() {
+    setUpAll(() {
       t = exLibrary.typedefs.firstWhere((t) => t.name == 'processMessage');
       generic =
           fakeLibrary.typedefs.firstWhere((t) => t.name == 'NewGenericTypedef');
@@ -3155,7 +3152,7 @@
         applyCovariantParams;
     Parameter intNumber, intCheckOptional;
 
-    setUp(() {
+    setUpAll(() {
       c = exLibrary.classes.firstWhere((c) => c.name == 'Apple');
       CovariantMemberParams = fakeLibrary.classes
           .firstWhere((c) => c.name == 'CovariantMemberParams');
@@ -3248,7 +3245,7 @@
     Class b;
     List<Class> implA, implC;
 
-    setUp(() {
+    setUpAll(() {
       apple = exLibrary.classes.firstWhere((c) => c.name == 'Apple');
       b = exLibrary.classes.firstWhere((c) => c.name == 'B');
       implA = apple.publicImplementors.toList();
@@ -3300,7 +3297,7 @@
   group('Annotations', () {
     Class forAnnotation, dog;
     Method ctr;
-    setUp(() {
+    setUpAll(() {
       forAnnotation =
           exLibrary.classes.firstWhere((c) => c.name == 'HasAnnotation');
       dog = exLibrary.classes.firstWhere((c) => c.name == 'Dog');