mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
test: cut low-value tests, rewrite the rest around behavior, parallelize lanes (#285)
This commit is contained in:
1 parent
4b6842d034
commit
b48083ddd8
368 files changed
+18045
-60331
No files matched your search
@@ -1,12 +1,20 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import type { SubminerPluginRuntimeScriptOptConfig } from '../../shared/subminer-plugin-script-opts';
|
||||
import {
|
||||
buildWindowsMpvLaunchArgs,
|
||||
launchWindowsMpv,
|
||||
resolveWindowsMpvPath,
|
||||
type WindowsMpvLaunchDeps,
|
||||
type WindowsMpvRuntimePluginPolicy,
|
||||
} from './windows-mpv-launch';
|
||||
|
||||
const MPV_PATH = 'C:\\mpv\\mpv.exe';
|
||||
const BINARY_PATH = 'C:\\SubMiner\\SubMiner.exe';
|
||||
const PLUGIN_PATH = 'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua';
|
||||
const DEFAULT_PIPE = '\\\\.\\pipe\\subminer-socket';
|
||||
const CUSTOM_PIPE = '\\\\.\\pipe\\custom-subminer-socket';
|
||||
|
||||
function createDeps(overrides: Partial<WindowsMpvLaunchDeps> = {}): WindowsMpvLaunchDeps {
|
||||
return {
|
||||
getEnv: () => undefined,
|
||||
@@ -18,15 +26,77 @@ function createDeps(overrides: Partial<WindowsMpvLaunchDeps> = {}): WindowsMpvLa
|
||||
};
|
||||
}
|
||||
|
||||
test('resolveWindowsMpvPath prefers SUBMINER_MPV_PATH', () => {
|
||||
const resolved = resolveWindowsMpvPath(
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
}),
|
||||
);
|
||||
// Deps where SUBMINER_MPV_PATH resolves to an existing mpv.exe.
|
||||
function createResolvedDeps(overrides: Partial<WindowsMpvLaunchDeps> = {}): WindowsMpvLaunchDeps {
|
||||
return createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? MPV_PATH : undefined),
|
||||
fileExists: (candidate) => candidate === MPV_PATH,
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
|
||||
assert.equal(resolved, 'C:\\mpv\\mpv.exe');
|
||||
function pluginConfig(
|
||||
overrides: Partial<SubminerPluginRuntimeScriptOptConfig> = {},
|
||||
): SubminerPluginRuntimeScriptOptConfig {
|
||||
return {
|
||||
socketPath: DEFAULT_PIPE,
|
||||
binaryPath: '',
|
||||
backend: 'windows',
|
||||
autoStart: true,
|
||||
autoStartVisibleOverlay: true,
|
||||
autoStartPauseUntilReady: true,
|
||||
osdMessages: false,
|
||||
texthookerEnabled: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
type BuildArgsOptions = {
|
||||
targets?: string[];
|
||||
extraArgs?: string[];
|
||||
binaryPath?: string;
|
||||
launchMode?: Parameters<typeof buildWindowsMpvLaunchArgs>[4];
|
||||
runtimeConfig?: SubminerPluginRuntimeScriptOptConfig;
|
||||
};
|
||||
|
||||
function buildArgs(options: BuildArgsOptions = {}): string[] {
|
||||
return buildWindowsMpvLaunchArgs(
|
||||
options.targets ?? ['C:\\video.mkv'],
|
||||
options.extraArgs ?? [],
|
||||
'binaryPath' in options ? options.binaryPath : BINARY_PATH,
|
||||
PLUGIN_PATH,
|
||||
options.launchMode ?? 'normal',
|
||||
options.runtimeConfig,
|
||||
);
|
||||
}
|
||||
|
||||
type LaunchOptions = {
|
||||
targets?: string[];
|
||||
extraArgs?: string[];
|
||||
policy?: WindowsMpvRuntimePluginPolicy;
|
||||
runtimeConfig?: SubminerPluginRuntimeScriptOptConfig;
|
||||
};
|
||||
|
||||
function launch(deps: WindowsMpvLaunchDeps, options: LaunchOptions = {}) {
|
||||
return launchWindowsMpv(
|
||||
options.targets ?? ['C:\\video.mkv'],
|
||||
deps,
|
||||
options.extraArgs ?? [],
|
||||
BINARY_PATH,
|
||||
PLUGIN_PATH,
|
||||
'',
|
||||
'normal',
|
||||
options.policy,
|
||||
options.runtimeConfig,
|
||||
);
|
||||
}
|
||||
|
||||
function scriptOptsOf(args: readonly string[] | undefined): string {
|
||||
return args?.find((arg) => arg.startsWith('--script-opts=')) ?? '';
|
||||
}
|
||||
|
||||
test('resolveWindowsMpvPath prefers SUBMINER_MPV_PATH', () => {
|
||||
assert.equal(resolveWindowsMpvPath(createResolvedDeps()), MPV_PATH);
|
||||
});
|
||||
|
||||
test('resolveWindowsMpvPath prefers configured executable path before environment and PATH', () => {
|
||||
@@ -34,12 +104,12 @@ test('resolveWindowsMpvPath prefers configured executable path before environmen
|
||||
createDeps({
|
||||
getEnv: () => 'C:\\other\\mpv.exe',
|
||||
runWhere: () => ({ status: 0, stdout: 'C:\\tools\\mpv.exe\r\n' }),
|
||||
fileExists: (candidate) => ['C:\\mpv\\mpv.exe', 'C:\\other\\mpv.exe'].includes(candidate),
|
||||
fileExists: (candidate) => [MPV_PATH, 'C:\\other\\mpv.exe'].includes(candidate),
|
||||
}),
|
||||
' C:\\mpv\\mpv.exe ',
|
||||
);
|
||||
|
||||
assert.equal(resolved, 'C:\\mpv\\mpv.exe');
|
||||
assert.equal(resolved, MPV_PATH);
|
||||
});
|
||||
|
||||
test('resolveWindowsMpvPath falls back to where.exe output', () => {
|
||||
@@ -63,200 +133,89 @@ test('resolveWindowsMpvPath ignores an invalid environment override but keeps co
|
||||
assert.equal(resolveWindowsMpvPath(deps, 'C:\\missing\\mpv.exe'), '');
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs uses explicit SubMiner defaults and targets', () => {
|
||||
assert.deepEqual(
|
||||
buildWindowsMpvLaunchArgs(
|
||||
['C:\\a.mkv', 'C:\\b.mkv'],
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
),
|
||||
[
|
||||
'--player-operation-mode=pseudo-gui',
|
||||
'--force-window=immediate',
|
||||
'--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'--input-ipc-server=\\\\.\\pipe\\subminer-socket',
|
||||
'--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--sub-auto=fuzzy',
|
||||
'--sub-file-paths=subs;subtitles',
|
||||
'--sid=auto',
|
||||
'--secondary-sid=auto',
|
||||
'--sub-visibility=no',
|
||||
'--secondary-sub-visibility=no',
|
||||
'--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner.exe,subminer-socket_path=\\\\.\\pipe\\subminer-socket',
|
||||
'C:\\a.mkv',
|
||||
'C:\\b.mkv',
|
||||
],
|
||||
);
|
||||
});
|
||||
test('buildWindowsMpvLaunchArgs injects the plugin, default pipe and script opts before targets', () => {
|
||||
const args = buildArgs({ targets: ['C:\\a.mkv', 'C:\\b.mkv'] });
|
||||
|
||||
test('buildWindowsMpvLaunchArgs inserts maximized launch mode before explicit extra args when configured', () => {
|
||||
assert.deepEqual(
|
||||
buildWindowsMpvLaunchArgs(
|
||||
['C:\\video.mkv'],
|
||||
['--window-maximized=no'],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'maximized',
|
||||
),
|
||||
[
|
||||
'--player-operation-mode=pseudo-gui',
|
||||
'--force-window=immediate',
|
||||
'--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'--input-ipc-server=\\\\.\\pipe\\subminer-socket',
|
||||
'--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--sub-auto=fuzzy',
|
||||
'--sub-file-paths=subs;subtitles',
|
||||
'--sid=auto',
|
||||
'--secondary-sid=auto',
|
||||
'--sub-visibility=no',
|
||||
'--secondary-sub-visibility=no',
|
||||
'--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner.exe,subminer-socket_path=\\\\.\\pipe\\subminer-socket',
|
||||
'--window-maximized=yes',
|
||||
'--window-maximized=no',
|
||||
'C:\\video.mkv',
|
||||
],
|
||||
assert.deepEqual(args.slice(0, 2), [
|
||||
'--player-operation-mode=pseudo-gui',
|
||||
'--force-window=immediate',
|
||||
]);
|
||||
assert.ok(args.includes(`--script=${PLUGIN_PATH}`));
|
||||
assert.ok(args.includes(`--input-ipc-server=${DEFAULT_PIPE}`));
|
||||
assert.equal(
|
||||
scriptOptsOf(args),
|
||||
`--script-opts=subminer-binary_path=${BINARY_PATH},subminer-socket_path=${DEFAULT_PIPE}`,
|
||||
);
|
||||
assert.equal(args.includes('--idle=yes'), false);
|
||||
assert.deepEqual(args.slice(-2), ['C:\\a.mkv', 'C:\\b.mkv']);
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs keeps shortcut-only launches in idle mode', () => {
|
||||
assert.deepEqual(
|
||||
buildWindowsMpvLaunchArgs(
|
||||
[],
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
),
|
||||
[
|
||||
'--player-operation-mode=pseudo-gui',
|
||||
'--force-window=immediate',
|
||||
'--idle=yes',
|
||||
'--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'--input-ipc-server=\\\\.\\pipe\\subminer-socket',
|
||||
'--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--sub-auto=fuzzy',
|
||||
'--sub-file-paths=subs;subtitles',
|
||||
'--sid=auto',
|
||||
'--secondary-sid=auto',
|
||||
'--sub-visibility=no',
|
||||
'--secondary-sub-visibility=no',
|
||||
'--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner.exe,subminer-socket_path=\\\\.\\pipe\\subminer-socket',
|
||||
],
|
||||
);
|
||||
assert.ok(buildArgs({ targets: [] }).includes('--idle=yes'));
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs inserts maximized launch mode before explicit extra args', () => {
|
||||
const args = buildArgs({ extraArgs: ['--window-maximized=no'], launchMode: 'maximized' });
|
||||
|
||||
const maximized = args.indexOf('--window-maximized=yes');
|
||||
const explicit = args.indexOf('--window-maximized=no');
|
||||
assert.ok(maximized >= 0);
|
||||
assert.ok(explicit > maximized);
|
||||
assert.ok(args.indexOf('C:\\video.mkv') > explicit);
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs mirrors a custom input-ipc-server into script opts', () => {
|
||||
assert.deepEqual(
|
||||
buildWindowsMpvLaunchArgs(
|
||||
['C:\\video.mkv'],
|
||||
['--input-ipc-server', '\\\\.\\pipe\\custom-subminer-socket'],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
),
|
||||
[
|
||||
'--player-operation-mode=pseudo-gui',
|
||||
'--force-window=immediate',
|
||||
'--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'--input-ipc-server=\\\\.\\pipe\\custom-subminer-socket',
|
||||
'--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--sub-auto=fuzzy',
|
||||
'--sub-file-paths=subs;subtitles',
|
||||
'--sid=auto',
|
||||
'--secondary-sid=auto',
|
||||
'--sub-visibility=no',
|
||||
'--secondary-sub-visibility=no',
|
||||
'--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner.exe,subminer-socket_path=\\\\.\\pipe\\custom-subminer-socket',
|
||||
'--input-ipc-server',
|
||||
'\\\\.\\pipe\\custom-subminer-socket',
|
||||
'C:\\video.mkv',
|
||||
],
|
||||
const extraArgs = ['--input-ipc-server', CUSTOM_PIPE];
|
||||
const args = buildArgs({ extraArgs });
|
||||
|
||||
assert.ok(args.includes(`--input-ipc-server=${CUSTOM_PIPE}`));
|
||||
assert.equal(
|
||||
scriptOptsOf(args),
|
||||
`--script-opts=subminer-binary_path=${BINARY_PATH},subminer-socket_path=${CUSTOM_PIPE}`,
|
||||
);
|
||||
assert.deepEqual(args.slice(-3), [...extraArgs, 'C:\\video.mkv']);
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs includes socket script opts when plugin entrypoint is present without binary path', () => {
|
||||
assert.deepEqual(
|
||||
buildWindowsMpvLaunchArgs(
|
||||
['C:\\video.mkv'],
|
||||
['--input-ipc-server', '\\\\.\\pipe\\custom-subminer-socket'],
|
||||
undefined,
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
),
|
||||
[
|
||||
'--player-operation-mode=pseudo-gui',
|
||||
'--force-window=immediate',
|
||||
'--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'--input-ipc-server=\\\\.\\pipe\\custom-subminer-socket',
|
||||
'--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
|
||||
'--sub-auto=fuzzy',
|
||||
'--sub-file-paths=subs;subtitles',
|
||||
'--sid=auto',
|
||||
'--secondary-sid=auto',
|
||||
'--sub-visibility=no',
|
||||
'--secondary-sub-visibility=no',
|
||||
'--script-opts=subminer-socket_path=\\\\.\\pipe\\custom-subminer-socket',
|
||||
'--input-ipc-server',
|
||||
'\\\\.\\pipe\\custom-subminer-socket',
|
||||
'C:\\video.mkv',
|
||||
],
|
||||
);
|
||||
const args = buildArgs({
|
||||
extraArgs: ['--input-ipc-server', CUSTOM_PIPE],
|
||||
binaryPath: undefined,
|
||||
});
|
||||
|
||||
assert.equal(scriptOptsOf(args), `--script-opts=subminer-socket_path=${CUSTOM_PIPE}`);
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs uses runtime plugin config script opts', () => {
|
||||
const args = buildWindowsMpvLaunchArgs(
|
||||
['C:\\video.mkv'],
|
||||
['--input-ipc-server', '\\\\.\\pipe\\custom-subminer-socket'],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'normal',
|
||||
{
|
||||
socketPath: '\\\\.\\pipe\\ignored-config-socket',
|
||||
binaryPath: 'C:\\Custom\\SubMiner.exe',
|
||||
backend: 'windows',
|
||||
autoStart: true,
|
||||
autoStartVisibleOverlay: false,
|
||||
autoStartPauseUntilReady: false,
|
||||
osdMessages: false,
|
||||
texthookerEnabled: false,
|
||||
},
|
||||
const scriptOpts = scriptOptsOf(
|
||||
buildArgs({
|
||||
extraArgs: ['--input-ipc-server', CUSTOM_PIPE],
|
||||
runtimeConfig: pluginConfig({
|
||||
socketPath: '\\\\.\\pipe\\ignored-config-socket',
|
||||
binaryPath: 'C:\\Custom\\SubMiner.exe',
|
||||
autoStartVisibleOverlay: false,
|
||||
autoStartPauseUntilReady: false,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
const scriptOpts = args.find((arg) => arg.startsWith('--script-opts='));
|
||||
assert.match(scriptOpts ?? '', /subminer-binary_path=C:\\Custom\\SubMiner\.exe/);
|
||||
assert.match(scriptOpts ?? '', /subminer-socket_path=\\\\\.\\pipe\\custom-subminer-socket/);
|
||||
assert.match(scriptOpts ?? '', /subminer-backend=windows/);
|
||||
assert.match(scriptOpts ?? '', /subminer-auto_start=yes/);
|
||||
assert.match(scriptOpts ?? '', /subminer-auto_start_visible_overlay=no/);
|
||||
assert.match(scriptOpts ?? '', /subminer-auto_start_pause_until_ready=no/);
|
||||
assert.match(scriptOpts ?? '', /subminer-texthooker_enabled=no/);
|
||||
assert.match(scriptOpts, /subminer-binary_path=C:\\Custom\\SubMiner\.exe/);
|
||||
assert.match(scriptOpts, /subminer-socket_path=\\\\\.\\pipe\\custom-subminer-socket/);
|
||||
assert.match(scriptOpts, /subminer-backend=windows/);
|
||||
assert.match(scriptOpts, /subminer-auto_start=yes/);
|
||||
assert.match(scriptOpts, /subminer-auto_start_visible_overlay=no/);
|
||||
assert.match(scriptOpts, /subminer-auto_start_pause_until_ready=no/);
|
||||
assert.match(scriptOpts, /subminer-texthooker_enabled=no/);
|
||||
});
|
||||
|
||||
test('buildWindowsMpvLaunchArgs keeps Windows ipc default unless explicitly overridden', () => {
|
||||
const args = buildWindowsMpvLaunchArgs(
|
||||
['C:\\video.mkv'],
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'normal',
|
||||
{
|
||||
const args = buildArgs({
|
||||
runtimeConfig: pluginConfig({
|
||||
socketPath: 'C:\\Users\\tester\\AppData\\Local\\Temp\\subminer-smoke-sock\\subminer.sock',
|
||||
binaryPath: '',
|
||||
backend: 'windows',
|
||||
autoStart: true,
|
||||
autoStartVisibleOverlay: true,
|
||||
autoStartPauseUntilReady: true,
|
||||
osdMessages: false,
|
||||
texthookerEnabled: false,
|
||||
},
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
assert.ok(args.includes('--input-ipc-server=\\\\.\\pipe\\subminer-socket'));
|
||||
const scriptOpts = args.find((arg) => arg.startsWith('--script-opts='));
|
||||
assert.match(scriptOpts ?? '', /subminer-socket_path=\\\\\.\\pipe\\subminer-socket/);
|
||||
assert.ok(args.includes(`--input-ipc-server=${DEFAULT_PIPE}`));
|
||||
assert.match(scriptOptsOf(args), /subminer-socket_path=\\\\\.\\pipe\\subminer-socket/);
|
||||
});
|
||||
|
||||
test('launchWindowsMpv attaches a launched video to a running app and disables plugin auto-start', async () => {
|
||||
@@ -264,11 +223,8 @@ test('launchWindowsMpv attaches a launched video to a running app and disables p
|
||||
const controlArgv: string[][] = [];
|
||||
const waitedSockets: Array<{ socketPath: string; timeoutMs: number }> = [];
|
||||
const logs: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
['C:\\video.mkv'],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
const result = await launch(
|
||||
createResolvedDeps({
|
||||
isAppControlServerAvailable: async () => true,
|
||||
waitForSocketReady: async (socketPath, timeoutMs) => {
|
||||
waitedSockets.push({ socketPath, timeoutMs });
|
||||
@@ -283,30 +239,21 @@ test('launchWindowsMpv attaches a launched video to a running app and disables p
|
||||
spawnedArgs.push(args);
|
||||
},
|
||||
}),
|
||||
['--input-ipc-server', '\\\\.\\pipe\\warm-subminer'],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'',
|
||||
'normal',
|
||||
undefined,
|
||||
{
|
||||
socketPath: '\\\\.\\pipe\\ignored-config-socket',
|
||||
binaryPath: '',
|
||||
backend: 'windows',
|
||||
logLevel: 'debug',
|
||||
logRotation: 7,
|
||||
autoStart: true,
|
||||
autoStartVisibleOverlay: true,
|
||||
autoStartPauseUntilReady: true,
|
||||
osdMessages: false,
|
||||
texthookerEnabled: true,
|
||||
extraArgs: ['--input-ipc-server', '\\\\.\\pipe\\warm-subminer'],
|
||||
runtimeConfig: pluginConfig({
|
||||
socketPath: '\\\\.\\pipe\\ignored-config-socket',
|
||||
logLevel: 'debug',
|
||||
logRotation: 7,
|
||||
texthookerEnabled: true,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
const scriptOpts = spawnedArgs[0]?.find((arg) => arg.startsWith('--script-opts='));
|
||||
assert.match(scriptOpts ?? '', /subminer-auto_start=no/);
|
||||
assert.match(scriptOpts ?? '', /subminer-socket_path=\\\\\.\\pipe\\warm-subminer/);
|
||||
const scriptOpts = scriptOptsOf(spawnedArgs[0]);
|
||||
assert.match(scriptOpts, /subminer-auto_start=no/);
|
||||
assert.match(scriptOpts, /subminer-socket_path=\\\\\.\\pipe\\warm-subminer/);
|
||||
assert.deepEqual(waitedSockets, [{ socketPath: '\\\\.\\pipe\\warm-subminer', timeoutMs: 10000 }]);
|
||||
assert.deepEqual(controlArgv, [
|
||||
[
|
||||
@@ -330,11 +277,8 @@ test('launchWindowsMpv leaves plugin auto-start enabled when no running app cont
|
||||
const spawnedArgs: string[][] = [];
|
||||
let controlCalls = 0;
|
||||
let waitCalls = 0;
|
||||
const result = await launchWindowsMpv(
|
||||
['C:\\video.mkv'],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
const result = await launch(
|
||||
createResolvedDeps({
|
||||
isAppControlServerAvailable: async () => false,
|
||||
waitForSocketReady: async () => {
|
||||
waitCalls += 1;
|
||||
@@ -348,27 +292,11 @@ test('launchWindowsMpv leaves plugin auto-start enabled when no running app cont
|
||||
spawnedArgs.push(args);
|
||||
},
|
||||
}),
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'',
|
||||
'normal',
|
||||
undefined,
|
||||
{
|
||||
socketPath: '\\\\.\\pipe\\subminer-socket',
|
||||
binaryPath: '',
|
||||
backend: 'windows',
|
||||
autoStart: true,
|
||||
autoStartVisibleOverlay: true,
|
||||
autoStartPauseUntilReady: true,
|
||||
osdMessages: false,
|
||||
texthookerEnabled: false,
|
||||
},
|
||||
{ runtimeConfig: pluginConfig() },
|
||||
);
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
const scriptOpts = spawnedArgs[0]?.find((arg) => arg.startsWith('--script-opts='));
|
||||
assert.match(scriptOpts ?? '', /subminer-auto_start=yes/);
|
||||
assert.match(scriptOptsOf(spawnedArgs[0]), /subminer-auto_start=yes/);
|
||||
assert.equal(waitCalls, 0);
|
||||
assert.equal(controlCalls, 0);
|
||||
});
|
||||
@@ -387,31 +315,23 @@ test('launchWindowsMpv reports missing mpv path', async () => {
|
||||
assert.match(errors[0] ?? '', /mpv\.executablePath/i);
|
||||
});
|
||||
|
||||
test('launchWindowsMpv spawns detached mpv with targets', async () => {
|
||||
const calls: string[] = [];
|
||||
test('launchWindowsMpv spawns the resolved mpv with the bundled plugin and targets', async () => {
|
||||
const spawns: Array<{ command: string; args: string[] }> = [];
|
||||
const logs: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
['C:\\video.mkv'],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
const result = await launch(
|
||||
createResolvedDeps({
|
||||
logInfo: (message) => logs.push(message),
|
||||
spawnDetached: async (command, args) => {
|
||||
calls.push(command);
|
||||
calls.push(args.join('|'));
|
||||
spawns.push({ command, args });
|
||||
},
|
||||
}),
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
);
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.mpvPath, 'C:\\mpv\\mpv.exe');
|
||||
assert.deepEqual(calls, [
|
||||
'C:\\mpv\\mpv.exe',
|
||||
'--player-operation-mode=pseudo-gui|--force-window=immediate|--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua|--input-ipc-server=\\\\.\\pipe\\subminer-socket|--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us|--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us|--sub-auto=fuzzy|--sub-file-paths=subs;subtitles|--sid=auto|--secondary-sid=auto|--sub-visibility=no|--secondary-sub-visibility=no|--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner.exe,subminer-socket_path=\\\\.\\pipe\\subminer-socket|C:\\video.mkv',
|
||||
]);
|
||||
assert.deepEqual(result, { ok: true, mpvPath: MPV_PATH });
|
||||
assert.equal(spawns.length, 1);
|
||||
assert.equal(spawns[0]!.command, MPV_PATH);
|
||||
assert.ok(spawns[0]!.args.includes(`--script=${PLUGIN_PATH}`));
|
||||
assert.equal(spawns[0]!.args.at(-1), 'C:\\video.mkv');
|
||||
assert.match(logs[0] ?? '', /mpvPath=C:\\mpv\\mpv\.exe/);
|
||||
assert.match(logs[0] ?? '', /inputIpcServer=\\\\\.\\pipe\\subminer-socket/);
|
||||
assert.match(
|
||||
@@ -422,132 +342,95 @@ test('launchWindowsMpv spawns detached mpv with targets', async () => {
|
||||
});
|
||||
|
||||
test('launchWindowsMpv forwards runtime logging config to mpv and plugin', async () => {
|
||||
const calls: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
['C:\\video.mkv'],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
spawnDetached: async (command, args, env) => {
|
||||
calls.push(command);
|
||||
calls.push(args.join('|'));
|
||||
calls.push(env?.SUBMINER_LOG_LEVEL ?? '');
|
||||
calls.push(env?.SUBMINER_LOG_ROTATION ?? '');
|
||||
let spawned: { args: string[]; env?: NodeJS.ProcessEnv } | null = null;
|
||||
const result = await launch(
|
||||
createResolvedDeps({
|
||||
spawnDetached: async (_command, args, env) => {
|
||||
spawned = { args, env };
|
||||
},
|
||||
}),
|
||||
['--log-file=C:\\Users\\tester\\AppData\\Roaming\\SubMiner\\logs\\mpv-2026-05-26.log'],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'',
|
||||
'normal',
|
||||
undefined,
|
||||
{
|
||||
socketPath: '\\\\.\\pipe\\subminer-socket',
|
||||
binaryPath: '',
|
||||
backend: 'windows',
|
||||
logLevel: 'debug',
|
||||
logRotation: 0,
|
||||
autoStart: true,
|
||||
autoStartVisibleOverlay: false,
|
||||
autoStartPauseUntilReady: true,
|
||||
osdMessages: false,
|
||||
texthookerEnabled: false,
|
||||
extraArgs: [
|
||||
'--log-file=C:\\Users\\tester\\AppData\\Roaming\\SubMiner\\logs\\mpv-2026-05-26.log',
|
||||
],
|
||||
runtimeConfig: pluginConfig({
|
||||
logLevel: 'debug',
|
||||
logRotation: 0,
|
||||
autoStartVisibleOverlay: false,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
assert.match(calls[1] ?? '', /--msg-level=all=warn,subminer=debug/);
|
||||
assert.doesNotMatch(calls[1] ?? '', /subminer-log_level=debug/);
|
||||
assert.match(
|
||||
calls[1] ?? '',
|
||||
/--log-file=C:\\Users\\tester\\AppData\\Roaming\\SubMiner\\logs\\mpv-2026-05-26\.log/,
|
||||
);
|
||||
assert.equal(calls[2], 'debug');
|
||||
assert.equal(calls[3], '0');
|
||||
assert.ok(spawned);
|
||||
const { args, env } = spawned as { args: string[]; env?: NodeJS.ProcessEnv };
|
||||
assert.ok(args.includes('--msg-level=all=warn,subminer=debug'));
|
||||
assert.doesNotMatch(scriptOptsOf(args), /subminer-log_level=debug/);
|
||||
assert.equal(env?.SUBMINER_LOG_LEVEL, 'debug');
|
||||
assert.equal(env?.SUBMINER_LOG_ROTATION, '0');
|
||||
});
|
||||
|
||||
test('launchWindowsMpv skips bundled script when installed plugin is detected', async () => {
|
||||
const calls: string[] = [];
|
||||
const spawnedArgs: string[][] = [];
|
||||
const notifications: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
['C:\\video.mkv'],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
spawnDetached: async (command, args) => {
|
||||
calls.push(command);
|
||||
calls.push(args.join('|'));
|
||||
const result = await launch(
|
||||
createResolvedDeps({
|
||||
spawnDetached: async (_command, args) => {
|
||||
spawnedArgs.push(args);
|
||||
},
|
||||
}),
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'',
|
||||
'normal',
|
||||
{
|
||||
detectInstalledMpvPlugin: () => ({
|
||||
installed: true,
|
||||
path: 'C:\\Users\\tester\\AppData\\Roaming\\mpv\\scripts\\subminer\\main.lua',
|
||||
version: null,
|
||||
source: 'default-config',
|
||||
message: null,
|
||||
}),
|
||||
notifyInstalledPluginDetected: (detection) => {
|
||||
notifications.push(detection.path ?? '');
|
||||
policy: {
|
||||
detectInstalledMpvPlugin: () => ({
|
||||
installed: true,
|
||||
path: 'C:\\Users\\tester\\AppData\\Roaming\\mpv\\scripts\\subminer\\main.lua',
|
||||
version: null,
|
||||
source: 'default-config',
|
||||
message: null,
|
||||
}),
|
||||
notifyInstalledPluginDetected: (detection) => {
|
||||
notifications.push(detection.path ?? '');
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(calls[0], 'C:\\mpv\\mpv.exe');
|
||||
assert.doesNotMatch(calls[1] ?? '', /--script=C:\\Program Files\\SubMiner/);
|
||||
assert.match(calls[1] ?? '', /--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner\.exe/);
|
||||
assert.equal(spawnedArgs[0]?.includes(`--script=${PLUGIN_PATH}`), false);
|
||||
assert.match(scriptOptsOf(spawnedArgs[0]), /subminer-binary_path=C:\\SubMiner\\SubMiner\.exe/);
|
||||
assert.deepEqual(notifications, [
|
||||
'C:\\Users\\tester\\AppData\\Roaming\\mpv\\scripts\\subminer\\main.lua',
|
||||
]);
|
||||
});
|
||||
|
||||
test('launchWindowsMpv prompts before launch and injects bundled script after legacy plugin removal', async () => {
|
||||
const calls: string[] = [];
|
||||
const spawnedArgs: string[][] = [];
|
||||
const prompts: string[] = [];
|
||||
let detectCalls = 0;
|
||||
const result = await launchWindowsMpv(
|
||||
['C:\\video.mkv'],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
spawnDetached: async (command, args) => {
|
||||
calls.push(command);
|
||||
calls.push(args.join('|'));
|
||||
const result = await launch(
|
||||
createResolvedDeps({
|
||||
spawnDetached: async (_command, args) => {
|
||||
spawnedArgs.push(args);
|
||||
},
|
||||
}),
|
||||
[],
|
||||
'C:\\SubMiner\\SubMiner.exe',
|
||||
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
|
||||
'',
|
||||
'normal',
|
||||
{
|
||||
detectInstalledMpvPlugin: () => {
|
||||
detectCalls += 1;
|
||||
return detectCalls === 1
|
||||
? {
|
||||
installed: true,
|
||||
path: 'C:\\Users\\tester\\AppData\\Roaming\\mpv\\scripts\\subminer\\main.lua',
|
||||
version: '0.12.0',
|
||||
source: 'default-config',
|
||||
message: null,
|
||||
}
|
||||
: {
|
||||
installed: false,
|
||||
path: null,
|
||||
version: null,
|
||||
source: null,
|
||||
message: null,
|
||||
};
|
||||
},
|
||||
resolveInstalledPluginBeforeLaunch: async (detection) => {
|
||||
prompts.push(detection.path ?? '');
|
||||
return 'removed' as const;
|
||||
policy: {
|
||||
detectInstalledMpvPlugin: () => {
|
||||
detectCalls += 1;
|
||||
return detectCalls === 1
|
||||
? {
|
||||
installed: true,
|
||||
path: 'C:\\Users\\tester\\AppData\\Roaming\\mpv\\scripts\\subminer\\main.lua',
|
||||
version: '0.12.0',
|
||||
source: 'default-config',
|
||||
message: null,
|
||||
}
|
||||
: { installed: false, path: null, version: null, source: null, message: null };
|
||||
},
|
||||
resolveInstalledPluginBeforeLaunch: async (detection) => {
|
||||
prompts.push(detection.path ?? '');
|
||||
return 'removed' as const;
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -557,47 +440,42 @@ test('launchWindowsMpv prompts before launch and injects bundled script after le
|
||||
assert.deepEqual(prompts, [
|
||||
'C:\\Users\\tester\\AppData\\Roaming\\mpv\\scripts\\subminer\\main.lua',
|
||||
]);
|
||||
assert.equal(calls[0], 'C:\\mpv\\mpv.exe');
|
||||
assert.match(
|
||||
calls[1] ?? '',
|
||||
/--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main\.lua/,
|
||||
);
|
||||
assert.ok(spawnedArgs[0]?.includes(`--script=${PLUGIN_PATH}`));
|
||||
});
|
||||
|
||||
test('launchWindowsMpv reports spawn failures with path context', async () => {
|
||||
const errors: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
[],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
spawnDetached: async () => {
|
||||
throw new Error('spawn failed');
|
||||
},
|
||||
showError: (_title, content) => errors.push(content),
|
||||
}),
|
||||
);
|
||||
const spawnFailureCases: Array<{
|
||||
name: string;
|
||||
spawnDetached: WindowsMpvLaunchDeps['spawnDetached'];
|
||||
message: RegExp;
|
||||
}> = [
|
||||
{
|
||||
name: 'synchronous',
|
||||
spawnDetached: () => {
|
||||
throw new Error('spawn failed');
|
||||
},
|
||||
message: /spawn failed/,
|
||||
},
|
||||
{
|
||||
name: 'asynchronous',
|
||||
spawnDetached: () => Promise.reject(new Error('async spawn failed')),
|
||||
message: /async spawn failed/,
|
||||
},
|
||||
];
|
||||
|
||||
assert.equal(result.ok, false);
|
||||
assert.equal(result.mpvPath, 'C:\\mpv\\mpv.exe');
|
||||
assert.match(errors[0] ?? '', /Failed to launch mpv/i);
|
||||
assert.match(errors[0] ?? '', /C:\\mpv\\mpv\.exe/i);
|
||||
});
|
||||
for (const failure of spawnFailureCases) {
|
||||
test(`launchWindowsMpv reports ${failure.name} spawn failures with path context`, async () => {
|
||||
const errors: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
[],
|
||||
createResolvedDeps({
|
||||
spawnDetached: failure.spawnDetached,
|
||||
showError: (_title, content) => errors.push(content),
|
||||
}),
|
||||
);
|
||||
|
||||
test('launchWindowsMpv reports async spawn failures with path context', async () => {
|
||||
const errors: string[] = [];
|
||||
const result = await launchWindowsMpv(
|
||||
[],
|
||||
createDeps({
|
||||
getEnv: (name) => (name === 'SUBMINER_MPV_PATH' ? 'C:\\mpv\\mpv.exe' : undefined),
|
||||
fileExists: (candidate) => candidate === 'C:\\mpv\\mpv.exe',
|
||||
spawnDetached: () => Promise.reject(new Error('async spawn failed')),
|
||||
showError: (_title, content) => errors.push(content),
|
||||
}),
|
||||
);
|
||||
|
||||
assert.equal(result.ok, false);
|
||||
assert.equal(result.mpvPath, 'C:\\mpv\\mpv.exe');
|
||||
assert.match(errors[0] ?? '', /Failed to launch mpv/i);
|
||||
assert.match(errors[0] ?? '', /async spawn failed/i);
|
||||
});
|
||||
assert.deepEqual(result, { ok: false, mpvPath: MPV_PATH });
|
||||
assert.match(errors[0] ?? '', /Failed to launch mpv/i);
|
||||
assert.match(errors[0] ?? '', /C:\\mpv\\mpv\.exe/i);
|
||||
assert.match(errors[0] ?? '', failure.message);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user