#!/bin/bash
# compara-din: d2datdinc --din contra los .din congelados del corpus.
#
#   siru/corpus/compara-din [-v] [DIRECTORIO]
#
# Al lado de los .d y .ds de corpus estan sus .din, que son la
# salida de d2datdinc --din congelada. Esta prueba los vuelve a generar en un
# directorio aparte y los compara. Es la regresion del corpus completo para el
# .din, la que faltaba: compara-dat hace lo mismo con el .dat.
#
# Son dos archivos por circuito, y no todos los dan:
#
#   NOMBRE-de-d2datdinc.din          el sistema del circuito; 162 de los 191
#   NOMBRE-de-d2datdinc-ED<N>.din    el de un metodo de Runge-Kutta; 80, los
#                                    que eligen metodo y tienen que integrar
#
# La corrida --desde, hasta, paso, parametros, estados-- va en las secciones
# comentadas del propio -ED<N>.din: no hay ningun archivo de configuracion.
#
# El sufijo dice quien lo hizo: hay tres generadores de .din --este, el
# dat2din de siru y el Simusol::Din de Simul 1-- y no escriben el mismo
# sistema.
#
# El .din se compara byte a byte: no lleva ninguna ruta adentro, asi que no
# depende de donde se genero.
#
# Tambien se avisa si aparece un .din que no estaba congelado o falta uno que
# si: el conjunto tiene que ser el mismo.
#
# Estado 0 si no hay ninguna diferencia. -v muestra cada una.
#
# Copyright (C) Diego Saravia <dsa@unsa.edu.ar>
# GPL version 3 o posterior.

# el sufijo que d2datdinc le pone a lo que escribe: hay tres generadores de
# .din y no escriben el mismo sistema (ver el README.md de dods)
QUIEN=-de-d2datdinc

# 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; }

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
fi

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

iguales=0; distintos=0; faltan=0; sobran=0

# El archivo fuente de un .din, por su nombre. No se mira el .dat: esta
# prueba va del .d o el .ds al .din y no necesita el intermedio, que es
# justamente lo que se quiere poder afirmar (PARSERS.md, paso 4).
fuente() {
  local din="$1" dir base
  dir=$(dirname "$din"); base=$(basename "$din" .din)
  base=${base%$QUIEN}                     # el sufijo del generador
  if [ "${base%-desde-d}" != "$base" ]; then echo "$dir/${base%-desde-d}.d"
  elif [ -f "$dir/$base.ds" ]; then echo "$dir/$base.ds"
  else echo "$dir/$base.d"; fi
}

while IFS= read -r base_din; do
  f=$(fuente "$base_din")
  [ -f "$f" ] || continue
  dir=$(dirname "$base_din")
  nom=$(basename "$base_din" .din); nom=${nom%$QUIEN}
  desde=$dir
  grep -qiE '^[[:space:]]*#?[[:space:]]*(include|input)[[:space:]]+examples/' "$f" && desde=$(dirname "$dir")

  salida=$T/salida
  rm -rf "$salida"; mkdir -p "$salida"
  ( cd "$desde" && $E --din --directorio "$salida" "$f" >/dev/null 2>&1 )

  # los congelados de este circuito
  for cong in "$dir/$nom$QUIEN.din" "$dir/$nom$QUIEN"-ED*.din; do
    [ -f "$cong" ] || continue
    bn=$(basename "$cong")
    if [ ! -f "$salida/$bn" ]; then
      faltan=$((faltan+1)); echo "falta: $cong"; continue
    fi
    if cmp -s "$cong" "$salida/$bn"; then
      iguales=$((iguales+1))
    else
      distintos=$((distintos+1)); echo "distinto: $cong"
      [ $detalle -eq 1 ] && diff "$cong" "$salida/$bn" | head -20 | sed 's/^/    /'
    fi
  done

  # y al reves: algo que se genero y no estaba congelado
  for nuevo in "$salida"/*; do
    [ -f "$nuevo" ] || continue
    bn=$(basename "$nuevo")
    [ -f "$dir/$bn" ] || { sobran=$((sobran+1)); echo "sin congelar: $dir/$bn"; }
  done
done < <(find "$DODS" -name "*$QUIEN.din" -type f -not -name "*-ED*" -not -path '*/.svn/*' | sort)

echo "iguales $iguales, distintos $distintos, faltan $faltan, sin congelar $sobran"
exit $(( distintos > 0 || faltan > 0 || sobran > 0 ))
