From 32c0995e47c63b19fa8cd2c825bc9fa1daff1e73 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Fri, 22 Oct 2021 18:51:46 +0200 Subject: [PATCH] fix: handle missing solutions correctly Rather than creating an [[]] the parser now creates [] which isEmpty(). This makes the test suite check the next challenge for a solution. In addition, the logic for testing solutions was fixed. --- curriculum/schema/challengeSchema.js | 2 +- curriculum/test/test-challenges.js | 61 ++++++++++++------- .../parser/plugins/add-solution.js | 3 +- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/curriculum/schema/challengeSchema.js b/curriculum/schema/challengeSchema.js index de8016ea63..8154e4837e 100644 --- a/curriculum/schema/challengeSchema.js +++ b/curriculum/schema/challengeSchema.js @@ -87,7 +87,7 @@ const schema = Joi.object() crossDomain: Joi.bool() }) ), - solutions: Joi.array().items(Joi.array().items(fileJoi)), + solutions: Joi.array().items(Joi.array().items(fileJoi).min(1)), superBlock: Joi.string().regex(slugRE), superOrder: Joi.number(), suborder: Joi.number(), diff --git a/curriculum/test/test-challenges.js b/curriculum/test/test-challenges.js index 283f187529..965ae347eb 100644 --- a/curriculum/test/test-challenges.js +++ b/curriculum/test/test-challenges.js @@ -451,22 +451,26 @@ ${inspect(commentMap)} // This is expected to happen in the project based curriculum. const nextChallenge = challenges[id + 1]; - // TODO: can this be dried out, ideally by removing the redux - // handler? + if (nextChallenge) { const solutionFiles = cloneDeep(nextChallenge.challengeFiles); - solutionFiles.forEach(challengeFile => { - challengeFile.editableContents = getLines( - challengeFile.contents, - challenge.challengeFiles.find( - x => x.fileKey === challengeFile.fileKey - ).editableRegionBoundaries - ); - }); - solutions = [solutionFiles]; + const solutionFilesWithEditableContents = solutionFiles.map( + file => ({ + ...file, + editableContents: getLines( + file.contents, + file.editableRegionBoundaries + ) + }) + ); + // Since there is only one seed, there can only be one solution, + // but the tests assume solutions is an array. + solutions = [solutionFilesWithEditableContents]; solutionFromNext = true; } else { - throw Error('solution omitted'); + throw Error( + `solution omitted for ${challenge.superBlock} ${challenge.block} ${challenge.title}` + ); } } @@ -519,15 +523,11 @@ async function createTestRunner( solutionFromNext ) { const { required = [], template, removeComments } = challenge; - // we should avoid modifying challenge, as it gets reused: - const challengeFiles = cloneDeep(challenge.challengeFiles); - solutionFiles.forEach(solutionFile => { - const challengeFile = challengeFiles.find( - x => x.fileKey === solutionFile.fileKey - ); - challengeFile.contents = solutionFile.contents; - challengeFile.editableContents = solutionFile.editableContents; - }); + + const challengeFiles = replaceChallengeFilesContentsWithSolutions( + challenge.challengeFiles, + solutionFiles + ); const { build, sources, loadEnzyme } = await buildChallenge({ challengeFiles, @@ -567,6 +567,25 @@ async function createTestRunner( }; } +function replaceChallengeFilesContentsWithSolutions( + challengeFiles, + solutionFiles +) { + return challengeFiles.map(file => { + const matchingSolutionFile = solutionFiles.find( + ({ ext }) => ext === file.ext + ); + if (!matchingSolutionFile) { + throw Error(`No matching solution file found`); + } + return { + ...file, + contents: matchingSolutionFile.contents, + editableContents: matchingSolutionFile.editableContents + }; + }); +} + async function getContextEvaluator(build, sources, code, loadEnzyme) { await initializeTestRunner(build, sources, code, loadEnzyme); diff --git a/tools/challenge-parser/parser/plugins/add-solution.js b/tools/challenge-parser/parser/plugins/add-solution.js index af08df35e0..30407aa47c 100644 --- a/tools/challenge-parser/parser/plugins/add-solution.js +++ b/tools/challenge-parser/parser/plugins/add-solution.js @@ -1,3 +1,4 @@ +const { isEmpty } = require('lodash'); const { root } = require('mdast-builder'); const visitChildren = require('unist-util-visit-children'); @@ -30,7 +31,7 @@ function createPlugin() { ); visitForContents(solutionTree); - solutions.push(Object.values(solution)); + if (!isEmpty(solution)) solutions.push(Object.values(solution)); }); file.data = {