test-zip-extract.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import fs from 'fs/promises';
  2. import os from 'os';
  3. import path from 'path';
  4. import { execFile } from 'child_process';
  5. import { promisify } from 'util';
  6. import { createZipFromDir, extractZipToDir } from './src/utils/zip-extract.js';
  7. const execFileAsync = promisify(execFile);
  8. let passed = 0;
  9. let failed = 0;
  10. function test(name, fn) {
  11. return Promise.resolve()
  12. .then(fn)
  13. .then(() => {
  14. console.log(` ✓ ${name}`);
  15. passed++;
  16. })
  17. .catch((err) => {
  18. console.log(` ✗ ${name}: ${err.message}`);
  19. failed++;
  20. });
  21. }
  22. function assert(cond, msg) {
  23. if (!cond) throw new Error(msg || 'Assertion failed');
  24. }
  25. function assertEqual(actual, expected, msg) {
  26. if (actual !== expected) {
  27. throw new Error(msg || `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
  28. }
  29. }
  30. console.log('\n── ZIP Import/Export Regression ──');
  31. const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'vlcode-zip-'));
  32. const wrappedRoot = path.join(tmpRoot, 'wrapped');
  33. const targetDir = path.join(tmpRoot, 'imported');
  34. const archivePath = path.join(tmpRoot, 'wrapped.zip');
  35. await fs.mkdir(path.join(wrappedRoot, 'EduSystem', 'Apps'), { recursive: true });
  36. await fs.mkdir(path.join(wrappedRoot, 'EduSystem', 'Sections'), { recursive: true });
  37. await fs.mkdir(path.join(wrappedRoot, 'EduSystem', '.vl-code'), { recursive: true });
  38. await fs.writeFile(path.join(wrappedRoot, 'EduSystem', 'Apps', 'StudentApp.vx'), '// VL_VERSION:3.5\n<App_StudentApp>\n', 'utf8');
  39. await fs.writeFile(path.join(wrappedRoot, 'EduSystem', 'Sections', 'Home.sc'), '// VL_VERSION:3.5\n<Section_Home>\n', 'utf8');
  40. await fs.writeFile(path.join(wrappedRoot, 'EduSystem', '.vl-code', 'project.json'), JSON.stringify({ projectName: 'EduSystem' }, null, 2), 'utf8');
  41. await test('createZipFromDir packages project files including .vl-code metadata', async () => {
  42. const buf = await createZipFromDir(path.join(wrappedRoot, 'EduSystem'));
  43. await fs.writeFile(archivePath, buf);
  44. const { stdout } = await execFileAsync('unzip', ['-Z1', archivePath]);
  45. assert(stdout.includes('Apps/StudentApp.vx'), 'archive should include app files');
  46. assert(stdout.includes('.vl-code/project.json'), 'archive should include .vl-code metadata');
  47. });
  48. await test('extractZipToDir strips a single root wrapper directory on import', async () => {
  49. const wrappedArchive = await createZipFromDir(wrappedRoot);
  50. await fs.writeFile(archivePath, wrappedArchive);
  51. await fs.mkdir(targetDir, { recursive: true });
  52. await extractZipToDir(archivePath, targetDir);
  53. const importedApp = await fs.readFile(path.join(targetDir, 'Apps', 'StudentApp.vx'), 'utf8');
  54. assert(importedApp.includes('App_StudentApp'), 'expected app file at stripped path');
  55. let wrappedExists = true;
  56. try {
  57. await fs.access(path.join(targetDir, 'EduSystem', 'Apps', 'StudentApp.vx'));
  58. } catch {
  59. wrappedExists = false;
  60. }
  61. assertEqual(wrappedExists, false, 'wrapper directory should not be preserved');
  62. });
  63. console.log(`\n── Results ──\n\n ${passed} passed, ${failed} failed\n`);
  64. process.exit(failed > 0 ? 1 : 0);