From a78dc800969c9793e718663e058b3cb1a8951ff5 Mon Sep 17 00:00:00 2001 From: Edd Date: Mon, 19 Aug 2024 04:40:51 -0700 Subject: [PATCH] Remove unused code and features (#142) * Big tidyup - Remove unnecessary configurability of check-references - Remove category support (generally unused) - Remove next-file (totally unused) - Remove unnecessary configurability of minimumAcceptableAcs * Big tidyup - Remove unnecessary configurability of check-references - Remove category support (generally unused) - Remove next-file (totally unused) - Remove unnecessary configurability of minimumAcceptableAcs * handle a feature/release with 0 specs and 0 coverage * bump version and run audit --- README.md | 26 +-- bin/approbation.js | 108 +----------- package-lock.json | 22 ++- package.json | 2 +- src/check-codes.js | 5 +- src/check-features.js | 4 +- src/check-references.js | 161 ++---------------- src/config.js | 4 - src/lib/category.js | 105 ------------ src/lib/feature.js | 1 - src/lib/priority.js | 73 -------- src/next-code.js | 30 +++- src/next-filename.js | 113 ------------ test/check-references.test.js | 104 +---------- test/next-filename.test.js | 105 ------------ .../big-skip/0001-VALI-valid_filename.md | 1 - .../big-skip/0002-VALA-also_valid_filename.md | 1 - .../0003-VLAA-also_valid_filename copy.md | 1 - .../big-skip/1001-DONE-donec_euismod.md | 1 - .../0001-VALI-valid_filename.md | 1 - .../0003-DONE-donec_euismod.md | 1 - 21 files changed, 75 insertions(+), 794 deletions(-) delete mode 100644 src/config.js delete mode 100644 src/lib/category.js delete mode 100644 src/lib/priority.js delete mode 100644 src/next-filename.js delete mode 100644 test/next-filename.test.js delete mode 100644 test/next-filename/big-skip/0001-VALI-valid_filename.md delete mode 100644 test/next-filename/big-skip/0002-VALA-also_valid_filename.md delete mode 100644 test/next-filename/big-skip/0003-VLAA-also_valid_filename copy.md delete mode 100644 test/next-filename/big-skip/1001-DONE-donec_euismod.md delete mode 100644 test/next-filename/missing-sequence/0001-VALI-valid_filename.md delete mode 100644 test/next-filename/missing-sequence/0003-DONE-donec_euismod.md diff --git a/README.md b/README.md index 567f135..4950d02 100644 --- a/README.md +++ b/README.md @@ -106,26 +106,6 @@ npx github:vegaprotocol/approbation@latest check-references --specs="./specs/pro docker run -v "$(pwd):/run" ghcr.io/vegaprotocol/approbation:latest check-references --specs="/run/specs/protocol/**/*.{md,ipynb}" --tests="/run/MultisigControl/test/*.js" --ignore="/run/specs/protocol/{0001-*}" --categories="/run/specs/protocol/categories.json" --show-branches --show-mystery --output-csv --output="/run/results/" ``` -## next-filename -> Suggests what file sequence number to use next, given a list of spec files - -**Arguments** -| **Parameter** | **Type** | **Description** | **Example** | -|-----------------|----------|--------------------------------------|----------------------| -| `--specs` | glob | specs to pull AC codes from | `{specs/**/*.md}` | -| `--ignore` | glob | glob of files not to include | `specs/0001-spec.md` | -| `--verbose` | boolean | Display extra output | - | - -In the case of three specs, ['001...', '002...', '003...'] this would suggest '004'. However if '002' didn't exist, it would indicate that '002' is available, as well as '004'. -### next-filename example -```bash -# Use node -npx @vegaprotocol/approbation next-filename --specs="./specs/protocol/**/*.{md,ipynb}" - -# Or run the docker image -docker run -v "$(pwd):/run" ghcr.io/vegaprotocol/approbation:latest next-filename --specs="/run/specs/protocol/**/*.{md,ipynb}" -``` - ## next-code > Suggests what AC code to use next given a spec file @@ -136,15 +116,15 @@ docker run -v "$(pwd):/run" ghcr.io/vegaprotocol/approbation:latest next-filenam | `--ignore` | glob | glob of files not to include | `specs/0001-spec.md` | | `--verbose` | boolean | Display extra output | - | -Like `next-filename`, `next-code` will suggest the lowest available code in the sequence (e.g. if there is `0001-SPEC-001` and `0001-SPEC-003`), it will suggest both `0001-SPEC-002` and `000-SPEC-004`. If using the lowest available code, ensure it isn't already referenced by any tests (i.e. isn't listed as a 'Mystery Criteria' by `check-references`). +`next-code` will suggest the lowest available code in the sequence (e.g. if there is `0001-SPEC-001` and `0001-SPEC-003`), it will suggest both `0001-SPEC-002` and `000-SPEC-004`. If using the lowest available code, ensure it isn't already referenced by any tests (i.e. isn't listed as a 'Mystery Criteria' by `check-references`). ### next-code example ```bash # Use node -npx @vegaprotocol/approbation next-filename --specs="./specs/protocol/**/*.{md,ipynb}" +npx @vegaprotocol/approbation next-code --specs="./0030-ETHM-multisig_control_spec.md" # Or run the docker image -docker run -v "$(pwd):/run" ghcr.io/vegaprotocol/approbation:latest next-filename --specs="/run/specs/protocol/**/*.{md,ipynb}" +docker run -v "$(pwd):/run" ghcr.io/vegaprotocol/approbation:latest next-code --specs="./0030-ETHM-multisig_control_spec.md" ``` diff --git a/bin/approbation.js b/bin/approbation.js index 27b4345..7ff6f4e 100755 --- a/bin/approbation.js +++ b/bin/approbation.js @@ -2,7 +2,6 @@ const packageJson = require('../package.json') const { checkFilenames } = require('../src/check-filenames') -const { nextFilename } = require('../src/next-filename') const { nextCode } = require('../src/next-code') const { checkCodes } = require('../src/check-codes') const { checkFeatures } = require('../src/check-features') @@ -13,12 +12,6 @@ const argv = require('minimist')(process.argv.slice(2)) const command = argv._[0] const IS_DEBUG = process.env.debug !== undefined -function debugOutput(text) { - if (IS_DEBUG) { - console.log(pc.purple(text)) - } -} - function warn(lines) { console.warn('') lines.map(l => console.warn(pc.yellow(`! ${l}`))) @@ -44,99 +37,38 @@ if (argv && argv['show-branches']) { console.log() } -if (command === 'check-filenames') { - let paths = '{./non-protocol-specs/**/*.md,./protocol/**/*.md}' - const ignoreGlob = argv.ignore - - if (!argv.specs) { - warn(['No --specs argument provided, defaulting to:', `--specs="${paths}"`, '(This behaviour will be deprecated in 3.0.0)']) - } else { - paths = argv.specs - } +const paths = argv.specs +const ignoreGlob = argv.ignore +const isVerbose = argv.verbose === true +if (!argv.specs) { + process.exit('All commands require a --specs argument') +} +if (command === 'check-filenames') { res = checkFilenames(paths, ignoreGlob) process.exit(res.exitCode) -} else if (command === 'next-filename') { - let paths = '{./non-protocol-specs/**/*.md,./protocol/**/*.md}' - const ignoreGlob = argv.ignore - - if (!argv.specs) { - warn(['No --specs argument provided, defaulting to:', `--specs="${paths}"`, '(This behaviour will be deprecated in 3.0.0)']) - } else { - paths = argv.specs - } - const isVerbose = argv.verbose === true - - res = nextFilename(paths, ignoreGlob, isVerbose) - process.exit(res.exitCode) } else if (command === 'next-code') { - let paths = '{./non-protocol-specs/**/*.md,./protocol/**/*.md}' - const ignoreGlob = argv.ignore - const isVerbose = argv.verbose === true - - if (!argv.specs) { - warn(['No --specs argument provided, defaulting to:', `--specs="${paths}"`, '(This behaviour will be deprecated in 3.0.0)']) - } else { - paths = argv.specs - } - res = nextCode(paths, ignoreGlob, isVerbose) process.exit(res.exitCode) } else if (command === 'check-codes') { - let paths = '{./non-protocol-specs/**/*.md,./protocol/**/*.md}' - const ignoreGlob = argv.ignore - const isVerbose = argv.verbose === true - - if (!argv.specs) { - warn(['No --specs argument provided, defaulting to:', `--specs="${paths}"`, '(This behaviour will be deprecated in 3.0.0)']) - } else { - paths = argv.specs - } res = checkCodes(paths, ignoreGlob, isVerbose) process.exit(res.exitCode) } else if (command === 'check-features') { - let specs, features - const isVerbose = argv.verbose === true - const ignoreGlob = argv.ignore - if (!argv.features) { warn(['No --features argument provided)']) process.exit(1); - } else { - features = argv.features } - if (!argv.specs) { - warn(['No --specs argument provided']) - process.exit(1); - } else { - specs = argv.specs - } - - res = checkFeatures(specs, features, ignoreGlob, isVerbose) + res = checkFeatures(specs, argv.features, ignoreGlob, isVerbose) process.exit(res.exitCode) } else if (command === 'check-references') { - debugOutput('check-references') - const specsGlob = argv.specs const testsGlob = argv.tests const categories = argv.categories const features = argv.features const ignoreGlob = argv.ignore const currentMilestone = argv['current-milestone'] - const showMystery = argv['show-mystery'] === true - const showCategoryStats = argv['category-stats'] === true - const isVerbose = argv.verbose === true - const showFiles = argv['show-files'] === true - const shouldOutputCSV = argv['output-csv'] === true let outputPath = argv.output - const shouldOutputJenkins = argv['output-jenkins'] === true - const shouldShowFileStats = argv['show-file-stats'] === true - - if (!argv.specs) { - warn(['No --specs argument provided, exiting']) - process.exit(1) - } if (!argv.tests) { warn(['No --tests argument provided, exiting']) @@ -148,22 +80,8 @@ if (command === 'check-filenames') { process.exit(1) } - if (shouldOutputCSV || shouldOutputJenkins) { - if (!outputPath || outputPath.length === 0) { - console.error(pc.yellow('Output path should be provided with --output if CSV or Jenkins output are enabled. Defaulting to ./results')) - outputPath = './results' - } else { - // Ensure we don't have a trailing slash for consistency with the default - if (outputPath && outputPath.endsWith('/')) { - debugOutput(`Removing trailing slash from output path: ${outputPath}`) - outputPath = outputPath.slice(0, -1) - } - console.info(pc.yellow(`Output folder: ${outputPath}`)) - } - } - // TODO: Turn in to an object - res = checkReferences(specsGlob, testsGlob, categories, ignoreGlob, features, showMystery, isVerbose, showCategoryStats, showFiles, shouldOutputCSV, shouldOutputJenkins, shouldShowFileStats, currentMilestone, outputPath) + res = checkReferences(paths, testsGlob, ignoreGlob, features, currentMilestone, outputPath) process.exit(res.exitCode) } else { @@ -203,14 +121,6 @@ if (command === 'check-filenames') { showArg(`--categories="${pc.yellow('./specs/protocol/categories.json')}"`, 'Single JSON file that contains the categories for this test run') showArg(`--features="${pc.yellow('./specs/protocol/features.json')}"`, 'Single JSON file that contains the features for this test run') showArg(`--ignore="${pc.yellow('{tests/**/*.{py,feature}')}"`, 'glob of files to ignore for both tests and specs') - showArg('--show-mystery', 'If set, display criteria in tests that are not in any specs matched by --specs') - showArg('--category-stats', 'Show more detail for referenced/unreferenced codes') - showArg('--show-branches', 'Show git branches for subfolders of the current folder') - showArg('--show-files', 'Show basic stats per file') - showArg('--show-file-stats', 'Show detailed stats per file') - showArg('--verbose', 'Show more detail for each file') - showArg('--output-csv', 'Show more detail for each file') - showArg('--output-jenkins', 'Output a quick summary for CI') console.groupEnd('Arguments') console.groupEnd('check-references') } diff --git a/package-lock.json b/package-lock.json index b3476d0..63bb16e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@vegaprotocol/approbation", - "version": "4.7.1", + "version": "4.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@vegaprotocol/approbation", - "version": "4.7.1", + "version": "4.9.0", "license": "Unlicense", "dependencies": { "console-table-printer": "^2.10.0", @@ -175,11 +175,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -505,9 +506,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -946,6 +948,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1654,6 +1657,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, diff --git a/package.json b/package.json index 39554bd..e1f9c22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vegaprotocol/approbation", - "version": "4.8.0", + "version": "4.9.0", "description": "Match Acceptance Criteria Codes with the tests that test them", "engine": ">= 18", "bin": "./bin/approbation.js", diff --git a/src/check-codes.js b/src/check-codes.js index b537cdf..f45a2ef 100755 --- a/src/check-codes.js +++ b/src/check-codes.js @@ -27,7 +27,6 @@ const fs = require('fs') const glob = require('fast-glob') const path = require('path') const { validSpecificationPrefix, ignoreFiles } = require('./lib') -const { minimumAcceptableACsPerSpec } = require('./config') const pc = require('picocolors') /** @@ -145,7 +144,7 @@ function checkPath (files, output = true) { // The files are *valid*, at least. But do they have enough ACs? - if (totalAcceptanceCriteria.length >= minimumAcceptableACsPerSpec) { + if (totalAcceptanceCriteria.length >= 1) { countAcceptableFiles++ if (output && verbose) { console.group(pc.bold(file)) @@ -181,7 +180,7 @@ function checkCodes (paths, ignoreGlob, isVerbose = false) { if (fileList.length > 0) { res = checkPath(fileList) console.log('\r\n--------------------------------------------------') - console.log(`Acceptable ${res.countAcceptableFiles} (files with more than ${minimumAcceptableACsPerSpec} ACs)`) + console.log(`Acceptable ${res.countAcceptableFiles} (files with more than 1 ACs)`) console.log(`Need work ${res.countEmptyFiles}`) console.log(`Files with errors ${res.countErrorFiles}`) console.log(`Total ACs ${res.countAcceptanceCriteria}`) diff --git a/src/check-features.js b/src/check-features.js index 1f0c479..e88a82e 100755 --- a/src/check-features.js +++ b/src/check-features.js @@ -5,9 +5,7 @@ */ const fs = require('fs') const glob = require('fast-glob') -const path = require('path') -const { validSpecificationPrefix, ignoreFiles } = require('./lib') -const { minimumAcceptableACsPerSpec } = require('./config') +const { ignoreFiles } = require('./lib') const pc = require('picocolors') const { gatherSpecs, findDuplicateAcs } = require('./check-references') const { setFeatures } = require('./lib/feature') diff --git a/src/check-references.js b/src/check-references.js index d7e89bc..ba0c84e 100644 --- a/src/check-references.js +++ b/src/check-references.js @@ -10,20 +10,14 @@ const glob = require('fast-glob') const path = require('path') const pc = require('picocolors') const { validSpecificationPrefix, validAcceptanceCriteriaCode, ignoreFiles } = require('./lib') -const { getCategoriesForSpec, increaseCodesForCategory, increaseCoveredForCategory, increaseAcceptableSpecsForCategory, increaseUncoveredForCategory, increaseFeatureCoveredForCategory, increaseSystemTestCoveredForCategory, increaseSpecCountForCategory, setCategories } = require('./lib/category') -const { setFeatures, increaseAcceptableSpecsForFeature, increaseCodesForFeature, increaseCoveredForFeature, increaseFeatureCoveredForFeature, increaseSpecCountForFeature, increaseSystemTestCoveredForFeature, increaseUncoveredForFeature, specFeatures, findDuplicateAcs } = require('./lib/feature') +const { setFeatures, increaseCoveredForFeature, increaseFeatureCoveredForFeature, increaseSystemTestCoveredForFeature, increaseUncoveredForFeature, findDuplicateAcs } = require('./lib/feature') const { Table } = require('console-table-printer') -const { specPriorities } = require('./lib/priority') const sortBy = require('lodash.sortby') // can be overriden by passing in --current-milestone, this is set for an easy transition while Jenkins doesn't // have that param - see vegaprotocol/jenkins-shared-library/issues/751 const DEFAULT_CURRENT_MILESTONE = 'colosseo_II' -// Ugly globals -let verbose = false -let showFiles = false - function gatherSpecs(fileList) { // Step 1: Gather all the initial details const specFiles = new Map() @@ -48,20 +42,12 @@ function gatherSpecs(fileList) { criteria = [...new Set(labelledAcceptanceCriteria)] } - let categories - try { - categories = getCategoriesForSpec(codeStart[0]) - } catch (e) { - categories = []; - } - specFiles.set(fileName, { name: `${path}${file}`, code: codeStart[0], file, path, - criteria, - categories + criteria }) }) @@ -112,16 +98,9 @@ function processReferences(specs, tests) { value.referencedBySystemTest = 0 const unreferencedCriteria = [] - // Used as a title later on - const category = value.categories && value.categories !== ['Unknown'] ? ' ' + value.categories.filter(c => c !== 'Total').map(c => { return pc.bgYellow(pc.black(`#${c}`)) }).join(', ') : '' // Used as a shortcut for all the loops - const categories = value.categories - categories.forEach(c => increaseSpecCountForCategory(c)) - - const acceptableMinimum = 1 criteriaTotal += value.criteria.length - categories.forEach(c => increaseCodesForCategory(c, value.criteria.length)) let refOutput = '' const criteriaWithRefs = [] @@ -136,7 +115,6 @@ function processReferences(specs, tests) { refOutput += `${pc.green(c)}: ${linksForAC.length} (${linksForAC.toString()})\r\n` criteriaWithRefs.push(c) criteriaReferencedTotal++ - categories.forEach(c => increaseCoveredForCategory(c, 1)) increaseCoveredForFeature(c, 1) // Hacky hack: Limit these to 1 or 0 rather than a true tally. @@ -145,18 +123,14 @@ function processReferences(specs, tests) { linksForAC.forEach(l => { if (!criteriaAlreadyLoggedSystest && l.match('system-tests')) { increaseSystemTestCoveredForFeature(c, 1) - categories.forEach(c => increaseSystemTestCoveredForCategory(c, 1)) value.referencedBySystemTest++ criteriaAlreadyLoggedSystest = true } else if (!criteriaAlreadyLoggedFeature && l.match('.feature')) { increaseFeatureCoveredForFeature(c, 1) - categories.forEach(c => increaseFeatureCoveredForCategory(c, 1)) value.referencedByFeature++ criteriaAlreadyLoggedFeature = true } }) - } else { - categories.forEach(c => increaseCoveredForCategory(c, 0)) } // Delete used references, so that tests at the end contains only AC codes not found in specs @@ -171,28 +145,19 @@ function processReferences(specs, tests) { criteriaUnreferencedTotal++ } }) - - categories.forEach(c => increaseUncoveredForCategory(c, unreferencedCriteria.length)) - } - - if (value.criteria.length > acceptableMinimum) { - categories.forEach(c => increaseAcceptableSpecsForCategory(c)) } } - const count = value.criteria.length > acceptableMinimum ? pc.green(value.criteria.length) : pc.red(value.criteria.length) - const referenced = criteriaWithRefs.length > acceptableMinimum ? pc.green(criteriaWithRefs.length) : pc.red(criteriaWithRefs.length) + const count = pc.green(value.criteria.length) + const referenced = pc.green(criteriaWithRefs.length) value.count = value.criteria.length value.referenced = criteriaWithRefs.length value.uncovered = value.count - value.referenced - value.priority = specPriorities[value.code] || 10 - if (showFiles) { const tally = ` has ${count} ACs of which ${referenced} are tested` - console.log(`${pc.bold(key)}${tally}${category}`) - if (verbose) { + console.log(`${pc.bold(key)}`) console.group() console.log(`File: ${value.file}`) console.log(`Unreferenced ACs: ${unreferencedCriteria.join(', ')}`) @@ -202,8 +167,6 @@ function processReferences(specs, tests) { console.groupEnd() } console.groupEnd() - } - } }) return { @@ -220,39 +183,25 @@ function processReferences(specs, tests) { * * @param {*} specsGlob * @param {*} testsGlob - * @param {*} categoriesPath * @param {*} ignoreGlob * @param {*} featuresPath - * @param {*} showMystery - * @param {*} isVerbose - * @param {*} showCategoryStats - * @param {*} shouldShowFiles - * @param {*} shouldOutputCSV - * @param {*} shouldOutputJenkins - * @param {*} shouldShowFileStats * @param {*} currentMilestone * @param {*} outputPath * @returns */ -function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featuresPath, showMystery = false, isVerbose = false, showCategoryStats = false, shouldShowFiles = false, shouldOutputCSV = false, shouldOutputJenkins = false, shouldShowFileStats = false, currentMilestone = DEFAULT_CURRENT_MILESTONE, outputPath = './results') { - verbose = isVerbose - showFiles = shouldShowFiles +function checkReferences(specsGlob, testsGlob, ignoreGlob, featuresPath, currentMilestone = DEFAULT_CURRENT_MILESTONE, outputPath = './results') { const ignoreList = ignoreGlob ? glob.sync(ignoreGlob, {}) : [] const specList = ignoreFiles(glob.sync(specsGlob, {}), ignoreList) const testList = ignoreFiles(glob.sync(testsGlob, {}), ignoreList, 'test') - let categories const milestones = new Map() const totals = [] - let specs, tests, features, specFeatures + let specs, tests, specFeatures const exitCode = 0 if (specList.length > 0 && testList.length > 0) { try { - // Categories gather spec files in to categories, and tally the number of codes in each category - specCategories = JSON.parse(fs.readFileSync(categoriesPath)) - setCategories(specCategories) // Features gather Acceptance Criteria across spec files or categories, and tally the numbers if (featuresPath !== undefined && featuresPath.length > 0) { @@ -276,33 +225,15 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu const criteriaReferencedPercent = (criteriaReferencedTotal / criteriaTotal * 100).toFixed(1) const criteriaUnreferencedPercent = (criteriaUnreferencedTotal / criteriaTotal * 100).toFixed(1) - if (showMystery && unknownCriteriaInTests.size > 0) { - const g = pc.bold(`${pc.red('Mystery criteria')} referenced in tests, not found in specs:`) - console.group(g) - console.dir(unknownCriteriaInTests) - console.groupEnd(g) - console.log() - } - - if (!showCategoryStats) { - console.log(pc.bold('Total criteria') + `: ${criteriaTotal}`) - console.log(pc.green(pc.bold('With references')) + `: ${criteriaReferencedTotal} (${criteriaReferencedPercent}%)`) - console.log(pc.red(pc.bold('Without references')) + `: ${criteriaUnreferencedTotal} (${criteriaUnreferencedPercent}%)`) - } - if (showMystery) { - console.log(pc.red(pc.bold('Mystery criteria')) + `: ${unknownCriteriaInTests.size}`) - } - - let specsTableRows + console.log(pc.bold('Total criteria') + `: ${criteriaTotal}`) + console.log(pc.green(pc.bold('With references')) + `: ${criteriaReferencedTotal} (${criteriaReferencedPercent}%)`) + console.log(pc.red(pc.bold('Without references')) + `: ${criteriaUnreferencedTotal} (${criteriaUnreferencedPercent}%)`) - if (shouldShowFileStats) { - specsTableRows = Array.from(specs.keys()).map(key => { + let specsTableRows = Array.from(specs.keys()).map(key => { const s = specs.get(key) const coverage = (s.referenced / s.count * 100).toFixed(1) return { File: key, - Priority: s.priority, - Category: s.category, Criteria: s.count, Covered: s.referenced, 'by/FeatTest': s.referencedByFeature, @@ -312,9 +243,8 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu } }) const st = new Table() - st.addRows(sortBy(specsTableRows, ['Priority', 'Coverage'])) + st.addRows(sortBy(specsTableRows, ['Coverage'])) console.log(st.render()) - } if (featuresPath) { const milestoneNames = new Set() @@ -326,15 +256,8 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu const c = specFeatures[key] const coverage = (c.covered / (c.acs.length | 0) * 100).toFixed(1) - const mysteryFeatureAcs = [] - c.acs.forEach(ac => { - if (allCriteriaInSpecs.indexOf(ac) === -1) { - mysteryFeatureAcs.push(ac) - } - }) - const duplicateAcs = findDuplicateAcs(c.acs); - if (duplicateAcs.length > 0 || mysteryFeatureAcs.length > 0 || c.uncovered !== 0) { + if (duplicateAcs.length > 0 || c.uncovered !== 0) { console.group(pc.bold(`Feature errors: ${key}`)) console.group(); @@ -342,10 +265,6 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu console.log(pc.red(pc.bold(`Duplicate ACs for ${key}(${c.milestone})`)) + ` ${duplicateAcs.join(', ')}`) } - if (mysteryFeatureAcs.length > 0) { - console.log(pc.red(pc.bold(`Mystery ACs for ${key}(${c.milestone})`)) + ` ${JSON.stringify(mysteryFeatureAcs)} `) - } - if (c.uncovered !== 0 && c.uncoveredAcs) { console.log( pc.red(`Uncovered ACs for ${key}(${c.milestone}): `) + @@ -379,7 +298,8 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu } const Covered = featuresByMilestone.reduce((acc, cur) => acc + cur.Covered, 0); const acs = featuresByMilestone.reduce((acc, cur) => acc + cur.acs, 0); - const Coverage = `${(Covered / acs * 100).toFixed(1)}% ` + const coverageCalculated = (Covered / acs * 100).toFixed(1) + const Coverage = `${isNaN(coverageCalculated) ? '0' : coverageCalculated}% ` totals.push({ Feature: `Total`, Milestone: milestoneKey || '-', @@ -401,53 +321,10 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu console.log(tableOutput) } - if (showCategoryStats) { - const shouldOutputImage = false - - categories = Object.keys(specCategories).map(key => { - const c = specCategories[key] - const coverage = (c.covered / c.codes * 100).toFixed(1) - - return { - Category: key, - Specs: c.specCount || '-', - Acceptable: c.acceptableSpecCount ? c.acceptableSpecCount : '-', - Criteria: c.codes || '-', - Covered: c.covered || '-', - 'by/FeatTest': c.featureCovered || '-', - 'by/SysTest': c.systemTestCovered || '-', - Uncovered: c.uncovered || '-', - Coverage: isNaN(coverage) ? '-' : `${coverage}% ` - } - }) - - const t = new Table() - t.addRows(categories) - const tableOutput = t.render() - console.log(tableOutput) - - if (shouldOutputJenkins || shouldOutputCSV || shouldOutputImage) { if (!fs.existsSync(outputPath)) { fs.mkdirSync(outputPath, { recursive: true }) } - if (shouldOutputCSV) { - let categoriesCsvOutput = Object.keys(categories[0]).join(',') - categories.forEach(c => { - categoriesCsvOutput += `\r\n${Object.values(c).join(',')} ` - }) - fs.writeFileSync(`${outputPath}/approbation-categories.csv`, categoriesCsvOutput) - - if (shouldShowFileStats) { - let csvOutputFiles = Object.keys(specsTableRows[0]).join(',') - specsTableRows.forEach(c => { - csvOutputFiles += `\r\n${Object.values(c).join(',')}` - }) - fs.writeFileSync(`${outputPath}/approbation-files.csv`, csvOutputFiles) - } - } - - if (shouldOutputJenkins) { let cm // If current milestone is set by parameter, use it if (currentMilestone) { @@ -458,19 +335,14 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu cm = totals && totals.length > 0 ? totals.pop() : false } - const skipCategories = ['Category', 'Specs', 'Acceptable'] - let jenkinsLine = `All ACs: ${Object.entries(categories.pop()).map(([key, value]) => skipCategories.indexOf(key) === -1 ? `*${key}*: ${value}` : '').join(' ').trim()}` - + let jenkinsLine = `Total ACs: ${criteriaTotal}, Referenced ACs: ${criteriaReferencedTotal}, Unreferenced ACs: ${criteriaUnreferencedTotal}, Coverage: ${criteriaReferencedPercent}%` if (cm && cm.Milestone && cm.Coverage) { jenkinsLine += `\r\nCurrent milestone ACs: *${cm.Milestone}*: ${cm.Coverage}` } fs.writeFileSync(`${outputPath}/jenkins.txt`, jenkinsLine) - } console.groupEnd() - } - } return { exitCode, @@ -481,7 +353,6 @@ function checkReferences(specsGlob, testsGlob, categoriesPath, ignoreGlob, featu criteriaReferencedPercent, criteriaUnreferencedPercent, unknownCriteriaInTests, - categories } } } else { diff --git a/src/config.js b/src/config.js deleted file mode 100644 index 7443cbf..0000000 --- a/src/config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - // What is the acceptable minimum Acceptance Criteria count for a specification? - minimumAcceptableACsPerSpec: 1 -} diff --git a/src/lib/category.js b/src/lib/category.js deleted file mode 100644 index 031ab36..0000000 --- a/src/lib/category.js +++ /dev/null @@ -1,105 +0,0 @@ -// This should be committed as a JSON file to the specs repo - but for now, this will do -const ErrorCategoriesEmpty = new Error('Categories have not been set') -let specCategories - -function isCategoriesEmpty () { - if (specCategories === undefined) { - throw ErrorCategoriesEmpty - } - return Object.keys(specCategories).length === 0 -} - -function setCategories (categories) { - specCategories = categories - if (!specCategories.Unknown) { - specCategories.Unknown = { specs: [], specCount: 0 } - } - specCategories.Total = { specs: [], specCount: 0 } -} - -function getCategoriesForSpec (code) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - - const categories = Object.keys(specCategories).filter(category => { - return (specCategories[category].specs.indexOf(code) !== -1) - }) - - // There shouldn't be more than one. But if there is, take the first one. - return (categories.length > 0) ? [...categories, 'Total'] : ['Unknown', 'Total'] -} - -function setOrIncreaseProperty (category, property, value) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - - if (specCategories[category][property]) { - specCategories[category][property] += value - } else { - specCategories[category][property] = value - } -} - -function increaseCodesForCategory (category, count) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'codes', count) -} - -function increaseCoveredForCategory (category, count) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'covered', count) -} - -function increaseFeatureCoveredForCategory (category, count) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'featureCovered', count) -} - -function increaseSystemTestCoveredForCategory (category, count) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'systemTestCovered', count) -} - -function increaseUncoveredForCategory (category, count) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'uncovered', count) -} - -function increaseSpecCountForCategory (category) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'specCount', 1) -} - -function increaseAcceptableSpecsForCategory (category) { - if (isCategoriesEmpty()) { - throw ErrorCategoriesEmpty - } - setOrIncreaseProperty(category, 'acceptableSpecCount', 1) -} - -module.exports = { - specCategories, - getCategoriesForSpec, - increaseCodesForCategory, - increaseCoveredForCategory, - increaseUncoveredForCategory, - increaseSpecCountForCategory, - increaseSystemTestCoveredForCategory, - increaseFeatureCoveredForCategory, - increaseAcceptableSpecsForCategory, - setCategories -} diff --git a/src/lib/feature.js b/src/lib/feature.js index 0cb6498..e68fc5d 100644 --- a/src/lib/feature.js +++ b/src/lib/feature.js @@ -6,7 +6,6 @@ */ const { validAcceptanceCriteriaCode } = require("."); -const pc = require('picocolors') let specFeatures; let acToFeatureLookup = new Map() diff --git a/src/lib/priority.js b/src/lib/priority.js deleted file mode 100644 index f57df54..0000000 --- a/src/lib/priority.js +++ /dev/null @@ -1,73 +0,0 @@ -// This should be committed as a JSON file to the specs repo - but for now, this will do -const specPriorities = { - '0004-AMND': 1, - '0022-AUTH': 1, - '0066-VALW': 1, - '0069-VCBS': 1, - '0077-SNAP': 1, - '0073-LIMN': 1, - '0074-BTCH': 1, - '0075-PLUP': 1, - '0076-DANO': 1, - // ============== - '0006-POSI': 2, - '0008-TRAD': 2, - '0016-PFUT': 2, - '0027-ASSP': 2, - '0028-GOVE': 2, - '0033-OCAN': 2, - '0045-DSRC': 2, - '0046-DSRM': 2, - '0047-DSRF': 2, - '0048-DSRI': 2, - '0052-FPOS': 2, - '0055-TREA': 2, - '0056-REWA': 2, - '0057-TRAN': 2, - '0061-REWP': 2, - '0062-SPAM': 2, - '0064-VALP': 2, - '0067-KEYS': 2, - '0072-SPPW': 2, - '0078-NWLI': 2, - '0079-TGAP': 2, - '0011-NP-CLIE': 2, - '0063-VALK': 2, - '0012-NP-LIPE': 2, - '0080-SPOT': 2, - // ============== - '0017-PART': 3, - '0025-OCRE': 3, - '0044-LIME': 3, - '0070-MKTD': 3, - // ============== - '0021-MDAT': 4, - '0038-OLIQ': 4, - // ============== - '0002-STTL': 5, - '0010-MARG': 5, - '0011-MARA': 5, - '0019-MCAL': 5, - '0039-MKTD': 5, - '0040-ASSF': 5, - '0041-TSTK': 5, - '0042-LIQF': 5, - // ============== - '0026-AUCT': 6, - '0043-MKTL': 6, - // ============== - '0024-OSTA': 7, - '0051-PROD': 7, - // ============== - '0007-POSN': 8, - '0036-BRIE': 8, - '0054-NETP': 8, - // ============== - '0013-ACCT': 9, - '0015-INSR': 9, - '0018-RSKM': 9 -} - -module.exports = { - specPriorities -} diff --git a/src/next-code.js b/src/next-code.js index ddf84cc..101728a 100644 --- a/src/next-code.js +++ b/src/next-code.js @@ -3,10 +3,38 @@ const pc = require('picocolors') const { ignoreFiles, acceptanceCodeElements, validSpecificationPrefix } = require('./lib') const { checkPath } = require('./check-codes') -const { findLowestNumber, padNumber, getRandomCode } = require('./next-filename') const path = require('path') const glob = require('fast-glob') +function padNumber(number, length = 4) { + // Convert the number to a string + let str = number.toString(); + + // Pad the string with zeros if necessary + while (str.length < length) { + str = "0" + str; + } + + return str; +} + +function findLowestNumber(numbers) { + // Convert the numbers to integers and sort them in ascending order + numbers = numbers.map(Number).sort((a, b) => a - b); + + // Find the lowest number that is not present in the array + let lowestNumber = 1; + for (let i = 0; i < numbers.length; i++) { + if (numbers[i] === lowestNumber) { + lowestNumber++; + } else if (numbers[i] > lowestNumber) { + break; + } + } + + return lowestNumber; +} + /** * Given a list of all of the codes in a file, it gives you the file's sequence (e.g. 001) * @param {array} codes An array of string AC codes diff --git a/src/next-filename.js b/src/next-filename.js deleted file mode 100644 index 90bab68..0000000 --- a/src/next-filename.js +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Returns the next filename in a sequence, giving the next number, - * or if there is one missing giving the lowest number possible as - * well as the highest. - */ -const glob = require('fast-glob') -const path = require('path') -const { validSpecificationFilename, ignoreFiles } = require('./lib') -const pc = require('picocolors') - -function getRandomCode() { - return Array.from({length: 4}, () => "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[Math.floor(Math.random() * 26)]).join(''); -} - -function padNumber(number, length = 4) { - // Convert the number to a string - let str = number.toString(); - - // Pad the string with zeros if necessary - while (str.length < length) { - str = "0" + str; - } - - return str; -} - -function findLowestNumber(numbers) { - // Convert the numbers to integers and sort them in ascending order - numbers = numbers.map(Number).sort((a, b) => a - b); - - // Find the lowest number that is not present in the array - let lowestNumber = 1; - for (let i = 0; i < numbers.length; i++) { - if (numbers[i] === lowestNumber) { - lowestNumber++; - } else if (numbers[i] > lowestNumber) { - break; - } - } - - return lowestNumber; -} - -function nextFilename(paths, ignoreGlob, verbose) { - const ignoreList = ignoreGlob ? glob.sync(ignoreGlob, {}) : [] - const fileList = ignoreFiles(glob.sync(paths, {}), ignoreList) - const seenSequenceNumbers = [] - let nextHighest = 0 - let nextLowest = 0 - - let exitCode = 0 - - if (fileList.length > 0) { - fileList.forEach(file => { - const fileName = path.basename(file) - - if (fileName.toLowerCase().indexOf('readme') !== -1) { - return - } - - const codeStart = fileName.match(validSpecificationFilename) - - // If the filename doesn't match, it's an error - if (codeStart !== null) { - // If the sequence number is 0000, it's incorrect - if (codeStart[1] !== '0000') { - // If the sequence number is a duplicate, it's incorrect - if (seenSequenceNumbers.indexOf(codeStart[1]) === -1) { - seenSequenceNumbers.push(codeStart[1]) - } - } - } - }) - - fileList.sort() - - nextHighest = seenSequenceNumbers.length > 0 ? parseInt(seenSequenceNumbers[seenSequenceNumbers.length - 1]) + 1 : 1 - nextLowest = findLowestNumber(seenSequenceNumbers) - if (verbose) { - console.log(`Files that matched: ${fileList.map(s => pc.green(path.basename(s))).join(', ')}`) - } - - if (nextHighest) { - let moreSpecific = ''; - if (nextHighest !== nextLowest) { - moreSpecific = 'highest ' - } - const n = padNumber(nextHighest) - console.log(`Next ${moreSpecific}sequence number: ${pc.green(n)} (e.g. ${pc.green(`${n}-${getRandomCode()}-descriptive_name.md`)})`) - } - - if (nextLowest && nextLowest !== nextHighest) { - const n = padNumber(nextLowest) - console.log(`Lowest unused sequence number: ${pc.green(n)} (e.g. ${pc.green(`${n}-${getRandomCode()}-descriptive_feature_name.md`)})`) - } - } else { - console.error(pc.red(`glob matched no files (${paths})`)) - exitCode = 1 - } - - return { - nextHighest: nextHighest && nextHighest !== 0 ? padNumber(nextHighest) : '-', - nextLowest: nextLowest && nextLowest !== 0 ? padNumber(nextLowest) : '-', - exitCode - } -} - -module.exports = { - getRandomCode, - padNumber, - findLowestNumber, - nextFilename -} diff --git a/test/check-references.test.js b/test/check-references.test.js index 54a7506..7442214 100644 --- a/test/check-references.test.js +++ b/test/check-references.test.js @@ -54,106 +54,4 @@ test('check-references: README is ignored', t => { t.equal(res.criteriaTotal, 1, 'One criteria exists') t.equal(res.criteriaReferencedTotal, 1, 'That one criteria is referenced') t.equal(res.criteriaReferencedPercent, '100.0', 'That is 100%') -}) - -test('check-references: Ignore ignores specs...', t => { - const path = './test/check-references/ignore-specs/**/' - t.plan(4) - - quiet() - const allFiles = checkReferences(`${path}*.md`, `${path}*.{feature,py}`, './test/test-data/categories.json') - const ignore = checkReferences(`${path}*.md`, `${path}*.{feature,py}`, './test/test-data/categories.json', `${path}0002*.md`) - loud() - - t.equal(allFiles.res.criteriaTotal, 2, 'All files: two criteria exist') - t.equal(allFiles.res.criteriaReferencedPercent, '50.0', 'All files: coverage is 50%') - - t.equal(ignore.res.criteriaTotal, 1, 'Ignore: One criteria exists') - t.equal(ignore.res.criteriaReferencedPercent, '100.0', 'Ignore: coverage is 100%') -}) - -test('check-references: ...ignore also applies to tests...', t => { - const path = './test/check-references/ignore-tests/**/' - t.plan(4) - - quiet() - const allFiles = checkReferences(`${path}*.md`, `${path}*.{feature,py}`, './test/test-data/categories.json') - const ignore = checkReferences(`${path}*.md`, `${path}*.{feature,py}`, './test/test-data/categories.json', `${path}another-test.feature`) - loud() - - t.equal(allFiles.res.criteriaTotal, 2, 'All files: two criteria exist') - t.equal(allFiles.res.criteriaReferencedPercent, '100.0', 'All files: coverage is 100%') - - t.equal(ignore.res.criteriaTotal, 2, 'Ignore: Two criteria exist') - t.equal(ignore.res.criteriaReferencedPercent, '50.0', 'Ignore: coverage is 50%') -}) - -test('check-references: ...which is to say both simultaneously', t => { - const path = './test/check-references/ignore-both/**/' - t.plan(4) - - quiet() - const allFiles = checkReferences(`${path}*.md`, `${path}*.{feature,py}`, './test/test-data/categories.json') - const ignore = checkReferences(`${path}*.md`, `${path}*.{feature,py}`, './test/test-data/categories.json', `${path}{another-test*,0001*}`) - loud() - - t.equal(allFiles.res.criteriaTotal, 2, 'All files: two criteria exist') - t.equal(allFiles.res.criteriaReferencedPercent, '100.0', 'All files: coverage is 100%') - - t.equal(ignore.res.criteriaTotal, 1, 'Ignore: One criteria exists') - t.equal(ignore.res.criteriaReferencedPercent, '100.0', 'Ignore: coverage is 100%') -}) - -test('check-references: detect references in tests that are not in specs', t => { - const path = './test/check-references/mystery-criteria/**/' - t.plan(4) - - quiet() - const { res } = checkReferences(`${path}*.md`, `${path}*.feature`, './test/test-data/categories.json') - loud() - - t.equal(res.criteriaTotal, 2, 'Two valid criteria exist in specs') - - const mc = res.unknownCriteriaInTests - t.equal(mc.size, 1, 'There should be 1 mystery criteria') - - t.equal(mc.keys().next().value, '0007-MYST-001', 'It should list the unkown code') - t.equal(mc.values().next().value[0], './test/check-references/mystery-criteria/tests/test.feature', 'It should point to the file with the unknown code') -}) - -test('check-references: Specs can be in multiple categories at once', t => { - const path = './test/check-references/multiple-categories/**/' - t.plan(20) - - quiet() - const { res } = checkReferences(`${path}*.md`, `${path}*.feature`, './test/check-references/multiple-categories/categories/categories.json', '', undefined, false, false, true, true) - loud() - - const c = res.categories - - t.equal(c[0].Category, 'JustTheOneSpec', 'Just The One Spec category exists') - t.equal(c[0].Specs, 1, 'Just The One Spec category has just the one spec') - t.equal(c[0].Criteria, 1, 'The spec in this category has one criteria') - - t.equal(c[1].Category, 'AnotherCategoryWithJustOneSpec', 'Another Category With Just One Spec category exists') - t.equal(c[1].Specs, 1, 'Another Category with Just One Spec category has just the one spec') - t.equal(c[1].Criteria, 3, 'The spec in this category has three criteria') - - t.equal(c[2].Category, 'CATEisAlsoInHere', 'Cate Is Also In Here category exists') - t.equal(c[2].Specs, 1, 'CATE Is Also In Here category has one spec, which has been in a previous category') - t.equal(c[2].Criteria, 3, 'The spec in this category has three criteria (same as the last one)') - - t.equal(c[3].Category, 'AllSpecs', 'AllSpecs contains two specifications') - t.equal(c[3].Specs, 2, 'AllSpecs contains both specifications') - t.equal(c[3].Criteria, 4, 'The specs in this category have four criteria (total)') - - t.equal(c[4].Category, 'Unknown', 'No specs with no category') - t.equal(c[4].Specs, '-', 'No specs with no category') - t.equal(c[4].Criteria, '-', 'No criteria in no specs with no category') - - t.equal(c[5].Category, 'Total', 'Total should be 2, not the sum of all categories') - t.equal(c[5].Specs, 2, 'There are 2 specs, same as AllSpecs') - t.equal(c[5].Criteria, 4, 'There are 4 criteria, same as AllSpecs') - t.equal(c[5].Covered, 4, 'There are 4 covered criteria, same as AllSpecs') - t.equal(c[5]['by/FeatTest'], 4, 'There are 4 criteria covered by feature tests, same as AllSpecs') -}) +}) \ No newline at end of file diff --git a/test/next-filename.test.js b/test/next-filename.test.js deleted file mode 100644 index f75e634..0000000 --- a/test/next-filename.test.js +++ /dev/null @@ -1,105 +0,0 @@ -const test = require("tape"); -const { - getRandomCode, - padNumber, - findLowestNumber, - nextFilename -} = require("../src/next-filename"); -const { quiet, loud } = require("./lib"); - -test("next-filename: getRandomCode: returns a string", (t) => { - t.plan(3); - t.equal(typeof getRandomCode(), "string", "Returns a string"); - t.equal(getRandomCode().length, 4, "Returns a 4 character string"); - t.match( - getRandomCode(), - /^[A-Z]+$/, - "Returns an uppercase string of uppercase letters" - ); -}); - -test("next-filename: padNumber", (t) => { - t.plan(5); - t.equal(typeof padNumber(42), "string", "Returns a string"); - t.equal(padNumber(9876), "9876", "Does not pad a 4 digit number"); - t.equal(padNumber(123), "0123", "Pads a 3 digit number with one zero"); - t.equal(padNumber(42), "0042", "Pads a 2 digit number with two zeros"); - t.equal(padNumber(5), "0005", "Pads a single digit number with three zeros"); -}); - -test("next-filename: findLowestNumber", (t) => { - t.plan(8); - - t.equal( - findLowestNumber([1, 3, 5]), - 2, - "Should return 2 (sorted, middle number)" - ); - t.equal( - findLowestNumber([2, 3, 4]), - 1, - "Should return 1 (sorted, first number)" - ); - t.equal( - findLowestNumber([10, 8, 6]), - 1, - "Should return 1 if it is unused (reverse sort)" - ); - t.equal( - findLowestNumber([5, 4, 3]), - 1, - "Should return 1 if it is unused (reverse sort, long gap" - ); - t.equal(findLowestNumber([1, 3, 7]), 2, "Should return 2 in a short"); - t.equal( - findLowestNumber([1, 2, 3, 4, 5, 6, 7]), - 8, - "Should return next number in a long array" - ); - t.equal( - findLowestNumber([1]), - 2, - "Should return next number in a single item array" - ); - t.equal( - findLowestNumber([1, 1001]), - 2, - "Should return 2 even though there a large number" - ); -}); - -test('next-filename: correctly detect 0002 as next lowest', t => { - t.plan(3) - - quiet() - const { exitCode, nextLowest, nextHighest } = nextFilename('./test/next-filename/missing-sequence/**/*.md', '', false) - loud() - - t.equal(exitCode, 0, 'Expected no error') - t.equal(nextLowest, '0002', '0002 is missing, so it is the lowest available sequence number') - t.equal(nextHighest, '0004', '0004 is the highest available sequence number') - }) - - test('next-filename: correctly detect 0003 as next lowest, 1002 as next highest', t => { - t.plan(3) - - quiet() - const { exitCode, nextLowest, nextHighest } = nextFilename('./test/next-filename/big-skip/**/*.md', '', false) - loud() - - t.equal(exitCode, 0, 'Expected no error') - t.equal(nextLowest, '0004', '0004 is missing, so it is the lowest available sequence number') - t.equal(nextHighest, '1002', '1002 is the highest available sequence number') - }) - - test('next-filename: no matched files', t => { - t.plan(3) - - quiet() - const { exitCode, nextLowest, nextHighest } = nextFilename('./test/next-filename/no-files/**/*.md', '', false) - loud() - - t.equal(exitCode, 1, 'Expected an error') - t.equal(nextLowest, '-', 'no lowest available sequence number, because there are no files') - t.equal(nextHighest, '-', 'no highest available sequence number, because there are no files') - }) \ No newline at end of file diff --git a/test/next-filename/big-skip/0001-VALI-valid_filename.md b/test/next-filename/big-skip/0001-VALI-valid_filename.md deleted file mode 100644 index bcc14ca..0000000 --- a/test/next-filename/big-skip/0001-VALI-valid_filename.md +++ /dev/null @@ -1 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lobortis eros sit amet justo eleifend, eget egestas nulla consectetur. Phasellus id sapien ut nibh auctor viverra. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec odio volutpat, cursus augue sit amet, auctor urna. Nulla tincidunt blandit quam ut convallis. Sed mollis felis id leo lacinia, non blandit metus commodo. Curabitur ullamcorper ultrices aliquam. Nam eu velit diam. Sed id vehicula ligula. Fusce tempus nec nunc sed viverra. Vivamus a nisl nibh. Mauris tempus lobortis malesuada. Phasellus non quam nisi. \ No newline at end of file diff --git a/test/next-filename/big-skip/0002-VALA-also_valid_filename.md b/test/next-filename/big-skip/0002-VALA-also_valid_filename.md deleted file mode 100644 index 54dd89f..0000000 --- a/test/next-filename/big-skip/0002-VALA-also_valid_filename.md +++ /dev/null @@ -1 +0,0 @@ -Fusce euismod, orci eu tristique ultricies, sapien turpis lacinia nulla, vel mattis turpis turpis eget urna. Pellentesque purus risus, dignissim non tincidunt sed, tristique vel est. Vivamus at leo ligula. Integer accumsan ultricies est, sed ultricies erat mollis a. Phasellus id sollicitudin ex, quis consequat sem. Sed et tristique mauris. Cras vehicula volutpat sem eget tempor. Cras vitae posuere arcu. In commodo mi at arcu egestas, sed auctor nibh tempus. Nullam enim dolor, condimentum ac sagittis sed, rhoncus interdum dolor. Mauris cursus diam massa, nec congue sem feugiat vel. Integer faucibus lectus lacus. Donec sollicitudin magna vitae tellus imperdiet, non scelerisque ex malesuada. \ No newline at end of file diff --git a/test/next-filename/big-skip/0003-VLAA-also_valid_filename copy.md b/test/next-filename/big-skip/0003-VLAA-also_valid_filename copy.md deleted file mode 100644 index 54dd89f..0000000 --- a/test/next-filename/big-skip/0003-VLAA-also_valid_filename copy.md +++ /dev/null @@ -1 +0,0 @@ -Fusce euismod, orci eu tristique ultricies, sapien turpis lacinia nulla, vel mattis turpis turpis eget urna. Pellentesque purus risus, dignissim non tincidunt sed, tristique vel est. Vivamus at leo ligula. Integer accumsan ultricies est, sed ultricies erat mollis a. Phasellus id sollicitudin ex, quis consequat sem. Sed et tristique mauris. Cras vehicula volutpat sem eget tempor. Cras vitae posuere arcu. In commodo mi at arcu egestas, sed auctor nibh tempus. Nullam enim dolor, condimentum ac sagittis sed, rhoncus interdum dolor. Mauris cursus diam massa, nec congue sem feugiat vel. Integer faucibus lectus lacus. Donec sollicitudin magna vitae tellus imperdiet, non scelerisque ex malesuada. \ No newline at end of file diff --git a/test/next-filename/big-skip/1001-DONE-donec_euismod.md b/test/next-filename/big-skip/1001-DONE-donec_euismod.md deleted file mode 100644 index 63166ee..0000000 --- a/test/next-filename/big-skip/1001-DONE-donec_euismod.md +++ /dev/null @@ -1 +0,0 @@ -Donec sagittis tempor aliquam. Vestibulum ut ex et erat iaculis mollis. Maecenas congue congue odio, ac placerat dui facilisis eget. Suspendisse id augue finibus magna aliquam consequat eu sed nulla. Aliquam a porttitor felis, sed semper nulla. Quisque mattis fermentum erat, ac ultricies mi tempor sed. Aenean blandit metus vel vestibulum imperdiet. diff --git a/test/next-filename/missing-sequence/0001-VALI-valid_filename.md b/test/next-filename/missing-sequence/0001-VALI-valid_filename.md deleted file mode 100644 index bcc14ca..0000000 --- a/test/next-filename/missing-sequence/0001-VALI-valid_filename.md +++ /dev/null @@ -1 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lobortis eros sit amet justo eleifend, eget egestas nulla consectetur. Phasellus id sapien ut nibh auctor viverra. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec odio volutpat, cursus augue sit amet, auctor urna. Nulla tincidunt blandit quam ut convallis. Sed mollis felis id leo lacinia, non blandit metus commodo. Curabitur ullamcorper ultrices aliquam. Nam eu velit diam. Sed id vehicula ligula. Fusce tempus nec nunc sed viverra. Vivamus a nisl nibh. Mauris tempus lobortis malesuada. Phasellus non quam nisi. \ No newline at end of file diff --git a/test/next-filename/missing-sequence/0003-DONE-donec_euismod.md b/test/next-filename/missing-sequence/0003-DONE-donec_euismod.md deleted file mode 100644 index 63166ee..0000000 --- a/test/next-filename/missing-sequence/0003-DONE-donec_euismod.md +++ /dev/null @@ -1 +0,0 @@ -Donec sagittis tempor aliquam. Vestibulum ut ex et erat iaculis mollis. Maecenas congue congue odio, ac placerat dui facilisis eget. Suspendisse id augue finibus magna aliquam consequat eu sed nulla. Aliquam a porttitor felis, sed semper nulla. Quisque mattis fermentum erat, ac ultricies mi tempor sed. Aenean blandit metus vel vestibulum imperdiet.