1import * as fs from 'fs';
2import { vol } from 'memfs';
3
4import { XcodeProject } from '../../Plugin.types';
5import rnFixture from '../../plugins/__tests__/fixtures/react-native-project';
6import * as WarningAggregator from '../../utils/warnings';
7import { setBitcodeWithConfig } from '../Bitcode';
8import { getPbxproj, isNotComment } from '../utils/Xcodeproj';
9
10jest.mock('fs');
11jest.mock('../../utils/warnings');
12
13describe(setBitcodeWithConfig, () => {
14  const projectRoot = '/tablet';
15  beforeEach(async () => {
16    vol.fromJSON(
17      {
18        'ios/testproject.xcodeproj/project.pbxproj':
19          rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'],
20        'ios/testproject/AppDelegate.m': '',
21      },
22      projectRoot
23    );
24  });
25
26  afterEach(() => {
27    vol.reset();
28  });
29
30  it('defaults to not modifying the bitcode settings', async () => {
31    setBitcodeEnabledForRoot({ ios: {} }, projectRoot, validateDefaultBitcode);
32  });
33
34  it('enables bitcode for everything', async () => {
35    setBitcodeEnabledForRoot({ ios: { bitcode: true } }, projectRoot, (project) => {
36      const configurations = getConfigurations(project);
37      for (const [, configuration] of configurations) {
38        expect(configuration.buildSettings.ENABLE_BITCODE).toBe('YES');
39      }
40    });
41  });
42
43  it('disables bitcode for everything', async () => {
44    setBitcodeEnabledForRoot({ ios: { bitcode: false } }, projectRoot, (project) => {
45      const configurations = getConfigurations(project);
46      for (const [, configuration] of configurations) {
47        expect(configuration.buildSettings.ENABLE_BITCODE).toBe('NO');
48      }
49    });
50  });
51
52  it('enables bitcode on specific configuration', async () => {
53    setBitcodeEnabledForRoot({ ios: { bitcode: 'Debug' } }, projectRoot, (project) => {
54      const configurations = getConfigurations(project);
55      for (const [, configuration] of configurations) {
56        // ensure all others are disabled
57        expect(configuration.buildSettings.ENABLE_BITCODE).toBe(
58          configuration.name === 'Debug' ? 'YES' : 'NO'
59        );
60      }
61    });
62  });
63
64  it('warns when enabling bitcode on an invalid configuration', async () => {
65    setBitcodeEnabledForRoot({ ios: { bitcode: 'Bacon' } }, projectRoot, validateDefaultBitcode);
66    expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith(
67      'ios.bitcode',
68      'No configuration named "Bacon". Expected one of: "Debug", "Release".'
69    );
70  });
71});
72
73function getConfigurations(project: XcodeProject) {
74  return Object.entries(project.pbxXCBuildConfigurationSection()).filter(isNotComment);
75}
76
77function setBitcodeEnabledForRoot(
78  config: { ios?: { bitcode?: boolean | string } & any },
79  projectRoot: string,
80  validate: (project: XcodeProject) => void
81) {
82  let project = getPbxproj(projectRoot);
83  project = setBitcodeWithConfig(config, { project });
84  validate(project);
85  fs.writeFileSync(project.filepath, project.writeSync());
86}
87
88function validateDefaultBitcode(project: XcodeProject) {
89  const configurations = getConfigurations(project);
90  for (const [id, configuration] of configurations) {
91    expect(configuration.buildSettings.ENABLE_BITCODE).toBe(
92      // Ensure nothing changed.
93      {
94        '13B07F941A680F5B00A75B9A': 'NO',
95        '13B07F951A680F5B00A75B9A': undefined,
96        '83CBBA201A601CBA00E9B192': undefined,
97        '83CBBA211A601CBA00E9B192': undefined,
98      }[id]
99    );
100  }
101}
102