#!/usr/bin/env bash # Copyright (c) 2015-present, Facebook, Inc. All rights reserved. set -eu setglobal WARNING = ''\033[0;31m'' setglobal SUCCESS = ''\033[0;32m'' setglobal INFO = '''' setglobal DEBUG = '''' setglobal RESET = ''\033[0m'' setglobal VERBOSE = $(VERBOSE:-) setglobal DIR = $[ cd $[ dirname $(BASH_SOURCE[0])] && pwd] setglobal REFMT = ""$DIR/../refmt_impl.native"" if [[ -f REFMT ]] { echo "Cannot find refmt at $REFMT" !1 > !2 exit 1; } setglobal UNIT_TEST_INPUT = "$DIR/unit_tests/input" setglobal UNIT_TEST_OUTPUT = "$DIR/unit_tests/actual_output" setglobal UNIT_TEST_EXPECTED_OUTPUT = "$DIR/unit_tests/expected_output" setglobal TYPE_TEST_INPUT = "$DIR/typeCheckedTests/input" setglobal TYPE_TEST_OUTPUT = "$DIR/typeCheckedTests/actual_output" setglobal TYPE_TEST_EXPECTED_OUTPUT = "$DIR/typeCheckedTests/expected_output" setglobal ERROR_TEST_INPUT = "$DIR/errorTests/input" setglobal ERROR_TEST_OUTPUT = "$DIR/errorTests/actual_output" setglobal ERROR_TEST_EXPECTED_OUTPUT = "$DIR/errorTests/expected_output" setglobal FAILED_TESTS = "$DIR/failed_tests" proc info { printf "$(INFO)$1$(RESET)\n" } proc debug { if test ! -z $VERBOSE { printf "$(DEBUG)$1$(RESET)\n" } } proc success { printf "$(SUCCESS)$1$(RESET)\n" } proc output { printf "$1\n" } proc warning { printf "$(WARNING)$1$(RESET)\n" } proc setup_test_dir { echo "Setting up test dirs actual_output alongside the tests' expected_output" mkdir -p $UNIT_TEST_OUTPUT $TYPE_TEST_OUTPUT $ERROR_TEST_OUTPUT touch $FAILED_TESTS } setup_test_dir set +e proc stdin_test { setglobal INPUT_FILE = $1 setglobal OUTPUT_FILE = $2 setglobal EXPECTED_OUTPUT_FILE = $3 # explicitly pass in heuristics file because idempotent tests read from output directory setglobal HEURISTICS_FILE = $4 setglobal FILENAME = $[basename $INPUT_FILE] setglobal FILEEXT = $(FILENAME##*.) if [[ $FILEEXT = "re" ]] { cat $INPUT_FILE | $REFMT -is-interface-pp false -print-width 50 -parse re -print re -use-stdin true !2 > !1 > $OUTPUT_FILE } elif [[ $FILEEXT = "rei" ]] { cat $INPUT_FILE | $REFMT -is-interface-pp true -print-width 50 -parse re -print re -use-stdin true !2 > !1 > $OUTPUT_FILE } elif [[ $FILEEXT = "ml" ]] { cat $INPUT_FILE | $REFMT -heuristics-file $HEURISTICS_FILE -is-interface-pp false -print-width 50 -parse ml -print re -use-stdin true !2 > !1 > $OUTPUT_FILE } elif [[ $FILEEXT = "mli" ]] { cat $INPUT_FILE | $REFMT -heuristics-file $HEURISTICS_FILE -is-interface-pp true -print-width 50 -parse ml -print re -use-stdin true !2 > !1 > $OUTPUT_FILE } else { warning " ⊘ FAILED -use-stdin \n" info " Cannot determine default implementation parser for extension $(FILEEXT)" return 1 } if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED -use-stdin \n" info " There was an error when testing -use-stdin" info " for input file $INPUT_FILE" info " and output file $OUTPUT_FILE$(RESET)" echo "" return 1 } debug " Comparing -use-stdin results: diff $OUTPUT_FILE $EXPECTED_OUTPUT_FILE" diff --unchanged-line-format="" --new-line-format=":%dn: %L" --old-line-format=":%dn: %L" $OUTPUT_FILE $EXPECTED_OUTPUT_FILE if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED -use-stdin \n" info " $(INFO)$OUTPUT_FILE$(RESET)" info " doesn't match expected output" info " $(INFO)$EXPECTED_OUTPUT_FILE$(RESET)" echo "" return 1 } return 0 } proc unit_test { setglobal FILE = $1 setglobal INPUT = $2 setglobal OUTPUT = $3 setglobal EXPECTED_OUTPUT = $4 setglobal FILENAME = $[basename $FILE] setglobal FILEEXT = $(FILENAME##*.) info "Unit Test: $FILE" if test $[basename $FILE] != $[basename $FILE .ml] || test $[basename $FILE] != $[basename $FILE .mli] { if test $[basename $FILE] != $[basename $FILE .ml] { setglobal REFILE = ""$[basename $FILE .ml].re"" } else { setglobal REFILE = ""$[basename $FILE .mli].rei"" } debug "$REFMT -heuristics-file $INPUT/arity.txt -print-width 50 -print re $INPUT/$FILE 2>&1 > $OUTPUT/$REFILE" $REFMT -heuristics-file $INPUT/arity.txt -print-width 50 -print re $INPUT/$FILE !2 > !1 > $OUTPUT/$REFILE if ! [[ $? -eq 0 ]] { warning " ⊘ TEST FAILED CONVERTING ML TO RE\n" return 1 } setglobal FILE = $REFILE } else { debug " '$REFMT -print-width 50 -print re $INPUT/$FILE 2>&1 > $OUTPUT/$FILE'" $REFMT -print-width 50 -print re $INPUT/$FILE !2 > !1 > $OUTPUT/$FILE } debug " Comparing results: diff $OUTPUT/$FILE $EXPECTED_OUTPUT/$FILE" diff --unchanged-line-format="" --new-line-format=":%dn: %L" --old-line-format=":%dn: %L" $OUTPUT/$FILE $EXPECTED_OUTPUT/$FILE if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED\n" info " $(INFO)$OUTPUT/$FILE$(RESET)" info " doesn't match expected output" info " $(INFO)$EXPECTED_OUTPUT/$FILE$(RESET)" echo "" return 1 } debug "Testing -use-stdin" stdin_test $INPUT/$1 $OUTPUT/$FILE $EXPECTED_OUTPUT/$FILE $INPUT/arity.txt if ! [[ $? -eq 0 ]] { return 1 } else { success " ☑ PASS" echo } } proc idempotent_test { setglobal FILE = $1 setglobal INPUT = $2 setglobal OUTPUT = $3 setglobal FILENAME = $[basename $FILE] setglobal FILEEXT = $(FILENAME##*.) info "Idempotent Test: $FILE" if test $[basename $FILE] != $[basename $FILE .ml] || test $[basename $FILE] != $[basename $FILE .mli] { if test $[basename $FILE] != $[basename $FILE .ml] { setglobal REFILE = ""$[basename $FILE .ml].re"" } else { setglobal REFILE = ""$[basename $FILE .mli].rei"" } debug " Converting $FILE to $REFILE:" debug " Formatting Once: $REFMT -heuristics-file $INPUT/arity.txt -print-width 50 -print re $INPUT/$FILE 2>&1 > $OUTPUT/$REFILE" $REFMT -heuristics-file $INPUT/arity.txt -print-width 50 -print re $INPUT/$FILE !2 > !1 > $OUTPUT/$REFILE if ! [[ $? -eq 0 ]] { warning "⊘ FAILED\n" return 1 } setglobal FILE = $REFILE debug " Generating output again: $REFMT -print-width 50 -print re $OUTPUT/$FILE 2>&1 > $OUTPUT/$FILE.formatted" $REFMT -print-width 50 -print re $OUTPUT/$FILE !2 > !1 > $OUTPUT/$FILE.formatted } else { debug " Formatting Once: '$REFMT -print-width 50 -print re $INPUT/$FILE 2>&1 > $OUTPUT/$FILE'" $REFMT -print-width 50 -print re $INPUT/$FILE !2 > !1 > $OUTPUT/$FILE debug " Generating output again: $REFMT -print-width 50 -print re $OUTPUT/$FILE 2>&1 > $OUTPUT/$FILE.formatted" $REFMT -print-width 50 -print re $OUTPUT/$FILE !2 > !1 > $OUTPUT/$FILE.formatted } diff --unchanged-line-format="" --new-line-format=":%dn: %L" --old-line-format=":%dn: %L" $OUTPUT/$FILE $OUTPUT/$FILE.formatted if ! [[ $? -eq 0 ]] { warning "⊘ FAILED\n" info " $(INFO)$OUTPUT/$FILE.formatted$(RESET)\n" info " is not same as" info " $(INFO)$OUTPUT/$FILE$(RESET)" return 1 } debug "Testing -use-stdin" stdin_test $INPUT/$1 $OUTPUT/$FILE $OUTPUT/$FILE $INPUT/arity.txt if ! [[ $? -eq 0 ]] { return 1 } else { stdin_test $OUTPUT/$FILE $OUTPUT/$FILE.formatted $OUTPUT/$FILE $INPUT/arity.txt if ! [[ $? -eq 0 ]] { return 1 } else { success " ☑ PASS" echo } } } proc typecheck_test { setglobal FILE = $1 setglobal INPUT = $2 setglobal OUTPUT = $3 info "Typecheck Test: $FILE" if test $[basename $FILE] != $[basename $FILE .ml] || test $[basename $FILE] != $[basename $FILE .mli] { if test $[basename $FILE] != $[basename $FILE .ml] { setglobal REFILE = ""$[basename $FILE .ml].re"" } else { setglobal REFILE = ""$[basename $FILE .mli].rei"" } debug " Converting $FILE to $REFILE:" debug "$REFMT -heuristics-file $INPUT/arity.txt -print-width 50 -print re $INPUT/$FILE 2>&1 > $OUTPUT/$REFILE" $REFMT -heuristics-file $INPUT/arity.txt -print-width 50 -print re $INPUT/$FILE !2 > !1 > $OUTPUT/$REFILE if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED\n" return 1 } setglobal FILE = $REFILE } else { debug " Formatting: $REFMT -print-width 50 -print re $INPUT/$FILE 2>&1 > $OUTPUT/$FILE" $REFMT -print-width 50 -print re $INPUT/$FILE !2 > !1 > $OUTPUT/$FILE if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED\n" return 1 } } if test $[basename $FILE] != $[basename $FILE .re] { setglobal COMPILE_FLAGS = '"-intf-suffix .rei -impl'" } else { setglobal COMPILE_FLAGS = '"-intf'" } debug " Compiling: ocamlc -c -pp $REFMT $COMPILE_FLAGS $OUTPUT/$FILE" ocamlc -c -pp $REFMT $COMPILE_FLAGS "$OUTPUT/$FILE" if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED\n" return 1 } success " ☑ PASS" echo } proc error_test { setglobal FILE = $1 setglobal INPUT = $2 setglobal OUTPUT = $3 setglobal EXPECTED_OUTPUT = $4 info "Error Test: $FILE" if test $[basename $FILE] != $[basename $FILE .ml] || test $[basename $FILE] != $[basename $FILE .mli] { warning " ⊘ FAILED: .ml files should not need to be run against error tests. \n" return 1 } else { debug " '$REFMT -print-width 50 -print re $INPUT/$FILE &> $OUTPUT/$FILE'" # ensure errors are not absolute filepaths cd $INPUT $REFMT -print-width 50 -print re $[basename $FILE] &> $OUTPUT/$FILE cd - > /dev/null } debug " Comparing results: diff $OUTPUT/$FILE $EXPECTED_OUTPUT/$FILE" diff --unchanged-line-format="" --new-line-format=":%dn: %L" --old-line-format=":%dn: %L" $OUTPUT/$FILE $EXPECTED_OUTPUT/$FILE if ! [[ $? -eq 0 ]] { warning " ⊘ FAILED\n" info " $(INFO)$OUTPUT/$FILE$(RESET)" info " doesn't match expected output" info " $(INFO)$EXPECTED_OUTPUT/$FILE$(RESET)" echo "" return 1 } success " ☑ PASS" echo } cd $UNIT_TEST_INPUT && find . -type f '(' -name "*.re*" -or -name "*.ml*" ')' | while read file { unit_test $file $UNIT_TEST_INPUT $UNIT_TEST_OUTPUT $UNIT_TEST_EXPECTED_OUTPUT if ! [[ $? -eq 0 ]] { echo "$file -- failed unit_test" >> $FAILED_TESTS } idempotent_test $file $UNIT_TEST_INPUT $UNIT_TEST_OUTPUT $UNIT_TEST_EXPECTED_OUTPUT if ! [[ $? -eq 0 ]] { echo "$file -- failed idempotent_test" >> $FAILED_TESTS } } cd $TYPE_TEST_INPUT && find . -type f '(' -name "*.re*" -or -name "*.ml*" ')' | sort | while read file { typecheck_test $file $TYPE_TEST_INPUT $TYPE_TEST_OUTPUT if ! [[ $? -eq 0 ]] { echo "$file -- failed typecheck_test" >> $FAILED_TESTS } unit_test $file $TYPE_TEST_INPUT $TYPE_TEST_OUTPUT $TYPE_TEST_EXPECTED_OUTPUT if ! [[ $? -eq 0 ]] { echo "$file -- failed unit_test" >> $FAILED_TESTS } idempotent_test $file $TYPE_TEST_INPUT $TYPE_TEST_OUTPUT $TYPE_TEST_EXPECTED_OUTPUT if ! [[ $? -eq 0 ]] { echo "$file -- failed idempotent_test" >> $FAILED_TESTS } } cd $ERROR_TEST_INPUT && find . -type f '(' -name "*.re*" -or -name "*.ml*" ')' | while read file { error_test $file $ERROR_TEST_INPUT $ERROR_TEST_OUTPUT $ERROR_TEST_EXPECTED_OUTPUT if ! [[ $? -eq 0 ]] { echo "$file -- failed error_test" >> $FAILED_TESTS } } if [[ -s $FAILED_TESTS ]] { warning "Failed tests:" cat $FAILED_TESTS exit 1 } exit 0