I received some feedback that it would be nice to present a short example on how you can use Tavor
https://github.com/zimmski/tavor. There is an example at
https://github.com/zimmski/tavor/blob/master/doc/complete-example.md which shows how a key-driven approach based on a state machine can be implemented, tested and debugged. It is still a little verbose, so I will give a shorter example for a file format fuzzer.
Imagine that we want to test a command line application which reads in a CSV file with three columns given as an argument.
- "name": Is a string starting with an uppercase letter followed by at least one and at maximum 9 lowercase letters
- "value": Is a number from 0 to 255
- "type": Is "true" or "false"
Testing this program seems very easy. We can immediately write a table-driven test and then we could write some test inputs manually. Sure, this would lead to a nice coverage but we would have to think and type a lot, and I can guarantee that some corner cases will be missed by some testers. Furthermore, what if we add a fourth column? All test inputs have to be rewritten. These are serious problems and we can make them go away by using Tavor to generate the test inputs.
First we define the format of the CSV file using the Tavor format
https://github.com/zimmski/tavor/blob/master/doc/format.md```
START = Columns *(Row)
Delimiter = ","
LineDelimiter = "\n"
Columns = "name" Delimiter "value" Delimiter "type" LineDelimiter
Row = Name Delimiter Value Delimiter Type LineDelimiter
Name = [A-Z] +1,9([a-z])
$Value Int = from: 0,
to: 255
Type = "true" | "false"
```Let's save this file as "csv.tavor". We can now use Tavor to generate test inputs:
tavor --format-file csv.tavor fuzzThis command will generate on each call a random test input such as:
```
name,value,type
```
```
name,value,type
Gbs,221,true
```
```
name,value,type
Tjedr,179,false
Jirrqxyl,120,true
```We could write the generated CSV data to files and then test our application or we could just use Tavor to test it directly:
tavor --format-file csv.tavor fuzz --exec "app TAVOR_FUZZ_FILE" --exec-argument-type argument --exec-exact-exit-code 0 --result-folder .This command will generate on each call a random test input, execute the application "app" with it and verify that the exit code is 0. If it is not 0 it is an error and the test input will be saved in the current folder. We can now run this command in a loop to test more than once. We can also use a different fuzzing strategy with the --strategy option so the test inputs are generated in a smarter way than just pure random.
Another example where Tavor is extremely useful is reducing data. Imagine that we have a CSV file with hundreds of rows which lets our application crash with another exit code. We could use the file directly and debug the application or we could use Tavor first to reduce the file to a smaller version where the crash is still present. Maybe it is just a single row of the hundreds of rows that crashes the application. Reducing the file first, will help us debug and save time. Using our format and the file "crash.csv", which lets our application crash, we can execute the following command:
tavor --format-file csv.tavor reduce --input-file crash.csv --exec "app TAVOR_DD_FILE" --exec-argument-type argument --exec-exact-exit-codeTavor will then reduce the rows and even the names until only the data is left which crashes the application.
I hope you liked this example and can incorporate Tavor into your own projects. If you have any questions just send me a mail or ask here in this thread. I am always happy to help out!
Cheers,
Markus