#!/usr/bin/env bash # Copyright (c) 2015-present, Facebook, Inc. All rights reserved. set -eu setvar WARNING = ''\033[0;31m'' setvar SUCCESS = ''\033[0;32m'' setvar INFO = '''' setvar DEBUG = '''' setvar RESET = ''\033[0m'' setvar VERBOSE = ${VERBOSE:-} setvar DIR = "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" setvar REFMT = ""$DIR/../refmt_impl.native"" if [[ -f REFMT ]] { echo "Cannot find refmt at $REFMT" 1>&2 exit 1; } setvar UNIT_TEST_INPUT = "$DIR/unit_tests/input" setvar UNIT_TEST_OUTPUT = "$DIR/unit_tests/actual_output" setvar UNIT_TEST_EXPECTED_OUTPUT = "$DIR/unit_tests/expected_output" setvar TYPE_TEST_INPUT = "$DIR/typeCheckedTests/input" setvar TYPE_TEST_OUTPUT = "$DIR/typeCheckedTests/actual_output" setvar TYPE_TEST_EXPECTED_OUTPUT = "$DIR/typeCheckedTests/expected_output" setvar ERROR_TEST_INPUT = "$DIR/errorTests/input" setvar ERROR_TEST_OUTPUT = "$DIR/errorTests/actual_output" setvar ERROR_TEST_EXPECTED_OUTPUT = "$DIR/errorTests/expected_output" setvar 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 { setvar INPUT_FILE = "$1" setvar OUTPUT_FILE = "$2" setvar EXPECTED_OUTPUT_FILE = "$3" # explicitly pass in heuristics file because idempotent tests read from output directory setvar HEURISTICS_FILE = "$4" setvar FILENAME = $(basename $INPUT_FILE) setvar 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 { setvar FILE = "$1" setvar INPUT = "$2" setvar OUTPUT = "$3" setvar EXPECTED_OUTPUT = "$4" setvar FILENAME = $(basename $FILE) setvar 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) { setvar REFILE = ""$(basename $FILE .ml).re"" } else { setvar 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 } setvar 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 { setvar FILE = "$1" setvar INPUT = "$2" setvar OUTPUT = "$3" setvar FILENAME = $(basename $FILE) setvar 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) { setvar REFILE = ""$(basename $FILE .ml).re"" } else { setvar 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 } setvar 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 { setvar FILE = "$1" setvar INPUT = "$2" setvar 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) { setvar REFILE = ""$(basename $FILE .ml).re"" } else { setvar 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 } setvar 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) { setvar COMPILE_FLAGS = ""-intf-suffix .rei -impl"" } else { setvar 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 { setvar FILE = "$1" setvar INPUT = "$2" setvar OUTPUT = "$3" setvar 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