@isTest private class PkceUtilTest { @isTest static void verifier_isBase64Url_andLongEnough() { String verifier = PkceUtil.generateCodeVerifier(); System.assertNotEquals(null, verifier); System.assert(verifier.length() >= 43, 'verifier length below RFC 7636 minimum'); System.assert(!verifier.contains('+'), 'verifier must not contain +'); System.assert(!verifier.contains('/'), 'verifier must not contain /'); System.assert(!verifier.contains('='), 'verifier must not contain ='); } @isTest static void challenge_isStableForVerifier() { String verifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; String c1 = PkceUtil.generateCodeChallenge(verifier); String c2 = PkceUtil.generateCodeChallenge(verifier); System.assertEquals(c1, c2, 'challenge must be deterministic for the same verifier'); System.assertEquals('E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM', c1, 'should match RFC 7636 worked example'); } @isTest static void embedAndExtract_roundTrip() { String original = 'https://example.com|login|Theme4d'; String verifier = PkceUtil.generateCodeVerifier(); String state = PkceUtil.embedVerifierInState(original, verifier); System.assertEquals(verifier, PkceUtil.extractVerifier(state)); System.assertEquals(original, PkceUtil.extractOriginalState(state)); } @isTest static void extract_handlesMissingDelimiter() { System.assertEquals('', PkceUtil.extractVerifier('legacyStateNoPkce')); System.assertEquals('legacyStateNoPkce', PkceUtil.extractOriginalState('legacyStateNoPkce')); } @isTest static void issuePkceForState_returnsBothFields() { Map result = PkceUtil.issuePkceForState('orig'); System.assertNotEquals(null, result.get('codeChallenge')); System.assertNotEquals(null, result.get('state')); System.assert(result.get('state').startsWith('orig')); } }