import * as assert from 'assert'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; import { existsSync } from 'fs'; import * as luaAddonsManager from '../lua-addons-manager'; /** * Integration tests for lua-addons-manager * Uses temporary directories to avoid polluting the file system */ suite('lua-addons-manager', () => { let tempDir: string; suiteSetup(async () => { tempDir = path.join(os.tmpdir(), `dcs-test-${Date.now()}-${Math.random()}`); }); suiteTeardown(async () => { if (existsSync(tempDir)) { await fs.rm(tempDir, { recursive: true, force: true }); } }); suite('getExtensionVersion', () => { test('should read version from package.json', async () => { const testDir = path.join(tempDir, 'getExtensionVersion-1'); await fs.mkdir(testDir, { recursive: true }); const packageJson = path.join(testDir, 'package.json'); await fs.writeFile(packageJson, JSON.stringify({ version: '1.2.3' })); const version = await luaAddonsManager.getExtensionVersion(testDir); assert.strictEqual(version, '1.2.3'); }); test('should throw error if package.json not found', async () => { const testDir = path.join(tempDir, 'getExtensionVersion-2'); await fs.mkdir(testDir, { recursive: true }); await assert.rejects( () => luaAddonsManager.getExtensionVersion(testDir), /Failed to read extension version/ ); }); test('should throw error if version field missing', async () => { const testDir = path.join(tempDir, 'getExtensionVersion-3'); await fs.mkdir(testDir, { recursive: true }); const packageJson = path.join(testDir, 'package.json'); await fs.writeFile(packageJson, JSON.stringify({ name: 'test' })); await assert.rejects( () => luaAddonsManager.getExtensionVersion(testDir), /Version field not found/ ); }); }); suite('discoverLuaAddons', () => { test('should discover lua-addons directories', async () => { const testDir = path.join(tempDir, 'discoverLuaAddons-1'); const luaAddonsDir = path.join(testDir, 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'addon1'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon2'), { recursive: true }); const addons = await luaAddonsManager.discoverLuaAddons(testDir); assert.strictEqual(addons.size, 2); assert.strictEqual(addons.has('addon1'), true); assert.strictEqual(addons.has('addon2'), true); }); test('should return empty map if lua-addons directory does not exist', async () => { const testDir = path.join(tempDir, 'discoverLuaAddons-2'); await fs.mkdir(testDir, { recursive: true }); const addons = await luaAddonsManager.discoverLuaAddons(testDir); assert.strictEqual(addons.size, 0); }); test('should ignore non-directory entries', async () => { const testDir = path.join(tempDir, 'discoverLuaAddons-3'); const luaAddonsDir = path.join(testDir, 'lua-addons'); await fs.mkdir(luaAddonsDir, { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon1'), { recursive: true }); await fs.writeFile(path.join(luaAddonsDir, 'file.txt'), 'test'); const addons = await luaAddonsManager.discoverLuaAddons(testDir); assert.strictEqual(addons.size, 1); assert.strictEqual(addons.has('addon1'), true); }); }); suite('getWorkspaceLuaAddonsDir', () => { test('should return correct .vscode/lua-addons path', () => { const workspaceRoot = '/path/to/workspace'; const result = luaAddonsManager.getWorkspaceLuaAddonsDir(workspaceRoot); assert.strictEqual(result, path.join(workspaceRoot, '.vscode', 'lua-addons')); }); }); suite('getInstalledVersions', () => { test('should parse installed addon versions from folder names', async () => { const testDir = path.join(tempDir, 'getInstalledVersions-1'); const luaAddonsDir = path.join(testDir, '.vscode', 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'dcs-types.0.0.5'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'mission-utils.1.2.3'), { recursive: true }); const installed = await luaAddonsManager.getInstalledVersions(testDir); assert.strictEqual(installed.size, 2); assert.strictEqual(installed.has('dcs-types'), true); assert.strictEqual(installed.has('mission-utils'), true); assert.strictEqual(installed.get('dcs-types')?.version, '0.0.5'); assert.strictEqual(installed.get('mission-utils')?.version, '1.2.3'); }); test('should return empty map if directory does not exist', async () => { const testDir = path.join(tempDir, 'getInstalledVersions-2'); await fs.mkdir(testDir, { recursive: true }); const installed = await luaAddonsManager.getInstalledVersions(testDir); assert.strictEqual(installed.size, 0); }); test('should ignore folders with invalid version format', async () => { const testDir = path.join(tempDir, 'getInstalledVersions-3'); const luaAddonsDir = path.join(testDir, '.vscode', 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'dcs-types.0.0.5'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'invalid-addon'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'bad-format.v1'), { recursive: true }); const installed = await luaAddonsManager.getInstalledVersions(testDir); assert.strictEqual(installed.size, 1); assert.strictEqual(installed.has('dcs-types'), true); assert.strictEqual(installed.has('invalid-addon'), false); assert.strictEqual(installed.has('bad-format'), false); }); }); suite('copyLuaAddons', () => { test('should copy addons with versioned folder names', async () => { const testDir = path.join(tempDir, 'copyLuaAddons-1'); const sourceAddon1 = path.join(testDir, 'source-addons', 'addon1'); await fs.mkdir(sourceAddon1, { recursive: true }); await fs.writeFile(path.join(sourceAddon1, 'file1.lua'), 'content1'); const addonsToCopy = new Map([ ['addon1', sourceAddon1] ]); const result = await luaAddonsManager.copyLuaAddons( testDir, testDir, '1.0.0', addonsToCopy ); assert.strictEqual(result.size, 1); const copiedPath = result.get('addon1'); assert.strictEqual(copiedPath !== undefined, true); if (copiedPath) { assert.strictEqual(copiedPath.includes('addon1.1.0.0'), true); assert.strictEqual(existsSync(path.join(copiedPath, 'file1.lua')), true); } }); test('should create .vscode directory if it does not exist', async () => { const testDir = path.join(tempDir, 'copyLuaAddons-2'); const sourceAddon = path.join(testDir, 'source', 'addon1'); await fs.mkdir(sourceAddon, { recursive: true }); const addonsToCopy = new Map([ ['addon1', sourceAddon] ]); await luaAddonsManager.copyLuaAddons( testDir, testDir, '1.0.0', addonsToCopy ); const vscodeDir = path.join(testDir, '.vscode'); assert.strictEqual(existsSync(vscodeDir), true); }); test('should copy nested directories recursively', async () => { const testDir = path.join(tempDir, 'copyLuaAddons-3'); const sourceAddon = path.join(testDir, 'source', 'addon1'); await fs.mkdir(path.join(sourceAddon, 'subdir'), { recursive: true }); await fs.writeFile(path.join(sourceAddon, 'file.lua'), 'root'); await fs.writeFile(path.join(sourceAddon, 'subdir', 'file.lua'), 'nested'); const addonsToCopy = new Map([ ['addon1', sourceAddon] ]); const result = await luaAddonsManager.copyLuaAddons( testDir, testDir, '1.0.0', addonsToCopy ); const copiedPath = result.get('addon1')!; assert.strictEqual(existsSync(path.join(copiedPath, 'file.lua')), true); assert.strictEqual(existsSync(path.join(copiedPath, 'subdir', 'file.lua')), true); }); }); suite('deleteOldVersions', () => { test('should delete old versions of an addon', async () => { const testDir = path.join(tempDir, 'deleteOldVersions-1'); const luaAddonsDir = path.join(testDir, '.vscode', 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.1'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.2'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.3'), { recursive: true }); await luaAddonsManager.deleteOldVersions(testDir, 'addon1', '0.0.3'); const remaining = await fs.readdir(luaAddonsDir); assert.deepStrictEqual(remaining.sort(), ['addon1.0.0.3']); }); test('should not delete other addons', async () => { const testDir = path.join(tempDir, 'deleteOldVersions-2'); const luaAddonsDir = path.join(testDir, '.vscode', 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.1'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.2'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon2.0.0.1'), { recursive: true }); await luaAddonsManager.deleteOldVersions(testDir, 'addon1', '0.0.2'); const remaining = await fs.readdir(luaAddonsDir); assert.strictEqual(remaining.includes('addon1.0.0.2'), true); assert.strictEqual(remaining.includes('addon2.0.0.1'), true); assert.strictEqual(remaining.includes('addon1.0.0.1'), false); }); test('should handle missing directory gracefully', async () => { const testDir = path.join(tempDir, 'deleteOldVersions-3'); await fs.mkdir(testDir, { recursive: true }); // Should not throw await luaAddonsManager.deleteOldVersions(testDir, 'addon1', '0.0.1'); }); }); suite('deleteAllVersionsOfAddon', () => { test('should delete all versions of an addon', async () => { const testDir = path.join(tempDir, 'deleteAllVersionsOfAddon-1'); const luaAddonsDir = path.join(testDir, '.vscode', 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.1'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon1.0.0.2'), { recursive: true }); await fs.mkdir(path.join(luaAddonsDir, 'addon2.0.0.1'), { recursive: true }); await luaAddonsManager.deleteAllVersionsOfAddon(testDir, 'addon1'); const remaining = await fs.readdir(luaAddonsDir); assert.deepStrictEqual(remaining.sort(), ['addon2.0.0.1']); }); }); suite('requiresUpdate', () => { test('should return true if no version installed', () => { const result = luaAddonsManager.requiresUpdate(undefined, '1.0.0'); assert.strictEqual(result, true); }); test('should return true if versions do not match', () => { const result = luaAddonsManager.requiresUpdate('1.0.0', '1.0.1'); assert.strictEqual(result, true); }); test('should return false if versions match', () => { const result = luaAddonsManager.requiresUpdate('1.0.0', '1.0.0'); assert.strictEqual(result, false); }); }); suite('getInstalledAddons', () => { test('should return installed addon information', async () => { const testDir = path.join(tempDir, 'getInstalledAddons-1'); const luaAddonsDir = path.join(testDir, '.vscode', 'lua-addons'); await fs.mkdir(path.join(luaAddonsDir, 'dcs-types.0.0.5'), { recursive: true }); const installed = await luaAddonsManager.getInstalledAddons(testDir); assert.strictEqual(installed.size, 1); const addonInfo = installed.get('dcs-types'); assert.strictEqual(addonInfo !== undefined, true); if (addonInfo) { assert.strictEqual(addonInfo.name, 'dcs-types'); assert.strictEqual(addonInfo.version, '0.0.5'); assert.strictEqual(addonInfo.path.includes('dcs-types.0.0.5'), true); } }); }); });