|
1 | 1 | import {expect, test} from '@jest/globals' |
2 | | -import {parsePURL} from '../src/purl' |
| 2 | +import {parsePURL, purlsMatch} from '../src/purl' |
3 | 3 |
|
4 | 4 | test('parsePURL returns an error if the purl does not start with "pkg:"', () => { |
5 | 5 | const purl = 'not-a-purl' |
@@ -184,3 +184,66 @@ test('parsePURL table test', () => { |
184 | 184 | expect(result).toEqual(example.expected) |
185 | 185 | } |
186 | 186 | }) |
| 187 | + |
| 188 | +test('purlsMatch matches identical PURLs', () => { |
| 189 | + const a = parsePURL('pkg:npm/@scope/[email protected]') |
| 190 | + const b = parsePURL('pkg:npm/@scope/[email protected]') |
| 191 | + expect(purlsMatch(a, b)).toBe(true) |
| 192 | +}) |
| 193 | + |
| 194 | +test('purlsMatch matches when namespace separator is percent-encoded', () => { |
| 195 | + // %2F-encoded separator puts everything in name with no namespace |
| 196 | + const encoded = parsePURL('pkg:npm/%40lancedb%2Flancedb') |
| 197 | + // literal / splits into namespace + name |
| 198 | + const literal = parsePURL('pkg:npm/%40lancedb/lancedb') |
| 199 | + expect(purlsMatch(encoded, literal)).toBe(true) |
| 200 | +}) |
| 201 | + |
| 202 | +test('purlsMatch matches scoped npm packages regardless of encoding', () => { |
| 203 | + const a = parsePURL('pkg:npm/%40lancedb%2Flancedb') |
| 204 | + const b = parsePURL('pkg:npm/@lancedb/lancedb') |
| 205 | + const c = parsePURL('pkg:npm/%40lancedb/[email protected]') |
| 206 | + expect(purlsMatch(a, b)).toBe(true) |
| 207 | + expect(purlsMatch(a, c)).toBe(true) |
| 208 | + expect(purlsMatch(b, c)).toBe(true) |
| 209 | +}) |
| 210 | + |
| 211 | +test('purlsMatch does not match different packages', () => { |
| 212 | + const a = parsePURL('pkg:npm/@scope/foo') |
| 213 | + const b = parsePURL('pkg:npm/@scope/bar') |
| 214 | + expect(purlsMatch(a, b)).toBe(false) |
| 215 | +}) |
| 216 | + |
| 217 | +test('purlsMatch does not match different types', () => { |
| 218 | + const a = parsePURL('pkg:npm/@scope/name') |
| 219 | + const b = parsePURL('pkg:pypi/@scope/name') |
| 220 | + expect(purlsMatch(a, b)).toBe(false) |
| 221 | +}) |
| 222 | + |
| 223 | +test('purlsMatch matches packages without namespaces', () => { |
| 224 | + const a = parsePURL('pkg:npm/[email protected]') |
| 225 | + const b = parsePURL('pkg:npm/[email protected]') |
| 226 | + expect(purlsMatch(a, b)).toBe(true) |
| 227 | +}) |
| 228 | + |
| 229 | +test('purlsMatch is case-insensitive for GitHub Actions', () => { |
| 230 | + const a = parsePURL('pkg:githubactions/MyOrg/[email protected]') |
| 231 | + const b = parsePURL('pkg:githubactions/myorg/[email protected]') |
| 232 | + expect(purlsMatch(a, b)).toBe(true) |
| 233 | +}) |
| 234 | + |
| 235 | +test('purlsMatch is case-insensitive for scoped npm packages', () => { |
| 236 | + const a = parsePURL('pkg:npm/@MyScope/MyPackage') |
| 237 | + const b = parsePURL('pkg:npm/@myscope/mypackage') |
| 238 | + expect(purlsMatch(a, b)).toBe(true) |
| 239 | +}) |
| 240 | + |
| 241 | +test('purlsMatch is case-insensitive for GitHub Actions with file paths', () => { |
| 242 | + const a = parsePURL( |
| 243 | + 'pkg:githubactions/MyOrg/MyWorkflows/.github/workflows/general.yml' |
| 244 | + ) |
| 245 | + const b = parsePURL( |
| 246 | + 'pkg:githubactions/myorg/myworkflows/.github/workflows/general.yml' |
| 247 | + ) |
| 248 | + expect(purlsMatch(a, b)).toBe(true) |
| 249 | +}) |
0 commit comments