#!/usr/bin/env bash # # Author: Lukas Bulwahn # # DESCRIPTION: mutant-testing for counterexample generators and automated tools PRG="$(basename "$0")" function usage() { [ -n "$MUTABELLE_OUTPUT_PATH" ] || MUTABELLE_OUTPUT_PATH="None" echo echo "Usage: isabelle $PRG [OPTIONS] THEORY" echo echo " Options are:" echo " -L LOGIC parent logic to use (default $MUTABELLE_LOGIC)" echo " -T THEORY parent theory to use (default $MUTABELLE_IMPORT_THEORY)" echo " -O DIR output directory for test data (default $MUTABELLE_OUTPUT_PATH)" echo " -N NUMBER number of lemmas to choose randomly, if not given all lemmas are chosen" echo " -M NUMBER number of mutants for each lemma (default $MUTABELLE_NUMBER_OF_MUTANTS)" echo " -X NUMBER number of mutations in a mutant (default $MUTABELLE_NUMBER_OF_MUTATIONS)" echo echo " THEORY is the name of the theory of which all theorems should be" echo " mutated and tested." echo exit 1 } ## process command line # options MUTABELLE_IMPORTS="" while getopts "L:T:O:N:M:X:" OPT do case "$OPT" in L) MUTABELLE_LOGIC="$OPTARG" ;; T) MUTABELLE_IMPORTS="$MUTABELLE_IMPORTS \"$OPTARG\"" ;; O) MUTABELLE_OUTPUT_PATH="$OPTARG" ;; N) NUMBER_OF_LEMMAS="$OPTARG" ;; M) MUTABELLE_NUMBER_OF_MUTANTS="$OPTARG" ;; X) MUTABELLE_NUMBER_OF_MUTATIONS="$OPTARG" ;; \?) usage ;; esac done shift $(($OPTIND - 1)) if [ "$MUTABELLE_IMPORTS" = "" ] then MUTABELLE_IMPORTS="$MUTABELLE_IMPORT_THEORY" fi [ "$#" -ne 1 ] && usage MUTABELLE_TEST_THEORY="$1" if [ -z "$MUTABELLE_OUTPUT_PATH" ]; then MUTABELLE_OUTPUT_PATH="${ISABELLE_TMP_PREFIX}-mutabelle$$" PURGE_OUTPUT="true" fi export MUTABELLE_OUTPUT_PATH if [ "$NUMBER_OF_LEMMAS" != "" ]; then MUTABELLE_FILTER="|> MutabelleExtra.take_random $NUMBER_OF_LEMMAS" fi ## main echo "Starting Mutabelle..." # setup mkdir -p "$MUTABELLE_OUTPUT_PATH" echo "theory Mutabelle_Test imports $MUTABELLE_IMPORTS uses \"$MUTABELLE_HOME/mutabelle.ML\" \"$MUTABELLE_HOME/mutabelle_extra.ML\" begin declare [[quickcheck_timeout = 30]] ML {* val mtds = [ MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"random\"])) \"random\", MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"random\"]) #> Config.put Quickcheck.finite_types false) \"random_int\", MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"exhaustive\"])) \"exhaustive\", MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"exhaustive\"]) #> Config.put Quickcheck.finite_types false) \"exhaustive_int\", MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"narrowing\"]) #> Config.put Quickcheck.finite_types true) \"narrowing\", MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"narrowing\"]) #> Config.put Quickcheck.finite_types false) \"narrowing_int\", MutabelleExtra.quickcheck_mtd (Context.proof_map (Quickcheck.set_active_testers [\"narrowing\"]) #> Config.put Quickcheck.finite_types false #> Context.proof_map (Quickcheck.map_test_params (apfst (K [@{typ nat}])))) \"narrowing_nat\" (*, MutabelleExtra.refute_mtd, *) , MutabelleExtra.nitpick_mtd ] *} ML {* fun mutation_testing_of thy = (MutabelleExtra.random_seed := 1.0; MutabelleExtra.thms_of false thy $MUTABELLE_FILTER |> (fn thms => MutabelleExtra.mutate_theorems_and_write_report @{theory} ($MUTABELLE_NUMBER_OF_MUTATIONS, $MUTABELLE_NUMBER_OF_MUTANTS) mtds thms (\"$MUTABELLE_OUTPUT_PATH/log\"))) *} ML {* mutation_testing_of @{theory $MUTABELLE_TEST_THEORY} *} end" > "$MUTABELLE_OUTPUT_PATH/Mutabelle_Test.thy" # execution isabelle process -o auto_time_limit=10.0 \ -T "$MUTABELLE_OUTPUT_PATH/Mutabelle_Test" -l "$MUTABELLE_LOGIC" > "$MUTABELLE_OUTPUT_PATH/err" 2>&1 [ $? -ne 0 ] && echo "isabelle processing of mutabelle failed" # make statistics function count() { cat "$MUTABELLE_OUTPUT_PATH/log" | grep "$1: $2" | wc -l | sed "s/ //" } function mk_stat() { printf "%-40s C:$(count $1 "GenuineCex") P:$(count $1 "PotentialCex") N:$(count $1 "NoCex") T:$(count $1 "Timeout") D:$(count $1 "Donno") E: $(count $1 "Error")\n" "$1" } mk_stat "quickcheck_random" mk_stat "quickcheck_random_int" mk_stat "quickcheck_exhaustive" mk_stat "quickcheck_exhaustive_int" mk_stat "quickcheck_narrowing" mk_stat "quickcheck_narrowing_int" mk_stat "quickcheck_narrowing_nat" ##mk_stat "refute" mk_stat "nitpick" ## cleanup if [ -n "$PURGE_OUTPUT" ]; then rm -rf "$MUTABELLE_OUTPUT_PATH" fi