#! /bin/bash
# Last edited on 2025-04-25 06:47:52 by stolfi

# To be executed in a subfolder of the "tests" subfolder
# of a library folder.
#
# Usage: "{cmd} {tprog} {ipref}.."
# 
# Compares the list of functions defined in the interfaces "../../{ipref}.h",
# for each given {ipref}, with the list of test functions defined
# in "{tprog}.c". Writes the differences to ".${tprog}.funcs.diff".
#
# The test program should define a function called {test_{func}} for 
# each function {func} defined in any of the interfaces.  A function
# that tests two or more functions {func1,func2,...} should be called
# {test_{func1}__{func2}__...}.
#
# If the test program does not intend to test a function {func},
# it should have a line somewhere containing the substrng 
# "!! {func} NOT TESTED"

tprog="$1"; shift
iprefs=( "$@" )

tmp="/tmp/$$"

echo '############################################################' 1>&2

# List of functions defined in the ".h" files:
f_lib_funcs="${tmp}-all.h.funcs" 
for ipref in "${iprefs[@]}"; do
  # Extract function definitions from the "{ipref}.h" file:
  if [[ ! ( -s ../../${ipref}.h ) ]]; then 
    echo "** ../../${ipref}.h does not exist" 1>&2 ; exit 1
  fi
  cat ../../${ipref}.h \
    | egrep -e '^[a-zA-Z]' \
    | sed \
        -e '/typedef/d' \
        -e 's:[(].*$::g' \
        -e 's:[ ][ ]*$::g' \
        -e 's:^.*[ *][ *]*::g' \
    > ${tmp}-${ipref}.h.funcs
done
cat ${tmp}-*.h.funcs \
  | sort | uniq \
  > ${f_lib_funcs}

# Extract "test__XXX" function definitions from the "{tprog}.c" file:
f_tested_funcs="${tmp}-${tprog}.c.funcs"
if [[ ! ( -s ${tprog}.c ) ]]; then 
  echo "** ${tprog}.c does not exist" 1>&2 ; exit 1
fi
cat ${tprog}.c \
  | egrep -e '^[ ]+(.*[=] *|)test[_]+[a-zA-Z][a-zA-Z0-9_]*[(][^()]*[)][;][ ]*$' \
  | sed \
      -e 's:^.*[=] *test[_][_]*::g' \
      -e 's:^ *test[_][_]*::g' \
      -e 's:[(].*$::g' \
      -e 's:__:@:g' \
  | tr '@' '\012' \
  | sed \
      -e 's:[ ][ ]*$::g' \
      -e 's:^[ ][ ]*::g' \
      -e '/^test$/d' \
  | sort | uniq \
  > ${f_tested_funcs}
  
# echo "--- RAW TESTED ---" 1>&2
# cat ${f_tested_funcs} 1>&2
  
# Extract "NOT TESTED" lines from the "{tprog}.c" file:
f_not_tested_funcs="${tmp}-${tprog}.c.nofuncs"
cat ${tprog}.c \
  | egrep -e 'NOT TESTED' \
  | sed \
      -e 's:.*[!][!] *::g' \
      -e 's: *NOT TESTED.*$: NOT TESTED:g' \
  | sort | uniq \
  > ${f_not_tested_funcs}
    
f_good=".${tprog}.funcs.good"
bool 1.2 ${f_lib_funcs} ${f_tested_funcs} > ${f_good}
if [[ -s ${f_good} ]]; then
  echo "--- tested ---" 1>&2
  cat ${f_good} 1>&2
fi
 
f_plus=".${tprog}.funcs.plus"
bool 2-1 ${f_lib_funcs} ${f_tested_funcs} > ${f_plus}
if [[ -s ${f_plus} ]]; then
  echo "--- apparently bogus tests ---" 1>&2
  cat ${f_plus} 1>&2
fi

f_miss=".${tprog}.funcs.miss"
( bool 1-2 ${f_lib_funcs} ${f_tested_funcs} ; cat ${f_not_tested_funcs} ) > ${f_miss}
if [[ -s ${f_miss} ]]; then
  echo "--- apparently NOT tested ---" 1>&2
  cat ${f_miss} 1>&2
fi

echo '############################################################' 1>&2

rm ${tmp}-*
