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

import 'package:args/command_runner.dart';
6 7
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
8
import 'package:flutter_tools/src/artifacts.dart';
9
import 'package:flutter_tools/src/base/file_system.dart';
10 11 12
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/assemble.dart';
13
import 'package:flutter_tools/src/convert.dart';
14
import 'package:flutter_tools/src/features.dart';
15
import 'package:flutter_tools/src/globals.dart' as globals;
16

17
import '../../src/common.dart';
18
import '../../src/context.dart';
19
import '../../src/fakes.dart';
20
import '../../src/test_build_system.dart';
21
import '../../src/test_flutter_command_runner.dart';
22 23

void main() {
24
  Cache.disableLocking();
25
  Cache.flutterRoot = '';
26
  final StackTrace stackTrace = StackTrace.current;
27

28 29 30 31
  testUsingContext('flutter assemble can run a build', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true)),
    ));
32
    await commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']);
33 34

    expect(testLogger.traceText, contains('build succeeded.'));
35
  }, overrides: <Type, Generator>{
36
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
37 38
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
39 40
  });

41 42 43 44 45 46
  testUsingContext('flutter assemble can parse defines whose values contain =', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
        expect(environment.defines, containsPair('FooBar', 'fizz=2'));
      })
    ));
47
    await commandRunner.run(<String>['assemble', '-o Output', '-dFooBar=fizz=2', 'debug_macos_bundle_flutter_assets']);
48

49
    expect(testLogger.traceText, contains('build succeeded.'));
50
  }, overrides: <Type, Generator>{
51
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
52 53
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
54
  });
55

56
  testUsingContext('flutter assemble can parse inputs', () async {
57
    final AssembleCommand command = AssembleCommand(
58 59
      buildSystem: TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
        expect(environment.inputs, containsPair('Foo', 'Bar.txt'));
60 61
    }));
    final CommandRunner<void> commandRunner = createTestCommandRunner(command);
62 63 64
    await commandRunner.run(<String>['assemble', '-o Output', '-iFoo=Bar.txt', 'debug_macos_bundle_flutter_assets']);

    expect(testLogger.traceText, contains('build succeeded.'));
65 66 67 68 69 70 71 72 73 74 75
    expect(await command.requiredArtifacts, isEmpty);
  }, overrides: <Type, Generator>{
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
  });

  testUsingContext('flutter assemble sets required artifacts from target platform', () async {
    final AssembleCommand command = AssembleCommand(
        buildSystem: TestBuildSystem.all(BuildResult(success: true)));
    final CommandRunner<void> commandRunner = createTestCommandRunner(command);
76
    await commandRunner.run(<String>['assemble', '-o Output', '-dTargetPlatform=darwin', '-dDarwinArchs=x86_64', 'debug_macos_bundle_flutter_assets']);
77 78 79 80

    expect(await command.requiredArtifacts, <DevelopmentArtifact>{
      DevelopmentArtifact.macOS,
    });
81
  }, overrides: <Type, Generator>{
82
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
83 84
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
85
    FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
86 87
  });

88 89 90 91
  testUsingContext('flutter assemble throws ToolExit if not provided with output', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true)),
    ));
92

93 94
    expect(commandRunner.run(<String>['assemble', 'debug_macos_bundle_flutter_assets']), throwsToolExit());
  }, overrides: <Type, Generator>{
95
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
96 97
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
98
  });
99

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
  testUsingContext('flutter assemble throws ToolExit if dart-defines are not base64 encoded', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true)),
    ));

    final List<String> command = <String>[
      'assemble',
      '--output',
      'Output',
      '--DartDefines=flutter.inspector.structuredErrors%3Dtrue',
      'debug_macos_bundle_flutter_assets',
    ];
    expect(
      commandRunner.run(command),
      throwsToolExit(message: 'Error parsing assemble command: your generated configuration may be out of date')
    );
  }, overrides: <Type, Generator>{
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
  });

122 123 124 125
  testUsingContext('flutter assemble throws ToolExit if called with non-existent rule', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true)),
    ));
126

127
    expect(commandRunner.run(<String>['assemble', '-o Output', 'undefined']),
Dan Field's avatar
Dan Field committed
128
      throwsToolExit());
129
  }, overrides: <Type, Generator>{
130
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
131 132
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
133 134
  });

135 136 137
  testUsingContext('flutter assemble does not log stack traces during build failure', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: false, exceptions: <String, ExceptionMeasurement>{
138
        'hello': ExceptionMeasurement('hello', 'bar', stackTrace, fatal: true),
139 140
      }))
    ));
141 142

    await expectLater(commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']),
Dan Field's avatar
Dan Field committed
143
      throwsToolExit());
144
    expect(testLogger.errorText, contains('Target hello failed: bar'));
145 146
    expect(testLogger.errorText, isNot(contains(stackTrace.toString())));
  }, overrides: <Type, Generator>{
147
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
148 149
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
150
  });
151

152 153 154 155
  testUsingContext('flutter assemble outputs JSON performance data to provided file', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(
        BuildResult(success: true, performance: <String, PerformanceMeasurement>{
156 157
          'hello': PerformanceMeasurement(
            target: 'hello',
158
            analyticsName: 'bar',
159 160 161 162
            elapsedMilliseconds: 123,
            skipped: false,
            succeeded: true,
          ),
163 164 165
        }),
      ),
    ));
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

    await commandRunner.run(<String>[
      'assemble',
      '-o Output',
      '--performance-measurement-file=out.json',
      'debug_macos_bundle_flutter_assets',
    ]);

    expect(globals.fs.file('out.json'), exists);
    expect(
      json.decode(globals.fs.file('out.json').readAsStringSync()),
      containsPair('targets', contains(
        containsPair('name', 'bar'),
      )),
    );
181
  }, overrides: <Type, Generator>{
182
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
183 184
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
185 186
  });

187 188 189 190 191 192
  testUsingContext('flutter assemble does not inject engine revision with local-engine', () async {
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
        expect(environment.engineVersion, isNull);
      })
    ));
193 194
    await commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']);
  }, overrides: <Type, Generator>{
195
    Artifacts: () => Artifacts.test(localEngine: 'out/host_release'),
196
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
197 198
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
199 200
  });

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
  testUsingContext('flutter assemble only writes input and output files when the values change', () async {
    final BuildSystem buildSystem = TestBuildSystem.list(<BuildResult>[
      BuildResult(
        success: true,
        inputFiles: <File>[globals.fs.file('foo')..createSync()],
        outputFiles: <File>[globals.fs.file('bar')..createSync()],
      ),
      BuildResult(
        success: true,
        inputFiles: <File>[globals.fs.file('foo')..createSync()],
        outputFiles: <File>[globals.fs.file('bar')..createSync()],
      ),
      BuildResult(
        success: true,
        inputFiles: <File>[globals.fs.file('foo'), globals.fs.file('fizz')..createSync()],
        outputFiles: <File>[globals.fs.file('bar'), globals.fs.file(globals.fs.path.join('.dart_tool', 'fizz2'))..createSync(recursive: true)],
      ),
    ]);
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(buildSystem: buildSystem));
220 221 222 223 224 225 226
    await commandRunner.run(<String>[
      'assemble',
      '-o Output',
      '--build-outputs=outputs',
      '--build-inputs=inputs',
      'debug_macos_bundle_flutter_assets',
    ]);
227

228 229
    final File inputs = globals.fs.file('inputs');
    final File outputs = globals.fs.file('outputs');
230 231 232 233 234 235
    expect(inputs.readAsStringSync(), contains('foo'));
    expect(outputs.readAsStringSync(), contains('bar'));

    final DateTime theDistantPast = DateTime(1991, 8, 23);
    inputs.setLastModifiedSync(theDistantPast);
    outputs.setLastModifiedSync(theDistantPast);
236 237 238 239 240 241 242
    await commandRunner.run(<String>[
      'assemble',
      '-o Output',
      '--build-outputs=outputs',
      '--build-inputs=inputs',
      'debug_macos_bundle_flutter_assets',
    ]);
243 244 245 246

    expect(inputs.lastModifiedSync(), theDistantPast);
    expect(outputs.lastModifiedSync(), theDistantPast);

247 248 249 250 251 252 253
    await commandRunner.run(<String>[
      'assemble',
      '-o Output',
      '--build-outputs=outputs',
      '--build-inputs=inputs',
      'debug_macos_bundle_flutter_assets',
    ]);
254 255 256 257

    expect(inputs.readAsStringSync(), contains('foo'));
    expect(inputs.readAsStringSync(), contains('fizz'));
    expect(inputs.lastModifiedSync(), isNot(theDistantPast));
258
  }, overrides: <Type, Generator>{
259
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
260 261
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
262
  });
263 264 265 266

  testWithoutContext('writePerformanceData outputs performance data in JSON form', () {
    final List<PerformanceMeasurement> performanceMeasurement = <PerformanceMeasurement>[
      PerformanceMeasurement(
267
        analyticsName: 'foo',
268 269 270 271
        target: 'hidden',
        skipped: false,
        succeeded: true,
        elapsedMilliseconds: 123,
272
      ),
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    ];
    final FileSystem fileSystem = MemoryFileSystem.test();
    final File outFile = fileSystem.currentDirectory
      .childDirectory('foo')
      .childFile('out.json');

    writePerformanceData(performanceMeasurement, outFile);

    expect(outFile, exists);
    expect(json.decode(outFile.readAsStringSync()), <String, Object>{
      'targets': <Object>[
        <String, Object>{
          'name': 'foo',
          'skipped': false,
          'succeeded': true,
          'elapsedMilliseconds': 123,
        },
      ],
    });
  });
293

294 295 296 297 298 299 300 301 302 303 304
  testUsingContext('test --dart-define-from-file option with err file format', () {
    globals.fs.directory('config').createSync();
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true)),
    ));

    expect(commandRunner.run(<String>['assemble',
      '-o Output',
      'debug_macos_bundle_flutter_assets',
      '--dart-define=k=v',
      '--dart-define-from-file=config']),
305
        throwsToolExit(message: 'Did not find the file passed to "--dart-define-from-file". Path: config'));
306 307 308 309 310 311
  }, overrides: <Type, Generator>{
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
  });

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
  testUsingContext('test --dart-define-from-file option with err json format', () async {
    await globals.fs.file('config.json').writeAsString(
        '''
          {
            "kInt": 1,
            "kDouble": 1.1,
            "name": "err json format,
            "title": "this is title from config json file"
          }
        '''
    );
    final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
      buildSystem: TestBuildSystem.all(BuildResult(success: true)),
    ));

    expect(commandRunner.run(<String>['assemble',
      '-o Output',
      'debug_macos_bundle_flutter_assets',
      '--dart-define=k=v',
      '--dart-define-from-file=config.json']),
        throwsToolExit(message: 'Json config define file "--dart-define-from-file=config.json" format err, please fix first! format err:'));
  }, overrides: <Type, Generator>{
    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
    FileSystem: () => MemoryFileSystem.test(),
    ProcessManager: () => FakeProcessManager.any(),
  });
338
}