From 5d7bac8de27cb8f4468bf286e436f2d87d4d017f Mon Sep 17 00:00:00 2001 From: achingbrain Date: Sun, 10 Nov 2024 10:37:17 +0000 Subject: [PATCH] chore: add tests to ensure there are no regressions Adds a test suite that just verifies every model solution. --- .../{solution.js => solution.mjs} | 0 .../2_streams/{solution.js => solution.mjs} | 0 .../{solution.js => solution.mjs} | 0 .../{solution.js => solution.mjs} | 0 .../{solution.js => solution.mjs} | 0 .../{solution.js => solution.mjs} | 0 exercises/7_rpc/{solution.js => solution.mjs} | 0 package.json | 4 +- patches/workshopper-adventure+7.0.0.patch | 17 ++++ test/exercises.spec.js | 85 +++++++++++++++++++ 10 files changed, 105 insertions(+), 1 deletion(-) rename exercises/1_hello_world/{solution.js => solution.mjs} (100%) rename exercises/2_streams/{solution.js => solution.mjs} (100%) rename exercises/3_custom_protocols/{solution.js => solution.mjs} (100%) rename exercises/4_imperative_protocols/{solution.js => solution.mjs} (100%) rename exercises/5_length_prefixed_data/{solution.js => solution.mjs} (100%) rename exercises/6_structured_data/{solution.js => solution.mjs} (100%) rename exercises/7_rpc/{solution.js => solution.mjs} (100%) create mode 100644 test/exercises.spec.js diff --git a/exercises/1_hello_world/solution.js b/exercises/1_hello_world/solution.mjs similarity index 100% rename from exercises/1_hello_world/solution.js rename to exercises/1_hello_world/solution.mjs diff --git a/exercises/2_streams/solution.js b/exercises/2_streams/solution.mjs similarity index 100% rename from exercises/2_streams/solution.js rename to exercises/2_streams/solution.mjs diff --git a/exercises/3_custom_protocols/solution.js b/exercises/3_custom_protocols/solution.mjs similarity index 100% rename from exercises/3_custom_protocols/solution.js rename to exercises/3_custom_protocols/solution.mjs diff --git a/exercises/4_imperative_protocols/solution.js b/exercises/4_imperative_protocols/solution.mjs similarity index 100% rename from exercises/4_imperative_protocols/solution.js rename to exercises/4_imperative_protocols/solution.mjs diff --git a/exercises/5_length_prefixed_data/solution.js b/exercises/5_length_prefixed_data/solution.mjs similarity index 100% rename from exercises/5_length_prefixed_data/solution.js rename to exercises/5_length_prefixed_data/solution.mjs diff --git a/exercises/6_structured_data/solution.js b/exercises/6_structured_data/solution.mjs similarity index 100% rename from exercises/6_structured_data/solution.js rename to exercises/6_structured_data/solution.mjs diff --git a/exercises/7_rpc/solution.js b/exercises/7_rpc/solution.mjs similarity index 100% rename from exercises/7_rpc/solution.js rename to exercises/7_rpc/solution.mjs diff --git a/package.json b/package.json index c133cc5..5bcf783 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ }, "scripts": { "lint": "standard", - "postinstall": "patch-package" + "postinstall": "patch-package", + "test": "mocha test/*.spec.js" }, "dependencies": { "@chainsafe/libp2p-yamux": "^7.0.1", @@ -37,6 +38,7 @@ "workshopper-wrappedexec": "^0.1.1" }, "devDependencies": { + "mocha": "^10.8.2", "pre-commit": "^1.2.2", "standard": "^17.1.0" }, diff --git a/patches/workshopper-adventure+7.0.0.patch b/patches/workshopper-adventure+7.0.0.patch index a0babb7..28fc10d 100644 --- a/patches/workshopper-adventure+7.0.0.patch +++ b/patches/workshopper-adventure+7.0.0.patch @@ -1,3 +1,20 @@ +diff --git a/node_modules/workshopper-adventure/index.js b/node_modules/workshopper-adventure/index.js +index 7e85fe3..0538dbe 100644 +--- a/node_modules/workshopper-adventure/index.js ++++ b/node_modules/workshopper-adventure/index.js +@@ -79,8 +79,10 @@ function WA (options) { + + this.options = options + +- var globalStorage = storage(storage.userDir, '.config', 'workshopper') +- this.appStorage = storage(storage.userDir, '.config', options.name) ++ const storageDir = process.env.WORKSHOPPER_ADVENTURE_STORAGE_DIR ?? storage.userDir ++ ++ var globalStorage = storage(storageDir, '.config', 'workshopper') ++ this.appStorage = storage(storageDir, '.config', options.name) + + this.exercises = [] + this._meta = {} diff --git a/node_modules/workshopper-adventure/lib/msee.js b/node_modules/workshopper-adventure/lib/msee.js index 1fcbf99..605c566 100644 --- a/node_modules/workshopper-adventure/lib/msee.js diff --git a/test/exercises.spec.js b/test/exercises.spec.js new file mode 100644 index 0000000..49f3183 --- /dev/null +++ b/test/exercises.spec.js @@ -0,0 +1,85 @@ +/* eslint-env mocha */ + +const { spawn } = require('node:child_process') +const path = require('node:path') +const os = require('node:os') +const fs = require('node:fs') +const menu = require('../exercises/menu.json') + +function makeConfigDir () { + const dir = path.join(os.tmpdir(), 'protocol-adventure-test', `dir-${Math.random()}`) + fs.mkdirSync(dir, { + recursive: true + }) + + return dir +} + +function selectLanguage (selected, dir) { + const containingDir = path.join(dir, '.config', 'workshopper') + fs.mkdirSync(containingDir, { + recursive: true + }) + fs.writeFileSync(path.join(containingDir, 'lang.json'), `${JSON.stringify({ selected }, 0, 2)}\n`) +} + +function selectExercise (exercise, dir) { + const containingDir = path.join(dir, '.config', '@libp2p/protocol-adventure') + fs.mkdirSync(containingDir, { + recursive: true + }) + fs.writeFileSync(path.join(containingDir, 'current.json'), `${JSON.stringify(exercise)}\n`) +} + +describe('protocol-adventure', () => { + let configDir + + before(() => { + configDir = makeConfigDir() + selectLanguage('en', configDir) + }) + + beforeEach(() => { + + }) + + for (const exercise of menu) { + it(`should pass ${exercise}`, async () => { + selectExercise(exercise, configDir) + + const verify = spawn('protocol-adventure', ['verify', `exercises/${exercise}/solution.mjs`], { + env: { + ...process.env, + WORKSHOPPER_ADVENTURE_STORAGE_DIR: configDir + } + }) + + let stdout = '' + let stderr = '' + + verify.stdout.on('data', (data) => { + stdout += data.toString() + }) + + verify.stderr.on('data', (data) => { + stderr += data.toString() + }) + + await new Promise((resolve, reject) => { + verify.on('close', (code) => { + if (code === 0) { + resolve() + } else { + console.error('--- STDOUT ---') + console.error(stdout) + + console.error('--- STDERR ---') + console.error(stderr) + + reject(new Error(`Failed to verify solution to ${exercise} - child process exited with code ${code}`)) + } + }) + }) + }) + } +})