import { describe, it, expect } from 'vitest'
import { isBase64Safe } from '../src/bidi/utils.js'
function getRandomBytes(length: number): Uint8Array {
const MAX_CHUNK = 65536
const result = new Uint8Array(length)
for (let i = 0; i < length; i += MAX_CHUNK) {
const chunkSize = Math.min(MAX_CHUNK, length - i)
const chunk = crypto.getRandomValues(new Uint8Array(chunkSize))
result.set(chunk, i)
}
return result
}
function bytesToBase64(bytes: Uint8Array): string {
let binary = ''
const CHUNK_SIZE = 8192
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
const chunk = bytes.subarray(i, i + CHUNK_SIZE)
binary += String.fromCharCode.apply(null, chunk as unknown as number[])
}
return btoa(binary)
}
const generateBase64 = (length: number): string => {
const randomBytes = getRandomBytes(length)
return bytesToBase64(randomBytes)
}
const generateInvalidBase64 = (length: number): string => {
let validBase64 = generateBase64(length)
if (validBase64.length === 0) {
validBase64 = 'AA=='
}
const invalidationMethods = [
() => {
const position = Math.floor(Math.random() * validBase64.length)
const invalidChars = '!@#$%^&*()_{}[]|"\'\\:;<>,.?~`'
const invalidChar = invalidChars.charAt(Math.floor(Math.random() * invalidChars.length))
return validBase64.substring(0, position) + invalidChar + validBase64.substring(position + 1)
},
() => {
if (validBase64.endsWith('==')) {
return validBase64.substring(0, validBase64.length - 1)
} else if (validBase64.endsWith('=')) {
return validBase64 + '=='
}
const validLength = validBase64.length % 4
if (validLength === 0) {
return validBase64 + '='
}
return validBase64.substring(0, validBase64.length - 1) + '='
},
() => {
const position = Math.floor(Math.random() * (validBase64.length - 1)) + 1
return validBase64.substring(0, position) + '=' + validBase64.substring(position)
},
() => {
if (validBase64.length % 4 === 0) {
return validBase64.substring(0, validBase64.length - 1)
}
return validBase64.substring(0, validBase64.length - (validBase64.length % 4) - 1)
},
() => {
return '?' + validBase64
}
]
const method = invalidationMethods[Math.floor(Math.random() * invalidationMethods.length)]
const result = method()
return result
}
describe('bidi utils', () => {
describe('isBase64Safe', () => {
it('should return false for non-string inputs', () => {
expect(isBase64Safe(null as any)).toBe(false)
expect(isBase64Safe(undefined as any)).toBe(false)
expect(isBase64Safe(123 as any)).toBe(false)
expect(isBase64Safe({} as any)).toBe(false)
expect(isBase64Safe([] as any)).toBe(false)
})
it('should return true for valid base64 strings', () => {
expect(isBase64Safe('SGVsbG8gV29ybGQ=')).toBe(true)
expect(isBase64Safe('dGVzdA==')).toBe(true)
expect(isBase64Safe('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODk=')).toBe(true)
expect(isBase64Safe('')).toBe(true)
})
it('should return false for invalid base64 strings', () => {
expect(isBase64Safe('SGVsbG8gV29ybGQ')).toBe(false)
expect(isBase64Safe('SGVsbG8gV29ybGQ===')).toBe(false)
expect(isBase64Safe('SGVsbG8_V29ybGQ=')).toBe(false)
expect(isBase64Safe('Hello World')).toBe(false)
expect(isBase64Safe('*&^%$#@!')).toBe(false)
})
it('should handle large strings efficiently', () => {
const superLargeValidBase64 = 'A'.repeat(1000000)
expect(isBase64Safe(superLargeValidBase64)).toBe(true)
const invalidAtStart = '?' + 'A'.repeat(999999)
expect(isBase64Safe(invalidAtStart)).toBe(false)
const invalidAtEnd = 'A'.repeat(999999) + '?'
expect(isBase64Safe(invalidAtEnd)).toBe(false)
const invalidAtMiddle = 'A'.repeat(500000) + '?' + 'A'.repeat(499999)
expect(isBase64Safe(invalidAtMiddle)).toBe(false)
const invalidAtChunkBoundary = 'A'.repeat(99999) + '?' + 'A'.repeat(900000)
expect(isBase64Safe(invalidAtChunkBoundary)).toBe(false)
const invalidAtMultipleChunkBoundaries =
'A'.repeat(99999) + '?' +
'A'.repeat(99999) + '?' +
'A'.repeat(800000)
expect(isBase64Safe(invalidAtMultipleChunkBoundaries)).toBe(false)
})
it('should handle exactly 4,053,844 character strings', () => {
const exactSizeValidString = 'A'.repeat(4053844)
expect(isBase64Safe(exactSizeValidString)).toBe(true)
const invalidAtStartExact = '?' + 'A'.repeat(4053843)
expect(isBase64Safe(invalidAtStartExact)).toBe(false)
const invalidAtMiddleExact = 'A'.repeat(2026922) + '?' + 'A'.repeat(2026921)
expect(isBase64Safe(invalidAtMiddleExact)).toBe(false)
const invalidAtEndExact = 'A'.repeat(4053843) + '?'
expect(isBase64Safe(invalidAtEndExact)).toBe(false)
expect(isBase64Safe(exactSizeValidString)).toBe(true)
expect(isBase64Safe(exactSizeValidString)).toBe(true)
expect(isBase64Safe(invalidAtMiddleExact)).toBe(false)
})
it('should validate random valid base64 strings of various lengths', {
timeout: 300_000
}, () => {
for (let i = 0; i < 10000; i++) {
const length = Math.floor(Math.pow(Math.random(), 2) * 1000000)
const validString = generateBase64(length)
const result = isBase64Safe(validString)
if (!result) {
console.error(`Valid string failed validation: Length=${validString.length}`)
console.error(`String: ${validString}`)
console.error(`Padding count: ${(validString.match(/=/g) || []).length}`)
}
expect(result).toBe(true)
}
})
it('should identify random invalid base64 strings of various lengths', {
timeout: 300_000
}, () => {
for (let i = 0; i < 10000; i++) {
const length = Math.max(1, Math.floor(Math.pow(Math.random(), 2) * 1000000))
const invalidString = generateInvalidBase64(length)
const result = isBase64Safe(invalidString)
if (result) {
console.error(`Invalid string incorrectly passed validation: Length=${invalidString.length}`)
console.error(`String: ${invalidString}`)
console.error(`Padding count: ${(invalidString.match(/=/g) || []).length}`)
}
expect(result).toBe(false)
}
})
})
})