packages feed

base32-1.0: test/typecheck.sh

#!/bin/sh
# Run inside the package environment: cabal exec -- sh test/typecheck.sh
set -eu

compiler=${GHC:-ghc}
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT HUP INT TERM

compile() {
    "$compiler" -v0 -fno-code -fforce-recomp -package base32 \
        -odir "$work" -hidir "$work" "$work/Api.hs" > "$work/result" 2>&1
}

reject() {
    cat "$work/header" > "$work/Api.hs"
    printf '%s\n' "$1" >> "$work/Api.hs"
    if compile; then
        printf 'Unexpectedly accepted in %s: %s\n' "$api" "$1" >&2
        exit 1
    fi
    if ! grep -F "$2" "$work/result" > /dev/null; then
        cat "$work/result" >&2
        exit 1
    fi
}

while read -r api representation value suffix; do
    [ "$suffix" != - ] || suffix=
    padded="encodeBase32$suffix"
    unpadded="encodeBase32Unpadded$suffix"
    cat > "$work/header" <<EOF
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Api where
import Data.Base32.Types
import Data.Coerce (coerce)
import qualified $representation as R
import qualified Data.Text as Error
import qualified $api as S
import qualified $api.Hex as H
type Value = R.$value
EOF
    cat "$work/header" > "$work/Api.hs"
    cat >> "$work/Api.hs" <<EOF
standard :: StdAlphabet k => Base32 k Value -> Value
standard = S.decodeBase32
hexadecimal :: HexAlphabet k => Base32 k Value -> Value
hexadecimal = H.decodeBase32
roundtrips :: Value -> [Value]
roundtrips value =
  [ standard (S.$padded value), standard (S.$unpadded value)
  , S.decodeBase32Padded (S.$padded value)
  , S.decodeBase32Unpadded (S.$unpadded value)
  , hexadecimal (H.$padded value), hexadecimal (H.$unpadded value)
  , H.decodeBase32Padded (H.$padded value)
  , H.decodeBase32Unpadded (H.$unpadded value)
  ]
stdPadded :: Value -> Either Error.Text (Base32 'StdPadded Value)
stdPadded = S.parseBase32Padded
stdUnpadded :: Value -> Either Error.Text (Base32 'StdUnpadded Value)
stdUnpadded = S.parseBase32Unpadded
hexPadded :: Value -> Either Error.Text (Base32 'HexPadded Value)
hexPadded = H.parseBase32Padded
hexUnpadded :: Value -> Either Error.Text (Base32 'HexUnpadded Value)
hexUnpadded = H.parseBase32Unpadded
EOF
    if ! compile; then
        cat "$work/result" >&2
        exit 1
    fi
    for encoder in "$padded" "$unpadded"; do
        reject "bad = S.decodeBase32 . H.$encoder" 'standard alphabet'
        reject "bad = H.decodeBase32 . S.$encoder" 'extended-hex alphabet'
    done
    for alphabet in S H; do
        reject "bad = $alphabet.decodeBase32Padded . $alphabet.$unpadded" \
            "Couldn't match type"
        reject "bad = $alphabet.decodeBase32Unpadded . $alphabet.$padded" \
            "Couldn't match type"
        reject "bad = fmap $alphabet.decodeBase32Padded . $alphabet.parseBase32Unpadded" \
            "Couldn't match type"
        reject "bad = fmap $alphabet.decodeBase32Unpadded . $alphabet.parseBase32Padded" \
            "Couldn't match type"
    done
    reject "bad :: Base32 'StdPadded Value -> Base32 'StdUnpadded Value
bad = coerce" "Couldn't match type"
    reject "bad :: Base32 'StdPadded Value -> Base32 'HexPadded Value
bad = coerce" "Couldn't match type"
    printf 'Type checks passed: %s\n' "$api"
done <<'EOF'
Data.ByteString.Base32 Data.ByteString ByteString '
Data.ByteString.Lazy.Base32 Data.ByteString.Lazy ByteString '
Data.ByteString.Short.Base32 Data.ByteString.Short ShortByteString '
Data.Text.Encoding.Base32 Data.Text Text -
Data.Text.Lazy.Encoding.Base32 Data.Text.Lazy Text -
Data.Text.Short.Encoding.Base32 Data.Text.Short ShortText -
EOF