Writing a test script#
For each testbench in your test suite, you need to write a test script that MCY can call to run that testbench on a mutated design.
MCY will create a temporary directory, place a file named input.txt
with a numbered list of mutations in it, run your test script, and expect to find the return status of the testbench for each mutation in a correspondingly numbered list in a file named output.txt
. (By default, the list will only contain a single entry, as this is the most straightforward to use. The parameter maxbatchsize
can be set in the [test]
section of config.mcy
to increase the number of mutations included.)
The test script will usually consist of three steps: exporting the mutated source, running the testbench, and reporting the result.
Exporting the Mutated Source#
The first step is to obtain the modified source that includes the mutation(s) listed in input.txt
. The script create_mutated.sh
makes this painless as long as your testbench can accept verilog or rtlil sources for the mutated module. When executing the test, MCY sets the variable $SCRIPTS
to the path of the directory where you can find this script.
If you want to substitute a mutated verilog module with identical interface to the original, simply call it with no arguments:
bash $SCRIPTS/create_mutated.sh
This will result in a file named mutated.v
containing a mutated module with the same name as the original module being created in the temporary directory where the test is executed (task/<uuid>
).
If you want to use the maxbatchsize
parameter to test multiple mutations in a single call of the test script, call the script with -c
:
bash $SCRIPTS/create_mutated.sh -c
This will result in a file mutated.v
with a module of the same name but with an extra input signal mutsel
, which you can use to select which mutation to enable.
For more details about mutation generation, see Mutation export options.
Running the Testbench#
Substitute the mutated module for the original in your testbench sources (usually by replacing the source file in the sources list with mutated.v
). If you are testing a single mutation at a time and did not pass the -c
argument to create_mutated.sh
, you can now prepare and run your testbench as usual. The mutated module seamlessly replaces the original.
If you did enable multiple mutations to be included in the module, modify your testbench to add the mutsel
input to the mutated module. If your testbench is compiled, add a way to pass the value of mutsel
to the test at execution, e.g. via command line argument. The first column in input.txt
is the number that selects the corresponding mutation. Run the testbench for each value appearing in input.txt
.
For example, if using iverilog
(from the picorv32_primes
example):
iverilog -o sim ../../sim_simple.v mutated.v
while read idx mut; do
vvp -N sim +mut=${idx} > sim_${idx}.out
done < input.txt
Reporting the Result#
The results of the testbench run should be written to output.txt
. Each line should be the number identifying the mutation followed by a status. The status can be an arbitrary string not containing whitespace; however, any value not listed with the expect
keyword in the test section of config.mcy
is considered an error and will cause the mcy run to be aborted. Commonly used return values are “PASS”, “FAIL” and sometimes “TIMEOUT”.
If only a single mutation is evaluated at a time, the associated number is always 1
. In this case, simply write 1
followed by the outcome of the testbench to output.txt
:
if $test_ok; then
echo "1 PASS" > output.txt
else
echo "1 FAIL" > output.txt
fi
If more than one mutation are evaluated in a run, each result should be on its own line, preceded by the corresponding value of mutsel
. The order does not matter.
For the previous example with iverilog
:
while read idx mut; do
this_md5sum=$(md5sum sim_${idx}.out | awk '{ print $1; }')
if [ $good_md5sum = $this_md5sum ]; then
echo "$idx PASS" >> output.txt
else
echo "$idx FAIL" >> output.txt
fi
done < input.txt