#!/bin/bash
set -eo pipefail

FAILED_TXT="${RED}[FAILED]${NC}"
SUCCESS_TXT="${GREEN}[SUCCESS]${NC}"

# Check $TESTS_DIR is given
if [[ -z "$TESTS_DIR" ]]; then
  echo "Must provide \$TESTS_DIR env variable"
  exit 1
fi

# Check $INVOCATION_ID is given: we use it as cache key to be sure compiled tester-lcmp is actual (see file $TESTS_DIR/tester-lcmp/tester-lcmp.$INVOCATION_ID)
if [[ -z "$INVOCATION_ID" ]]; then
  echo "Must provide \$INVOCATION_ID env variable"
  exit 1
fi

mkdir -p "$TESTS_DIR"/tester-lcmp

# If compiled tester-lcmp is not actual
if [ ! -f "$TESTS_DIR"/tester-lcmp/tester-lcmp."$INVOCATION_ID" ]; then
  # Clear
  rm -f "$TESTS_DIR"/tester-lcmp/*

  # Compile it
  CPP_INCLUDE_DIR_=$CPP_INCLUDE_DIR
  export CPP_INCLUDE_DIR=$TESTS_DIR/lib
  bash "$TESTS_DIR"/scripts/compile "$TESTS_DIR"/src/tester-lcmp.cpp
  export CPP_INCLUDE_DIR=$CPP_INCLUDE_DIR_

  # Move from current dir to /tester-lcmp
  if [ ! -d ./tester-lcmp ]; then
    mv -f ./tester-lcmp "$TESTS_DIR"/tester-lcmp
  else
    mv -f ./tester-lcmp.exe "$TESTS_DIR"/tester-lcmp
  fi

  # Create file to inform that it was compiled to this $INVOCATION_ID
  touch "$TESTS_DIR"/tester-lcmp/tester-lcmp."$INVOCATION_ID"
fi

# First argument as a subdirectory in ./refs
ref_dir=$1
if [[ -z "$ref_dir" ]]; then
  echo "Must provide \$1 for test-ref"
  exit 1
fi

refs=refs/$1

shift 1

# Check if we don't have invocation reference files
if [ ! -d "$refs" ]; then
  if [[ "$TEST_REF_FORBID_GEN_REFS" == "true" ]]; then
    echo "You forgot to run push ref files for invocation: ""$*"""
    echo "Run test locally, it will produce ref files and push it into the repo"
    exit 1
  fi
  # Create them
  mkdir -p "$refs"
  echo Generating tester refs: "$*"
  exit_code=0
  # shellcheck disable=SC2048
  $* 1>"$refs"/stdout 2>"$refs"/stderr || exit_code=$?
  echo $exit_code >"$refs"/exit_code
  echo -e "${SUCCESS_TXT} generated execution reference files (exit code: $exit_code)\n"
else
  # Do invocation
  echo Testing refs: "$*"
  exit_code=0
  # shellcheck disable=SC2048
  $* 1>"$refs"/stdout.aux 2>"$refs"/stderr.aux || exit_code=$?
  stdout_size=$(wc -c < "$refs"/stdout.aux)
  stderr_size=$(wc -c < "$refs"/stderr.aux)
  echo "Program exit code: $exit_code, stdout size: $stdout_size bytes, stderr size: $stderr_size bytes"
  echo $exit_code >"$refs"/exit_code.aux

  # Check exit code is the same
  tester_lcmp_exit_code=0
  "$TESTS_DIR"/tester-lcmp/tester-lcmp "$TESTS_DIR"/tester-lcmp/tester-lcmp."$INVOCATION_ID" "$refs"/exit_code.aux "$refs"/exit_code 2>tester-lcmp.out || tester_lcmp_exit_code=$?
  if [[ ! "$tester_lcmp_exit_code" == "0" ]]; then
    echo -e "${FAILED_TXT} exit_code mismatched: found $(cat < "$refs"/exit_code.aux) but expected $(cat "$refs"/exit_code)\n"
    cat tester-lcmp.out
    rm -f tester-lcmp.out
    rm -f "$refs"/*.aux
    exit 1
  fi
  echo $exit_code >"$refs"/exit_code.aux

  # Check stdout is the same
  "$TESTS_DIR"/tester-lcmp/tester-lcmp "$TESTS_DIR"/tester-lcmp/tester-lcmp."$INVOCATION_ID" "$refs"/stdout.aux "$refs"/stdout 2>tester-lcmp.out || tester_lcmp_exit_code=$?
  if [[ ! "$tester_lcmp_exit_code" == "0" ]]; then
    echo -e "${FAILED_TXT} stdout mismatched\n"
    cat tester-lcmp.out
    rm -f tester-lcmp.out
    rm -f "$refs"/*.aux
    exit 1
  fi

  # Check stderr is the same
  "$TESTS_DIR"/tester-lcmp/tester-lcmp "$TESTS_DIR"/tester-lcmp/tester-lcmp."$INVOCATION_ID" "$refs"/stderr.aux "$refs"/stderr 2>tester-lcmp.out || tester_lcmp_exit_code=$?
  if [[ ! "$tester_lcmp_exit_code" == "0" ]]; then
    echo -e "${FAILED_TXT} stderr mismatched\n"
    cat tester-lcmp.out
    rm -f tester-lcmp.out
    rm -f "$refs"/*.aux
    exit 1
  fi

  # Invocation is the same!
  echo -e "${SUCCESS_TXT} execution matched with reference (exit code: $exit_code)\n"
  rm -f tester-lcmp.out
  rm -f "$refs"/*.aux
fi
