1import type { ExpoConfig } from '@expo/config-types';
2import fs from 'fs';
3import { vol } from 'memfs';
4import * as path from 'path';
5
6import { getName, setDisplayName, setName, setProductName } from '../Name';
7import { getPbxproj, isBuildConfig, isNotComment } from '../utils/Xcodeproj';
8
9const fsReal = jest.requireActual('fs') as typeof fs;
10
11jest.mock('fs');
12
13describe(getName, () => {
14  it(`returns null if no bundleIdentifier is provided`, () => {
15    expect(getName({} as any)).toBe(null);
16  });
17
18  it(`returns the name if provided`, () => {
19    expect(getName({ name: 'Some iOS app' })).toBe('Some iOS app');
20  });
21});
22describe(setDisplayName, () => {
23  it(`sets the CFBundleDisplayName if name is given`, () => {
24    expect(setDisplayName({ name: 'Expo app' }, {})).toMatchObject({
25      CFBundleDisplayName: 'Expo app',
26    });
27  });
28});
29describe(setName, () => {
30  it(`makes no changes to the infoPlist no name is provided`, () => {
31    expect(setName({} as any, {})).toMatchObject({});
32  });
33});
34describe(setProductName, () => {
35  const projectRoot = '/';
36  beforeAll(async () => {
37    vol.fromJSON(
38      {
39        'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync(
40          path.join(__dirname, 'fixtures/project.pbxproj'),
41          'utf-8'
42        ),
43        'ios/testproject/AppDelegate.m': '',
44      },
45      projectRoot
46    );
47  });
48
49  afterAll(() => {
50    vol.reset();
51  });
52
53  it(`sets the iOS PRODUCT_NAME value`, () => {
54    for (const [input, output] of [
55      ['My Cool Thing', `"MyCoolThing"`],
56      ['h"&<world/>��', `"hworld"`],
57    ]) {
58      // Ensure the value can be parsed and written.
59      const project = setProductNameForRoot({ name: input, slug: '' }, projectRoot);
60      expect(
61        Object.entries(project.pbxXCBuildConfigurationSection())
62          .filter(isNotComment)
63          // @ts-ignore
64          .filter(isBuildConfig)[0][1]?.buildSettings?.PRODUCT_NAME
65        // Ensure the value is wrapped in quotes.
66      ).toBe(output);
67    }
68  });
69});
70
71function setProductNameForRoot(config: ExpoConfig, projectRoot: string) {
72  let project = getPbxproj(projectRoot);
73  project = setProductName(config, project);
74  fs.writeFileSync(project.filepath, project.writeSync());
75  return project;
76}
77