Skip to content

Commit

Permalink
Add is-regex tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jdalton committed Oct 5, 2024
1 parent 3b31508 commit 616f07a
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 47 deletions.
9 changes: 8 additions & 1 deletion scripts/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const ENV = Object.freeze({
// .husky/pre-commit hook.
PRE_COMMIT: envAsBool(process.env.PRE_COMMIT)
})
const ESLINT_CONFIG_JS = 'eslint.config.js'
const ESNEXT = 'esnext'
const LICENSE = 'LICENSE'
const LICENSE_GLOB = 'LICEN[CS]E{[.-]*,}'
Expand Down Expand Up @@ -109,6 +110,7 @@ const WIN_32 = process.platform === 'win32'

const rootPath = path.resolve(__dirname, '..')
const rootLicensePath = path.join(rootPath, LICENSE)
const rootEslintConfigPath = path.join(rootPath, ESLINT_CONFIG_JS)
const rootNodeModulesPath = path.join(rootPath, NODE_MODULES)
const rootNodeModulesBinPath = path.join(rootNodeModulesPath, '.bin')
const rootPackageJsonPath = path.join(rootPath, PACKAGE_JSON)
Expand Down Expand Up @@ -426,6 +428,7 @@ const skipTestsByEcosystem = Object.freeze({
'hyrious__bun.lockb',
// Has known test fails in its package:
// https://github.com/es-shims/Date/issues/3
// https://github.com/es-shims/Date/tree/v2.0.5
'date',
// Has no unit tests.
// https://github.com/rubennorte/es6-object-assign/tree/v1.1.0
Expand All @@ -436,10 +439,12 @@ const skipTestsByEcosystem = Object.freeze({
// The package tests don't account for the `require('node:util/types).isRegExp`
// method having no observable side-effects and assumes the "getOwnPropertyDescriptor"
// trap will be triggered by `Object.getOwnPropertyDescriptor(value, 'lastIndex')`.
// https://github.com/inspect-js/is-regex/issues/35
// https://github.com/inspect-js/is-regex/tree/v1.1.4
'is-regex',
// Has known failures in its package.
// https://github.com/ChALkeR/safer-buffer/issues/16
// https://github.com/ChALkeR/safer-buffer/tree/v2.1.2
'safer-buffer'
])
})
Expand Down Expand Up @@ -473,6 +478,7 @@ const constants = Object.freeze(
[kInternalsSymbol]: internals,
EMPTY_FILE,
ENV,
ESLINT_CONFIG_JS,
ESNEXT,
LICENSE,
// Lazily defined values are initialized as `undefined` to keep their key order.
Expand Down Expand Up @@ -541,12 +547,13 @@ const constants = Object.freeze(
relPackagesPath,
relTestNpmPath,
relTestNpmNodeModulesPath,
rootPath,
rootEslintConfigPath,
rootLicensePath,
rootNodeModulesPath,
rootPackageJsonPath,
rootPackageLockPath,
rootPackagesPath,
rootPath,
rootTsConfigPath,
skipTestsByEcosystem,
tapCiConfigPath,
Expand Down
2 changes: 1 addition & 1 deletion test/npm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ describe('npm', async () => {
for (const regPkgName of packageNames) {
const nwPkgPath = path.join(testNpmNodeWorkspacesPath, regPkgName)
const nwPkgJson = fs.readJsonSync(path.join(nwPkgPath, PACKAGE_JSON))
const manifestData = getManifestData('npm', regPkgName)
const nodeRange = nwPkgJson.engines?.node
const origPkgName = resolveOriginalPackageName(regPkgName)
const manifestData = getManifestData('npm', regPkgName)
const skip =
!nwPkgJson.scripts?.test ||
(WIN_32 && !manifestData.interop.includes('browserify')) ||
Expand Down
9 changes: 9 additions & 0 deletions test/npm/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

const { rootEslintConfigPath } = require('@socketregistry/scripts/constants')

module.exports = [
{
extends: rootEslintConfigPath
}
]
150 changes: 150 additions & 0 deletions test/npm/is-regex.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import assert from 'node:assert/strict'
import path from 'node:path'
import { describe, it } from 'node:test'

// @ts-ignore
import constants from '@socketregistry/scripts/constants'
const { testNpmNodeWorkspacesPath } = constants

const regPkgName = 'is-regex'
const pkgPath = path.join(testNpmNodeWorkspacesPath, regPkgName)
const isRegex = require(pkgPath)

// The package tests don't account for the `require('node:util/types).isRegExp`
// method having no observable side-effects and assumes the "getOwnPropertyDescriptor"
// trap will be triggered by `Object.getOwnPropertyDescriptor(value, 'lastIndex')`.
// https://github.com/inspect-js/is-regex/issues/35
// https://github.com/inspect-js/is-regex/tree/v1.1.4
describe(`npm > ${regPkgName}`, async () => {
it('not regexes', () => {
assert.strictEqual(isRegex(), false, 'undefined is not regex')
assert.strictEqual(isRegex(null), false, 'null is not regex')
assert.strictEqual(isRegex(false), false, 'false is not regex')
assert.strictEqual(isRegex(true), false, 'true is not regex')
assert.strictEqual(isRegex(42), false, 'number is not regex')
assert.strictEqual(isRegex('foo'), false, 'string is not regex')
assert.strictEqual(isRegex([]), false, 'array is not regex')
assert.strictEqual(isRegex({}), false, 'object is not regex')
assert.strictEqual(
isRegex(function () {}),
false,
'function is not regex'
)
})

it('@@toStringTag', () => {
const regex = /a/g
const fakeRegex = {
toString() {
return String(regex)
},
valueOf() {
return regex
},
[Symbol.toStringTag]: 'RegExp'
}

assert.strictEqual(
isRegex(fakeRegex),
false,
'fake RegExp with @@toStringTag "RegExp" is not regex'
)
})

it('regexes', () => {
assert.ok(isRegex(/a/g), 'regex literal is regex')
assert.ok(isRegex(new RegExp('a', 'g')), 'regex object is regex')
})

it('does not mutate regexes', async t => {
await t.test('lastIndex is a marker object', () => {
const regex = /a/
const marker = {}
;(regex as any).lastIndex = marker
assert.strictEqual(
regex.lastIndex,
marker,
'lastIndex is the marker object'
)
assert.ok(isRegex(regex), 'is regex')
assert.strictEqual(
regex.lastIndex,
marker,
'lastIndex is the marker object after isRegex'
)
})

await t.test('lastIndex is nonzero', () => {
const regex = /a/
regex.lastIndex = 3
assert.equal(regex.lastIndex, 3, 'lastIndex is 3')
assert.ok(isRegex(regex), 'is regex')
assert.equal(regex.lastIndex, 3, 'lastIndex is 3 after isRegex')
})
})

it('does not perform operations observable to Proxies', async t => {
class Handler {
trapCalls: string[]
constructor() {
this.trapCalls = []
}
}

for (const trapName of [
'defineProperty',
'deleteProperty',
'get',
'getOwnPropertyDescriptor',
'getPrototypeOf',
'has',
'isExtensible',
'ownKeys',
'preventExtensions',
'set',
'setPrototypeOf'
]) {
;(Handler.prototype as any)[trapName] = function () {
this.trapCalls.push(trapName)
return (Reflect as any)[trapName].apply(Reflect, arguments)
}
}

await t.test('proxy of object', () => {
const target = { lastIndex: 0 }
const handler = new Handler()
const proxy = new Proxy(
{ lastIndex: 0 },
<ProxyHandler<typeof target>>handler
)

assert.strictEqual(
isRegex(proxy),
false,
'proxy of plain object is not regex'
)
assert.deepStrictEqual(
handler.trapCalls,
[],
'no unexpected proxy traps were triggered'
)
})

await t.test('proxy of RegExp instance', () => {
const target = /a/
const handler = new Handler()
const proxy = new Proxy(/a/, <ProxyHandler<typeof target>>handler)

assert.strictEqual(
isRegex(proxy),
false,
'proxy of RegExp instance is not regex'
)
assert.deepStrictEqual(
handler.trapCalls,
[],
'no unexpected proxy traps were triggered'
)
})
})
})
Loading

0 comments on commit 616f07a

Please sign in to comment.