blob: c7beb0fa660ae890b93c15c079ffd5005433d57f [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import assert from 'node:assert/strict';
import { EventEmitter } from 'node:events';
import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, posix, win32 } from 'node:path';
import { test } from 'node:test';
import { createDevelopmentEnvironmentFile, startDevelopmentApp } from './dev-app-runtime.mjs';
import { worktreeDevelopmentLaunch } from './dev-worktree.mjs';
function worktreeFixture(t) {
const parent = mkdtempSync(join(tmpdir(), 'maka-worktree-profile-'));
const first = join(parent, 'first', 'checkout with spaces');
const second = join(parent, 'second', 'checkout with spaces');
for (const directory of [first, second]) mkdirSync(directory, { recursive: true });
t.after(() => rmSync(parent, { recursive: true, force: true }));
return { parent, first, second };
}
test('worktree profiles are stable across launches and distinct for identically named checkouts', (t) => {
const { parent, first, second } = worktreeFixture(t);
const home = posix.join('/test-homes', posix.basename(parent.replaceAll('\\', '/')));
const options = { platform: 'darwin', home, env: {}, repoRoot: first };
const one = worktreeDevelopmentLaunch([], options);
assert.equal(one.userDataDir, worktreeDevelopmentLaunch([], options).userDataDir);
assert.notEqual(
one.userDataDir,
worktreeDevelopmentLaunch([], { ...options, repoRoot: second }).userDataDir,
);
assert.equal(
posix.dirname(one.userDataDir),
posix.join(home, 'Library', 'Application Support', 'Maka Dev Worktrees'),
);
assert.equal(
existsSync(one.userDataDir),
false,
'selection does not copy or initialize user data',
);
});
test('a symlink to a worktree uses the same data directory', {
skip: process.platform === 'win32',
}, (t) => {
const { parent, first } = worktreeFixture(t);
const alias = join(parent, 'alias');
symlinkSync(first, alias, 'dir');
assert.equal(
worktreeDevelopmentLaunch([], { repoRoot: first }).userDataDir,
worktreeDevelopmentLaunch([], { repoRoot: alias }).userDataDir,
);
});
test('worktree profiles use the platform data location and ignore relative config roots', (t) => {
const { first } = worktreeFixture(t);
for (const [platform, home, env, expected] of [
['win32', 'C:\\Users\\dev', { APPDATA: 'D:\\Roaming' }, 'D:\\Roaming\\Maka Dev Worktrees'],
['win32', 'C:\\Users\\dev', {}, 'C:\\Users\\dev\\AppData\\Roaming\\Maka Dev Worktrees'],
[
'linux',
'/home/dev',
{ XDG_CONFIG_HOME: '/custom/config' },
'/custom/config/Maka Dev Worktrees',
],
['linux', '/home/dev', { XDG_CONFIG_HOME: 'relative' }, '/home/dev/.config/Maka Dev Worktrees'],
['linux', '/home/dev', {}, '/home/dev/.config/Maka Dev Worktrees'],
]) {
const result = worktreeDevelopmentLaunch([], { platform, home, env, repoRoot: first });
const paths = platform === 'win32' ? win32 : posix;
assert.equal(paths.dirname(result.userDataDir), expected);
assert.ok(paths.isAbsolute(result.userDataDir));
}
});
test('an explicit data directory overrides automatic selection and survives plain and TCC forwarding', async (t) => {
const { first } = worktreeFixture(t);
const override = join(first, 'explicit data');
for (const flags of [[`--user-data-dir=${override}`], ['--user-data-dir', override]]) {
const result = worktreeDevelopmentLaunch(['--inspect=0', ...flags, '--runtime-host-peer'], {
repoRoot: first,
});
assert.equal(result.userDataDir, override);
assert.deepEqual(result.argv, [
'--inspect=0',
'--runtime-host-peer',
`--user-data-dir=${override}`,
]);
const calls = [];
const child = new EventEmitter();
await startDevelopmentApp({
argv: result.argv,
prepareMacosDevelopmentLaunch: async () => null,
devSingleInstanceConstants: async () => ({}),
spawn: (command, args) => {
calls.push(args);
return child;
},
});
assert.deepEqual(calls[0].slice(1), result.argv);
const tcc = createDevelopmentEnvironmentFile({
argv: result.argv,
env: {},
viteUrl: 'http://localhost:5173',
});
assert.equal(tcc.userDataDir, override);
assert.deepEqual(tcc.electronArgs, ['--inspect=0', '--runtime-host-peer']);
}
});
test('invalid profile overrides cannot fall back to the shared profile', (t) => {
const { first } = worktreeFixture(t);
for (const argv of [
['--user-data-dir='],
['--user-data-dir'],
['--user-data-dir', '--inspect=0'],
['--user-data-dir=/one', '--user-data-dir=/two'],
])
assert.throws(() => worktreeDevelopmentLaunch(argv, { repoRoot: first }), /--user-data-dir/);
});
test('relative profile overrides resolve from the checkout rather than the caller directory', (t) => {
const { first } = worktreeFixture(t);
const result = worktreeDevelopmentLaunch(['--user-data-dir', 'local profile'], {
repoRoot: first,
});
assert.equal(result.userDataDir, join(realpathSync(first), 'local profile'));
});