import './setup.mjs'; import test from 'node:test'; import assert from 'node:assert/strict'; import { load } from './setup.mjs'; const { analyzeInstaller, listInstallerTechnologies } = await load('../services/installerIntelService.js'); const { buildDetectionRule } = await load('../services/detectionRuleService.js'); // --- installer detection + silent switches -------------------------------- test('MSI is detected with high confidence and product-code uninstall', () => { const result = analyzeInstaller({ fileName: 'ContosoVpn.msi', productCode: '{12345678-1234-1234-1234-123456789012}' }); assert.equal(result.confidence, 'high'); assert.equal(result.primary.id, 'msi'); assert.ok(result.primary.install.includes('/qn')); assert.ok(result.primary.uninstall.includes('{12345678-1234-1234-1234-123456789012}')); }); test('MSIX is detected from its extension', () => { const result = analyzeInstaller({ fileName: 'App_1.0.0.0_x64.msixbundle' }); assert.equal(result.primary.id, 'msix'); assert.ok(result.primary.install.includes('Add-AppxProvisionedPackage')); }); test('EXE with a name hint matches the technology at medium confidence', () => { const result = analyzeInstaller({ fileName: 'app-nsis-setup.exe' }); assert.equal(result.confidence, 'medium'); assert.equal(result.primary.id, 'nsis'); assert.equal(result.primary.install, '"app-nsis-setup.exe" /S'); }); test('ambiguous EXE falls back to generic and offers candidates', () => { const result = analyzeInstaller({ fileName: 'installer.exe' }); assert.equal(result.confidence, 'low'); assert.equal(result.primary.id, 'exe'); const ids = result.candidates.map((c) => c.id); assert.ok(ids.includes('inno') && ids.includes('installshield')); assert.equal(ids[ids.length - 1], 'exe', 'generic EXE is offered last'); }); test('unknown extension reports unknown', () => { const result = analyzeInstaller({ fileName: 'notes.txt' }); assert.equal(result.confidence, 'unknown'); assert.equal(result.primary, null); }); test('listInstallerTechnologies exposes the catalog', () => { const list = listInstallerTechnologies(); assert.ok(list.find((t) => t.id === 'inno')); assert.ok(list.every((t) => Array.isArray(t.extensions))); }); // --- detection rule generation -------------------------------------------- test('MSI detection maps to a product-code rule', () => { const rule = buildDetectionRule({ type: 'msi', productCode: '{abc}' }); assert.equal(rule.detectionType, 'msi-product-code'); assert.equal(rule.detectionRule, '{abc}'); }); test('file detection generates a versioned PowerShell script', () => { const rule = buildDetectionRule({ type: 'file', path: 'C:\\Program Files\\App\\app.exe', version: '2.0.0' }); assert.equal(rule.detectionType, 'custom-script'); assert.ok(rule.detectionRule.includes('Test-Path')); assert.ok(rule.detectionRule.includes("[version]'2.0.0'")); assert.ok(rule.detectionRule.includes("Write-Output 'Detected'")); }); test('registry detection with a value comparison', () => { const rule = buildDetectionRule({ type: 'registry', keyPath: 'HKLM:\\SOFTWARE\\Contoso', valueName: 'Version', valueData: '2.0' }); assert.equal(rule.detectionType, 'custom-script'); assert.ok(rule.detectionRule.includes('HKLM:\\SOFTWARE\\Contoso')); assert.ok(rule.detectionRule.includes("-eq '2.0'")); }); test('detection generator validates required inputs', () => { assert.throws(() => buildDetectionRule({ type: 'msi' })); assert.throws(() => buildDetectionRule({ type: 'file' })); assert.throws(() => buildDetectionRule({ type: 'bogus' })); });