#!/usr/bin/env bash

#------------------------------------------------------------------------------
#
# This program runs inside a Docker container that contains every known YAML
# parser that supports the parse event DSL output.
#
# It is used to run every test in the suite against each YAML parser.
#
#------------------------------------------------------------------------------

set -e -u -o pipefail

main() (
  id=$ID
  tmp=/tmp/test/$id

  set -- $RUNNERS

  run-all-parsers "$@"

  write-tsv-line "$@"
)

run-all-parsers() (
  cat > "$tmp-input.yaml"

  for parser; do
    (
      timeout 5 \
      "$parser" \
        < "$tmp-input.yaml" \
        > "$tmp-$parser.stdout" \
        2> "$tmp-$parser.stderr" || (
          echo $? > "$tmp-$parser.err"
        )
    ) &
  done

  wait
)

write-tsv-line() (
  refparser=$1
  shift

  if [[ -e $tmp-$refparser.err ]]; then
    got_ref=''
  else
    got_ref=$(< "$tmp-$refparser.stdout")
  fi

  out=''
  for parser; do
    want=$got_ref

    if [[ -e $tmp-$parser.err ]]; then
      got=''
    elif [[
      -s $tmp-$parser.stderr &&
      $(< "$tmp-$parser.stdout") != *-STR
    ]]; then
      got=''
    else
      got=$(grep -v '=COMMENT' < "$tmp-$parser.stdout" || true)
    fi

    if [[ $parser == *-rustyaml ]]; then
      got=$(adjust-got-for-rust <<<"$got")
      want=$(adjust-want-for-rust <<<"$want")
    fi

    if [[ $parser == *-rapid ]]; then
      got=$(adjust-got-for-rapid <<<"$got")
      want=$(adjust-want-for-rapid <<<"$want")
    fi

    if [[ $parser == *-refhs ]]; then
      [[ $got =~ (=ERR|=REST) ]] && got=''
      if [[ $got && $want ]]; then
        out+=$'\t'
      elif [[ ! $got && ! $want ]]; then
        out+=$'\t'
      else
        out+=$'\tx'
      fi
    else
      [[ $got =~ $'\n'-STR$ ]] || got=''
      if [[ $got == "$want" ]]; then
        out+=$'\t'
      else
        got=${got//+MAP\ \{\}/+MAP}
        got=${got//+SEQ\ \[\]/+SEQ}
        want2=${want//+MAP\ \{\}/+MAP}
        want2=${want2//+SEQ\ \[\]/+SEQ}

        # Ignore Go parser bug:
        got=${got//+DOC\ ---/+DOC}
        want2=${want2//+DOC\ ---/+DOC}

        if [[ $got == "$want2" ]]; then
          out+=$'\t'
        else
          out+=$'\tx'
        fi
      fi
    fi
  done

  printf '%s' "$out"
)

adjust-got-for-rust() {
  perl -p0e '
    s/<Tag\("!!",\ "(.*?)"\)>/<tag:yaml.org,2002:$1>/g;
    s/<Tag\("!",\ "(.*?)"\)>/<!$1>/g;
    s/<Tag\("",\ "!"\)>/<!>/g;
    s/<Tag\("",\ "(tag:.*?)"\)>/<$1>/g;
    s/<Tag\("",\ "(!.*?)"\)>/<$1>/g;
  '
}

adjust-want-for-rust() {
  perl -p0e '
    s/^\+DOC ---$/+DOC/gm;
    s/^-DOC \.\.\.$/-DOC/gm;
    s/^=VAL :$/=VAL :~/gm;
    s/^\+MAP\ \{\}(\ ?)/+MAP$1/gm;
    s/^\+SEQ\ \[\](\ ?)/+SEQ$1/gm;

    my ($c, %a) = (1);
    s{^(\+MAP|\+SEQ|=VAL|=ALI) (&|\*)(\S+)(.*)}
     {"$1 $2".($2 eq "&" ? ($a{$3} = $c++) : $a{$3}).$4}gem;
  '
}

adjust-got-for-rapid() {
  perl -p0e '
    s/^\+DOC ---/+DOC/gm;
  '
}

adjust-want-for-rapid() {
  perl -p0e '
    s/^=VAL ((?:&\S+ |<\S*> )*)[">|]/=VAL $1'"'"'/gm;
    s/^\+DOC ---/+DOC/gm;
    s/^-DOC \.\.\./-DOC/gm;
  '
}

warn() ( echo "$*" >&2 )

die() ( echo "$*" >&2; exit 1 )

[[ -f /.dockerenv ]] || die "Not in docker"

main "$@"
