#!/bin/sh

#############################################################

# run pascal rejection tests

#############################################################

function ldiff {
    diff --text $1 $2 | less
}

# use this difference program
if [ -n "$DISPLAY" ] && which kdiff3 &> /dev/null; then
    DIFF=kdiff3
else
    DIFF=ldiff
fi

echo -n "rejection tests"; pwd
echo

if [ -z $P5CDIR ] ; then
   echo "\$P5CDIR is not set, bailing out"
   exit 1;
fi

function dcheck {
  if [ -f $PASFILE.out ]
  then
    if diff -qb --ignore-matching-lines="INFO" $PASFILE.{out,cmp} ; then
       echo -n -e "\r$PASFILE is OK "
    else
       $DIFF $PASFILE.{out,cmp}
    fi
  else
    echo "failed: $PASFILE did not produce an output"
    read -rsp $'Press any key to continue...\n' -n1 key
  fi
}

rm -f *.out *.lst *.err *.1.pas *.p *.c *.exe

#echo '******* skipping generic tests *******'; for i in d[01]*[^.]?.pas d251.pas ; do
for i in d[012]*[^.]?.pas; do
  PASFILE=`basename $i .pas`
  if grep -q "^ARG" $i ; then
    #echo "generic test $PASFILE"
    for n1 in `awk '/^ARG/ {$1=""; print}' $PASFILE.pas` ; do
        for n2 in `awk '/^ADJ/ {$1=""; print}' $PASFILE.pas` ; do
            rm -f $PASFILE
            cpp -E -nostdinc -w \
                -D ARG1=$n1 -D ARG2=$(($n1+$n2)) $i \
                | grep -v -e "^# 1 \"<" > $PASFILE.p
            $P5CDIR/pc $PASFILE.p &> /dev/null; ./$PASFILE 2> $PASFILE.out > xout
            echo -n "  ($n1, $n2)    "
            dcheck
        done
    done
#    echo -n "             \r"
  else
    rm -f $PASFILE
    if grep -q __LINE__ $PASFILE.pas; then
        $P5CDIR/pc -cpp $PASFILE &> /dev/null; ./$PASFILE 2> $PASFILE.out > xout
    else
        $P5CDIR/pc $PASFILE &> /dev/null; ./$PASFILE 2> $PASFILE.out > xout
    fi
    cat xout >> $PASFILE.out
    dcheck
  fi
done

echo
for i in [le]*[^.]?.pas; do
  PASFILE=`basename $i .pas`
  rm -f $PASFILE
  $P5CDIR/r $PASFILE &> /dev/null

  if [ -f $PASFILE.lst ]
  then
    if diff -qb -I 'P5. Pascal compiler v' $PASFILE.{lst,exp} ; then
       echo -e -n "\r$PASFILE is OK"
    else
       $DIFF $PASFILE.{lst,exp}
    fi
  else
    echo "failed: $PASFILE did not produce a list file"
    read -rsp $'Press any key to continue...\n' -n1 key
  fi
done

echo
test -x x00? && rm x00?

rm -f xf.txt
$P5CDIR/r x001 xf.txt  &> x001.out
if [ 1 == $(wc -l < xf.txt) ] ; then
  echo "x001 detected"
else
  echo "x001 is not correctly terminated after fatal error"
fi

$P5CDIR/r x002 &> x002.out
if grep "undefined reference to \`Tgamma'" x002.err; then
  echo "x002 detected error"
else
  echo "x002 failed to detect error in external case"
fi

$P5CDIR/r x003 &> x003.out
if grep "conflicting types for .tgamma." x003.err; then
  echo "x003 detected error correctly"
else
  echo "x003 failed to detect parameter error in external case"
fi

rm -f x1001.txt
$P5CDIR/r x1001 &> x1001.out
if [ 1 == $(wc -l < x1001.txt) ] ; then
  echo x1001 is OK
else
  echo "x1001 is not correctly terminated after fatal error"
fi

echo

#exit

if [ -d ../std-tests ] ; then
  cat ../std-tests/{deviance,errorHandling}.pas | \
      awk 'BEGIN { FS="[ (]"; i=0; \
                   l[0] = "{ --- DO NOT EDIT THIS FILE --- }" ;} \
        /^{ *TEST +/ { if(i>0) l[i++] = "xxx ERROR xxx" ; \
                       else i=1; name = "d6p10d" }; \
        i>0 { l[i++]=$0}; \
        /^ *program +/ { name=$2 }; \
        /^ *end\./ {n=i; for(i=0; i<n; i++) print l[i] > name ".p"; i=0 }'

  if grep -c "xxx ERROR xxx" [de]*[^.]?.p | grep -v "p:0"
  then
    grep -c "xxx ERROR xxx" [de]*[^.]?.p | \
    awk -F ":" '$2 != 0 {print $1, "seems to have", $2, "errors"}'
    read -rsp $'Press any key to continue...\n' -n1 key
  fi

  for i in [de][1-9]p[1-9]*[^.]?.p; do
    PASFILE=`basename $i .p`
    rm -f $PASFILE $PASFILE.lst $PASFILE.out
    echo -n ' ' | $P5CDIR/r $PASFILE &> $PASFILE.out
    echo -n "$i: "
    if grep -qF "Errors in program: 0" $PASFILE.lst ; then
      if [ -f $PASFILE.out ] ; then
          awk 'BEGIN {err=1; ln=0} \
               NR==FNR { if( $1~/fatal/ ) ln=$5; next} \
               /!!!/ {if(FNR":" == ln) {print "OK"; err=0} } \
              END { if( ln == 0 ) print "no runtime error"; \
                    else if(err) print "unverified runtime error"}' ./$PASFILE.{out,p}
      else
          echo "$PASFILE did not produce an output"
          read -rsp $'Press any key to continue...\n' -n1 key
      fi
    else
        rm -f $PASFILE.out
        # compile failed - expected errors are marked with '!!!'
        awk 'BEGIN {e=0; l=""; } \
             /\*\*\*\* +\^/ && l ~ /!!!/ { e = 1; } \
             { l = $0; } \
             END { if(!e) print "------ unverified compile error -------"; \
                   else print "OK"; } \
             ' $PASFILE.lst
    fi
  done

# TODO: this could be improved, it misses some verifiable errors
  echo
  echo "`ls [de][1-9]p[1-9]*[^.]?.p | wc -w` tests"
  echo '---------------'
  awk ' BEGIN { n=0; } \
        FNR==1 {e=1;} \
        /program [de][1-9]p[1-9]/ {prog=$3;} \
        $2 ~ /\*\*\*\*/ && e { \
               e=0; \
               if( l !~ /!!!/ )  { n++; \
                 print "program " prog;    \
                 print l; \
                 print; \
                 print "------" } }\
        { l = $0; } \
        END { print "unverified compilation errors found in " n " tests";  } ' \
        [de][1-9]p[1-9]*[^.]?.lst


  echo
  echo '---------------'
  awk ' BEGIN { n=0; } \
       /DEVIATES/ { a[n++] = FILENAME ": " $0 }; \
       END {print "deviations found in " n " tests:"; \
       for(i=0;i<n;i++) print a[i]; } ' [de][1-9]p[1-9]*[^.]?.out

  echo '---------------'
  awk ' BEGIN { n=0; } \
       /ERROR NOT DETECTED/ { a[n++] = FILENAME ": " $0 }; \
       END {print n " tests did not detect an error:"; \
       for(i=0;i<n;i++) print a[i]; } ' [de][1-9]p[1-9]*[^.]?.out

  #exit

  read -rsp $'Press any key to continue...\n' -n1 key
fi

echo
echo
for i in iso7185prt*[^.]?.pas; do
  PASFILE=`basename $i .pas`
  rm -f $PASFILE $PASFILE.out $PASFILE.lst
  echo -n "$PASFILE "
  $P5CDIR/r $PASFILE 2> /dev/null > $PASFILE.out
  if diff -qb -I 'P5. Pascal compiler v' $PASFILE.{lst,exp} ; then
      if [ -f $PASFILE.cmp ] ; then
          if diff -qb -I '++IGNORE++' $PASFILE.{out,cmp} ; then
              echo "runtime check OK"
          else
              $DIFF $PASFILE.{out,cmp}
          fi
      else
          echo "compile time check OK"
      fi
  else
      $DIFF $PASFILE.{lst,exp}
  fi
done

echo
echo "`ls iso7185prt*[^.]?.pas | wc -w` tests"
echo '---------------'
awk ' BEGIN { n=0; } \
     /error not detected/ { a[n++] = FILENAME ": " $0 }; \
     END {print n " tests did not detect an error:"; \
     for(i=0;i<n;i++) print a[i]; } ' iso7185prt*[^.]?.out

echo '---------------'
awk ' BEGIN { n=0; } \
     /deviation/ { a[n++] = FILENAME ": " $0 }; \
     END {print "deviations found in " n " tests:"; \
     for(i=0;i<n;i++) print a[i]; } ' iso7185prt*[^.]?.out


echo '---------------'
awk ' BEGIN { n=0; } \
     /not an error/ { a[n++] = FILENAME ": " $0 }; \
     END {print "no p5x error found in " n " tests:"; \
     for(i=0;i<n;i++) print a[i]; } ' iso7185prt*[^.]?.out

echo '---------------'
for i in *.lst ; do
    if ! grep -q "Errors in program:" $i ; then
        echo "$i did not compile";
    fi;
done

for i in [^x]*.err ; do
    if grep -q ": error:" $i ; then
        echo "bad c code in $i";
    fi;
done

grep 'Compiler internal error' *.lst

# for debug version of pcom.pas
# show where memory leaks
echo "found `grep 'new memory at line' *.lst | wc -l` memory leaks"
cat *.lst | grep "new memory at line" | sort | uniq

read -rsp $'Press any key to continue...\n' -n1 key
