source_test.dart 7.88 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
7
import 'package:flutter_tools/src/base/platform.dart';
8 9 10
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/exceptions.dart';
11
import 'package:flutter_tools/src/globals.dart' as globals;
12 13

import '../../src/common.dart';
14
import '../../src/fake_process_manager.dart';
15 16
import '../../src/testbed.dart';

17 18 19 20
final Platform windowsPlatform = FakePlatform(
  operatingSystem: 'windows',
);

21
void main() {
22 23 24
  late Testbed testbed;
  late SourceVisitor visitor;
  late Environment environment;
25 26 27

  setUp(() {
    testbed = Testbed(setup: () {
28 29
      globals.fs.directory('cache').createSync();
      final Directory outputs = globals.fs.directory('outputs')
30
          ..createSync();
31 32
      environment = Environment.test(
        globals.fs.currentDirectory,
33
        outputDir: outputs,
34
        artifacts: globals.artifacts!, // using real artifacts
35 36
        processManager: FakeProcessManager.any(),
        fileSystem: globals.fs,
37
        // engineVersion being null simulates a local engine.
38
        logger: globals.logger,
39 40 41 42 43 44
      );
      visitor = SourceVisitor(environment);
      environment.buildDir.createSync(recursive: true);
    });
  });

45
  test('configures implicit vs explicit correctly', () => testbed.run(() {
46 47 48 49 50
    expect(const Source.pattern('{PROJECT_DIR}/foo').implicit, false);
    expect(const Source.pattern('{PROJECT_DIR}/*foo').implicit, true);
  }));

  test('can substitute {PROJECT_DIR}/foo', () => testbed.run(() {
51
    globals.fs.file('foo').createSync();
52 53 54
    const Source fooSource = Source.pattern('{PROJECT_DIR}/foo');
    fooSource.accept(visitor);

55
    expect(visitor.sources.single.path, globals.fs.path.absolute('foo'));
56 57
  }));

58
  test('can substitute {OUTPUT_DIR}/foo', () => testbed.run(() {
59
    globals.fs.file('foo').createSync();
60 61 62
    const Source fooSource = Source.pattern('{OUTPUT_DIR}/foo');
    fooSource.accept(visitor);

63
    expect(visitor.sources.single.path, globals.fs.path.absolute(globals.fs.path.join('outputs', 'foo')));
64 65 66
  }));


67
  test('can substitute {BUILD_DIR}/bar', () => testbed.run(() {
68 69
    final String path = globals.fs.path.join(environment.buildDir.path, 'bar');
    globals.fs.file(path).createSync();
70 71 72
    const Source barSource = Source.pattern('{BUILD_DIR}/bar');
    barSource.accept(visitor);

73
    expect(visitor.sources.single.path, globals.fs.path.absolute(path));
74 75 76
  }));

  test('can substitute {FLUTTER_ROOT}/foo', () => testbed.run(() {
77 78
    final String path = globals.fs.path.join(environment.flutterRootDir.path, 'foo');
    globals.fs.file(path).createSync();
79 80 81
    const Source barSource = Source.pattern('{FLUTTER_ROOT}/foo');
    barSource.accept(visitor);

82
    expect(visitor.sources.single.path, globals.fs.path.absolute(path));
83 84 85
  }));

  test('can substitute Artifact', () => testbed.run(() {
86 87
    final String path = globals.fs.path.join(
      globals.cache.getArtifactDirectory('engine').path,
88 89 90
      'windows-x64',
      'foo',
    );
91
    globals.fs.file(path).createSync(recursive: true);
92
    const Source fizzSource = Source.artifact(Artifact.windowsDesktopPath, platform: TargetPlatform.windows_x64);
93 94
    fizzSource.accept(visitor);

95
    expect(visitor.sources.single.resolveSymbolicLinksSync(), globals.fs.path.absolute(path));
96 97 98 99 100 101 102 103
  }));

  test('can substitute {PROJECT_DIR}/*.fizz', () => testbed.run(() {
    const Source fizzSource = Source.pattern('{PROJECT_DIR}/*.fizz');
    fizzSource.accept(visitor);

    expect(visitor.sources, isEmpty);

104 105
    globals.fs.file('foo.fizz').createSync();
    globals.fs.file('foofizz').createSync();
106 107 108 109


    fizzSource.accept(visitor);

110
    expect(visitor.sources.single.path, globals.fs.path.absolute('foo.fizz'));
111 112 113 114 115 116 117 118
  }));

  test('can substitute {PROJECT_DIR}/fizz.*', () => testbed.run(() {
    const Source fizzSource = Source.pattern('{PROJECT_DIR}/fizz.*');
    fizzSource.accept(visitor);

    expect(visitor.sources, isEmpty);

119 120
    globals.fs.file('fizz.foo').createSync();
    globals.fs.file('fizz').createSync();
121 122 123

    fizzSource.accept(visitor);

124
    expect(visitor.sources.single.path, globals.fs.path.absolute('fizz.foo'));
125 126 127 128 129 130 131 132 133
  }));


  test('can substitute {PROJECT_DIR}/a*bc', () => testbed.run(() {
    const Source fizzSource = Source.pattern('{PROJECT_DIR}/bc*bc');
    fizzSource.accept(visitor);

    expect(visitor.sources, isEmpty);

134 135
    globals.fs.file('bcbc').createSync();
    globals.fs.file('bc').createSync();
136 137 138

    fizzSource.accept(visitor);

139
    expect(visitor.sources.single.path, globals.fs.path.absolute('bcbc'));
140 141 142 143 144 145
  }));


  test('crashes on bad substitute of two **', () => testbed.run(() {
    const Source fizzSource = Source.pattern('{PROJECT_DIR}/*.*bar');

146
    globals.fs.file('abcd.bar').createSync();
147

Dan Field's avatar
Dan Field committed
148
    expect(() => fizzSource.accept(visitor), throwsA(isA<InvalidPatternException>()));
149 150 151
  }));


152
  test("can't substitute foo", () => testbed.run(() {
153 154
    const Source invalidBase = Source.pattern('foo');

Dan Field's avatar
Dan Field committed
155
    expect(() => invalidBase.accept(visitor), throwsA(isA<InvalidPatternException>()));
156
  }));
157 158 159 160

  test('can substitute optional files', () => testbed.run(() {
    const Source missingSource = Source.pattern('{PROJECT_DIR}/foo', optional: true);

161
    expect(globals.fs.file('foo').existsSync(), false);
162 163 164
    missingSource.accept(visitor);
    expect(visitor.sources, isEmpty);
  }));
165 166

  test('can resolve a missing depfile', () => testbed.run(() {
167
    visitor.visitDepfile('foo.d');
168 169 170 171 172 173 174 175 176

    expect(visitor.sources, isEmpty);
    expect(visitor.containsNewDepfile, true);
  }));

  test('can resolve a populated depfile', () => testbed.run(() {
    environment.buildDir.childFile('foo.d')
      .writeAsStringSync('a.dart : c.dart');

177
    visitor.visitDepfile('foo.d');
178 179 180 181
    expect(visitor.sources.single.path, 'c.dart');
    expect(visitor.containsNewDepfile, false);

    final SourceVisitor outputVisitor = SourceVisitor(environment, false);
182
    outputVisitor.visitDepfile('foo.d');
183 184 185 186 187 188 189 190 191

    expect(outputVisitor.sources.single.path, 'a.dart');
    expect(outputVisitor.containsNewDepfile, false);
  }));

  test('does not crash on completely invalid depfile', () => testbed.run(() {
    environment.buildDir.childFile('foo.d')
        .writeAsStringSync('hello, world');

192
    visitor.visitDepfile('foo.d');
193 194 195 196 197 198 199 200
    expect(visitor.sources, isEmpty);
    expect(visitor.containsNewDepfile, false);
  }));

  test('can parse depfile with windows paths', () => testbed.run(() {
    environment.buildDir.childFile('foo.d')
        .writeAsStringSync(r'a.dart: C:\\foo\\bar.txt');

201
    visitor.visitDepfile('foo.d');
202 203 204
    expect(visitor.sources.single.path, r'C:\foo\bar.txt');
    expect(visitor.containsNewDepfile, false);
  }, overrides: <Type, Generator>{
205
    Platform: () => windowsPlatform,
206 207 208 209 210 211
  }));

  test('can parse depfile with spaces in paths', () => testbed.run(() {
    environment.buildDir.childFile('foo.d')
        .writeAsStringSync(r'a.dart: foo\ bar.txt');

212
    visitor.visitDepfile('foo.d');
213 214 215
    expect(visitor.sources.single.path, r'foo bar.txt');
    expect(visitor.containsNewDepfile, false);
  }));
216 217

  test('Non-local engine builds use the engine.version file as an Artifact dependency', () => testbed.run(() {
218
    final Artifacts artifacts = Artifacts.test();
219 220
    final Environment environment = Environment.test(
      globals.fs.currentDirectory,
221
      artifacts: artifacts,
222 223 224 225 226 227 228
      processManager: FakeProcessManager.any(),
      fileSystem: globals.fs,
      logger: globals.logger,
      engineVersion: 'abcdefghijklmon' // Use a versioned engine.
    );
    visitor = SourceVisitor(environment);

229
    const Source fizzSource = Source.artifact(Artifact.windowsDesktopPath, platform: TargetPlatform.windows_x64);
230 231 232 233
    fizzSource.accept(visitor);

    expect(visitor.sources.single.path, contains('engine.version'));
  }));
234
}