UNPKG

sortier

Version:
119 lines (118 loc) 4.61 kB
import { describe, it, expect } from "@jest/globals"; import { globbySync } from "globby"; import { basename, dirname } from "path"; import { fileURLToPath } from "url"; import { FileUtils } from "./file-utils.js"; function sentenceCase(text) { const spacedText = text.replace(/_/g, " "); return spacedText.charAt(0).toUpperCase() + spacedText.slice(1); } /** * Given a directory, reads all the files from the test_assets folder in that directory and generates * an array of tests information to be run. * * The file format for all files in the test_assets folder should be as follows: * - Input: (category_path\.)*?test_name.input.extension.txt * - Output: (category_path\.)*?test_name.output.extension.txt * * Given this, some valid examples are: * - context_barrier.input.css.txt * - es6.imports.input.js.txt * - es6.spread.imports.input.js.txt * * @param testFileUrl The test file that has a test_assets folder as a sibling * @param transform The reprinting logic to transform the input code and return the output */ export function runTestAssetsTests(testFileUrl, transform) { const folderPath = getFolderPathFromFileUrl(testFileUrl); const testNodes = getTestAssetsTree(folderPath); runNodes(testNodes, transform); } export function getFolderPathFromFileUrl(filePath) { return dirname(fileURLToPath(filePath)); } /** * Given a directory, reads all the files from the test_assets folder in that directory and generates * an array of tests information to be run. * * The file format for all files in the test_assets folder should be as follows: * - Input: (category_path\.)*?test_name.input.extension.txt * - Output: (category_path\.)*?test_name.output.extension.txt * * Given this, some valid examples are: * - context_barrier.input.css.txt * - es6.imports.input.js.txt * - es6.spread.imports.input.js.txt * * @param folderPath The directory that contains a test_assets folder * @param transform The reprinting logic to transform the input code and return the output * @deprecated use runTestAssetsTests instead */ export function runTestAssestsTests(folderPath, transform) { const testNodes = getTestAssetsTree(folderPath); runNodes(testNodes, transform); } function runNodes(testNode, transform) { const nodes = testNode.nodes; for (const name in nodes) { const testNode = nodes[name]; if (testNode.type === "leaf") { const { inputFilePath, outputFilePath } = testNode; it(sentenceCase(name), () => { const input = FileUtils.readFileContents(inputFilePath); const expected = FileUtils.readFileContents(outputFilePath); const actual = transform(inputFilePath, input); expect(actual).toEqual(expected); }); } else if (testNode.type === "branch") { describe(sentenceCase(name), () => { runNodes(testNode, transform); }); } else { throw new Error("Unexpected testNode type"); } } } function getTestAssetsTree(folderPath) { const root = { nodes: {}, type: "branch", }; const assetsFolderPath = FileUtils.globbyJoin(folderPath, `test_assets/*.input.*.txt`); const filePaths = globbySync(assetsFolderPath); for (const filePath of filePaths) { const segments = basename(filePath).split("."); if (segments.length < 4) { throw new Error(`${filePath} does not match getTestAssetsTree pattern. Expected (one_or.more_segments).input.js.txt`); } // Find or create the path in the tree needed let possibleChildren = root.nodes; while (segments.length > 4) { const name = segments.shift(); if (name == null) { break; } if (!(name in possibleChildren)) { possibleChildren[name] = { nodes: {}, type: "branch", }; } const nextChild = possibleChildren[name]; if (nextChild.type === "branch") { possibleChildren = nextChild.nodes; } } if (possibleChildren[segments[0]] != null) { throw new Error(`${segments[0]} already exists in the test tree, do you have a file naming collision?`); } possibleChildren[segments[0]] = { inputFilePath: filePath, outputFilePath: filePath.replace(".input.", ".output."), type: "leaf", }; } return root; }