foundation-0.0.14: tests/Test/Foundation/String/Base64.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Test.Foundation.String.Base64
( testBase64Refs
) where
import Control.Monad
import Foundation
import Foundation.Numerical
import Foundation.String
import Foundation.Check
testBase64Refs :: Test
testBase64Refs = Group "String"
[ Group "Base64" testBase64Cases
]
testBase64Cases :: [Test]
testBase64Cases =
[ Group "toBase64"
[ Property "length with padding" $ \l ->
let s = fromList l
b = toBytes UTF8 s
blen = length b
in (length . toBytes UTF8 . toBase64 $ s) === outputLengthBase64 True blen
, Property "valid chars" $ \l ->
let s = fromList l
s64 = toBase64 s
b64 = toBytes UTF8 s64
in all ((||) <$> isPlainBase64Char <*> isPadding) b64 === True
, Property "test string: 'pleasure.'" $ do
let s = fromList "pleasure."
toBase64 s === fromList "cGxlYXN1cmUu"
, Property "test string: 'leasure.'" $ do
let s = fromList "leasure."
toBase64 s === fromList "bGVhc3VyZS4="
, Property "test string: 'easure.'" $ do
let s = fromList "easure."
toBase64 s === fromList "ZWFzdXJlLg=="
, Property "test string: 'asure.'" $ do
let s = fromList "asure."
toBase64 s === fromList "YXN1cmUu"
, Property "test string: 'sure.'" $ do
let s = fromList "sure."
toBase64 s === fromList "c3VyZS4="
]
, Group "toBase64OpenBSD"
[ Property "length without padding" $ \l ->
let s = fromList l
b = toBytes UTF8 s
blen = length b
in (length . toBytes UTF8 . toBase64OpenBSD $ s) === outputLengthBase64 False blen
, Property "valid chars" $ \l ->
let s = fromList l
s64 = toBase64OpenBSD s
b64 = toBytes UTF8 s64
in all isBase64OpenBSDChar b64 === True
]
, Group "toBase64URL"
[ Property "length with padding" $ \l ->
let s = fromList l
b = toBytes UTF8 s
blen = length b
in (length . toBytes UTF8 . toBase64URL True $ s) === outputLengthBase64 True blen,
Property "length without padding" $ \l ->
let s = fromList l
b = toBytes UTF8 s
blen = length b
in (length . toBytes UTF8 . toBase64URL False $ s) === outputLengthBase64 False blen
, Property "valid chars (with padding)" $ \l ->
let s = fromList l
s64 = toBase64URL True s
b64 = toBytes UTF8 s64
in all ((||) <$> isBase64URLChar <*> isPadding) b64 === True
, Property "valid chars (without padding)" $ \l ->
let s = fromList l
s64 = toBase64URL False s
b64 = toBytes UTF8 s64
in all isBase64URLChar b64 === True
, Property "test string: 'pleasure.'" $ do
let s = fromList "pleasure."
toBase64URL False s === fromList "cGxlYXN1cmUu"
, Property "test string: 'leasure.'" $ do
let s = fromList "leasure."
toBase64URL False s === fromList "bGVhc3VyZS4"
, Property "test string: '<empty>'" $ do
let s = fromList ""
toBase64URL False s === fromList ""
, Property "test string: '\\DC4\\251\\156\\ETX\\217~'" $ do
-- the byte list represents "\DC4\251\156\ETX\217~"
let s = fromBytesUnsafe . fromList $ [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]
toBase64URL False s === fromList "FPucA9l-"
, Property "test string: '\\DC4\\251\\156\\ETX\\217\\DEL'" $ do
-- the byte list represents "\DC4\251\156\ETX\217\DEL"
let s = fromBytesUnsafe . fromList $ [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7f]
toBase64URL False s === fromList "FPucA9l_"
]
]
outputLengthBase64 :: Bool -> CountOf Word8 -> CountOf Word8
outputLengthBase64 padding (CountOf inputLenInt) = outputLength
where
outputLength = if padding then CountOf lenWithPadding else CountOf (lenWithPadding - numPadChars)
lenWithPadding :: Int
lenWithPadding = 4 * roundUp (fromIntegral inputLenInt / 3.0 :: Double)
numPadChars :: Int
numPadChars = case inputLenInt `mod` 3 of
1 -> 2
2 -> 1
_ -> 0
isPlainBase64Char :: Word8 -> Bool
isPlainBase64Char w = isAlphaDigit w || isPlus w || isSlash w
isBase64URLChar :: Word8 -> Bool
isBase64URLChar w = isAlphaDigit w || isDash w || isUnderscore w
isBase64OpenBSDChar :: Word8 -> Bool
isBase64OpenBSDChar w = isPeriod w || isSlash w || isAlphaDigit w
isPadding :: Word8 -> Bool
isPadding w = w == 61
isAlphaDigit :: Word8 -> Bool
isAlphaDigit w = isAlpha w || isDigit w
isAlpha :: Word8 -> Bool
isAlpha w = isUpperAlpha w || isLowerAlpha w
isUpperAlpha :: Word8 -> Bool
isUpperAlpha w = w - 65 <= 25
isLowerAlpha :: Word8 -> Bool
isLowerAlpha w = w - 97 <= 25
isDigit :: Word8 -> Bool
isDigit w = w - 48 <= 9
isPlus :: Word8 -> Bool
isPlus w = w == 43
isSlash :: Word8 -> Bool
isSlash w = w == 47
isDash :: Word8 -> Bool
isDash w = w == 45
isUnderscore :: Word8 -> Bool
isUnderscore w = w == 95
isPeriod :: Word8 -> Bool
isPeriod w = w == 46