commit 75d269fb6d9921f0090d9ec5ddf7880d25fd0247
parent b26d630f43826b38df0e7ec28242b28bb99178ab
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date: Wed, 13 Jan 2021 12:08:02 +0100
add rangetest for binary search testing of programs
Diffstat:
A | rangetest | | | 75 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 75 insertions(+), 0 deletions(-)
diff --git a/rangetest b/rangetest
@@ -0,0 +1,75 @@
+#!/usr/bin/awk -f
+# uses a binary search to run a "cmd" where the first occurence of
+# string @PARAM@ is substituted for a value between "min_val" and
+# max_val". Successful runs are reported on stdout, failed runs on
+# stderr. The "cmd" command must successfully run with either "min_val"
+# or "max_val".
+
+function die(s) {
+ printf "error: %s\n", s > "/dev/stderr"
+ exit 1
+}
+
+function launch(cmd, val) {
+ sub(/@PARAM@/, val, cmd)
+ if (system(cmd)) {
+ printf "%g\n", val > "/dev/stderr"
+ return 1
+ } else {
+ printf "%g\n", val > "/dev/stdout"
+ return 0
+ }
+}
+
+function binary_search(cmd, min, max, maxiter) {
+
+ minfail = launch(cmd, min)
+ maxfail = launch(cmd, max)
+
+ if (minfail && maxfail)
+ die("both min_val and max_val runs errored")
+
+ if (!minfail && !maxfail)
+ die("both min_val and max_val ran successfully")
+
+ while (min <= max && iter < maxiter) {
+ val = min + 0.5 * (max - min)
+
+ if (launch(cmd, val)) { # the cmd fails
+ if (maxfail) {
+ max = val
+ maxfail = 1
+ } else {
+ min = val
+ minfail = 1
+ }
+ } else { # the cmd is ok
+ if (maxfail) {
+ min = val
+ minfail = 0
+ } else {
+ max = val
+ maxfail = 0
+ }
+ }
+ iter++
+ }
+}
+
+BEGIN {
+
+ if (ARGC != 4)
+ die("usage: rangetest cmd min_val max_val")
+
+ cmd = ARGV[1]
+ min = ARGV[2]
+ max = ARGV[3]
+
+ if (!match(cmd, /@PARAM@/))
+ die("@PARAM@ not found in cmd")
+
+ if (min >= max)
+ die("min_val must be smaller than max_val")
+
+ binary_search(cmd, min, max, 20)
+}