1

I am trying to write test cases in a script template which runs the function run_test_args that takes three commands: an optional command-line argument, a string of integers each separated by a space (ex "1 2 3 4 5") that serves as the user input of the program's prompt, and a string of the expected output. Since the program is to be tested using a large sequence of numbers, I am trying to use seq in place of the second argument in the following form: $(seq -s " " 100000) to generate 1 to 100,000 separated by spaces and formatted as a string.

However, when I run the test script, the function always recognizes the first element from the output of seq, which is 1 in the above case, as the user input, and the second element as the expected output.

How can I take the output from seq and format it as all one string rather than an array of strings (which is seems to be doing given how the function is receiving arguments)?

Here is the run_test_args function and the tests that use the seq command:

run_test_args() {
(( ++total ))
echo -n "Running test $total..."
expected=$3
local ismac=0
date --version >/dev/null 2>&1
if [ $? -ne 0 ]; then
   ismac=1
fi
local start=0
if (( ismac )); then
    start=$(python -c 'import time; print time.time()')
else
    start=$(date +%s.%N)
fi
(cat << ENDOFTEXT
$2
ENDOFTEXT
) > input.txt
if timeout $MAXTIME "cat input.txt | $command $1 2>&1 | tr -d '\r' > tmp.txt"; then
    echo "failure [timed out after $MAXTIME seconds]"
else
    received=$(cat tmp.txt)
    local end=$(date +%s.%N)
    if (( ismac )); then
        end=$(python -c 'import time; print time.time()')
    else
        end=$(date +%s.%N)
    fi
    local elapsed=$(echo "scale=3; $end - $start" | bc | awk '{printf "%.3f", $0}') 
    if [ "$expected" != "$received" ]; then
        echo -e "failure\n\nExpected$line\n$expected\n"
        echo -e "Received$line\n$received\n"
    else
        echo "success [$elapsed seconds]"
        (( ++num_right ))
    fi
fi
}

run_test_args "slow" $(seq 1 100000) "Enter sequence of integers, each followed by a space: Number of inversions: 0"
run_test_args "slow" $(seq -s " " 100000 -1 1) "Enter sequence of integers, each followed by a space: Number of inversions: 4999950000"

run_test_args "" $(seq -s " " 100000) "Enter sequence of integers, each followed by a space: Number of inversions: 0"
run_test_args "" $(seq -s " " 100000 -1 1) "Enter sequence of integers, each followed by a space: Number of inversions: 4999950000"
anandp773
  • 17
  • 1
  • 6
  • Show your script. – Cyrus Mar 29 '18 at 20:35
  • Here it is, the relevant lines are 115-116 and 132-133: https://pastebin.com/6CLdH1N1 – anandp773 Mar 29 '18 at 20:37
  • The shortest possible code necessary to reproduce a problem should be *included in the question itself*. See the docs on building a [mcve], and entry #1 in the "some questions are still off-topic" list at https://stackoverflow.com/help/on-topic. – Charles Duffy Mar 29 '18 at 20:39
  • 1
    In general, though, `s=$(seq ...)` *does* assign just one string, and if you use it in quotes, as `"$s"`, it'll remain so. If you don't quote everywhere you need to... well, there's your problem. (Similarly, `printf '%s\n' "$(seq 1 10)"` passes one string to `printf` with all your numbers, but `printf '%s\n' $(seq 1 10)`, without the quotes, passes each number as a separate argument). – Charles Duffy Mar 29 '18 at 20:40
  • Exactly what I said in the comment above -- you can't leave out the quotes. `"$(seq ...)"`, not `$(seq ...)` alone. – Charles Duffy Mar 29 '18 at 20:48
  • See http://shellcheck.net/ for some automated testing on your scripts. – Charles Duffy Mar 29 '18 at 20:51
  • BTW -- in general, `printf` should be used instead of `echo -e` or `echo -n`. `printf '%s\n' "first line: $var1" "second line: $var2"` is much safer, as only the format string is evaluated for escapes and such, and your variable contents (in subsequent arguments) will be literal; moreover, `echo -e` isn't permitted by the POSIX spec for `echo` -- meaning it's one of the very few places where bash isn't just extending the standard but breaking it outright. See the spec @ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html, particularly APPLICATION USAGE and RATIONALE sections. – Charles Duffy Mar 29 '18 at 20:54
  • ...I'd also suggest encapsulating your date logic: `if date --version >/dev/null 2>&1; then getdate() { date +%s.%N; }; else getdate() { python -c 'import time; print time.time()'; }; fi` or such, then just `start=$(getdate)` and `end=$(getdate)` thereafter -- and no `ismac` flag needed. – Charles Duffy Mar 29 '18 at 21:06
  • btw, do note that there's a limit on maximum allowed (command line length + environment variable size). A big sequence runs the risk of hitting that limit, if you pass it to an external command (vs a shell function, which doesn't call `execv` and thus isn't subject to the limit). – Charles Duffy Mar 29 '18 at 21:09

0 Answers0