#!/bin/bash
# compara-dat: d2datdinc contra los .dat congelados del corpus.
#
#   siru/corpus/compara-dat [-v] [DIRECTORIO]
#
# Al lado de 191 de los 246 archivos de corpus hay su .dat, que es
# la salida de d2datdinc --entonces examples/10-- congelada en siru r1472, y que
# en su momento se
# comprobo igual a la de ds2dat (ver el README.md de dods). Esta prueba corre
# d2datdinc sobre cada uno de esos 191 y compara con el .dat de al lado: es la
# regresion del corpus completo, y a diferencia de slex/d2datdinc/pruebas/contra-ds2dat no
# necesita Perl ni Simulparser, solo los archivos.
#
# El .dat lleva el nombre del .ds2, que para un .d que convive con un .ds del
# mismo nombre termina en -desde-d. De ahi se saca cual es el archivo fuente.
#
# Se compara el JSON entero salvo OTHERINFO, que tiene rutas y cambia con el
# directorio desde el que se corrio. Estado 0 si no hay ninguna diferencia.
# -v muestra cada diferencia.
#
# Copyright (C) Diego Saravia <dsa@unsa.edu.ar>
# GPL version 3 o posterior.

# La herramienta vive en siru/corpus/ y los circuitos en siru/corpus/corpus/
AQUI_TOOL=$(cd "$(dirname "$0")" && pwd)
CORPUS=$AQUI_TOOL/corpus
# d2datdinc, su tabla y su biblioteca: en siru/slex/d2datdinc
AQUI=$(cd "$AQUI_TOOL/../../slex/d2datdinc" 2>/dev/null && pwd || echo "$AQUI_TOOL/../../slex/d2datdinc")
E="${D2DATDINC:-$AQUI/d2datdinc} -c $AQUI/d2datdinc.slex -b $AQUI/biblioteca"
detalle=0
[ "$1" = -v ] && { detalle=1; shift; }

# por defecto, el corpus; slex/d2datdinc -> slex -> siru
DODS=${1:-$CORPUS}

[ -x "${E%% *}" ] || { echo "no esta ${E%% *}: falta hacer make" >&2; exit 77; }
if [ ! -d "$DODS" ]; then
  echo "no esta $DODS: hace falta la copia de trabajo de siru" >&2
  exit 77   # skip, como espera automake
fi

T=$(mktemp -d)
trap 'rm -rf "$T"' EXIT

cat > "$T/cmp.py" <<'PY'
import json, sys
a, b = (json.load(open(f)) for f in sys.argv[1:3])
for d in (a, b): d.pop('OTHERINFO', None)
def diff(x, y, p):
    if type(x) != type(y) and not (isinstance(x, (int, float)) and isinstance(y, (int, float))):
        print(p, 'tipo:', repr(x)[:150], '|', repr(y)[:150]); return
    if isinstance(x, dict):
        for k in sorted(set(x) | set(y)):
            if k not in x: print(p + '/' + k, 'falta:', repr(y[k])[:150])
            elif k not in y: print(p + '/' + k, 'sobra:', repr(x[k])[:150])
            else: diff(x[k], y[k], p + '/' + k)
    elif isinstance(x, list):
        if len(x) != len(y): print(p, 'largo', len(x), len(y)); return
        for i, (u, v) in enumerate(zip(x, y)): diff(u, v, p + '[%d]' % i)
    elif x != y: print(p, repr(x)[:200], '|', repr(y)[:200])
diff(a, b, '')
PY

iguales=0; distintos=0; sin_fuente=0

while IFS= read -r dat; do
  dir=$(dirname "$dat")
  base=$(basename "$dat" .dat)
  # el nombre es el del .ds2: -desde-d marca el que salio del .d
  if [ "${base%-desde-d}" != "$base" ]; then
    f="$dir/${base%-desde-d}.d"
  elif [ -f "$dir/$base.ds" ]; then
    f="$dir/$base.ds"
  else
    f="$dir/$base.d"
  fi
  if [ ! -f "$f" ]; then
    sin_fuente=$((sin_fuente+1)); echo "sin fuente: $dat"; continue
  fi

  # igual que cuando se genero: si el archivo incluye examples/..., se corre
  # desde el directorio de arriba, como corria Siru
  desde=$dir
  grep -qiE '^[[:space:]]*#?[[:space:]]*(include|input)[[:space:]]+examples/' "$f" && desde=$(dirname "$dir")

  ( cd "$desde" && $E "$f" -o "$T/e.dat" 2>"$T/e.err" )
  if [ $? -ne 0 ]; then
    distintos=$((distintos+1))
    echo "d2datdinc falla: $f: $(head -c 200 "$T/e.err")"
    continue
  fi
  python3 "$T/cmp.py" "$T/e.dat" "$dat" > "$T/d"
  if [ -s "$T/d" ]; then
    distintos=$((distintos+1))
    echo "distinto: $f ($(wc -l < "$T/d") diferencias)"
    [ $detalle -eq 1 ] && sed 's/^/    /' "$T/d"
  else
    iguales=$((iguales+1))
  fi
  rm -f "$T/e.dat"
done < <(find "$DODS" -name '*.dat' -type f -not -path '*/.svn/*' | sort)

echo "iguales $iguales, distintos $distintos, sin fuente $sin_fuente"
exit $((distintos > 0 || sin_fuente > 0))
