source_test.dart 7.05 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

8 9 10 11
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';
import 'package:flutter_tools/src/build_system/source.dart';
12
import 'package:flutter_tools/src/globals.dart' as globals;
13
import 'package:mockito/mockito.dart';
14
import 'package:platform/platform.dart';
15 16 17 18 19 20 21 22

import '../../src/common.dart';
import '../../src/testbed.dart';

void main() {
  Testbed testbed;
  SourceVisitor visitor;
  Environment environment;
23
  MockPlatform mockPlatform;
24 25

  setUp(() {
26 27
    mockPlatform = MockPlatform();
    when(mockPlatform.isWindows).thenReturn(true);
28
    testbed = Testbed(setup: () {
29 30
      globals.fs.directory('cache').createSync();
      final Directory outputs = globals.fs.directory('outputs')
31
          ..createSync();
32 33
      environment = Environment.test(
        globals.fs.currentDirectory,
34
        outputDir: outputs,
35 36 37 38 39 40 41 42 43 44 45 46
      );
      visitor = SourceVisitor(environment);
      environment.buildDir.createSync(recursive: true);
    });
  });

  test('configures implicit vs explict correctly', () => testbed.run(() {
    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(() {
47
    globals.fs.file('foo').createSync();
48 49 50
    const Source fooSource = Source.pattern('{PROJECT_DIR}/foo');
    fooSource.accept(visitor);

51
    expect(visitor.sources.single.path, globals.fs.path.absolute('foo'));
52 53
  }));

54
  test('can substitute {OUTPUT_DIR}/foo', () => testbed.run(() {
55
    globals.fs.file('foo').createSync();
56 57 58
    const Source fooSource = Source.pattern('{OUTPUT_DIR}/foo');
    fooSource.accept(visitor);

59
    expect(visitor.sources.single.path, globals.fs.path.absolute(globals.fs.path.join('outputs', 'foo')));
60 61 62
  }));


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

69
    expect(visitor.sources.single.path, globals.fs.path.absolute(path));
70 71 72
  }));

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

78
    expect(visitor.sources.single.path, globals.fs.path.absolute(path));
79 80 81
  }));

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

91
    expect(visitor.sources.single.resolveSymbolicLinksSync(), globals.fs.path.absolute(path));
92 93 94 95 96 97 98 99
  }));

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

    expect(visitor.sources, isEmpty);

100 101
    globals.fs.file('foo.fizz').createSync();
    globals.fs.file('foofizz').createSync();
102 103 104 105


    fizzSource.accept(visitor);

106
    expect(visitor.sources.single.path, globals.fs.path.absolute('foo.fizz'));
107 108 109 110 111 112 113 114
  }));

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

    expect(visitor.sources, isEmpty);

115 116
    globals.fs.file('fizz.foo').createSync();
    globals.fs.file('fizz').createSync();
117 118 119

    fizzSource.accept(visitor);

120
    expect(visitor.sources.single.path, globals.fs.path.absolute('fizz.foo'));
121 122 123 124 125 126 127 128 129
  }));


  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);

130 131
    globals.fs.file('bcbc').createSync();
    globals.fs.file('bc').createSync();
132 133 134

    fizzSource.accept(visitor);

135
    expect(visitor.sources.single.path, globals.fs.path.absolute('bcbc'));
136 137 138 139 140 141
  }));


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

142
    globals.fs.file('abcd.bar').createSync();
143

Dan Field's avatar
Dan Field committed
144
    expect(() => fizzSource.accept(visitor), throwsA(isA<InvalidPatternException>()));
145 146 147
  }));


148
  test("can't substitute foo", () => testbed.run(() {
149 150
    const Source invalidBase = Source.pattern('foo');

Dan Field's avatar
Dan Field committed
151
    expect(() => invalidBase.accept(visitor), throwsA(isA<InvalidPatternException>()));
152
  }));
153 154 155 156

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

157
    expect(globals.fs.file('foo').existsSync(), false);
158 159 160
    missingSource.accept(visitor);
    expect(visitor.sources, isEmpty);
  }));
161 162

  test('can resolve a missing depfile', () => testbed.run(() {
163
    visitor.visitDepfile('foo.d');
164 165 166 167 168 169 170 171 172

    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');

173
    visitor.visitDepfile('foo.d');
174 175 176 177
    expect(visitor.sources.single.path, 'c.dart');
    expect(visitor.containsNewDepfile, false);

    final SourceVisitor outputVisitor = SourceVisitor(environment, false);
178
    outputVisitor.visitDepfile('foo.d');
179 180 181 182 183 184 185 186 187

    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');

188
    visitor.visitDepfile('foo.d');
189 190 191 192 193 194 195 196
    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');

197
    visitor.visitDepfile('foo.d');
198 199 200 201 202 203 204 205 206 207
    expect(visitor.sources.single.path, r'C:\foo\bar.txt');
    expect(visitor.containsNewDepfile, false);
  }, overrides: <Type, Generator>{
    Platform: () => mockPlatform,
  }));

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

208
    visitor.visitDepfile('foo.d');
209 210 211
    expect(visitor.sources.single.path, r'foo bar.txt');
    expect(visitor.containsNewDepfile, false);
  }));
212 213
}

214
class MockPlatform extends Mock implements Platform {}