Skip to content

Commit 24d5d2c

Browse files
committed
compile macho binaries at runtime using hellow-world.c for fixtures in lipo tests
1 parent 17bcff3 commit 24d5d2c

9 files changed

+84
-70
lines changed

jest.setup.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
1+
import { execFileSync } from 'child_process';
12
import * as fs from 'fs-extra';
23
import * as path from 'path';
3-
import { appsDir, asarsDir, templateApp } from './test/util';
4+
import { appsDir, asarsDir, fixtureDir, templateApp } from './test/util';
5+
6+
// generates binaries from helloorld.c
7+
// hello-world-universal, hello-world-x86_64, hello-world-arm64
8+
const generateMachO = async () => {
9+
const src = path.resolve(fixtureDir, 'hello-world.c');
10+
11+
const outputFiles = ['x86_64', 'arm64'].map((arch) => {
12+
const machO = path.resolve(appsDir, `hello-world-${arch === 'x86_64' ? 'x64' : arch}`);
13+
execFileSync('clang', ['-arch', arch, '-o', machO, src]);
14+
return machO;
15+
});
16+
17+
execFileSync('lipo', [
18+
...outputFiles,
19+
'-create',
20+
'-output',
21+
path.resolve(appsDir, 'hello-world-universal'),
22+
]);
23+
};
424

525
export default async () => {
626
await fs.remove(appsDir);
727
await fs.mkdirp(appsDir);
28+
29+
// generate mach-o binaries to be leveraged in lipo tests
30+
generateMachO();
31+
832
await templateApp('Arm64Asar.app', 'arm64', async (appPath) => {
933
await fs.copy(
1034
path.resolve(asarsDir, 'app.asar'),

test/__snapshots__/index.spec.ts.snap

+31-47
Original file line numberDiff line numberDiff line change
@@ -627,21 +627,17 @@ exports[`makeUniversalApp no asar mode different app dirs with different macho f
627627
"integrity": {
628628
"algorithm": "SHA256",
629629
"blockSize": 4194304,
630-
"blocks": [
631-
"f1e14240f7c833900fca84fabc2f0ff27084efdf1c5b228b015515de3f8fa28e",
632-
],
633-
"hash": "f1e14240f7c833900fca84fabc2f0ff27084efdf1c5b228b015515de3f8fa28e",
630+
"blocks": "<stripped>",
631+
"hash": "<stripped>",
634632
},
635633
"size": 1063,
636634
},
637635
"package.json": {
638636
"integrity": {
639637
"algorithm": "SHA256",
640638
"blockSize": 4194304,
641-
"blocks": [
642-
"2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
643-
],
644-
"hash": "2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
639+
"blocks": "<stripped>",
640+
"hash": "<stripped>",
645641
},
646642
"size": 33,
647643
},
@@ -657,8 +653,8 @@ exports[`makeUniversalApp no asar mode different app dirs with different macho f
657653

658654
exports[`makeUniversalApp no asar mode different app dirs with different macho files (shim and lipo) 3`] = `
659655
[
656+
"hello-world",
660657
"index.js",
661-
"node-mac-permissions.node",
662658
{
663659
"content": "{
664660
"name": "app",
@@ -676,8 +672,8 @@ exports[`makeUniversalApp no asar mode different app dirs with different macho f
676672

677673
exports[`makeUniversalApp no asar mode different app dirs with different macho files (shim and lipo) 4`] = `
678674
[
675+
"hello-world",
679676
"index.js",
680-
"node-mac-permissions.node",
681677
{
682678
"content": "{
683679
"name": "app",
@@ -698,7 +694,7 @@ exports[`makeUniversalApp no asar mode different app dirs with different macho f
698694
"Contents/Info.plist": {
699695
"Resources/app.asar": {
700696
"algorithm": "SHA256",
701-
"hash": "27433ee3e34b3b0dabb29d18d40646126e80c56dbce8c4bb2adef7278b5a46c0",
697+
"hash": "<stripped>",
702698
},
703699
},
704700
}
@@ -711,21 +707,17 @@ exports[`makeUniversalApp no asar mode different app dirs with universal macho f
711707
"integrity": {
712708
"algorithm": "SHA256",
713709
"blockSize": 4194304,
714-
"blocks": [
715-
"f1e14240f7c833900fca84fabc2f0ff27084efdf1c5b228b015515de3f8fa28e",
716-
],
717-
"hash": "f1e14240f7c833900fca84fabc2f0ff27084efdf1c5b228b015515de3f8fa28e",
710+
"blocks": "<stripped>",
711+
"hash": "<stripped>",
718712
},
719713
"size": 1063,
720714
},
721715
"package.json": {
722716
"integrity": {
723717
"algorithm": "SHA256",
724718
"blockSize": 4194304,
725-
"blocks": [
726-
"2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
727-
],
728-
"hash": "2873266521e41d58d02e7acfbbbdb046edfa04b6ce262b8987de8e8548671fc7",
719+
"blocks": "<stripped>",
720+
"hash": "<stripped>",
729721
},
730722
"size": 33,
731723
},
@@ -741,8 +733,8 @@ exports[`makeUniversalApp no asar mode different app dirs with universal macho f
741733

742734
exports[`makeUniversalApp no asar mode different app dirs with universal macho files (shim but don't lipo) 3`] = `
743735
[
736+
"hello-world",
744737
"index.js",
745-
"node-mac-permissions.node",
746738
{
747739
"content": "{
748740
"name": "app",
@@ -760,8 +752,8 @@ exports[`makeUniversalApp no asar mode different app dirs with universal macho f
760752

761753
exports[`makeUniversalApp no asar mode different app dirs with universal macho files (shim but don't lipo) 4`] = `
762754
[
755+
"hello-world",
763756
"index.js",
764-
"node-mac-permissions.node",
765757
{
766758
"content": "{
767759
"name": "app",
@@ -782,16 +774,16 @@ exports[`makeUniversalApp no asar mode different app dirs with universal macho f
782774
"Contents/Info.plist": {
783775
"Resources/app.asar": {
784776
"algorithm": "SHA256",
785-
"hash": "27433ee3e34b3b0dabb29d18d40646126e80c56dbce8c4bb2adef7278b5a46c0",
777+
"hash": "<stripped>",
786778
},
787779
},
788780
}
789781
`;
790782

791783
exports[`makeUniversalApp no asar mode identical app dirs with different macho files (e.g. do not shim, but still lipo) 1`] = `
792784
[
785+
"hello-world",
793786
"index.js",
794-
"node-mac-permissions.node",
795787
{
796788
"content": "{
797789
"name": "app",
@@ -814,8 +806,8 @@ exports[`makeUniversalApp no asar mode identical app dirs with different macho f
814806

815807
exports[`makeUniversalApp no asar mode identical app dirs with universal macho files (e.g., do not shim, just copy x64 dir) 1`] = `
816808
[
809+
"hello-world",
817810
"index.js",
818-
"node-mac-permissions.node",
819811
{
820812
"content": "{
821813
"name": "app",
@@ -940,37 +932,31 @@ exports[`makeUniversalApp no asar mode should shim two different app folders 5`]
940932
exports[`makeUniversalApp works for lipo binary resources 1`] = `
941933
{
942934
"files": {
943-
"index.js": {
935+
"hello-world": {
944936
"integrity": {
945937
"algorithm": "SHA256",
946938
"blockSize": 4194304,
947-
"blocks": [
948-
"0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
949-
],
950-
"hash": "0f6311dac07f0876c436ce2be042eb88c96e17eaf140b39627cf720dd87ad5b8",
939+
"blocks": "<stripped>",
940+
"hash": "<stripped>",
951941
},
952-
"size": 66,
942+
"size": 49824,
943+
"unpacked": true,
953944
},
954-
"node-mac-permissions.node": {
945+
"index.js": {
955946
"integrity": {
956947
"algorithm": "SHA256",
957948
"blockSize": 4194304,
958-
"blocks": [
959-
"24ade05d87f584976bae70ff260e114e8384f9aa867f6e323be0ff429655a95d",
960-
],
961-
"hash": "24ade05d87f584976bae70ff260e114e8384f9aa867f6e323be0ff429655a95d",
949+
"blocks": "<stripped>",
950+
"hash": "<stripped>",
962951
},
963-
"size": 273984,
964-
"unpacked": true,
952+
"size": 66,
965953
},
966954
"package.json": {
967955
"integrity": {
968956
"algorithm": "SHA256",
969957
"blockSize": 4194304,
970-
"blocks": [
971-
"d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
972-
],
973-
"hash": "d6226276d47adc7aa20e6c46e842e258f5157313074a035051a89612acdd6be3",
958+
"blocks": "<stripped>",
959+
"hash": "<stripped>",
974960
},
975961
"size": 41,
976962
},
@@ -989,10 +975,8 @@ exports[`makeUniversalApp works for lipo binary resources 1`] = `
989975
"integrity": {
990976
"algorithm": "SHA256",
991977
"blockSize": 4194304,
992-
"blocks": [
993-
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
994-
],
995-
"hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
978+
"blocks": "<stripped>",
979+
"hash": "<stripped>",
996980
},
997981
"size": 11,
998982
},
@@ -1011,7 +995,7 @@ exports[`makeUniversalApp works for lipo binary resources 2`] = `[]`;
1011995

1012996
exports[`makeUniversalApp works for lipo binary resources 3`] = `
1013997
[
1014-
"node-mac-permissions.node",
998+
"hello-world",
1015999
]
10161000
`;
10171001

@@ -1020,7 +1004,7 @@ exports[`makeUniversalApp works for lipo binary resources 4`] = `
10201004
"Contents/Info.plist": {
10211005
"Resources/app.asar": {
10221006
"algorithm": "SHA256",
1023-
"hash": "c5dbde39636962cfe49a91eacdc969f56cd13234a1d2b1b1ea0a2a050dc7028f",
1007+
"hash": "<stripped>",
10241008
},
10251009
},
10261010
}

test/fixtures/hello-world.c

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdio.h>
2+
3+
int main() {
4+
printf("Hello, World!\n");
5+
return 0;
6+
}

test/fixtures/native/README.txt

-6
This file was deleted.
Binary file not shown.
Binary file not shown.
Binary file not shown.

test/index.spec.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('makeUniversalApp', () => {
4949

5050
const out = path.resolve(appsOutPath, 'Lipo.app');
5151
await makeUniversalApp({ x64AppPath, arm64AppPath, outAppPath: out, mergeASARs: true });
52-
await verifyApp(out);
52+
await verifyApp(out, true);
5353
},
5454
VERIFY_APP_TIMEOUT,
5555
);
@@ -329,7 +329,7 @@ describe('makeUniversalApp', () => {
329329
arm64AppPath,
330330
outAppPath,
331331
});
332-
await verifyApp(outAppPath);
332+
await verifyApp(outAppPath, true);
333333
},
334334
VERIFY_APP_TIMEOUT,
335335
);
@@ -362,7 +362,7 @@ describe('makeUniversalApp', () => {
362362
arm64AppPath,
363363
outAppPath,
364364
});
365-
await verifyApp(outAppPath);
365+
await verifyApp(outAppPath, true);
366366
},
367367
VERIFY_APP_TIMEOUT,
368368
);
@@ -387,7 +387,7 @@ describe('makeUniversalApp', () => {
387387
arm64AppPath,
388388
outAppPath: out,
389389
});
390-
await verifyApp(out);
390+
await verifyApp(out, true);
391391
},
392392
VERIFY_APP_TIMEOUT,
393393
);
@@ -410,7 +410,7 @@ describe('makeUniversalApp', () => {
410410

411411
const out = path.resolve(appsOutPath, 'UniversalMachoApp.app');
412412
await makeUniversalApp({ x64AppPath, arm64AppPath, outAppPath: out });
413-
await verifyApp(out);
413+
await verifyApp(out, true);
414414
},
415415
VERIFY_APP_TIMEOUT,
416416
);

test/util.ts

+17-11
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,19 @@ import * as fs from 'fs-extra';
55
import * as path from 'path';
66
import plist from 'plist';
77
import * as fileUtils from '../dist/cjs/file-utils';
8-
import { createPackage, createPackageWithOptions, getRawHeader } from '@electron/asar';
8+
import { createPackageWithOptions, getRawHeader } from '@electron/asar';
99

1010
// We do a LOT of verifications in `verifyApp` 😅
1111
// exec universal binary -> verify ALL asars -> verify ALL app dirs -> verify ALL asar integrity entries
1212
// plus some tests create fixtures at runtime
1313
export const VERIFY_APP_TIMEOUT = 80 * 1000;
1414

15-
const fixtureDir = path.resolve(__dirname, 'fixtures');
15+
export const fixtureDir = path.resolve(__dirname, 'fixtures');
1616
export const asarsDir = path.resolve(fixtureDir, 'asars');
1717
export const appsDir = path.resolve(fixtureDir, 'apps');
1818
export const appsOutPath = path.resolve(appsDir, 'out');
19-
const nativeModulesPath = path.resolve(fixtureDir, 'native');
2019

21-
export const verifyApp = async (appPath: string) => {
20+
export const verifyApp = async (appPath: string, containsRuntimeGeneratedMacho = false) => {
2221
await ensureUniversal(appPath);
2322

2423
const resourcesDir = path.resolve(appPath, 'Contents', 'Resources');
@@ -29,7 +28,9 @@ export const verifyApp = async (appPath: string) => {
2928
for await (const asar of asars) {
3029
// verify header
3130
const asarFs = getRawHeader(path.resolve(resourcesDir, asar));
32-
expect(removeUnstableProperties(asarFs.header)).toMatchSnapshot();
31+
expect(
32+
removeUnstableProperties(asarFs.header, containsRuntimeGeneratedMacho),
33+
).toMatchSnapshot();
3334
}
3435

3536
// check all app and unpacked dirs (incl. shimmed)
@@ -66,12 +67,14 @@ export const verifyApp = async (appPath: string) => {
6667
for (let i = 0; i < integrity.length; i++) {
6768
const relativePath = infoPlists[i];
6869
const asarIntegrity = integrity[i];
69-
integrityMap[relativePath] = asarIntegrity;
70+
// note: `infoPlistsToIgnore` will not have integrity in sub-app plists
71+
integrityMap[relativePath] = asarIntegrity
72+
? removeUnstableProperties(asarIntegrity, containsRuntimeGeneratedMacho)
73+
: undefined;
7074
}
7175
expect(integrityMap).toMatchSnapshot();
7276
};
7377

74-
// note: `infoPlistsToIgnore` will not have integrity in sub-app plists
7578
const extractAsarIntegrity = async (infoPlist: string) => {
7679
const { ElectronAsarIntegrity: integrity, ...otherData } = plist.parse(
7780
await fs.readFile(infoPlist, 'utf-8'),
@@ -104,12 +107,15 @@ export const toSystemIndependentPath = (s: string): string => {
104107
return path.sep === '/' ? s : s.replace(/\\/g, '/');
105108
};
106109

107-
export const removeUnstableProperties = (data: any) => {
110+
export const removeUnstableProperties = (data: any, containsRuntimeGeneratedMacho: boolean) => {
108111
return JSON.parse(
109112
JSON.stringify(data, (name, value) => {
110113
if (name === 'offset') {
111114
return undefined;
112115
}
116+
if (containsRuntimeGeneratedMacho && (name === 'hash' || name === 'blocks')) {
117+
return '<stripped>'; // these are unstable for macho fixtures due to runtime generation
118+
}
113119
return value;
114120
}),
115121
);
@@ -211,12 +217,12 @@ export const generateNativeApp = async (options: {
211217
additionalFiles,
212218
);
213219
await fs.copy(
214-
path.join(nativeModulesPath, `node-mac-permissions.${nativeModuleArch}.node`),
215-
path.join(testPath, 'node-mac-permissions.node'),
220+
path.join(appsDir, `hello-world-${nativeModuleArch}`),
221+
path.join(testPath, 'hello-world'),
216222
);
217223
if (createAsar) {
218224
await createPackageWithOptions(testPath, path.resolve(resources, 'app.asar'), {
219-
unpack: '**/*.node',
225+
unpack: '**/hello-world',
220226
});
221227
} else {
222228
await fs.copy(testPath, resourcesApp);

0 commit comments

Comments
 (0)