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

5 6
import 'package:file/memory.dart';

7
import 'package:flutter_tools/src/artifacts.dart';
8
import 'package:flutter_tools/src/base/file_system.dart';
9
import 'package:flutter_tools/src/base/logger.dart';
10 11
import 'package:flutter_tools/src/build_info.dart';

12
import '../src/common.dart';
13
import '../src/context.dart';
14 15

void main() {
16
  late BufferLogger logger;
17 18 19
  setUp(() {
    logger = BufferLogger.test();
  });
20 21

  group('Validate build number', () {
22
    testWithoutContext('CFBundleVersion for iOS', () async {
23
      String? buildName = validatedBuildNumberForPlatform(TargetPlatform.ios, 'xyz', logger);
24
      expect(buildName, isNull);
25
      buildName = validatedBuildNumberForPlatform(TargetPlatform.ios, '0.0.1', logger);
26
      expect(buildName, '0.0.1');
27
      buildName = validatedBuildNumberForPlatform(TargetPlatform.ios, '123.xyz', logger);
28
      expect(buildName, '123');
29
      buildName = validatedBuildNumberForPlatform(TargetPlatform.ios, '123.456.xyz', logger);
30 31 32
      expect(buildName, '123.456');
    });

33
    testWithoutContext('versionCode for Android', () async {
34
      String? buildName = validatedBuildNumberForPlatform(TargetPlatform.android_arm, '123.abc+-', logger);
35
      expect(buildName, '123');
36
      buildName = validatedBuildNumberForPlatform(TargetPlatform.android_arm, 'abc', logger);
37 38 39 40 41
      expect(buildName, '1');
    });
  });

  group('Validate build name', () {
42
    testWithoutContext('CFBundleShortVersionString for iOS', () async {
43
      String? buildName = validatedBuildNameForPlatform(TargetPlatform.ios, 'xyz', logger);
44
      expect(buildName, isNull);
45
      buildName = validatedBuildNameForPlatform(TargetPlatform.ios, '0.0.1', logger);
46
      expect(buildName, '0.0.1');
47 48 49

      buildName = validatedBuildNameForPlatform(TargetPlatform.ios, '123.456.xyz', logger);
      expect(logger.traceText, contains('Invalid build-name'));
50
      expect(buildName, '123.456.0');
51 52

      buildName = validatedBuildNameForPlatform(TargetPlatform.ios, '123.xyz', logger);
53 54 55
      expect(buildName, '123.0.0');
    });

56
    testWithoutContext('versionName for Android', () async {
57
      String? buildName = validatedBuildNameForPlatform(TargetPlatform.android_arm, '123.abc+-', logger);
58
      expect(buildName, '123.abc+-');
59
      buildName = validatedBuildNameForPlatform(TargetPlatform.android_arm, 'abc+-', logger);
60 61
      expect(buildName, 'abc+-');
    });
62

63
    testWithoutContext('build mode configuration is correct', () {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
      expect(BuildMode.debug.isRelease, false);
      expect(BuildMode.debug.isPrecompiled, false);
      expect(BuildMode.debug.isJit, true);

      expect(BuildMode.profile.isRelease, false);
      expect(BuildMode.profile.isPrecompiled, true);
      expect(BuildMode.profile.isJit, false);

      expect(BuildMode.release.isRelease, true);
      expect(BuildMode.release.isPrecompiled, true);
      expect(BuildMode.release.isJit, false);

      expect(BuildMode.jitRelease.isRelease, true);
      expect(BuildMode.jitRelease.isPrecompiled, false);
      expect(BuildMode.jitRelease.isJit, true);

80 81 82 83 84
      expect(BuildMode.fromCliName('debug'), BuildMode.debug);
      expect(BuildMode.fromCliName('profile'), BuildMode.profile);
      expect(BuildMode.fromCliName('jit_release'), BuildMode.jitRelease);
      expect(BuildMode.fromCliName('release'), BuildMode.release);
      expect(() => BuildMode.fromCliName('foo'), throwsArgumentError);
85
    });
86
  });
87

88
  testWithoutContext('getDartNameForDarwinArch returns name used in Dart SDK', () {
89 90 91
    expect(DarwinArch.armv7.dartName,  'armv7');
    expect(DarwinArch.arm64.dartName,  'arm64');
    expect(DarwinArch.x86_64.dartName, 'x64');
92 93 94
  });

  testWithoutContext('getNameForDarwinArch returns Apple names', () {
95 96 97
    expect(DarwinArch.armv7.name,  'armv7');
    expect(DarwinArch.arm64.name,  'arm64');
    expect(DarwinArch.x86_64.name, 'x86_64');
98 99
  });

100
  testWithoutContext('getNameForTargetPlatform on Darwin arches', () {
101 102 103 104 105
    expect(getNameForTargetPlatform(TargetPlatform.ios, darwinArch: DarwinArch.arm64), 'ios-arm64');
    expect(getNameForTargetPlatform(TargetPlatform.ios, darwinArch: DarwinArch.armv7), 'ios-armv7');
    expect(getNameForTargetPlatform(TargetPlatform.ios, darwinArch: DarwinArch.x86_64), 'ios-x86_64');
    expect(getNameForTargetPlatform(TargetPlatform.android), isNot(contains('ios')));
  });
106

107
  testUsingContext('defaultIOSArchsForEnvironment', () {
108 109
    expect(defaultIOSArchsForEnvironment(
      EnvironmentType.physical,
110
      Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_unopt'),
111 112 113 114
    ).single, DarwinArch.arm64);

    expect(defaultIOSArchsForEnvironment(
      EnvironmentType.simulator,
115
      Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_sim_unopt'),
116 117 118 119
    ).single, DarwinArch.x86_64);

    expect(defaultIOSArchsForEnvironment(
      EnvironmentType.simulator,
120
      Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_sim_unopt_arm64'),
121 122 123 124 125 126 127 128 129
    ).single, DarwinArch.arm64);

    expect(defaultIOSArchsForEnvironment(
      EnvironmentType.physical, Artifacts.test(),
    ).single, DarwinArch.arm64);

    expect(defaultIOSArchsForEnvironment(
      EnvironmentType.simulator, Artifacts.test(),
    ), <DarwinArch>[ DarwinArch.x86_64, DarwinArch.arm64 ]);
130 131 132 133
  }, overrides: <Type, Generator>{
      FileSystem: () => MemoryFileSystem.test(),
      ProcessManager: () => FakeProcessManager.any(),
    });
134

135
  testUsingContext('defaultMacOSArchsForEnvironment', () {
136
    expect(defaultMacOSArchsForEnvironment(
137
      Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'host_debug_unopt'),
138 139 140
    ).single, DarwinArch.x86_64);

    expect(defaultMacOSArchsForEnvironment(
141
      Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'host_debug_unopt_arm64'),
142 143 144 145 146
    ).single, DarwinArch.arm64);

    expect(defaultMacOSArchsForEnvironment(
      Artifacts.test(),
    ), <DarwinArch>[ DarwinArch.x86_64, DarwinArch.arm64 ]);
147 148 149 150
  }, overrides: <Type, Generator>{
      FileSystem: () => MemoryFileSystem.test(),
      ProcessManager: () => FakeProcessManager.any(),
    });
151

152
  testWithoutContext('getIOSArchForName on Darwin arches', () {
153 154 155 156
    expect(getIOSArchForName('armv7'), DarwinArch.armv7);
    expect(getIOSArchForName('arm64'), DarwinArch.arm64);
    expect(getIOSArchForName('arm64e'), DarwinArch.arm64);
    expect(getIOSArchForName('x86_64'), DarwinArch.x86_64);
157
    expect(() => getIOSArchForName('bogus'), throwsException);
158
  });
159

160 161 162 163 164 165 166 167 168 169 170
  testWithoutContext('named BuildInfo has correct defaults', () {
    expect(BuildInfo.debug.mode, BuildMode.debug);
    expect(BuildInfo.debug.trackWidgetCreation, true);

    expect(BuildInfo.profile.mode, BuildMode.profile);
    expect(BuildInfo.profile.trackWidgetCreation, false);

    expect(BuildInfo.release.mode, BuildMode.release);
    expect(BuildInfo.release.trackWidgetCreation, false);
  });

171 172 173 174 175 176 177 178 179 180
  testWithoutContext('toBuildSystemEnvironment encoding of standard values', () {
    const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
      treeShakeIcons: true,
      trackWidgetCreation: true,
      dartDefines: <String>['foo=2', 'bar=2'],
      dartObfuscation: true,
      splitDebugInfoPath: 'foo/',
      extraFrontEndOptions: <String>['--enable-experiment=non-nullable', 'bar'],
      extraGenSnapshotOptions: <String>['--enable-experiment=non-nullable', 'fizz'],
      bundleSkSLPath: 'foo/bar/baz.sksl.json',
181
      packagesPath: 'foo/.dart_tool/package_config.json',
182 183 184
      codeSizeDirectory: 'foo/code-size',
      fileSystemRoots: <String>['test5', 'test6'],
      fileSystemScheme: 'scheme',
185 186
      buildName: '122',
      buildNumber: '22'
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    );

    expect(buildInfo.toBuildSystemEnvironment(), <String, String>{
      'BuildMode': 'debug',
      'DartDefines': 'Zm9vPTI=,YmFyPTI=',
      'DartObfuscation': 'true',
      'ExtraFrontEndOptions': '--enable-experiment=non-nullable,bar',
      'ExtraGenSnapshotOptions': '--enable-experiment=non-nullable,fizz',
      'SplitDebugInfo': 'foo/',
      'TrackWidgetCreation': 'true',
      'TreeShakeIcons': 'true',
      'BundleSkSLPath': 'foo/bar/baz.sksl.json',
      'CodeSizeDirectory': 'foo/code-size',
      'FileSystemRoots': 'test5,test6',
      'FileSystemScheme': 'scheme',
202 203
      'BuildName': '122',
      'BuildNumber': '22',
204 205 206
    });
  });

207
  testWithoutContext('toEnvironmentConfig encoding of standard values', () {
208 209 210 211 212 213 214 215
    const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
      treeShakeIcons: true,
      trackWidgetCreation: true,
      dartDefines: <String>['foo=2', 'bar=2'],
      dartObfuscation: true,
      splitDebugInfoPath: 'foo/',
      extraFrontEndOptions: <String>['--enable-experiment=non-nullable', 'bar'],
      extraGenSnapshotOptions: <String>['--enable-experiment=non-nullable', 'fizz'],
216
      bundleSkSLPath: 'foo/bar/baz.sksl.json',
217
      packagesPath: 'foo/.dart_tool/package_config.json',
218
      codeSizeDirectory: 'foo/code-size',
219 220
      // These values are ignored by toEnvironmentConfig
      androidProjectArgs: <String>['foo=bar', 'fizz=bazz']
221 222 223 224 225
    );

    expect(buildInfo.toEnvironmentConfig(), <String, String>{
      'TREE_SHAKE_ICONS': 'true',
      'TRACK_WIDGET_CREATION': 'true',
226
      'DART_DEFINES': 'Zm9vPTI=,YmFyPTI=',
227 228
      'DART_OBFUSCATION': 'true',
      'SPLIT_DEBUG_INFO': 'foo/',
229 230
      'EXTRA_FRONT_END_OPTIONS': '--enable-experiment=non-nullable,bar',
      'EXTRA_GEN_SNAPSHOT_OPTIONS': '--enable-experiment=non-nullable,fizz',
231
      'BUNDLE_SKSL_PATH': 'foo/bar/baz.sksl.json',
232
      'PACKAGE_CONFIG': 'foo/.dart_tool/package_config.json',
233
      'CODE_SIZE_DIRECTORY': 'foo/code-size',
234 235
    });
  });
236

237 238 239 240 241
  testWithoutContext('toGradleConfig encoding of standard values', () {
    const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
      treeShakeIcons: true,
      trackWidgetCreation: true,
      dartDefines: <String>['foo=2', 'bar=2'],
242
      dartDefineConfigJsonMap: <String, Object>{'baz': '2'},
243 244 245 246 247
      dartObfuscation: true,
      splitDebugInfoPath: 'foo/',
      extraFrontEndOptions: <String>['--enable-experiment=non-nullable', 'bar'],
      extraGenSnapshotOptions: <String>['--enable-experiment=non-nullable', 'fizz'],
      bundleSkSLPath: 'foo/bar/baz.sksl.json',
248
      packagesPath: 'foo/.dart_tool/package_config.json',
249
      codeSizeDirectory: 'foo/code-size',
250
      androidProjectArgs: <String>['foo=bar', 'fizz=bazz']
251 252 253 254 255 256 257 258 259 260 261
    );

    expect(buildInfo.toGradleConfig(), <String>[
      '-Pdart-defines=Zm9vPTI=,YmFyPTI=',
      '-Pdart-obfuscation=true',
      '-Pextra-front-end-options=--enable-experiment=non-nullable,bar',
      '-Pextra-gen-snapshot-options=--enable-experiment=non-nullable,fizz',
      '-Psplit-debug-info=foo/',
      '-Ptrack-widget-creation=true',
      '-Ptree-shake-icons=true',
      '-Pbundle-sksl-path=foo/bar/baz.sksl.json',
262 263
      '-Pcode-size-directory=foo/code-size',
      '-Pfoo=bar',
264
      '-Pfizz=bazz',
265
      '-Pbaz=2',
266 267 268
    ]);
  });

269
  testWithoutContext('encodeDartDefines encodes define values with base64 encoded components', () {
270 271 272 273 274
    expect(encodeDartDefines(<String>['"hello"']), 'ImhlbGxvIg==');
    expect(encodeDartDefines(<String>['https://www.google.com']), 'aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbQ==');
    expect(encodeDartDefines(<String>['2,3,4', '5']), 'MiwzLDQ=,NQ==');
    expect(encodeDartDefines(<String>['true', 'false', 'flase']), 'dHJ1ZQ==,ZmFsc2U=,Zmxhc2U=');
    expect(encodeDartDefines(<String>['1232,456', '2']), 'MTIzMiw0NTY=,Mg==');
275 276
  });

277
  testWithoutContext('decodeDartDefines decodes base64 encoded dart defines', () {
278
    expect(decodeDartDefines(<String, String>{
279
      kDartDefines: 'ImhlbGxvIg==',
280
    }, kDartDefines), <String>['"hello"']);
281
    expect(decodeDartDefines(<String, String>{
282
      kDartDefines: 'aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbQ==',
283
    }, kDartDefines), <String>['https://www.google.com']);
284
    expect(decodeDartDefines(<String, String>{
285
      kDartDefines: 'MiwzLDQ=,NQ==',
286
    }, kDartDefines), <String>['2,3,4', '5']);
287
    expect(decodeDartDefines(<String, String>{
288
      kDartDefines: 'dHJ1ZQ==,ZmFsc2U=,Zmxhc2U=',
289
    }, kDartDefines), <String>['true', 'false', 'flase']);
290
    expect(decodeDartDefines(<String, String>{
291
      kDartDefines: 'MTIzMiw0NTY=,Mg==',
292
    }, kDartDefines), <String>['1232,456', '2']);
293
  });
294 295 296 297 298 299 300

  group('Check repeated buildInfo variables', () {
    testUsingContext('toEnvironmentConfig repeated variable', () async {
      const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
          treeShakeIcons: true,
          trackWidgetCreation: true,
          dartDefines: <String>['foo=2', 'bar=2'],
301
          dartDefineConfigJsonMap: <String, Object>{'DART_DEFINES': 'Define a variable, but it occupies the variable name of the system'},
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
          dartObfuscation: true,
      );
      buildInfo.toEnvironmentConfig();
      expect(testLogger.warningText, contains('The key: [DART_DEFINES] already exists, you cannot use environment variables that have been used by the system'));
    });

    testUsingContext('toEnvironmentConfig repeated variable with DART_DEFINES not set', () async {
      // Simulate operation flutterCommand.getBuildInfo  with `dart-define-from-file` set dartDefines
      const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
          treeShakeIcons: true,
          dartDefines: <String>['DART_DEFINES=Define a variable, but it occupies the variable name of the system'],
          trackWidgetCreation: true,
          dartDefineConfigJsonMap: <String, Object>{ 'DART_DEFINES' : 'Define a variable, but it occupies the variable name of the system'},
          dartObfuscation: true,
      );
      buildInfo.toEnvironmentConfig();
      expect(testLogger.warningText, contains('The key: [DART_DEFINES] already exists, you cannot use environment variables that have been used by the system'));

    });

    testUsingContext('toGradleConfig repeated variable', () async {
      const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
          treeShakeIcons: true,
          trackWidgetCreation: true,
          dartDefines: <String>['foo=2', 'bar=2'],
327
          dartDefineConfigJsonMap: <String, Object>{'dart-defines': 'Define a variable, but it occupies the variable name of the system'},
328 329 330
          dartObfuscation: true,
      );
      buildInfo.toGradleConfig();
331
      expect(testLogger.warningText, contains('The key: [dart-defines] already exists, you cannot use gradle variables that have been used by the system'));
332 333 334 335 336 337 338 339
    });

    testUsingContext('toGradleConfig repeated variable with not set', () async {
      // Simulate operation flutterCommand.getBuildInfo  with `dart-define-from-file` set dartDefines
      const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
          treeShakeIcons: true,
          trackWidgetCreation: true,
          dartDefines: <String>['dart-defines=Define a variable, but it occupies the variable name of the system'],
340
          dartDefineConfigJsonMap: <String, Object>{'dart-defines': 'Define a variable, but it occupies the variable name of the system'},
341 342 343
          dartObfuscation: true,
      );
      buildInfo.toGradleConfig();
344
      expect(testLogger.warningText, contains('The key: [dart-defines] already exists, you cannot use gradle variables that have been used by the system'));
345 346 347 348 349 350 351
    });

    testUsingContext('toGradleConfig with androidProjectArgs override gradle project variant', () async {
      const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
          treeShakeIcons: true,
          trackWidgetCreation: true,
          androidProjectArgs: <String>['applicationId=com.google'],
352
          dartDefineConfigJsonMap: <String, Object>{'applicationId': 'override applicationId'},
353 354 355
          dartObfuscation: true,
      );
      buildInfo.toGradleConfig();
356
      expect(testLogger.warningText, contains('The key: [applicationId] already exists, you cannot use gradle variables that have been used by the system'));
357 358 359
    });

  });
360
}