🏡 index : quine-global/webdriverio.git

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 {
    // Avoid stack overflows by processing in chunks
    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)
}

// Helper functions for the tests
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=='
    }

    // Choose a method to make it invalid (randomly)
    const invalidationMethods = [
        // Add invalid characters
        () => {
            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)
        },
        // Incorrect padding by adding extra padding or removing required padding
        () => {
            if (validBase64.endsWith('==')) {
                // Remove one = to make it invalid
                return validBase64.substring(0, validBase64.length - 1)
            } else if (validBase64.endsWith('=')) {
                // Add two more = to make it invalid (three = is never valid)
                return validBase64 + '=='
            }
            // For strings without padding, add a single = which will be invalid
            // if the length isn't right for padding
            const validLength = validBase64.length % 4
            if (validLength === 0) {
                // For strings with length multiple of 4, adding a single = is invalid
                return validBase64 + '='
            }
            // Remove a character to disrupt the length then add =
            return validBase64.substring(0, validBase64.length - 1) + '='

        },
        // Insert padding character in the middle (always invalid)
        () => {
            const position = Math.floor(Math.random() * (validBase64.length - 1)) + 1
            return validBase64.substring(0, position) + '=' + validBase64.substring(position)
        },
        // Disrupt the length to make it invalid (base64 length must be multiple of 4)
        () => {
            if (validBase64.length % 4 === 0) {
                // Remove 1 character to make length not a multiple of 4
                return validBase64.substring(0, validBase64.length - 1)
            }
            // Remove extra to ensure the length is invalid
            return validBase64.substring(0, validBase64.length - (validBase64.length % 4) - 1)

        },
        // Guaranteed invalid method - always prepend an invalid character
        () => {
            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) // Empty string is valid base64
        })

        it('should return false for invalid base64 strings', () => {
            expect(isBase64Safe('SGVsbG8gV29ybGQ')).toBe(false) // Missing padding
            expect(isBase64Safe('SGVsbG8gV29ybGQ===')).toBe(false) // Too much padding
            expect(isBase64Safe('SGVsbG8_V29ybGQ=')).toBe(false) // Invalid character
            expect(isBase64Safe('Hello World')).toBe(false) // Not base64
            expect(isBase64Safe('*&^%$#@!')).toBe(false) // Special characters
        })

        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)
        })

        // The case that produced the error
        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 // this can be a potential long test
        }, () => {
            // Test valid strings
            for (let i = 0; i < 10000; i++) {
                // Generate random length between 0 and 1000000
                const length = Math.floor(Math.pow(Math.random(), 2) * 1000000)
                const validString = generateBase64(length)

                const result = isBase64Safe(validString)
                if (!result) {
                    // If validation fails, log the string details
                    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 // this can be a potential long test
        }, () => {
            // Test invalid strings
            for (let i = 0; i < 10000; i++) {
                // Generate random length between 1 and 1000000
                const length = Math.max(1, Math.floor(Math.pow(Math.random(), 2) * 1000000))
                const invalidString = generateInvalidBase64(length)

                const result = isBase64Safe(invalidString)
                if (result) {
                    // If validation unexpectedly passes, log the string details
                    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)
            }
        })
    })
})