mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-08 09:24:41 +00:00
247 lines
7.8 KiB
JavaScript
Vendored
247 lines
7.8 KiB
JavaScript
Vendored
import {
|
|
copyFileSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
realpathSync,
|
|
rmSync,
|
|
symlinkSync,
|
|
writeFileSync,
|
|
} from 'node:fs';
|
|
import { execFileSync } from 'node:child_process';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { afterAll, describe, expect, test } from 'vitest';
|
|
import {
|
|
binRootFrom,
|
|
installedState,
|
|
recordedSource,
|
|
repositoryFromManifest,
|
|
selectedPlatforms,
|
|
writeRecordedSource,
|
|
} from './fetch-binaries.mjs';
|
|
|
|
const RELEASE = '@react-native-gpui/hermes@0.1.1';
|
|
const packageRoot = path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
'..',
|
|
);
|
|
|
|
describe('repositoryFromManifest', () => {
|
|
test('reads the string form', () => {
|
|
expect(
|
|
repositoryFromManifest({ repository: 'streetwriters/react-native-gpui' }),
|
|
).toBe('streetwriters/react-native-gpui');
|
|
});
|
|
|
|
test('reads the object form', () => {
|
|
expect(
|
|
repositoryFromManifest({
|
|
repository: {
|
|
type: 'git',
|
|
url: 'https://github.com/streetwriters/react-native-gpui',
|
|
},
|
|
}),
|
|
).toBe('streetwriters/react-native-gpui');
|
|
});
|
|
|
|
test('strips git+, the GitHub URL, .git and a directory field', () => {
|
|
expect(
|
|
repositoryFromManifest({
|
|
repository: {
|
|
type: 'git',
|
|
url: 'git+https://github.com/streetwriters/react-native-gpui.git',
|
|
directory: 'packages/hermes',
|
|
},
|
|
}),
|
|
).toBe('streetwriters/react-native-gpui');
|
|
});
|
|
|
|
test('is unaffected by GITHUB_REPOSITORY, which points at a fork in CI', () => {
|
|
const env = { GITHUB_REPOSITORY: 'someone/else' };
|
|
expect(
|
|
repositoryFromManifest(
|
|
{ repository: 'https://github.com/streetwriters/react-native-gpui' },
|
|
env,
|
|
),
|
|
).toBe('streetwriters/react-native-gpui');
|
|
expect(env.GITHUB_REPOSITORY).toBe('someone/else');
|
|
});
|
|
|
|
test('RN_GPUI_HERMES_REPO overrides the manifest, for mirrors', () => {
|
|
expect(
|
|
repositoryFromManifest(
|
|
{ repository: 'https://github.com/streetwriters/react-native-gpui' },
|
|
{ RN_GPUI_HERMES_REPO: 'https://example.test/mirror' },
|
|
),
|
|
).toBe('https://example.test/mirror');
|
|
});
|
|
|
|
test('names the manifest when there is no usable repository', () => {
|
|
expect(() => repositoryFromManifest({ name: 'hermes' })).toThrow(
|
|
/could not read the repository/u,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('binRootFrom', () => {
|
|
test('defaults to the package bin directory', () => {
|
|
expect(binRootFrom({})).toBe(path.join(packageRoot, 'bin'));
|
|
});
|
|
|
|
test('honours RN_GPUI_HERMES_BIN_ROOT, which CMake also reads', () => {
|
|
// CMake's desktop/CMakeLists.txt and desktop/node-api-exports.test.js both accept
|
|
// this variable. When the downloader ignored it, the binaries landed in the
|
|
// package while the build looked elsewhere, and configure failed with
|
|
// "Hermes library not found".
|
|
expect(binRootFrom({ RN_GPUI_HERMES_BIN_ROOT: '/tmp/hermes-bin' })).toBe(
|
|
'/tmp/hermes-bin',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('selectedPlatforms', () => {
|
|
test('honours --platform on any host', () => {
|
|
expect(selectedPlatforms({ platform: 'darwin-x64' })).toEqual([
|
|
'darwin-x64',
|
|
]);
|
|
expect(selectedPlatforms({ platform: 'win32-arm64' })).toEqual([
|
|
'win32-arm64',
|
|
]);
|
|
});
|
|
|
|
test('--all lists every platform', () => {
|
|
expect(selectedPlatforms({ all: true })).toHaveLength(6);
|
|
});
|
|
});
|
|
|
|
describe('installedState', () => {
|
|
const roots = [];
|
|
const tempRoot = () => {
|
|
const root = mkdtempSync(path.join(os.tmpdir(), 'hermes-test-'));
|
|
roots.push(root);
|
|
return root;
|
|
};
|
|
const install = (root, platform, files) => {
|
|
mkdirSync(path.join(root, platform), { recursive: true });
|
|
for (const file of files) {
|
|
writeFileSync(path.join(root, platform, file), 'binary');
|
|
}
|
|
};
|
|
|
|
afterAll(() => {
|
|
for (const root of roots) rmSync(root, { recursive: true, force: true });
|
|
});
|
|
|
|
test('a complete directory with no .release is stale', () => {
|
|
const root = tempRoot();
|
|
install(root, 'darwin-arm64', ['libhermesvm.dylib', 'hermesc']);
|
|
expect(installedState('darwin-arm64', RELEASE, root)).toEqual({
|
|
state: 'stale',
|
|
});
|
|
});
|
|
|
|
test('a matching .release is current', () => {
|
|
const root = tempRoot();
|
|
install(root, 'darwin-arm64', ['libhermesvm.dylib', 'hermesc']);
|
|
writeRecordedSource('darwin-arm64', RELEASE, root);
|
|
expect(installedState('darwin-arm64', RELEASE, root)).toEqual({
|
|
state: 'current',
|
|
});
|
|
expect(recordedSource('darwin-arm64', root)).toBe(RELEASE);
|
|
});
|
|
|
|
test('a different tag is stale, so a version bump replaces the binaries', () => {
|
|
const root = tempRoot();
|
|
install(root, 'darwin-arm64', ['libhermesvm.dylib', 'hermesc']);
|
|
writeRecordedSource(
|
|
'darwin-arm64',
|
|
'@react-native-gpui/hermes@0.1.0',
|
|
root,
|
|
);
|
|
expect(installedState('darwin-arm64', RELEASE, root)).toEqual({
|
|
state: 'stale',
|
|
});
|
|
});
|
|
|
|
test('a hand-installed source is foreign, and must be kept', () => {
|
|
const root = tempRoot();
|
|
install(root, 'darwin-arm64', ['libhermesvm.dylib', 'hermesc']);
|
|
writeRecordedSource('darwin-arm64', 'from:/tmp/my-build.zip', root);
|
|
expect(installedState('darwin-arm64', RELEASE, root)).toEqual({
|
|
state: 'foreign',
|
|
source: 'from:/tmp/my-build.zip',
|
|
});
|
|
});
|
|
|
|
test('a run source is foreign too', () => {
|
|
const root = tempRoot();
|
|
install(root, 'win32-x64', ['hermesvm.dll', 'hermesvm.lib', 'hermesc.exe']);
|
|
writeRecordedSource('win32-x64', 'run:12345', root);
|
|
expect(installedState('win32-x64', RELEASE, root)).toEqual({
|
|
state: 'foreign',
|
|
source: 'run:12345',
|
|
});
|
|
});
|
|
|
|
test('missing files win over a recorded source', () => {
|
|
const root = tempRoot();
|
|
install(root, 'darwin-arm64', ['libhermesvm.dylib']);
|
|
writeRecordedSource('darwin-arm64', RELEASE, root);
|
|
expect(installedState('darwin-arm64', RELEASE, root)).toEqual({
|
|
state: 'missing',
|
|
});
|
|
});
|
|
|
|
test('an empty directory is missing', () => {
|
|
const root = tempRoot();
|
|
expect(installedState('darwin-arm64', RELEASE, root)).toEqual({
|
|
state: 'missing',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('the CLI entry point', () => {
|
|
const script = fileURLToPath(
|
|
new URL('./fetch-binaries.mjs', import.meta.url),
|
|
);
|
|
const roots = [];
|
|
afterAll(() => {
|
|
for (const root of roots) rmSync(root, { recursive: true, force: true });
|
|
});
|
|
|
|
test('runs when reached through a path that differs from its real one', () => {
|
|
// A CMake build under /tmp is reached as /private/tmp, and os.tmpdir() is
|
|
// itself a symlink on macOS. Comparing unresolved paths made the script
|
|
// exit 0 without doing anything, which a missing Hermes library turned
|
|
// into a link error much later.
|
|
const root = mkdtempSync(path.join(os.tmpdir(), 'hermes-entry-'));
|
|
roots.push(root);
|
|
const scripts = path.join(root, 'scripts');
|
|
mkdirSync(scripts);
|
|
copyFileSync(script, path.join(scripts, 'fetch-binaries.mjs'));
|
|
const linked = path.join(root, 'linked');
|
|
// A directory symlink needs an elevated process or Developer Mode on
|
|
// Windows; a junction needs neither, and `realpathSync` resolves it to the
|
|
// same target, which is the behaviour under test.
|
|
symlinkSync(
|
|
scripts,
|
|
linked,
|
|
process.platform === 'win32' ? 'junction' : 'dir',
|
|
);
|
|
const invoked = path.join(linked, 'fetch-binaries.mjs');
|
|
expect(realpathSync(invoked)).not.toBe(invoked);
|
|
|
|
const output = execFileSync(process.execPath, [invoked, '--help'], {
|
|
encoding: 'utf8',
|
|
});
|
|
expect(output).toContain('Usage: node scripts/fetch-binaries.mjs');
|
|
});
|
|
|
|
test('does nothing when it is imported rather than run', () => {
|
|
// The import at the top of this file is the test: reaching this point
|
|
// without a download proves the guard holds.
|
|
expect(typeof repositoryFromManifest).toBe('function');
|
|
});
|
|
});
|