@@ -3418,6 +3418,191 @@ describe('PackageURL', () => {
34183418 const result3 = validateType ( 'type@invalid' , false )
34193419 expect ( result3 ) . toBe ( false )
34203420 } )
3421+
3422+ it ( 'should validate cocoapods name restrictions' , ( ) => {
3423+ // Test name with whitespace
3424+ expect (
3425+ ( ) => new PackageURL ( 'cocoapods' , null , 'Pod Name' , null , null , null ) ,
3426+ ) . toThrow ( 'cocoapods "name" component cannot contain whitespace' )
3427+
3428+ // Test name with plus character
3429+ expect (
3430+ ( ) => new PackageURL ( 'cocoapods' , null , 'Pod+Name' , null , null , null ) ,
3431+ ) . toThrow (
3432+ 'cocoapods "name" component cannot contain a plus (+) character' ,
3433+ )
3434+
3435+ // Test name beginning with period
3436+ expect (
3437+ ( ) => new PackageURL ( 'cocoapods' , null , '.PodName' , null , null , null ) ,
3438+ ) . toThrow ( 'cocoapods "name" component cannot begin with a period' )
3439+
3440+ // Test valid cocoapods name
3441+ const validPurl = new PackageURL (
3442+ 'cocoapods' ,
3443+ null ,
3444+ 'AFNetworking' ,
3445+ '4.0.0' ,
3446+ null ,
3447+ null ,
3448+ )
3449+ expect ( validPurl . toString ( ) ) . toBe ( 'pkg:cocoapods/[email protected] ' ) 3450+
3451+ // Test non-throwing mode
3452+ const result1 = ( PurlType [ 'cocoapods' ] as any ) . validate (
3453+ { name : 'Pod Name' } ,
3454+ false ,
3455+ )
3456+ expect ( result1 ) . toBe ( false )
3457+
3458+ const result2 = ( PurlType [ 'cocoapods' ] as any ) . validate (
3459+ { name : 'Pod+Name' } ,
3460+ false ,
3461+ )
3462+ expect ( result2 ) . toBe ( false )
3463+
3464+ const result3 = ( PurlType [ 'cocoapods' ] as any ) . validate (
3465+ { name : '.PodName' } ,
3466+ false ,
3467+ )
3468+ expect ( result3 ) . toBe ( false )
3469+ } )
3470+
3471+ it ( 'should validate cpan namespace requirements' , ( ) => {
3472+ // Test lowercase namespace
3473+ expect (
3474+ ( ) =>
3475+ new PackageURL ( 'cpan' , 'author' , 'Module-Name' , null , null , null ) ,
3476+ ) . toThrow ( 'cpan "namespace" component must be UPPERCASE' )
3477+
3478+ // Test mixed case namespace
3479+ expect (
3480+ ( ) =>
3481+ new PackageURL ( 'cpan' , 'Author' , 'Module-Name' , null , null , null ) ,
3482+ ) . toThrow ( 'cpan "namespace" component must be UPPERCASE' )
3483+
3484+ // Test valid cpan with uppercase namespace
3485+ const validPurl = new PackageURL (
3486+ 'cpan' ,
3487+ 'AUTHOR' ,
3488+ 'Module-Name' ,
3489+ '1.0.0' ,
3490+ null ,
3491+ null ,
3492+ )
3493+ expect ( validPurl . toString ( ) ) . toBe ( 'pkg:cpan/AUTHOR/[email protected] ' ) 3494+
3495+ // Test valid cpan without namespace (namespace is optional)
3496+ const validPurl2 = new PackageURL (
3497+ 'cpan' ,
3498+ null ,
3499+ 'DateTime' ,
3500+ '1.55' ,
3501+ null ,
3502+ null ,
3503+ )
3504+ expect ( validPurl2 . toString ( ) ) . toBe ( 'pkg:cpan/[email protected] ' ) 3505+
3506+ // Test non-throwing mode
3507+ const result1 = ( PurlType [ 'cpan' ] as any ) . validate (
3508+ { name : 'Module-Name' , namespace : 'author' } ,
3509+ false ,
3510+ )
3511+ expect ( result1 ) . toBe ( false )
3512+
3513+ const result2 = ( PurlType [ 'cpan' ] as any ) . validate (
3514+ { name : 'Module-Name' , namespace : 'Author' } ,
3515+ false ,
3516+ )
3517+ expect ( result2 ) . toBe ( false )
3518+ } )
3519+
3520+ it ( 'should validate swid qualifier requirements' , ( ) => {
3521+ // Test missing tag_id qualifier
3522+ expect (
3523+ ( ) =>
3524+ new PackageURL (
3525+ 'swid' ,
3526+ 'Acme' ,
3527+ 'example.com/Enterprise+Server' ,
3528+ '1.0.0' ,
3529+ { } ,
3530+ null ,
3531+ ) ,
3532+ ) . toThrow ( 'swid requires a "tag_id" qualifier' )
3533+
3534+ // Test empty tag_id (whitespace gets normalized away, so this tests missing tag_id)
3535+ expect (
3536+ ( ) =>
3537+ new PackageURL (
3538+ 'swid' ,
3539+ 'Acme' ,
3540+ 'example.com/Enterprise+Server' ,
3541+ '1.0.0' ,
3542+ { tag_id : ' ' } ,
3543+ null ,
3544+ ) ,
3545+ ) . toThrow ( 'swid requires a "tag_id" qualifier' )
3546+
3547+ // Test uppercase GUID tag_id
3548+ expect (
3549+ ( ) =>
3550+ new PackageURL (
3551+ 'swid' ,
3552+ 'Acme' ,
3553+ 'example.com/Enterprise+Server' ,
3554+ '1.0.0' ,
3555+ { tag_id : '75B8C285-FA7B-485B-B199-4745E3004D0D' } ,
3556+ null ,
3557+ ) ,
3558+ ) . toThrow ( 'swid "tag_id" qualifier must be lowercase when it is a GUID' )
3559+
3560+ // Test valid swid with lowercase GUID
3561+ const validPurl = new PackageURL (
3562+ 'swid' ,
3563+ 'Acme' ,
3564+ 'example.com/Enterprise+Server' ,
3565+ '1.0.0' ,
3566+ { tag_id : '75b8c285-fa7b-485b-b199-4745e3004d0d' } ,
3567+ null ,
3568+ )
3569+ expect ( validPurl . toString ( ) ) . toContain (
3570+ 'pkg:swid/Acme/example.com%2FEnterprise%[email protected] ?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d' , 3571+ )
3572+
3573+ // Test valid swid with non-GUID tag_id (mixed case allowed)
3574+ const validPurl2 = new PackageURL (
3575+ 'swid' ,
3576+ 'Acme' ,
3577+ 'example.com/Enterprise+Server' ,
3578+ '1.0.0' ,
3579+ { tag_id : 'CustomTagId123' } ,
3580+ null ,
3581+ )
3582+ expect ( validPurl2 . toString ( ) ) . toContain ( 'tag_id=CustomTagId123' )
3583+
3584+ // Test non-throwing mode
3585+ const result1 = ( PurlType [ 'swid' ] as any ) . validate (
3586+ { name : 'test' , qualifiers : undefined } ,
3587+ false ,
3588+ )
3589+ expect ( result1 ) . toBe ( false )
3590+
3591+ const result2 = ( PurlType [ 'swid' ] as any ) . validate (
3592+ { name : 'test' , qualifiers : { tag_id : ' ' } } ,
3593+ false ,
3594+ )
3595+ expect ( result2 ) . toBe ( false )
3596+
3597+ const result3 = ( PurlType [ 'swid' ] as any ) . validate (
3598+ {
3599+ name : 'test' ,
3600+ qualifiers : { tag_id : '75B8C285-FA7B-485B-B199-4745E3004D0D' } ,
3601+ } ,
3602+ false ,
3603+ )
3604+ expect ( result3 ) . toBe ( false )
3605+ } )
34213606 } )
34223607 } )
34233608} )
0 commit comments