pebblisp/src/tests.sh

280 lines
9.0 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
VALCOM="valgrind -q --leak-check=full --error-exitcode=1 --track-origins=yes"
TOTAL_PASSES=0
TOTAL_FAILS=0
TOTAL_VALGRIND_ERRORS=0
FAILS=0
FAIL_OUTPUT=""
VALGRIND=false
DISABLED=false
if [ "$1" == "-val" ]; then
VALGRIND=true
filter="$2"
else
filter="$1"
fi
FIRST_TITLE=true
title() {
if ! $FIRST_TITLE; then
echo ""
if (($FAILS != 0)); then
echo -e "$FAIL_OUTPUT"
FAIL_OUTPUT=""
fi
FAILS=0
DISABLED=false
else
FIRST_TITLE=false
fi
echo -n "[$1] "
if [[ "$2" == "disabled" ]]; then
echo -n "DISABLED"
DISABLED=true
fi
}
pass() {
local color=32
if [[ "$2" != "0" ]]; then
((TOTAL_VALGRIND_ERRORS++))
color=33
fi
echo -n "[1;${color}m✓"
((TOTAL_PASSES++))
}
fail() {
echo -n "X"
FAIL_OUTPUT="$FAIL_OUTPUT $1 FAILED\n When running \"$2\""
((FAILS++))
((TOTAL_FAILS++))
}
regex="regex"
check() {
if $DISABLED || ! [[ "$1" =~ $filter ]]; then
return 1
fi
local output
local exit_code=0
if $VALGRIND; then
echo -ne "\n $1"
output="$($VALCOM ./pl --ignore-config "(loadfile \"examples/lib.pbl\") $2")"
exit_code=$?
if [[ "$exit_code" == "0" ]]; then
echo -ne "\r "
fi
else
output="$(./pl --ignore-config "(loadfile \"examples/lib.pbl\") $2")"
fi
if [ "$3" == "$regex" ]; then
if [[ "$output" =~ ^$4$ ]]; then
pass "$1" $exit_code
return
fi
elif [ "$output" == "$3" ]; then
pass "$1" $exit_code
return
fi
fail "$1" "$2"
FAIL_OUTPUT="${FAIL_OUTPUT}\n  expected '$3' but received '$output'\n"
}
echo "::SHELL TESTS::"
title "Plain returns"
check "PlainRet" "10" "10"
check "StrRetrn" '"hey"' "hey"
check "HexReturn" "0x0f0f0" "61680"
check "BinaryReturn" "0b011010011010011" "13523"
title "Arithmetic"
check "Addition" "(+ 1093 102852)" "103945"
check "Multiply" "(*1000 10000)" "10000000"
check "Division" "(/ 6418425 65)" "98745"
check "ChainAdd" "(+ 3917 17304 1293844 400 100000)" "1415465"
check "ChainMul" "(* 8263 23 123)" "23376027"
check "ChainDiv" "(/ 1493856 741 96 7)" "3"
title "Comparison"
check "GratrThn" "(> 23847123 19375933)" "T"
check "GratrThnMulti" "(> 9999 55 1 0)" "T"
check "LessThan" "(< 23847123 19375933)" "F"
check "Equality" "(= 987654321 987654321 )" "T"
check "StringEquality" '(= "Bean" "Bean" )' "T"
check "StringInequality" '(= "Beans" "Bean" )' "F"
check "NullInequality" '(= "Beans" "" )' "F"
title "ComplexStrings"
check "TripleQuoting" '"""Hello"""' 'Hello'
check "TripleQuotingWithQuotes" '"""My name is "yoink"."""' 'My name is "yoink".'
title "TypeCheck"
check "IsNum" "(isnum 23847123)" "T"
check "IsntNum" '(isnum "WORDS")' "F"
check "IsString" '(isstr "words")' "T"
check "IsStringEmpty" '(isstr "")' "T"
check "NumNotString" "(isstr 5)" "F"
check "ListNotString" '(isstr ("hello"))' "F"
title "Ifs/Bools"
check "IfReturn" "(if (T) 123456789 987654321)" "123456789"
check "IfRetTwo" "(if F 123456789 987654321)" "987654321"
check "EmptyCnd" "(if () T F)" "F"
check "EtyLstLt" "(if (()) T F)" "T"
title "Lists"
check "RegLists" "(1 2 3 4 5)" "( 1 2 3 4 5 )"
check "MultiTypeList" '(10 20 "rascals")' "( 10 20 rascals )"
check "EmptyLst" "()" "( )"
check "EmptLst2" "( )" "( )"
check "ListIndex" "(at (+ 1 1) (1 2 1000 4 5))" "1000"
check "EvalElems" "((* 10 10) 7)" "( 100 7 )"
check "AppendToList" "(ap (1 20 300 4000 50000) 600000)" "( 1 20 300 4000 50000 600000 )"
check "AppndToEnvList" "(def l (50000 4000 300 20)) (def l (ap l 1)) l" "( 50000 4000 300 20 1 )"
check "PrependToList" "(pre (1 20 300 4000 50000) 600000)" "( 600000 1 20 300 4000 50000 )"
check "PrepndToEnvList" "(def l (50000 4000 300 20)) (def l (pre l 1)) l" "( 1 50000 4000 300 20 )"
check "Rest(Tail)OfList" "(def l (50000 4000 300 20)) (rest l)" "( 4000 300 20 )"
check "ListLength" "(def l (1 20 3 \"abc\" \"banana\" (+ 10 5))) (len l)" "6"
check "Identifying list" "(islist (1 2 3))" "T"
check "Identifying empty list" "(islist ())" "T"
check "Identifying not a list" "(islist 1)" "F"
deep_nesting="10"
for _ in {0..25}; do deep_nesting="( $deep_nesting )"; done
check "DeepNesting" "$deep_nesting" "$deep_nesting" # Above 25 it starts to stack-smash
title "Spacing"
check "DenseSpc" "(+1093 102852)" "103945"
check "WideSpac" "( + 1093 102852 )" "103945"
check "VWidwSpc" " ( + 1093 102852 ) " "103945"
title "DemoFunctions"
check "Squaring" "(sq 9876)" "97535376"
check "Cubing" "(cube 81)" "531441"
check "Exponent" "(exp 9 9)" "387420489"
check "MaxRight" "(max 5 20)" "20"
check "MaxLeft" "(max 135890 98372)" "135890"
check "MinRight" "(min 8429 192449)" "8429"
check "MinLeft" "(min 17294722 17294721)" "17294721"
title "Lambdas"
check "MultStmt" "(def yee (fn (a) (* 10 a))) ; (yee 5)" "50"
check "MultStmtNoSemi" "(def yee (fn (a) (* 10 a)))(yee 5)" "50"
check "DefinMap" "(def yee (fn (a) (* 10 a))) ; (map yee (5 10 2 (+ 12 0)))" "( 50 100 20 120 )"
check "AnonymousLambda" "\
(map (fn (a) (* a a)) (5 6 7))" "( 25 36 49 )"
check "FbnciSeq" "\
(def fib (fn (a) \
(if (< a 2) \
a \
(+ (fib (- a 1)) (fib (- a 2))) \
)));\
(fib 11)" "89"
check "Factorial" "\
(def fac (fn (a) \
(if (= a 1) \
1 \
(* a (fac (- a 1)) ) \
)));\
(fac 11)" "39916800"
check "LambdaClone" "(def y (fn (a) (* 10 a))) (def b y) (def y 12345) ((b 5) y)" "( 50 12345 )"
check "Duplicate" "(def dupe (fn (a) (() (a a a))));(dupe (*10 10))" "( 100 100 100 )"
title "Cat"
check "ExplicitCat" '(cat "Big" " Kitty")' "Big Kitty"
check "CatNums" '(cat "There are " (+ 2 3) " kitties")' "There are 5 kitties"
title "Filtering"
check "Filtering" "(fil (fn (a) (< 321 a)) (30 300 90 1200 135 801))" "( 1200 801 )"
check "FilterEval" "(fil (fn (a) (= 1000 a)) ((+ 450 550) (* 20 50) (/ 30 3) (- 10000 100)))" "( 1000 1000 )"
check "MapFilter" "(fil (fn (a) (< 50 a)) (map sq (1 2 3 4 5 6 7 8 9 10 11 12)))" "( 64 81 100 121 144 )"
title "Structs"
check "StructDef" "(struct Post (title body))" "T"
check "Building a struct"\
'(struct Post (title body)) (Post "A title" "The Body")'\
'{ title: "A title", body: "The Body" }'
check "Accessing struct fields"\
"(struct Post (title body)) (def p (Post \"TITLE\" \"BODY\")) (p.title p.body)"\
"( TITLE BODY )"
title "HigherOrder"
check "Simple reducing" '(reduce (1 2 3) + 0)' '6'
check "NonListReducing" '(reduce 1 + 0)' '1'
check "StringReducing" '(reduce (" my" " friend") cat "Hello,")' 'Hello, my friend'
check "FuncReturningAFunc" "(def plusser (fn (outer) (fn (inner) (+ outer inner))))\
(def plusFive (plusser 5))\
(plusFive 10)" "15"
title "ShouldError"
check "LenOfNotList" "(len 5)" regex "BAD_PARAMS.*"
check "NoMapList" "(map sq)" "NULL_MAP_ARGS"
check "BadNumber" "(5df)" regex "BAD_NUMBER.*"
check "BadHex" "(0x0zf)" regex "BAD_NUMBER.*"
check "BadBinary" "(0b01120)" regex "BAD_NUMBER.*"
check "UnsupportedNumber" "(00000)" regex "UNSUPPORTED_NUMBER.*"
check "BadParens1" "(hey()" regex "MISMATCHED_PARENS.*"
check "BadParens2" "(hey)(" regex "MISMATCHED_PARENS.*"
check "BadParens3" "((hey(" regex "MISMATCHED_PARENS.*"
check "BadParens4" ")))hey" regex "MISMATCHED_PARENS.*"
check "BadParens5" "hey))(" regex "MISMATCHED_PARENS.*"
check "BadParens6" '(ey")"' regex "MISMATCHED_PARENS.*"
title "ListArithmetic" disabled
check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE"
check "ListAddi" "(+ 5 (1 2 3 (+ 10 10)))" "( 6 7 8 25 )"
check "ListModu" "(% 5 (1 2 3 (* 11 11)))" "( 1 2 3 1 )"
check "ListsMul" "(* (10 20 30) (1 20 300))" "( 10 400 9000 )"
title "Eval"
check "BasicNumberEval" '(eval "5")' "5"
check "BasicOpEval" '(eval "(+ 5 10)")' "15"
check "MapFilter" '(eval "(fil (fn (a) (< 50 a)) (map sq (1 2 3 4 5 6 7 8 9 10 11 12)))")' "( 64 81 100 121 144 )"
title "Forbble" disabled
check "BasicForbbleOp" '(loadfile "examples/forbble.pbl") (feval (10 10 * .)) ""' "100"
check "FibForbble" '(loadfile "examples/forbble.pbl") (feval (1 1 _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f _f .)) ""' "28657"
check "ForbbleDefine" '(loadfile "examples/forbble.pbl") (feval ( : "cubed" dup dup * * $ )) (feval (4 cubed .)) ""' "64"
title "Environment"
check "EnvStressTestEarly" '(def a 1)(def b 20)(def c "yee")(def d "yeehunnid")(def e 3) (a)' "( 1 )"
check "EnvStressTestLate" "(def a 1)(def b 2)(def c 3)(def d 4)(def e 5)(def g 6)(def n 40) n" "40"
hard_test_string="(def n 1000)"
for c in {0..50}; do hard_test_string="(def a$c 1)$hard_test_string"; done
check "HardEnvStressTest" "$hard_test_string n" "1000"
echo ""
echo ""
if [ "$TOTAL_PASSES" -ne "0" ]; then
echo -n ""
fi
echo -n "$TOTAL_PASSES Tests Passed"
if [ "$TOTAL_VALGRIND_ERRORS" -ne "0" ]; then
echo -n " ($TOTAL_VALGRIND_ERRORS with valgrind errors)"
fi
echo
if [ "$TOTAL_FAILS" -ne "0" ]; then
echo -n ""
fi
echo "$TOTAL_FAILS Tests Failed"
echo ""
if $VALGRIND; then
$VALCOM ./pl --run-tests=detailed
else
./pl --run-tests
fi