mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-20 03:16:46 -07:00
fix(plugin): add lowercase linux binary fallbacks
This commit is contained in:
@@ -2,11 +2,13 @@ import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import net from 'node:net';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import type { Args } from './types';
|
||||
import {
|
||||
cleanupPlaybackSession,
|
||||
findAppBinary,
|
||||
runAppCommandCaptureOutput,
|
||||
shouldResolveAniSkipMetadata,
|
||||
startOverlay,
|
||||
@@ -233,3 +235,72 @@ test('cleanupPlaybackSession preserves background app while stopping mpv-owned c
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// ── findAppBinary: Linux packaged path discovery ──────────────────────────────
|
||||
|
||||
function makeExecutable(filePath: string): void {
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
fs.writeFileSync(filePath, '#!/bin/sh\nexit 0\n');
|
||||
fs.chmodSync(filePath, 0o755);
|
||||
}
|
||||
|
||||
test('findAppBinary resolves ~/.local/bin/SubMiner.AppImage when it exists', () => {
|
||||
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-home-'));
|
||||
const originalHomedir = os.homedir;
|
||||
try {
|
||||
os.homedir = () => baseDir;
|
||||
const appImage = path.join(baseDir, '.local/bin/SubMiner.AppImage');
|
||||
makeExecutable(appImage);
|
||||
|
||||
const result = findAppBinary('/some/other/path/subminer');
|
||||
assert.equal(result, appImage);
|
||||
} finally {
|
||||
os.homedir = originalHomedir;
|
||||
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('findAppBinary resolves /opt/SubMiner/SubMiner.AppImage when ~/.local/bin candidate does not exist', () => {
|
||||
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-home-'));
|
||||
const originalHomedir = os.homedir;
|
||||
const originalAccessSync = fs.accessSync;
|
||||
try {
|
||||
os.homedir = () => baseDir;
|
||||
// No ~/.local/bin/SubMiner.AppImage; patch accessSync so only /opt path is executable
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(fs as any).accessSync = (filePath: string, mode?: number): void => {
|
||||
if (filePath === '/opt/SubMiner/SubMiner.AppImage') return;
|
||||
throw Object.assign(new Error(`EACCES: ${filePath}`), { code: 'EACCES' });
|
||||
};
|
||||
|
||||
const result = findAppBinary('/some/other/path/subminer');
|
||||
assert.equal(result, '/opt/SubMiner/SubMiner.AppImage');
|
||||
} finally {
|
||||
os.homedir = originalHomedir;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(fs as any).accessSync = originalAccessSync;
|
||||
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('findAppBinary finds subminer on PATH when AppImage candidates do not exist', () => {
|
||||
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-path-'));
|
||||
const originalHomedir = os.homedir;
|
||||
const originalPath = process.env.PATH;
|
||||
try {
|
||||
os.homedir = () => baseDir;
|
||||
// No AppImage candidates in empty home dir; place subminer wrapper on PATH
|
||||
const binDir = path.join(baseDir, 'bin');
|
||||
const wrapperPath = path.join(binDir, 'subminer');
|
||||
makeExecutable(wrapperPath);
|
||||
process.env.PATH = `${binDir}${path.delimiter}${originalPath ?? ''}`;
|
||||
|
||||
// selfPath must differ from wrapperPath so the self-check does not exclude it
|
||||
const result = findAppBinary(path.join(baseDir, 'launcher', 'subminer'));
|
||||
assert.equal(result, wrapperPath);
|
||||
} finally {
|
||||
os.homedir = originalHomedir;
|
||||
process.env.PATH = originalPath;
|
||||
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
90
launcher/picker.test.ts
Normal file
90
launcher/picker.test.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { findRofiTheme } from './picker';
|
||||
|
||||
// ── findRofiTheme: Linux packaged path discovery ──────────────────────────────
|
||||
|
||||
const ROFI_THEME_FILE = 'subminer.rasi';
|
||||
|
||||
function makeFile(filePath: string): void {
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
fs.writeFileSync(filePath, '/* theme */');
|
||||
}
|
||||
|
||||
test('findRofiTheme resolves /usr/local/share/SubMiner/themes/subminer.rasi when it exists', () => {
|
||||
const originalExistsSync = fs.existsSync;
|
||||
const targetPath = `/usr/local/share/SubMiner/themes/${ROFI_THEME_FILE}`;
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(fs as any).existsSync = (filePath: unknown): boolean => {
|
||||
if (filePath === targetPath) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
const result = findRofiTheme('/usr/local/bin/subminer');
|
||||
assert.equal(result, targetPath);
|
||||
} finally {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(fs as any).existsSync = originalExistsSync;
|
||||
}
|
||||
});
|
||||
|
||||
test('findRofiTheme resolves /usr/share/SubMiner/themes/subminer.rasi when /usr/local/share one does not exist', () => {
|
||||
const originalExistsSync = fs.existsSync;
|
||||
const localSharePath = `/usr/local/share/SubMiner/themes/${ROFI_THEME_FILE}`;
|
||||
const sharePath = `/usr/share/SubMiner/themes/${ROFI_THEME_FILE}`;
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(fs as any).existsSync = (filePath: unknown): boolean => {
|
||||
if (filePath === sharePath) return true;
|
||||
if (filePath === localSharePath) return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
const result = findRofiTheme('/usr/bin/subminer');
|
||||
assert.equal(result, sharePath);
|
||||
} finally {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(fs as any).existsSync = originalExistsSync;
|
||||
}
|
||||
});
|
||||
|
||||
test('findRofiTheme resolves XDG_DATA_HOME/SubMiner/themes/subminer.rasi when set and file exists', () => {
|
||||
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-xdg-'));
|
||||
const originalXdgDataHome = process.env.XDG_DATA_HOME;
|
||||
try {
|
||||
process.env.XDG_DATA_HOME = baseDir;
|
||||
const themePath = path.join(baseDir, `SubMiner/themes/${ROFI_THEME_FILE}`);
|
||||
makeFile(themePath);
|
||||
|
||||
const result = findRofiTheme('/usr/bin/subminer');
|
||||
assert.equal(result, themePath);
|
||||
} finally {
|
||||
process.env.XDG_DATA_HOME = originalXdgDataHome;
|
||||
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('findRofiTheme resolves ~/.local/share/SubMiner/themes/subminer.rasi when XDG_DATA_HOME unset', () => {
|
||||
const baseDir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-test-home-'));
|
||||
const originalHomedir = os.homedir;
|
||||
const originalXdgDataHome = process.env.XDG_DATA_HOME;
|
||||
try {
|
||||
os.homedir = () => baseDir;
|
||||
delete process.env.XDG_DATA_HOME;
|
||||
const themePath = path.join(baseDir, `.local/share/SubMiner/themes/${ROFI_THEME_FILE}`);
|
||||
makeFile(themePath);
|
||||
|
||||
const result = findRofiTheme('/usr/bin/subminer');
|
||||
assert.equal(result, themePath);
|
||||
} finally {
|
||||
os.homedir = originalHomedir;
|
||||
if (originalXdgDataHome !== undefined) {
|
||||
process.env.XDG_DATA_HOME = originalXdgDataHome;
|
||||
}
|
||||
fs.rmSync(baseDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user