#!/bin/sh

# hfst tools needed
XFST_TOOL="../hfst-xfst -s --pipe-mode=input"
STRINGS2FST="../../hfst-strings2fst -S"
TXT2FST="../../hfst-txt2fst"
COMPARE="../../hfst-compare --quiet"
HFST_FORMAT="../../hfst-format" # optional

# other tools needed
DIFF="diff --ignore-blank-lines"
REMOVE="rm -f"
GREP="grep"
CAT="cat"
LS="ls"
TEST="test"
TR="tr"
# ECHO="echo" # present on all platforms?

EXTRA_FILES="tmp startup tmpdiff test" # files generated by tests

# edit this is hfst-format is not available
for format in sfst openfst-tropical foma;
do
    # comment this if hfst-format is not available
    if ! (${HFST_FORMAT} --list-formats | ${GREP} $format > /dev/null); then
    continue;
    fi

    echo ""
    echo "Performing hfst-xfst tests for "$format" format..."
    echo ""

    ## Create a transducer [Foo Bar Baz] where Foo is [foo], Bar [bar] and Baz [Baz].
    ## Definition of Foo is given in startup file, and definitions of Bar and Baz
    ## on command line. Baz is later undefined in input.
    echo "define Foo foo" > startup
    if ! ((echo "undefine Baz" && echo "regex Foo Bar Baz;" && echo "save stack tmp") | \
    ${XFST_TOOL} -f $format -l startup \
    -e "define Bar bar;" -e "define Baz baz;" > /dev/null 2> /dev/null)
    then
    ${REMOVE} ${EXTRA_FILES}
        echo "fail #1";
    exit 1
    fi

    # Test that the result is as intended.
    if ! (echo "foo bar Baz" | ${STRINGS2FST} -f $format | ${COMPARE} tmp);
    then
    ${REMOVE} ${EXTRA_FILES}
        echo "fail #2";
    exit 1
    fi

    # Create a transducer with literal words "define" and "regex".
    for word in define regex
    do
    if ! ((echo "regex "$word";" && echo "save stack tmp") | ${XFST_TOOL} -f $format > /dev/null 2> /dev/null)
    then
        ${REMOVE} ${EXTRA_FILES}
            echo "fail #3";
        exit 1
    fi
        # Test that the result is as intended.
    if ! (echo $word | ${STRINGS2FST} -f $format | ${COMPARE} tmp);
    then
        ${REMOVE} ${EXTRA_FILES}
            echo "fail #4";
        exit 1
    fi
    done

    ## Test that using special symbols in replace rules yields an error message
    if ! (echo 'regex a -> "@_foo_@";' | ../hfst-xfst --pipe-mode=input -f $format > /dev/null 2> tmp && ${GREP} "warning:" tmp > /dev/null); then
        echo "fail #5";
    exit 1;
    fi
    # silent mode
    if (echo 'regex a -> "@_foo_@";' | ../hfst-xfst --pipe-mode=input -s -f $format > /dev/null 2> tmp && ${GREP} "warning:" tmp > /dev/null); then
        echo "fail #6";
    exit 1;
    fi

    ## Test that using incompatible replace types in parallel rules yields an error message
    if (!(echo 'regex a -> b ,, c (->) d ;' | ../hfst-xfst --pipe-mode=input -f $format > /dev/null 2> tmp) && ${GREP} "failed" tmp > /dev/null); then
        echo "fail #6.5";
        exit 1;
    fi

    ## Test that the transducer info is correct
    if ! (echo 'regex [a|b|c|d|e] ([d|e|f|g]);' | ../hfst-xfst --pipe-mode=input -f $format > tmp 2> /dev/null); then
        echo "fail #7";
        exit 1;
    fi
    if (! ${GREP} "3 states" tmp > /dev/null); then
        exit 1;
    fi
    if (! ${GREP} "9 arcs" tmp > /dev/null); then
        exit 1;
    fi

    ## Test that the result of testfile.xfst (written in att format to standard output)
    ## is the same as testfile.att using att-to-fst conversion.
    for testfile in compose_net concatenate_net union_net ignore_net invert_net minus_net intersect_net \
    determinize_net epsilon_remove_net invert_net minimize_net \
    one_plus_net reverse_net upper_side_net zero_plus_net lower_side_net negate_net_1 negate_net_2 \
    define define_function prolog \
        substitute_symbol_1 substitute_symbol_2 substitute_symbol_3 \
        substitute_symbol_4 substitute_symbol_5 \
        substitute_label_1 substitute_label_2 substitute_label_3 substitute_label_4 \
        substitute_label_5 substitute_label_6 substitute_label_7 substitute_label_8 \
        substitute_defined_1 substitute_defined_2 substitute_defined_3 \
        substitute_defined_4 substitute_defined_5 substitute_defined_6 \
        at_re_1 at_re_2 at_re_3 at_txt at_stxt at_txt_and_stxt at_pl \
        quoted_literals replace_identity one_transition_regex merge \
        replace_test_flags_1 \
        replace_markup_1 replace_markup_2 replace_markup_3 replace_markup_4 replace_markup_5 \
        replace_markup_6 replace_markup_7 \
        priority_union_1 priority_union_2 priority_union_3 priority_union_4 \

        # replace_test_flags_2
        # substitute_symbol_6 fails on sfst,  substitute_symbol_7 substitute_symbol_8 should be added
        # angle_brackets omitted, since xfst and foma handle them differently
    do
    ${REMOVE} result result1 result2
    if ! (${LS} $testfile.xfst > /dev/null 2> /dev/null); then
        echo "skipping missing test for "$testfile"..."
        continue
    fi
    if ! (${CAT} $testfile.xfst | ../hfst-xfst --pipe-mode=input -q -f $format > result 2> /dev/null); then
        echo "ERROR: in compiling "$testfile".xfst"
        exit 1;
    fi
    if ! (${CAT} result | ${TXT2FST} > tmp1; ${CAT} $testfile.att | ${TXT2FST} > tmp2; ); then
        echo "ERROR: in compiling "$testfile".att"
        exit 1;
    fi
    if ! (${COMPARE} tmp1 tmp2); then
        echo "ERROR: "$testfile" test failed"
        exit 1;
    fi
    echo "* hfst-xfst subtest "$testfile" passed"
    done

    ## The same as above but only for openfst format
    if [ "$format" = "openfst-tropical" ]; then
        for testfile in merge_weighted
        do
        ${REMOVE} result result1 result2
        if ! (${LS} $testfile.xfst > /dev/null 2> /dev/null); then
            echo "skipping missing test for "$testfile"..."
            continue
        fi
        if ! (${CAT} $testfile.xfst | ../hfst-xfst --pipe-mode=input -q -f $format > result 2> /dev/null); then
            echo "ERROR: in compiling "$testfile".xfst"
            exit 1;
        fi
        if ! (${CAT} result | ${TXT2FST} > tmp1; ${CAT} $testfile.att | ${TXT2FST} > tmp2; ); then
            echo "ERROR: in compiling "$testfile".att"
            exit 1;
        fi
        if ! (${COMPARE} tmp1 tmp2); then
            echo "ERROR: "$testfile" test failed"
            exit 1;
        fi
        echo "* hfst-xfst subtest "$testfile" passed"
        done
    fi


    ## Failing tests
    for testfile in negate_fail
    do
    if ! (ls $testfile.xfst 2> /dev/null); then
        echo "skipping missing test for "$testfile"..."
        continue
    fi
    if (cat $testfile.xfst | ../hfst-xfst -s -f $format 2> tmp > /dev/null); then
        echo "ERROR: "$testfile".xfst should have failed"
        exit 1;
    fi
    if ! (grep "Negation is defined only for automata" tmp > /dev/null); then
        echo "ERROR: in "$testfile".xfst"
        exit 1;
    fi
    done

    ## Test that the result of testfile.xfst (written to standard output)
    ## is the same as testfile.output
    for testfile in print_stack print_labels print_label_tally \
    shortest_string set_variable print_net eliminate_flag empty_context xerox_composition \
    compile_replace_1 compile_replace_2 compile_replace_3 compile_replace_4 flag_with_unknown \
    tokenization_test
    do
    if ! (${LS} $testfile.xfst > /dev/null 2> /dev/null); then
        echo "skipping missing test for "$testfile"..."
        continue
    fi
        # apply up/down leak to stdout with readline..
    if ! (${CAT} $testfile.xfst | ../hfst-xfst --pipe-mode=input -f $format -s 2> /dev/null | ${TR} -d '\r' > tmp); then
        echo "ERROR: in compiling "$testfile.xfst
        exit 1;
    fi
    if ! ($DIFF tmp $testfile.output > tmpdiff); then
            if (${LS} $testfile.alternative_output > /dev/null 2> /dev/null); then
                if ! ($DIFF tmp $testfile.alternative_output); then
                    ${REMOVE} tmpdiff
                    echo "ERROR: in result from "$testfile.xfst
                    exit 1;
                fi
            else
                ${CAT} tmpdiff
                ${REMOVE} tmpdiff
            echo "ERROR: in result from "$testfile.xfst
            exit 1;
            fi
            ${REMOVE} tmpdiff
    fi
    echo "* hfst-xfst subtest "$testfile" passed"
    done

    ## Interactive commands
    for testfile in apply_up apply_down inspect_net
    do
    if ! (${LS} $testfile.xfst > /dev/null 2> /dev/null); then
        echo "skipping missing test for "$testfile"..."
        continue
    fi
        # apply up/down leak to stdout with readline..
        for param in --pipe-mode=input # --no-readline
        do
            # 'inspect net' requires input from stdin
            if (${TEST} "$param" = "--pipe-mode=input" -a "$testfile" = "inspect_net"); then
                continue
            fi
        if ! (${CAT} $testfile.xfst | ../hfst-xfst  $param -f $format -s | ${TR} -d '\r' > tmp); then
        echo "ERROR: in compiling "$testfile.xfst" with parameters "$param
        exit 1;
        fi
        if ! ($DIFF tmp $testfile.output > tmpdiff); then
                if (${LS} $testfile.alternative_output > /dev/null 2> /dev/null); then
                    if ! ($DIFF tmp $testfile.alternative_output); then
                        ${REMOVE} tmpdiff
                        echo "ERROR: in result from "$testfile.xfst
                        exit 1;
                    fi
                else
                    ${CAT} tmpdiff
                    ${REMOVE} tmpdiff
                echo "ERROR: in result from "$testfile.xfst
                exit 1;
                fi
                ${REMOVE} tmpdiff
        fi
        done
        echo "* hfst-xfst subtest "$testfile" passed"
    done


    ## Test that the results of testfile_true.xfst and testfile_false.xfst (written to file tmp)
    ## contain the lines listed in files test_true.input and test_false.output, respectively.
    for testcase in _true _false # whether we test the positive or negative case
    do
    for testfile in test_overlap test_sublanguage # the function to be tested
    do
        if ! (${LS} $testfile$testcase.xfst > /dev/null 2> /dev/null); then
        echo "skipping missing test for "$testfile$testcase"..."
        continue
        fi
        if ! (${CAT} $testfile$testcase.xfst | ../hfst-xfst --pipe-mode=input -s -f $format | ${TR} -d '\r' > tmp); then
        echo "ERROR: in compiling "$testfile$testcase.xfst
        exit 1;
        fi
        if ! ($DIFF tmp "test"$testcase.output); then
        echo "ERROR: in testing "$testfile$testcase.xfst
        exit 1;
        fi
    done
    done

    for file in quit-on-fail.xfst assert.xfst
    do
        if (${CAT} $file | ../hfst-xfst --pipe-mode=input -s -f $format > tmp 2> /dev/null); then
            echo "ERROR: in compiling "$file
            exit 1;
        fi
        if (${GREP} '^fail' tmp > /dev/null); then
            echo "ERROR: in testing "$file
            exit 1;
        fi
        if ! (${GREP} '^pass' tmp > /dev/null); then
            echo "ERROR: in testing "$file
            exit 1;
        fi
    echo "* hfst-xfst subtest "$file" passed"
    done

    if [ "$format" = "openfst-tropical" ]; 
    then
        for file in weighted_replace_right_1 weighted_replace_right_2 \
        weighted_replace_right_3 weighted_replace_right_4 weighted_replace_right_5 \
        weighted_replace_right_6 weighted_replace_right_7 weighted_replace_right_8 \
        weighted_replace_right_9 \
        weighted_optional_replace_right_1 weighted_optional_replace_right_2 \
        weighted_optional_replace_right_3 weighted_optional_replace_right_4 \
        weighted_optional_replace_right_5 \
        weighted_optional_replace_right_6 weighted_optional_replace_right_7 \
        weighted_optional_replace_right_8 weighted_optional_replace_right_9 \
        weighted_ltr_longest_match_1 weighted_ltr_longest_match_2 weighted_ltr_longest_match_3 \
        weighted_ltr_shortest_match_1 weighted_ltr_shortest_match_2 weighted_ltr_shortest_match_3
        do
        if ! (${LS} $file.xfst > /dev/null 2> /dev/null); then
            echo "skipping missing test for "$file"..."
            continue
        fi
            if ! (${CAT} $file.xfst | ../hfst-xfst --pipe-mode=input -s -f $format | ${TR} -d '\r' > tmp 2> /dev/null); then
                echo "ERROR: in compiling "$file".xfst"
                exit 1;
            fi
            if ! (${CAT} tmp | ${STRINGS2FST} -j -f $format > tmp1 2> /dev/null); then
                echo "ERROR: in compiling result file from "$file".xfst"
                exit 1;
            fi
            if ! (${CAT} $file.result | ${STRINGS2FST} -j -f $format > tmp2 2> /dev/null); then
                echo "ERROR: in compiling file "$file".result"
                exit 1;
            fi
        if ! (${COMPARE} tmp1 tmp2); then
            echo "ERROR: "$file" test failed"
            exit 1;
        fi
        echo "* hfst-xfst subtest "$file" passed"
        done
        for file in contains contains_with_weight contains_once contains_once_optional \
            replace_test_1 replace_test_2 replace_test_3 replace_test_4 replace_test_5 \
            replace_test_6 replace_test_7 replace_test_8 replace_test_9 replace_test_10 \
            replace_test_11 replace_test_12 replace_test_13 replace_test_14 replace_test_15 \
            replace_test_16 replace_test_17 replace_test_18 replace_test_19 replace_test_20 \
            replace_test_21 replace_test_22 replace_test_23 replace_test_24 replace_test_25 \
            replace_test_26 replace_test_27 replace_test_28 replace_test_29 replace_test_30 \
            replace_test_31 replace_test_32 replace_test_33 replace_test_34 replace_test_35 \
            replace_test_36 replace_test_37 replace_test_38 replace_test_39 replace_test_40 \
            replace_test_41 replace_test_42 replace_test_43 replace_test_44 replace_test_45 \
            replace_test_46 replace_test_47 replace_test_48 replace_test_49 replace_test_50 \
            replace_test_51 replace_test_52 replace_test_53 \
            weighted_parallel_rules_1 weighted_parallel_rules_2 weighted_parallel_rules_3 \
            weighted_parallel_rules_4 weighted_parallel_rules_5 weighted_parallel_rules_6 \
            weighted_parallel_rules_7 weighted_parallel_rules_8 weighted_parallel_rules_9 \
            weighted_parallel_rules_10 weighted_parallel_rules_11 weighted_parallel_rules_12 \
            weighted_parallel_rules_13
        do
            if ! (${LS} $file.xfst > /dev/null 2> /dev/null); then
            echo "skipping missing test for "$file"..."
            continue
        fi
            if ! (${CAT} $file.xfst | ../hfst-xfst --pipe-mode=input -s -f $format | ${TR} -d '\r' > tmp 2> /dev/null); then
                echo "ERROR: in compiling "$file".xfst"
                exit 1;
            fi
            if ! (${DIFF} $file.output tmp); then
            echo "ERROR: "$file" test failed"
            exit 1;
        fi
        echo "* hfst-xfst subtest "$file" passed"
        done
    fi

    echo ""
    ${REMOVE} result tmp1 tmp2 foo

## add properties
# alias
# apropos
# cleanup net
# clear stack
# collect epsilon-loops
# compact sigma
# compile-replace lower
# compile-replace upper
# complete net
# crossproduct net
# echo
# edit properties
# eliminate flag
# help
# ignore net
# inspect net
# label net
# list
# load defined
# load stack
# name net
# pop stack
# print aliases
# print arc-tally
# print defined
# print directory
# print file-info
# print flags
# print label-maps
# print labels
# print label-tally
# print list
# print lists
# print longest-string
# print longest-string-size
# print lower-words
# print name
# print net
# print random-lower
# print random-upper
# print random-words
# print shortest-string
# print shortest-string-size
# print sigma
# print sigma-tally
# print sigma-word-tally
# print size
# print upper-words
# print words
# push defined
# quit
# read att
# read lexc
# read prolog
# read properties
# read regex
# read spaced-text
# read text
# rotate stack
# save defined
# save stack
# set
# show
# shuffle net
# sigma net
# source
# substitute defined
# substitute label
# substitute symbol
# substring net
# system
# test equivalent
# test lower-bounded
# test lower-universal
# test non-null
# test null
# test overlap
# test sublanguage
# test upper-bounded
# test upper-universal
# turn stack
# twosided flag-diacritics
# undefine
# unlist
# write att
# write definition
# write definitions
# write dot
# write prolog
# write properties
# write spaced-text
# write text



done

${REMOVE} ${EXTRA_FILES}
exit 0;

