-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test,doc: make
cli.md
tests more robust
- Loading branch information
1 parent
3d35087
commit f602715
Showing
2 changed files
with
58 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,90 @@ | ||
'use strict'; | ||
const common = require('../common'); | ||
if (process.config.variables.node_without_node_options) | ||
common.skip('missing NODE_OPTIONS support'); | ||
|
||
// Test options specified by env variable. | ||
|
||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { test } = require('node:test'); | ||
|
||
const rootDir = path.resolve(__dirname, '..', '..'); | ||
const cliMd = path.join(rootDir, 'doc', 'api', 'cli.md'); | ||
const cliText = fs.readFileSync(cliMd, { encoding: 'utf8' }); | ||
|
||
const internalApiMd = path.join(rootDir, 'doc', 'contributing', 'internal-api.md'); | ||
const internalApiText = fs.readFileSync(internalApiMd, { encoding: 'utf8' }); | ||
// Skip test if NODE_OPTIONS support is missing | ||
if (process.config.variables.node_without_node_options) { | ||
common.skip('missing NODE_OPTIONS support'); | ||
} | ||
|
||
const nodeOptionsCC = fs.readFileSync(path.resolve(rootDir, 'src', 'node_options.cc'), 'utf8'); | ||
const rootDir = path.resolve(__dirname, '..', '..'); | ||
const cliFilePath = path.join(rootDir, 'doc', 'api', 'cli.md'); | ||
const internalApiFilePath = path.join(rootDir, 'doc', 'contributing', 'internal-api.md'); | ||
const manPagePath = path.join(rootDir, 'doc', 'node.1'); | ||
const nodeOptionsCCPath = path.join(rootDir, 'src', 'node_options.cc'); | ||
|
||
// Read files | ||
const cliText = fs.readFileSync(cliFilePath, 'utf8'); | ||
const internalApiText = fs.readFileSync(internalApiFilePath, 'utf8'); | ||
const manPageText = fs.readFileSync(manPagePath, 'utf8'); | ||
const nodeOptionsCC = fs.readFileSync(nodeOptionsCCPath, 'utf8'); | ||
|
||
// Regular Expressions | ||
const addOptionRE = /AddOption[\s\n\r]*\([\s\n\r]*"([^"]+)"(.*?)\);/gs; | ||
|
||
const nodeOptionsText = cliText.match(/<!-- node-options-node start -->(.*)<!-- node-options-others end -->/s)[1]; | ||
const v8OptionsText = cliText.match(/<!-- v8-options start -->(.*)<!-- v8-options end -->/s)[1]; | ||
|
||
const manPage = path.join(rootDir, 'doc', 'node.1'); | ||
const manPageText = fs.readFileSync(manPage, { encoding: 'utf8' }); | ||
|
||
// Documented in /doc/api/deprecations.md | ||
const deprecated = [ | ||
'--debug', | ||
'--debug-brk', | ||
]; | ||
|
||
|
||
const manPagesOptions = new Set(); | ||
// Deprecated options | ||
const deprecatedOptions = new Set(['--debug', '--debug-brk']); | ||
|
||
for (const [, envVar] of manPageText.matchAll(/\.It Fl (-[a-zA-Z0-9._-]+)/g)) { | ||
manPagesOptions.add(envVar); | ||
} | ||
// Helper Functions | ||
const isOptionDocumentedInCli = (envVar) => new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(cliText); | ||
const isOptionDocumentedInInternalApi = (envVar) => new RegExp(`####.*\`${envVar}[[=\\s\\b\`]`).test(internalApiText); | ||
const isOptionDocumentedInV8 = (envVar) => new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(v8OptionsText); | ||
const isOptionInNodeOptions = (envVar) => new RegExp(`\`${envVar}\``).test(nodeOptionsText); | ||
|
||
for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) { | ||
let hasTrueAsDefaultValue = false; | ||
let isInNodeOption = false; | ||
const validateOption = (envVar, config) => { | ||
let hasTrueAsDefault = false; | ||
let isInNodeOptions = false; | ||
let isV8Option = false; | ||
let isNoOp = false; | ||
const isNoOp = config.includes('NoOp{}'); | ||
|
||
if (config.includes('NoOp{}')) { | ||
isNoOp = true; | ||
} | ||
// Check option categories | ||
if (config.includes('kAllowedInEnvvar')) isInNodeOptions = true; | ||
if (config.includes('V8Option{}')) isV8Option = true; | ||
if (/^\s*true\s*$/.test(config.split(',').pop())) hasTrueAsDefault = true; | ||
|
||
if (config.includes('kAllowedInEnvvar')) { | ||
isInNodeOption = true; | ||
} | ||
if (config.includes('kDisallowedInEnvvar')) { | ||
isInNodeOption = false; | ||
const manpageEntry = hasTrueAsDefault ? `-no${envVar.slice(1)}` : envVar.slice(1); | ||
if (envVar.startsWith('[') || deprecatedOptions.has(envVar) || isNoOp) { | ||
return; | ||
} | ||
|
||
if (config.includes('V8Option{}')) { | ||
isV8Option = true; | ||
if (isOptionDocumentedInInternalApi(envVar)) { | ||
return; | ||
} | ||
|
||
if (/^\s*true\s*$/.test(config.split(',').pop())) { | ||
hasTrueAsDefaultValue = true; | ||
if (!isV8Option && !hasTrueAsDefault && !isOptionDocumentedInCli(envVar)) { | ||
assert.fail(`Should have option ${envVar} documented`); | ||
} | ||
|
||
if ( | ||
envVar.startsWith('[') || | ||
deprecated.includes(envVar) || | ||
isNoOp | ||
) { | ||
// assert(!manPagesOptions.has(envVar.slice(1)), `Option ${envVar} should not be documented`) | ||
manPagesOptions.delete(envVar.slice(1)); | ||
continue; | ||
if (!hasTrueAsDefault && isOptionDocumentedInCli(`--no${envVar.slice(1)}`)) { | ||
assert.fail(`Should not have option --no${envVar.slice(1)} documented`); | ||
} | ||
|
||
// Internal API options are documented in /doc/contributing/internal-api.md | ||
if (new RegExp(`####.*\`${envVar}[[=\\s\\b\`]`).test(internalApiText) === true) { | ||
manPagesOptions.delete(envVar.slice(1)); | ||
continue; | ||
if (!isV8Option && hasTrueAsDefault && !isOptionDocumentedInCli(`--no${envVar.slice(1)}`)) { | ||
assert.fail(`Should have option --no${envVar.slice(1)} documented`); | ||
} | ||
|
||
// CLI options | ||
if (!isV8Option && !hasTrueAsDefaultValue) { | ||
if (new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(cliText) === false) { | ||
assert(false, `Should have option ${envVar} documented`); | ||
} else { | ||
manPagesOptions.delete(envVar.slice(1)); | ||
} | ||
if (isInNodeOptions && !hasTrueAsDefault && !isOptionInNodeOptions(envVar)) { | ||
assert.fail(`Should have option ${envVar} in NODE_OPTIONS documented`); | ||
} | ||
|
||
if (!hasTrueAsDefaultValue && new RegExp(`###.*\`--no${envVar.slice(1)}[[=\\s\\b\`]`).test(cliText) === true) { | ||
assert(false, `Should not have option --no${envVar.slice(1)} documented`); | ||
if (isInNodeOptions && hasTrueAsDefault && !isOptionInNodeOptions(`--no${envVar.slice(1)}`)) { | ||
assert.fail(`Should have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); | ||
} | ||
|
||
if (!isV8Option && hasTrueAsDefaultValue) { | ||
if (new RegExp(`###.*\`--no${envVar.slice(1)}[[=\\s\\b\`]`).test(cliText) === false) { | ||
assert(false, `Should have option --no${envVar.slice(1)} documented`); | ||
} else { | ||
manPagesOptions.delete(`-no${envVar.slice(1)}`); | ||
} | ||
if (isV8Option && !isOptionDocumentedInV8(envVar)) { | ||
assert.fail(`Should have option ${envVar} in V8 options documented`); | ||
} | ||
|
||
// NODE_OPTIONS | ||
if (isInNodeOption && !hasTrueAsDefaultValue && new RegExp(`\`${envVar}\``).test(nodeOptionsText) === false) { | ||
assert(false, `Should have option ${envVar} in NODE_OPTIONS documented`); | ||
} | ||
|
||
if (isInNodeOption && hasTrueAsDefaultValue && new RegExp(`\`--no${envVar.slice(1)}\``).test(cliText) === false) { | ||
assert(false, `Should have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); | ||
} | ||
assert(manPageText.includes(manpageEntry), `Should have option ${envVar} in node.1`); | ||
}; | ||
|
||
if (!hasTrueAsDefaultValue && new RegExp(`\`--no${envVar.slice(1)}\``).test(cliText) === true) { | ||
assert(false, `Should not have option --no${envVar.slice(1)} in NODE_OPTIONS documented`); | ||
} | ||
|
||
// V8 options | ||
if (isV8Option) { | ||
if (new RegExp(`###.*\`${envVar}[[=\\s\\b\`]`).test(v8OptionsText) === false) { | ||
assert(false, `Should have option ${envVar} in V8 options documented`); | ||
} else { | ||
manPagesOptions.delete(envVar.slice(1)); | ||
} | ||
} | ||
// Parse node options from source file | ||
for (const [, envVar, config] of nodeOptionsCC.matchAll(addOptionRE)) { | ||
test(envVar, () => validateOption(envVar, config)); | ||
} | ||
|
||
// add alias handling | ||
manPagesOptions.delete('-trace-events-enabled'); | ||
|
||
assert.strictEqual(manPagesOptions.size, 0, `Man page options not documented: ${[...manPagesOptions]}`); |