Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@rtspecialty.com>2018-10-02 15:53:44 -0400
committerMike Gerwitz <mike.gerwitz@rtspecialty.com>2018-10-02 15:53:44 -0400
commitd251f7a79ba854a73a15d344bdad1627d21153a4 (patch)
tree3e2be060f52cf3f4f68046b9b1b348fcb01f5e86
parentbd65f433d25a4222e68b4a56ffcb3471ab47ef2b (diff)
parentbe59eb74a6573f036a766de4c9a9d625abf12e26 (diff)
downloadtame-3.2.0.tar.gz
tame-3.2.0.tar.bz2
tame-3.2.0.zip
csvm2csv: Syntax improvements and error checkingv3.2.0
-rw-r--r--Makefile.am2
-rwxr-xr-xbuild-aux/csvm2csv54
-rwxr-xr-xbuild-aux/test/test-csvm2csv269
3 files changed, 314 insertions, 11 deletions
diff --git a/Makefile.am b/Makefile.am
index 3546e5c..01ac8a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,6 +20,7 @@ SUBDIRS = doc progtest
path_src = src
path_test = test
+path_aux = build-aux
# all source files will be run through hoxsl; see `applies' target
apply_src := $(shell find "$(path_src)" "$(path_test)" \
@@ -49,6 +50,7 @@ applies: $(apply_dest)
test: check
check: | applies
+ for test in $(path_aux)/test/test-*; do ./$$test || exit 1; done
$(path_test)/runner
progtest: FORCE
diff --git a/build-aux/csvm2csv b/build-aux/csvm2csv
index a67f43e..addbe26 100755
--- a/build-aux/csvm2csv
+++ b/build-aux/csvm2csv
@@ -2,7 +2,7 @@
#
# Compiles a "magic" CSV file into a normal CSV
#
-# Copyright (C) 2016 R-T Specialty, LLC.
+# Copyright (C) 2016, 2018 R-T Specialty, LLC.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,6 +45,28 @@
##
+# Expand variable with its value, if any
+function expand_vars( s, value )
+{
+ # attempt to parse variable (may expand into a range)
+ if ( match( s, /^\$([a-zA-Z_-]+)$/, m ) )
+ {
+ value = vars[ m[1] ];
+
+ if ( value == "" )
+ {
+ print "error: unknown variable reference: `$" m[1] "'" > "/dev/stderr"
+ exit 1
+ }
+
+ return value
+ }
+
+ return s
+}
+
+
+# Expand line
function parseline( i, m, j, me, orig )
{
if ( i > NF )
@@ -55,6 +77,10 @@ function parseline( i, m, j, me, orig )
orig = $i
+ # expand variables before any processing so that expansions
+ # can include any type of formatting
+ $i = expand_vars( $i )
+
if ( match( $i, /^([0-9]+\/){2}[0-9]+$/, m ) )
{
cmd = "date --date=" $i " +%s"
@@ -78,17 +104,18 @@ function parseline( i, m, j, me, orig )
return
}
- # attempt to parse variable (may expand into a range)
- if ( match( $i, /^\$([a-zA-Z_-]+)$/, m ) )
- {
- $i = vars[ m[1] ];
- }
-
# parse range
- if ( match( $i, /^([0-9]+)--([0-9]+)$/, m ) )
+ if ( match( $i, /^([^-]+)--([^-]+)$/, m ) )
{
- j = m[1]
- me = m[2]
+ j = expand_vars( m[1] )
+ me = expand_vars( m[2] )
+
+ if ( !match( j, /^[0-9]+$/ ) || !match( me, /^[0-9]+$/ ) )
+ {
+ print "error: invalid range: `" $i "'" > "/dev/stderr"
+ exit 1
+ }
+
do
{
$i = j
@@ -117,7 +144,12 @@ BEGIN {
# lines that begin with a colon are variable definitions
/^:/ {
- match( $0, /^:([a-zA-Z_-]+)=(.*?)$/, m )
+ if ( !match( $0, /^:([a-zA-Z_-]+)=(.*?)$/, m ) )
+ {
+ print "error: invalid variable definition: `" $0 "'" > "/dev/stderr"
+ exit 1
+ }
+
vars[ m[1] ] = m[2]
next
}
diff --git a/build-aux/test/test-csvm2csv b/build-aux/test/test-csvm2csv
new file mode 100755
index 0000000..14ef407
--- /dev/null
+++ b/build-aux/test/test-csvm2csv
@@ -0,0 +1,269 @@
+#!/bin/bash
+# Test csvm2csv
+#
+# Copyright (C) 2018 R-T Specialty, LLC.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+cd "$( dirname "$0" )"
+
+
+# just to ensure that we run all the tests
+declare -i testsum=0
+
+
+# Run test case with input and expected values
+run-test()
+{
+ local -r input="${1?Missing input}"
+ local -r expected="${2?Missing expected}"
+
+ ((testsum++))
+
+ # SUT invocation
+ declare -r given=$( ../csvm2csv < <( cat <<< "$input" ) )
+
+ test $? -eq 0 || return 1
+
+ # expected output
+ diff <( cat <<< "$expected" ) <( cat <<< "$given" )
+}
+
+
+
+test-comment()
+{
+ local -r input='# comment before header should be removed
+header, line
+# this is also a comment
+1, 2
+# which should be ignored
+3, 4'
+
+ local -r expected='header,line
+1,2
+3,4'
+
+ run-test "$input" "$expected"
+}
+
+
+test-range()
+{
+ declare -r input='header, line
+1--3, 2
+3--5, 4--6'
+
+ declare -r expected='header,line
+1,2
+2,2
+3,2
+3,4
+3,5
+3,6
+4,4
+4,5
+4,6
+5,4
+5,5
+5,6'
+
+ run-test "$input" "$expected"
+}
+
+
+test-delim()
+{
+ declare -r input='header, line
+1;4, 2
+4;3, 6;9'
+
+ declare -r expected='header,line
+1,2
+4,2
+4,6
+4,9
+3,6
+3,9'
+
+ run-test "$input" "$expected"
+}
+
+
+test-var()
+{
+ declare -r input='header, line
+:foo=1
+:bar_baz-quux=2
+$foo,1
+$bar_baz-quux,$foo'
+
+ declare -r expected='header,line
+1,1
+2,1'
+
+ run-test "$input" "$expected"
+}
+
+
+test-range-delim()
+{
+ declare -r input='header, line
+1--3;5--6, 2'
+
+ declare -r expected='header,line
+1,2
+2,2
+3,2
+5,2
+6,2'
+
+ run-test "$input" "$expected"
+}
+
+
+test-var-in-range-delim()
+{
+ declare -r input='header, line
+:foo=1
+:bar=3
+$foo--$bar, $foo;$bar'
+
+ declare -r expected='header,line
+1,1
+1,3
+2,1
+2,3
+3,1
+3,3'
+
+ run-test "$input" "$expected"
+}
+
+
+test-var-with-range-delim()
+{
+ declare -r input='header, line
+:foo=1--2;4
+:bar=5
+$foo;$bar, 1'
+
+ declare -r expected='header,line
+1,1
+2,1
+4,1
+5,1'
+
+ run-test "$input" "$expected"
+}
+
+
+test-var-with-var()
+{
+ declare -r input='header, line
+:foo=2
+:bar=4
+:range=$foo--$bar
+:baz=$range;$foo
+$baz, 5'
+
+ declare -r expected='header,line
+2,5
+3,5
+4,5
+2,5'
+
+ run-test "$input" "$expected"
+}
+
+
+# :foo=0 should be considered to be defined
+test-var-zero-ref()
+{
+ declare -r input='header, line
+:foo=0
+$foo'
+
+ declare -r expected='header,line
+0'
+
+ run-test "$input" "$expected"
+}
+
+
+test-fail-unknown-var-ref()
+{
+ ((testsum++))
+
+ local -r result=$(
+ ../csvm2csv 2>&1 <<< '$undefined' \
+ && echo '(test failure: expected failure)'
+ )
+
+ grep -q 'unknown.*\$undefined' <<< "$result" \
+ || return 1
+}
+
+
+test-fail-non-numeric-range()
+{
+ ((testsum++))
+
+ local -r result=$(
+ ../csvm2csv 2>&1 <<< 'A--Z' \
+ && echo '(test failure: expected failure)'
+ )
+
+ grep -q 'invalid range.*A--Z' <<< "$result" \
+ || return 1
+}
+
+
+test-fail-invalid-var-dfn()
+{
+ ((testsum++))
+
+ local -r result=$(
+ ../csvm2csv 2>&1 <<< ':BAD@#=var' \
+ && echo '(test failure: expected failure)'
+ )
+
+ grep -q 'invalid variable definition.*:BAD@#=var' <<< "$result" \
+ || return 1
+}
+
+
+test-comment \
+ && test-range \
+ && test-delim \
+ && test-var \
+ && test-range-delim \
+ && test-var-in-range-delim \
+ && test-var-with-range-delim \
+ && test-var-with-var \
+ && test-var-zero-ref \
+ && test-fail-unknown-var-ref \
+ && test-fail-non-numeric-range \
+ && test-fail-invalid-var-dfn \
+ || {
+ echo 'csvm2csv test failed' >&2
+ exit 1
+ }
+
+# safety check
+test "$testsum" -eq 12 || {
+ echo 'error: did not run all csvm2csv tests!' >&2
+ exit 1
+}