const test = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const { spawnSync } = require('node:child_process'); const { createPrefs, DEFAULTS } = require('../src/features/appPrefs.js'); const { useBundledGit, applyGitIdentity, commitIdentity } = require('../src/git/gitBinary.js'); const { createRepoBackup, excludeMatcher } = require('../src/backup/GiteaRepoBackup.js'); const tmp = (p) => fs.mkdtempSync(path.join(os.tmpdir(), p)); test('Einstellungen: Standardwerte, Bereinigung und ungültige E-Mail', () => { const file = path.join(tmp('gm-prefs-'), 'app-settings.json'); const prefs = createPrefs(file); assert.deepStrictEqual(prefs.get(), DEFAULTS); const r = prefs.set({ zoom: 400, theme: 'pink', closeAction: 'tray', gitName: 'Max \n', unbekannt: 1, uploadSecretScan: 0 }); assert.strictEqual(r.prefs.zoom, 150); assert.strictEqual(r.prefs.theme, 'dark'); assert.strictEqual(r.prefs.closeAction, 'tray'); assert.strictEqual(r.prefs.gitName, 'Max x'); assert.strictEqual(r.prefs.uploadSecretScan, false); assert.ok(!('unbekannt' in r.prefs)); const bad = prefs.set({ gitEmail: 'keine-mail' }); assert.deepStrictEqual(bad.rejected, ['gitEmail']); assert.strictEqual(bad.prefs.gitEmail, ''); // nach dem Neuladen noch da assert.strictEqual(createPrefs(file).get().closeAction, 'tray'); }); test('Git-Identität greift nur als Rückfallwert und verschwindet beim Leeren', () => { useBundledGit(); const userData = tmp('gm-ud-'); const home = tmp('gm-home-'); const env = { ...process.env, HOME: home, USERPROFILE: home }; const ident = () => spawnSync('git', ['var', 'GIT_AUTHOR_IDENT'], { encoding: 'utf8', env: { ...env, GIT_CONFIG_SYSTEM: process.env.GIT_CONFIG_SYSTEM || '' } }).stdout; assert.strictEqual(applyGitIdentity({ name: 'Test Name', email: 'test@example.com' }, userData), true); assert.match(ident(), /^Test Name /); // Eine globale Einstellung hat Vorrang fs.writeFileSync(path.join(home, '.gitconfig'), '[user]\n\tname = Global\n\temail = global@example.com\n'); assert.match(ident(), /^Global /); applyGitIdentity({ name: '', email: '' }, userData); assert.strictEqual(process.env.GIT_CONFIG_SYSTEM, undefined); assert.ok(!fs.existsSync(path.join(userData, 'git-system.gitconfig'))); assert.deepStrictEqual(commitIdentity({ gitName: '', gitEmail: '' }), { name: 'Git Manager GUI', email: 'gui@gitmanager.local' }); }); test('Backup: Ausschlussmuster und Zeitpunkt für automatische Backups', () => { const m = excludeMatcher('test-*\nM_Viper/Alt?\n# Kommentar\nmy.repo'); assert.strictEqual(m('M_Viper/test-1'), true); assert.strictEqual(m('M_Viper/Alt1'), true); assert.strictEqual(m('M_Viper/Alt12'), false); assert.strictEqual(m('x/my.repo'), true); assert.strictEqual(m('x/myXrepo'), false); const configPath = path.join(tmp('gm-bk-'), 'repo-backup.json'); const backup = createRepoBackup({ configPath, getContext() {}, giteaCall() {}, runGit() {}, isPackFailure() {}, redact: (s) => s }); backup.setConfig({ targetDir: 'X:/irgendwo', interval: 'daily', time: '03:00' }); const at = (s) => new Date(s); // noch nie gelaufen: vor 03:00 nicht, danach schon assert.strictEqual(backup.isDue(at('2026-10-22T02:59:00')), true, 'Slot von gestern 03:00 ist offen'); fs.writeFileSync(configPath, JSON.stringify({ ...JSON.parse(fs.readFileSync(configPath, 'utf8')), lastRun: '2026-10-22T03:05:00' })); assert.strictEqual(backup.isDue(at('2026-10-22T20:00:00')), false, 'heute schon gelaufen'); assert.strictEqual(backup.isDue(at('2026-10-23T02:59:00')), false, 'vor 03:00 noch nicht'); assert.strictEqual(backup.isDue(at('2026-10-23T03:00:00')), true, 'ab 03:00 wieder fällig'); backup.setConfig({ time: '25:99' }); assert.strictEqual(backup.getState().config.time, ''); });