Skip to content

Commit 6c7e483

Browse files
committed
test: refactor to use shared utilities and it.each
Replace duplicated helper functions with imports from test/utils: - Use testInvalidParam, testValidParam from param-validation - Use createTestFunction from test-helpers - Convert 4 forEach loops to it.each for better test output Reduces duplication by 166 lines while maintaining 100% coverage
1 parent 0c6b0c6 commit 6c7e483

File tree

1 file changed

+61
-229
lines changed

1 file changed

+61
-229
lines changed

test/package-url.test.mts

Lines changed: 61 additions & 229 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ import {
3131
toSortedObjectFromEntries,
3232
} from '@socketsecurity/registry/lib/objects'
3333

34+
import {
35+
testInvalidParam,
36+
testInvalidStringParam,
37+
testValidParam,
38+
testValidStringParam,
39+
} from './utils/param-validation.mjs'
40+
import { createTestFunction } from './utils/test-helpers.mjs'
3441
import npmBuiltinNames from '../data/npm/builtin-names.json'
3542
import npmLegacyNames from '../data/npm/legacy-names.json'
3643
import { LOOP_SENTINEL } from '../dist/constants.js'
@@ -94,156 +101,20 @@ function toUrlSearchParams(search: any) {
94101
return searchParams
95102
}
96103

97-
// Helper functions for parameter validation tests.
98-
function testInvalidParam(
99-
paramName: string,
100-
paramMap: Record<string, number>,
101-
createArgs: (
102-
_name: string,
103-
_value: unknown,
104-
) => [unknown, unknown, unknown, unknown, unknown, unknown],
105-
) {
106-
const paramIndex = paramMap[paramName]
107-
;[
108-
createArgs(paramName, 0),
109-
createArgs(paramName, false),
110-
createArgs(paramName, 1),
111-
createArgs(paramName, true),
112-
createArgs(paramName, {}),
113-
createArgs(paramName, null),
114-
createArgs(paramName, undefined),
115-
createArgs(paramName, ''),
116-
].forEach(args => {
117-
const message = JSON.stringify(args[paramIndex])
118-
try {
119-
new PackageURL(...args)
120-
expect(false, message)
121-
} catch {
122-
expect(true, message)
123-
}
124-
})
125-
}
126-
127-
function testInvalidStringParam(
128-
paramName: string,
129-
paramMap: Record<string, number>,
130-
createArgs: (
131-
_name: string,
132-
_value: unknown,
133-
) => [unknown, unknown, unknown, unknown, unknown, unknown],
134-
) {
135-
const paramIndex = paramMap[paramName]
136-
;[
137-
createArgs(paramName, 0),
138-
createArgs(paramName, false),
139-
createArgs(paramName, 1),
140-
createArgs(paramName, true),
141-
createArgs(paramName, {}),
142-
].forEach(args => {
143-
const message = JSON.stringify(args[paramIndex])
144-
try {
145-
new PackageURL(...args)
146-
expect(false, message)
147-
} catch {
148-
expect(true, message)
149-
}
150-
})
151-
}
152-
153-
function testValidParam(
154-
paramName: string,
155-
paramMap: Record<string, number>,
156-
createArgs: (
157-
_name: string,
158-
_value: unknown,
159-
) => [unknown, unknown, unknown, unknown, unknown, unknown],
160-
) {
161-
const paramIndex = paramMap[paramName]
162-
const args = createArgs(paramName, paramName)
163-
const message = JSON.stringify(args[paramIndex])
164-
try {
165-
new PackageURL(...args)
166-
expect(true, message)
167-
} catch {
168-
expect(false, message)
169-
}
170-
}
171-
172-
function testValidStringParam(
173-
paramName: string,
174-
paramMap: Record<string, number>,
175-
createArgs: (
176-
_name: string,
177-
_value: unknown,
178-
) => [unknown, unknown, unknown, unknown, unknown, unknown],
179-
) {
180-
const paramIndex = paramMap[paramName]
181-
;[
182-
createArgs(paramName, paramName),
183-
createArgs(paramName, null),
184-
createArgs(paramName, undefined),
185-
createArgs(paramName, ''),
186-
].forEach(args => {
187-
const message = JSON.stringify(args[paramIndex])
188-
try {
189-
new PackageURL(...args)
190-
expect(true, message)
191-
} catch {
192-
expect(false, message)
193-
}
194-
})
195-
}
196-
197-
// Helper function for parameter testing.
198-
const testFunction = () => {}
199-
200-
// Helper functions for freeze testing.
201-
function createTestFunction(): any {
202-
return function () {}
203-
}
204-
205-
function createTestFunctionWithReturn(): any {
206-
return function () {
207-
return 'test'
208-
}
209-
}
210-
211-
function createTestFunction1(): any {
212-
return function () {
213-
return 'test1'
214-
}
215-
}
216-
217-
function createTestFunction2(): any {
218-
return function () {
219-
return 'test2'
220-
}
221-
}
222-
223-
function createAnotherTestFunction() {
224-
return function () {
225-
return 'another'
226-
}
227-
}
228-
229104
describe('PackageURL', () => {
230105
describe('KnownQualifierNames', () => {
231-
describe('check access', () => {
232-
;[
233-
['RepositoryUrl', 'repository_url'],
234-
['DownloadUrl', 'download_url'],
235-
['VcsUrl', 'vcs_url'],
236-
['FileName', 'file_name'],
237-
['Checksum', 'checksum'],
238-
].forEach(function ([name, expectedValue]) {
239-
it(`maps: ${name} => ${expectedValue}`, () => {
240-
expect(
241-
PackageURL.KnownQualifierNames[
242-
name as keyof typeof PackageURL.KnownQualifierNames
243-
],
244-
).toBe(expectedValue)
245-
})
246-
})
106+
it.each([
107+
['RepositoryUrl', 'repository_url'],
108+
['DownloadUrl', 'download_url'],
109+
['VcsUrl', 'vcs_url'],
110+
['FileName', 'file_name'],
111+
['Checksum', 'checksum'],
112+
])('maps: %s => %s', (name, expectedValue) => {
113+
expect(
114+
PackageURL.KnownQualifierNames[
115+
name as keyof typeof PackageURL.KnownQualifierNames
116+
],
117+
).toBe(expectedValue)
247118
})
248119

249120
it('readonly: cannot be written', () => {
@@ -378,9 +249,10 @@ describe('PackageURL', () => {
378249
})
379250

380251
describe('toString()', () => {
381-
it('type is validated', () => {
382-
// Tests type validation rules (no special chars, can't start with number)
383-
;['ty#pe', 'ty@pe', 'ty/pe', '1type'].forEach(type => {
252+
it.each(['ty#pe', 'ty@pe', 'ty/pe', '1type'])(
253+
'type %s is validated and rejected',
254+
type => {
255+
// Tests type validation rules (no special chars, can't start with number)
384256
expect(
385257
() =>
386258
new PackageURL(
@@ -392,8 +264,8 @@ describe('PackageURL', () => {
392264
undefined,
393265
),
394266
).toThrow(/contains an illegal character|cannot start with a number/)
395-
})
396-
})
267+
},
268+
)
397269

398270
it('encode #', () => {
399271
// Tests # encoding (delimiter between url and subpath, must be encoded in components)
@@ -1342,10 +1214,11 @@ describe('PackageURL', () => {
13421214

13431215
it('should handle function as parameter (should reject)', () => {
13441216
// Tests parameter type validation (functions rejected)
1217+
const testFn = () => {}
13451218
expect(
13461219
() =>
13471220
new PackageURL(
1348-
testFunction,
1221+
testFn,
13491222
null,
13501223
'name',
13511224
undefined,
@@ -1357,7 +1230,7 @@ describe('PackageURL', () => {
13571230
() =>
13581231
new PackageURL(
13591232
'type',
1360-
testFunction,
1233+
testFn,
13611234
'name',
13621235
undefined,
13631236
undefined,
@@ -1369,7 +1242,7 @@ describe('PackageURL', () => {
13691242
new PackageURL(
13701243
'type',
13711244
null,
1372-
testFunction,
1245+
testFn,
13731246
undefined,
13741247
undefined,
13751248
undefined,
@@ -2412,81 +2285,40 @@ describe('PackageURL', () => {
24122285
})
24132286

24142287
// Test purl-type.js lines 282-291 - npm name with non-URL-friendly characters
2415-
it('should test npm name validation with non-URL-friendly characters', () => {
2416-
// Import already at top of file
2417-
2418-
// Test names with non-URL-friendly characters that need encoding
2419-
const testCases = [
2420-
{
2421-
name: 'package<>',
2422-
expectedError:
2423-
/npm "name" component can only contain URL-friendly characters/,
2424-
},
2425-
{
2426-
name: 'package[brackets]',
2427-
expectedError:
2428-
/npm "name" component can only contain URL-friendly characters/,
2429-
},
2430-
{
2431-
name: 'package{braces}',
2432-
expectedError:
2433-
/npm "name" component can only contain URL-friendly characters/,
2434-
},
2435-
{
2436-
name: 'package|pipe',
2437-
expectedError:
2438-
/npm "name" component can only contain URL-friendly characters/,
2439-
},
2440-
{
2441-
name: 'package\\backslash',
2442-
expectedError:
2443-
/npm "name" component can only contain URL-friendly characters/,
2444-
},
2445-
{
2446-
name: 'package^caret',
2447-
expectedError:
2448-
/npm "name" component can only contain URL-friendly characters/,
2449-
},
2450-
{
2451-
name: 'package space',
2452-
expectedError:
2453-
/npm "name" component can only contain URL-friendly characters/,
2454-
},
2455-
{
2456-
name: 'パッケージ',
2457-
expectedError:
2458-
/npm "name" component can only contain URL-friendly characters/,
2459-
// Non-ASCII characters
2460-
},
2461-
]
2462-
2463-
testCases.forEach(({ expectedError, name }) => {
2464-
const comp = { namespace: '', name }
2465-
2466-
// Test with throwing disabled - should return false
2467-
const result = (PurlType['npm'] as any).validate(comp, false)
2468-
expect(result).toBe(false)
2288+
it.each([
2289+
'package<>',
2290+
'package[brackets]',
2291+
'package{braces}',
2292+
'package|pipe',
2293+
'package\\backslash',
2294+
'package^caret',
2295+
'package space',
2296+
// Non-ASCII characters
2297+
'パッケージ',
2298+
])('should reject npm name with non-URL-friendly chars: %s', name => {
2299+
const comp = { namespace: '', name }
2300+
const expectedError =
2301+
/npm "name" component can only contain URL-friendly characters/
2302+
2303+
// Test with throwing disabled - should return false
2304+
const result = (PurlType['npm'] as any).validate(comp, false)
2305+
expect(result).toBe(false)
24692306

2470-
// Test with throwing enabled - should throw with expected error
2471-
expect(() => (PurlType['npm'] as any).validate(comp, true)).toThrow(
2472-
expectedError,
2473-
)
2474-
})
2307+
// Test with throwing enabled - should throw with expected error
2308+
expect(() => (PurlType['npm'] as any).validate(comp, true)).toThrow(
2309+
expectedError,
2310+
)
2311+
})
24752312

2476-
// Test that URL-friendly characters pass validation
2477-
const validNames = [
2478-
'package-name',
2479-
'package_name',
2480-
'package.name',
2481-
'package123',
2482-
]
2483-
validNames.forEach(name => {
2313+
it.each(['package-name', 'package_name', 'package.name', 'package123'])(
2314+
'should accept npm name with URL-friendly chars: %s',
2315+
name => {
24842316
const comp = { namespace: '', name }
24852317
// Should not throw
24862318
const result = (PurlType['npm'] as any).validate(comp, true)
24872319
expect(result).toBe(true)
2488-
})
2489-
})
2320+
},
2321+
)
24902322

24912323
// Test encode.js line 21 - null/undefined handling
24922324
it('should test encode component with falsy values', () => {
@@ -3377,13 +3209,13 @@ describe('PackageURL', () => {
33773209
// Import already at top of file
33783210

33793211
// Test freezing object with function as property
3380-
const func: any = createTestFunctionWithReturn()
3212+
const func: any = createTestFunction('test')
33813213
;(func as any).prop = 'value'
33823214

33833215
const obj = {
33843216
fn: func,
33853217
nested: {
3386-
anotherFn: createAnotherTestFunction(),
3218+
anotherFn: createTestFunction('another'),
33873219
},
33883220
}
33893221

@@ -3443,10 +3275,10 @@ describe('PackageURL', () => {
34433275
// Import already at top of file
34443276

34453277
// Test freezing array with functions (line 33 branch for typeof item === 'function')
3446-
const func1: any = createTestFunction1()
3278+
const func1: any = createTestFunction('test1')
34473279
;(func1 as any).prop = 'value1'
34483280

3449-
const func2: any = createTestFunction2()
3281+
const func2: any = createTestFunction('test2')
34503282
;(func2 as any).nested = { data: 'nested' }
34513283

34523284
const arr = [func1, { method: func2 }, func2, null, 'string', 42]

0 commit comments

Comments
 (0)