import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import sharp from 'sharp'; import { CANONICAL_SYSTEM_ICON_KEYS, SYSTEM_ICON_SIZE, seedSystemCategoryIcons, } from '../../backend/src/database/system-category-icons'; function makeTempDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'hipctf-icons-')); } describe('seedSystemCategoryIcons', () => { const cleanup: string[] = []; afterEach(() => { while (cleanup.length > 0) { const dir = cleanup.pop(); if (dir && fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true }); } }); it('writes six 128x128 PNGs into a fresh temp directory', async () => { const dir = makeTempDir(); cleanup.push(dir); const result = await seedSystemCategoryIcons(dir); expect(result.written.length).toBe(CANONICAL_SYSTEM_ICON_KEYS.length); expect(result.skipped.length).toBe(0); for (const key of CANONICAL_SYSTEM_ICON_KEYS) { const target = path.join(dir, 'icons', `${key}.png`); expect(fs.existsSync(target)).toBe(true); const stat = fs.statSync(target); expect(stat.size).toBeGreaterThan(0); const meta = await sharp(target).metadata(); expect(meta.format).toBe('png'); expect(meta.width).toBe(SYSTEM_ICON_SIZE); expect(meta.height).toBe(SYSTEM_ICON_SIZE); } }); it('is idempotent and does not overwrite an existing admin-uploaded icon', async () => { const dir = makeTempDir(); cleanup.push(dir); const first = await seedSystemCategoryIcons(dir); expect(first.written.length).toBe(CANONICAL_SYSTEM_ICON_KEYS.length); const adminIconPath = path.join(dir, 'icons', 'CRY.png'); const adminMtime = fs.statSync(adminIconPath).mtimeMs; await new Promise((r) => setTimeout(r, 25)); const second = await seedSystemCategoryIcons(dir); expect(second.written.length).toBe(0); expect(second.skipped.length).toBe(CANONICAL_SYSTEM_ICON_KEYS.length); expect(fs.statSync(adminIconPath).mtimeMs).toBe(adminMtime); for (const key of CANONICAL_SYSTEM_ICON_KEYS) { const target = path.join(dir, 'icons', `${key}.png`); expect(fs.statSync(target).size).toBeGreaterThan(0); } }); it('creates the icons subdirectory when the parent directory is empty', async () => { const dir = makeTempDir(); cleanup.push(dir); const target = path.join(dir, 'icons'); expect(fs.existsSync(target)).toBe(false); const result = await seedSystemCategoryIcons(dir); expect(result.written.length).toBe(CANONICAL_SYSTEM_ICON_KEYS.length); expect(fs.existsSync(target)).toBe(true); expect(fs.readdirSync(target).sort()).toEqual( [...CANONICAL_SYSTEM_ICON_KEYS].map((k) => `${k}.png`).sort(), ); }); });