#!/bin/ksh
#
# Graphviz regression test driver
#
# Also relies on strps.awk.
#
# TODO:
#  Fix to allow multiple test data sets depending
# on architecture, etc. Maintain common ones in REFDIR.
#  Report differences with shared version and with new output.

# bsh, linux-ksh filter
bar=1;echo foo | read bar<<- \!         
2
!
if ((bar==1))
then
  echo "Graphviz test suite requires ksh93"
  exit 1
fi
# csh, ksh88 filter
(( 1.5 == 1 )) && { echo "Graphviz test suite requires ksh93"; exit 1; } 

TESTFILE=tests.txt     # Test specifications
GRAPHDIR=graphs        # Directory of input graphs and data
OUTDIR=ndata           # Directory for test output
OUTHTML=nhtml          # Directory for html test report
REFDIR=nshare          # Directory for expected test output
GENERATE=              # If set, generate test data
VERBOSE=               # If set, give verbose output
NOOP=                  # If set, just print list of tests
DOT=../cmd/dot/dot # build tree version with a builtin set of plugins
		       # should be $(top_builddir)/cmd/dot/dot_static
DIFFIMG=../contrib/diffimg/diffimg # build tree version

TESTNAME=   # name of test
GRAPH=      # graph specification
IDX=
typeset -i i j SUBTESTCNT
typeset -i CRASH_CNT=0 DIFF_CNT=0 TOT_CNT=0
typeset -i LINECNT=0
typeset -A TESTTYPES
typeset -a ALG
typeset -a FMT
typeset -a FLAGS
TMPINFILE=tmp$$.gv
TMPFILE1=tmpnew$$
TMPFILE2=tmpref$$

# Read single line, storing it in LINE and update count.
# Return 0 on success.
function readLine
{
  if read -u 3 LINE
  then
    (( LINECNT+=1 ))
    return 0
  else
    return 1
  fi
}

# Skip blank lines and comments (lines starting with #)
# Use first real line as the test name
function skipLines
{
  while readLine
  do
    if [[ -n $LINE && ${LINE:0:1} != \# ]]
    then
      return 0
    fi
  done
  return 1
}

# Subtests have the form: layout format optional_flags
# Store the 3 parts in the arrays ALG, FMT, FLAGS.
# Stop at a blank line
function readSubtests
{
  (( SUBTESTCNT=0 ))
  while readLine
  do
    if [[ -z "$LINE" ]]
    then
      return
    fi
    if [[ ${LINE:0:1} != \# ]]
    then
      echo $LINE | read ALG0 FMT0 FLAGS0
      ALG[$SUBTESTCNT]=$ALG0
      FMT[$SUBTESTCNT]=$FMT0
      FLAGS[$SUBTESTCNT]=$FLAGS0
      (( SUBTESTCNT+=1 ))
    fi
  done
}

function readTest
{
  # read test name
  if skipLines
  then
    TESTNAME=$LINE
  else
    return 1
  fi

  # read input graph
  if skipLines
  then
    GRAPH=$LINE
  else
    return 1
  fi

  readSubtests
  return 0
}

# newfile = $1
# oldfile = $2
# assume subscript indicates file type
function strip {
  case $1 in
    *.ps )
      awk -f strps.awk $1 > $TFILE1
      awk -f strps.awk $2 > $TFILE2
      ;;
    *.svg )
      sed '/^<!--/d' < $1 | sed '/-->$/d' > $TFILE1
      sed '/^<!--/d' < $2 | sed '/-->$/d' > $TFILE2
      ;;
    * )
      cp $1  $TFILE1
      cp $2  $TFILE2
      ;;
  esac

}

# Compare old and new output and report if different.
#  Args: testname index fmt
function doDiff
{
   FILE1=$OUTDIR/$OUTFILE
   FILE2=$REFDIR/$OUTFILE
   F=${3%%:*}
   case $F in
    ps | ps2 )
      awk -f strps.awk $FILE1 > $TMPFILE1
      awk -f strps.awk $FILE2 > $TMPFILE2
      diff -q $TMPFILE2 $TMPFILE1 > /dev/null 
      if [[ $? != 0 ]]
      then
          print -u 2 "Test $1:$2 : == Failed == $OUTFILE"
          (( DIFF_CNT+=1 ))
      fi
      ;;
    svg )
      sed '/^<!--/d' < $FILE1 | sed '/-->$/d' > $TMPFILE1
      sed '/^<!--/d' < $FILE2 | sed '/-->$/d' > $TMPFILE2
      diff -q $TMPFILE2 $TMPFILE1 > /dev/null 
      if [[ $? != 0 ]]
      then
          print -u 2 "Test $1:$2 : == Failed == $OUTFILE"
          (( DIFF_CNT+=1 ))
      fi
      ;;
    png )
      $DIFFIMG $FILE2 $FILE1 >$OUTHTML/dif_$OUTFILE
      if [[ $? != 0 ]]
      then
	  echo "<p>" >>$OUTHTML/index.html
	  cp $FILE2 $OUTHTML/old_$OUTFILE
	  echo "<img src=\"old_$OUTFILE\" width=\"192\" height=\"192\">" >>$OUTHTML/index.html
	  cp $FILE1 $OUTHTML/new_$OUTFILE
	  echo "<img src=\"new_$OUTFILE\" width=\"192\" height=\"192\">" >>$OUTHTML/index.html
	  echo "<img src=\"dif_$OUTFILE\" width=\"192\" height=\"192\">" >>$OUTHTML/index.html
          print -u 2 "Test $1:$2 : == Failed == $OUTFILE"
          (( DIFF_CNT+=1 ))
      else
	  rm $OUTHTML/dif_$OUTFILE
      fi
      ;;
    * )
      diff -q $FILE2 $FILE1 > /dev/null 
      if [[ $? != 0 ]]
      then
          print -u 2 "Test $1:$2 : == Failed == $OUTFILE"
          (( DIFF_CNT+=1 ))
      fi
      ;;
    esac
}

# Generate output file name given 3 parameters.
#   testname layout format
# If format ends in :*, remove this, change the colons to underscores,
# and append to basename
# If the last two parameters have been used before, add numeric suffix.
function genOutname
{
  if [[ $3 == *:* ]]
  then
    F=${3%%:*}
    XFMT=${3#$F}
    XFMT=${XFMT/:/_}
  else
    F=$3
    XFMT=""
  fi

  IDX="$2$XFMT$F"
  j=${TESTTYPES[$IDX]}
  if (( j == 0 ))
  then
    TESTTYPES[$IDX]=1
    J=""
  else
    TESTTYPES[$IDX]=$(( j+1 ))
    J=$j
  fi 
  OUTFILE="$1_$2$XFMT$J.$F"
}

# clear out all entries of associated array
function aunset #name
{
	typeset i
	nameref v=$1
	for i in ${!v[@]}
	do	unset v[$i]
	done
}

function doTest
{
  if (( SUBTESTCNT == 0 ))
  then
    return
  fi
  case $GRAPH in
    = )
      INFILE=$GRAPHDIR/$TESTNAME.gv
      ;;
    graph* | digraph* )
      INFILE=$TMPINFILE
      echo "$GRAPH" > $INFILE
      ;;
    *.gv )
      INFILE=$GRAPHDIR/$GRAPH
      ;;
    * )
      echo "Unknown graph spec, test $TESTNAME - ignoring"
      return
      ;;
  esac

  for ((i=0;i<SUBTESTCNT;i++))
  do
    (( TOT_CNT+=1 ))
    genOutname $TESTNAME ${ALG[$i]} ${FMT[$i]}
    OUTPATH=$OUTDIR/$OUTFILE
    KFLAGS=${ALG[$i]}
    TFLAGS=${FMT[$i]}
    test -z "$KFLAGS" || KFLAGS="-K$KFLAGS"
    test -z "$TFLAGS" || TFLAGS="-T$TFLAGS"
    testcmd="$DOT $KFLAGS $TFLAGS ${FLAGS[$i]} -o$OUTPATH $INFILE"
    if [[ -n "$VERBOSE" ]]
    then
      print $testcmd
    fi
    if [[ $NOOP == 1 ]]
    then
      continue
    fi
    
    $testcmd 2> errout
    RVAL=$?

    if [[ -s errout ]]
    then
      cat errout
    fi

    if [[ $RVAL != 0 || ! -s $OUTPATH ]]
    then
      (( CRASH_CNT+=1 ))
      print -u 2 "Test $TESTNAME:$i : == Layout failed =="
      print -u 2 "  $testcmd"
    elif [[ $GENERATE == 1 ]]
    then
      continue
    elif [[ -r $REFDIR/$OUTFILE ]]
    then
      doDiff $TESTNAME $i ${FMT[$i]}
    else
      print -u 2 "Test $TESTNAME:$i : == No file $REFDIR/$OUTFILE for comparison =="
    fi
  done

  # clear TESTTYPES
  aunset TESTTYPES
#  for W in ${!TESTTYPES[@]}
#  do
#    TESTTYPES[$W]=0
#  done 
}

trap 'rm -f $TMPFILE1 $TMPFILE2 $TMPINFILE errout; exit' 0 1 2 3 15

Usage='rtest [-gvn] [TESTFILE]\n
 -g : generate test data\n
 -v : verbose\n
 -n : print test'

while getopts :gnv c
do
  case $c in
  n )
    VERBOSE=1
    NOOP=1
    ;;
  v )
    VERBOSE=1
    ;;
  g )
    GENERATE=1
    if [[ ! -d "$REFDIR" ]]
    then
		mkdir $REFDIR
    fi
    OUTDIR=$REFDIR
    ;;
  :)
    echo $OPTARG requires a value
    exit 2
    ;;
  \? )
    if [[ "$OPTARG" == '?' ]]
    then
      print $Usage
      exit 0
    else
      echo "rtest: unknown flag $OPTARG - ignored"
    fi
    ;;
  esac
done
shift $((OPTIND-1))

if [[ $# > 0 ]]
then
  if [[ -r $1 ]]
  then
    TESTFILE=$1
  else
    print -u 2 "Test file $1 does not exist"
    exit 1
  fi
fi

# Check environment and initialize

if [[ $NOOP != 1 ]]
then
if [[ ! -d "$REFDIR" ]]
then
  print -u 2 "Test data directory $REFDIR does not exist"
  exit 1
fi

if [[ ! -d "$OUTDIR" ]]
then
  mkdir $OUTDIR
fi

if [[ ! -d "$OUTHTML" ]]
then
  mkdir $OUTHTML
fi
rm -f $OUTHTML/*

if [[ ! -x $DOT ]]
then
  print -u 2 "$DOT program is not executable"
  exit 1
fi

if [[ $GENERATE != 1 && ! -x $DIFFIMG ]]
then
  print -u 2 "$DIFFIMG program is not executable"
  exit 1
fi
fi


exec 3< $TESTFILE
while readTest
do
  doTest
done
if [[ $NOOP == 1 ]]
then
print -u 2 "No. tests: $TOT_CNT"
elif [[ $GENERATE == 1 ]]
then
print -u 2 "No. tests: $TOT_CNT Layout failures: $CRASH_CNT"
else
print -u 2 "No. tests: $TOT_CNT Layout failures: $CRASH_CNT Changes: $DIFF_CNT"
fi
