1*01826a49SYabin Cui# CLI tests 2*01826a49SYabin Cui 3*01826a49SYabin CuiThe CLI tests are focused on testing the zstd CLI. 4*01826a49SYabin CuiThey are intended to be simple tests that the CLI and arguments work as advertised. 5*01826a49SYabin CuiThey are not intended to test the library, only the code in `programs/`. 6*01826a49SYabin CuiThe library will get incidental coverage, but if you find yourself trying to trigger a specific condition in the library, this is the wrong tool. 7*01826a49SYabin Cui 8*01826a49SYabin Cui## Test runner usage 9*01826a49SYabin Cui 10*01826a49SYabin CuiThe test runner `run.py` will run tests against the in-tree build of `zstd` and `datagen` by default. Which means that `zstd` and `datagen` must be built. 11*01826a49SYabin Cui 12*01826a49SYabin CuiThe `zstd` binary used can be passed with `--zstd /path/to/zstd`. 13*01826a49SYabin CuiAdditionally, to run `zstd` through a tool like `valgrind` or `qemu`, set the `--exec-prefix 'valgrind -q'` flag. 14*01826a49SYabin Cui 15*01826a49SYabin CuiSimilarly, the `--datagen`, and `--zstdgrep` flags can be set to specify 16*01826a49SYabin Cuithe paths to their respective binaries. However, these tools do not use 17*01826a49SYabin Cuithe `EXEC_PREFIX`. 18*01826a49SYabin Cui 19*01826a49SYabin CuiEach test executes in its own scratch directory under `scratch/test/name`. E.g. `scratch/basic/help.sh/`. Normally these directories are removed after the test executes. However, the `--preserve` flag will preserve these directories after execution, and save the tests exit code, stdout, and stderr in the scratch directory to `exit`, `stderr`, and `stdout` respectively. This can be useful for debugging/editing a test and updating the expected output. 20*01826a49SYabin Cui 21*01826a49SYabin Cui### Running all the tests 22*01826a49SYabin Cui 23*01826a49SYabin CuiBy default the test runner `run.py` will run all the tests, and report the results. 24*01826a49SYabin Cui 25*01826a49SYabin CuiExamples: 26*01826a49SYabin Cui 27*01826a49SYabin Cui``` 28*01826a49SYabin Cui./run.py 29*01826a49SYabin Cui./run.py --preserve 30*01826a49SYabin Cui./run.py --zstd ../../build/programs/zstd --datagen ../../build/tests/datagen 31*01826a49SYabin Cui``` 32*01826a49SYabin Cui 33*01826a49SYabin Cui### Running specific tests 34*01826a49SYabin Cui 35*01826a49SYabin CuiA set of test names can be passed to the test runner `run.py` to only execute those tests. 36*01826a49SYabin CuiThis can be useful for writing or debugging a test, especially with `--preserve`. 37*01826a49SYabin Cui 38*01826a49SYabin CuiThe test name can either be the path to the test file, or the test name, which is the path relative to the test directory. 39*01826a49SYabin Cui 40*01826a49SYabin CuiExamples: 41*01826a49SYabin Cui 42*01826a49SYabin Cui``` 43*01826a49SYabin Cui./run.py basic/help.sh 44*01826a49SYabin Cui./run.py --preserve basic/help.sh basic/version.sh 45*01826a49SYabin Cui./run.py --preserve --verbose basic/help.sh 46*01826a49SYabin Cui``` 47*01826a49SYabin Cui 48*01826a49SYabin Cui### Updating exact output 49*01826a49SYabin Cui 50*01826a49SYabin CuiIf a test is failing because a `.stderr.exact` or `.stdout.exact` no longer matches, you can re-run the tests with `--set-exact-output` and the correct output will be written. 51*01826a49SYabin Cui 52*01826a49SYabin CuiExample: 53*01826a49SYabin Cui``` 54*01826a49SYabin Cui./run.py --set-exact-output 55*01826a49SYabin Cui./run.py basic/help.sh --set-exact-output 56*01826a49SYabin Cui``` 57*01826a49SYabin Cui 58*01826a49SYabin Cui## Writing a test 59*01826a49SYabin Cui 60*01826a49SYabin CuiTest cases are arbitrary executables, and can be written in any language, but are generally shell scripts. 61*01826a49SYabin CuiAfter the script executes, the exit code, stderr, and stdout are compared against the expectations. 62*01826a49SYabin Cui 63*01826a49SYabin CuiEach test is run in a clean directory that the test can use for intermediate files. This directory will be cleaned up at the end of the test, unless `--preserve` is passed to the test runner. Additionally, the `setup` script can prepare the directory before the test runs. 64*01826a49SYabin Cui 65*01826a49SYabin Cui### Calling zstd, utilities, and environment variables 66*01826a49SYabin Cui 67*01826a49SYabin CuiThe `$PATH` for tests is prepended with the `bin/` sub-directory, which contains helper scripts for ease of testing. 68*01826a49SYabin CuiThe `zstd` binary will call the zstd binary specified by `run.py` with the correct `$EXEC_PREFIX`. 69*01826a49SYabin CuiSimilarly, `datagen`, `unzstd`, `zstdgrep`, `zstdcat`, etc, are provided. 70*01826a49SYabin Cui 71*01826a49SYabin CuiHelper utilities like `cmp_size`, `println`, and `die` are provided here too. See their scripts for details. 72*01826a49SYabin Cui 73*01826a49SYabin CuiCommon shell script libraries are provided under `common/`, with helper variables and functions. They can be sourced with `source "$COMMON/library.sh`. 74*01826a49SYabin Cui 75*01826a49SYabin CuiLastly, environment variables are provided for testing, which can be listed when calling `run.py` with `--verbose`. 76*01826a49SYabin CuiThey are generally used by the helper scripts in `bin/` to coordinate everything. 77*01826a49SYabin Cui 78*01826a49SYabin Cui### Basic test case 79*01826a49SYabin Cui 80*01826a49SYabin CuiWhen executing your `$TEST` executable, by default the exit code is expected to be `0`. However, you can provide an alternate expected exit code in a `$TEST.exit` file. 81*01826a49SYabin Cui 82*01826a49SYabin CuiWhen executing your `$TEST` executable, by default the expected stderr and stdout are empty. However, you can override the default by providing one of three files: 83*01826a49SYabin Cui 84*01826a49SYabin Cui* `$TEST.{stdout,stderr}.exact` 85*01826a49SYabin Cui* `$TEST.{stdout,stderr}.glob` 86*01826a49SYabin Cui* `$TEST.{stdout,stderr}.ignore` 87*01826a49SYabin Cui 88*01826a49SYabin CuiIf you provide a `.exact` file, the output is expected to exactly match, byte-for-byte. 89*01826a49SYabin Cui 90*01826a49SYabin CuiIf you provide a `.glob` file, the output is expected to match the expected file, where each line is interpreted as a glob syntax. Additionally, a line containing only `...` matches all lines until the next expected line matches. 91*01826a49SYabin Cui 92*01826a49SYabin CuiIf you provide a `.ignore` file, the output is ignored. 93*01826a49SYabin Cui 94*01826a49SYabin Cui#### Passing examples 95*01826a49SYabin Cui 96*01826a49SYabin CuiAll these examples pass. 97*01826a49SYabin Cui 98*01826a49SYabin CuiExit 1, and change the expectation to be 1. 99*01826a49SYabin Cui 100*01826a49SYabin Cui``` 101*01826a49SYabin Cuiexit-1.sh 102*01826a49SYabin Cui--- 103*01826a49SYabin Cui#!/bin/sh 104*01826a49SYabin Cuiexit 1 105*01826a49SYabin Cui--- 106*01826a49SYabin Cui 107*01826a49SYabin Cuiexit-1.sh.exit 108*01826a49SYabin Cui--- 109*01826a49SYabin Cui1 110*01826a49SYabin Cui--- 111*01826a49SYabin Cui``` 112*01826a49SYabin Cui 113*01826a49SYabin CuiCheck the stdout output exactly matches. 114*01826a49SYabin Cui 115*01826a49SYabin Cui``` 116*01826a49SYabin Cuiecho.sh 117*01826a49SYabin Cui--- 118*01826a49SYabin Cui#!/bin/sh 119*01826a49SYabin Cuiecho "hello world" 120*01826a49SYabin Cui--- 121*01826a49SYabin Cui 122*01826a49SYabin Cuiecho.sh.stdout.exact 123*01826a49SYabin Cui--- 124*01826a49SYabin Cuihello world 125*01826a49SYabin Cui--- 126*01826a49SYabin Cui``` 127*01826a49SYabin Cui 128*01826a49SYabin CuiCheck the stderr output using a glob. 129*01826a49SYabin Cui 130*01826a49SYabin Cui``` 131*01826a49SYabin Cuirandom.sh 132*01826a49SYabin Cui--- 133*01826a49SYabin Cui#!/bin/sh 134*01826a49SYabin Cuihead -c 10 < /dev/urandom | xxd >&2 135*01826a49SYabin Cui--- 136*01826a49SYabin Cui 137*01826a49SYabin Cuirandom.sh.stderr.glob 138*01826a49SYabin Cui--- 139*01826a49SYabin Cui00000000: * * * * * * 140*01826a49SYabin Cui``` 141*01826a49SYabin Cui 142*01826a49SYabin CuiMultiple lines can be matched with ... 143*01826a49SYabin Cui 144*01826a49SYabin Cui``` 145*01826a49SYabin Cuirandom-num-lines.sh 146*01826a49SYabin Cui--- 147*01826a49SYabin Cui#!/bin/sh 148*01826a49SYabin Cuiecho hello 149*01826a49SYabin Cuiseq 0 $RANDOM 150*01826a49SYabin Cuiecho world 151*01826a49SYabin Cui--- 152*01826a49SYabin Cui 153*01826a49SYabin Cuirandom-num-lines.sh.stdout.glob 154*01826a49SYabin Cui--- 155*01826a49SYabin Cuihello 156*01826a49SYabin Cui0 157*01826a49SYabin Cui... 158*01826a49SYabin Cuiworld 159*01826a49SYabin Cui--- 160*01826a49SYabin Cui``` 161*01826a49SYabin Cui 162*01826a49SYabin Cui#### Failing examples 163*01826a49SYabin Cui 164*01826a49SYabin CuiExit code is expected to be 0, but is 1. 165*01826a49SYabin Cui 166*01826a49SYabin Cui``` 167*01826a49SYabin Cuiexit-1.sh 168*01826a49SYabin Cui--- 169*01826a49SYabin Cui#!/bin/sh 170*01826a49SYabin Cuiexit 1 171*01826a49SYabin Cui--- 172*01826a49SYabin Cui``` 173*01826a49SYabin Cui 174*01826a49SYabin CuiStdout is expected to be empty, but isn't. 175*01826a49SYabin Cui 176*01826a49SYabin Cui``` 177*01826a49SYabin Cuiecho.sh 178*01826a49SYabin Cui--- 179*01826a49SYabin Cui#!/bin/sh 180*01826a49SYabin Cuiecho hello world 181*01826a49SYabin Cui``` 182*01826a49SYabin Cui 183*01826a49SYabin CuiStderr is expected to be hello but is world. 184*01826a49SYabin Cui 185*01826a49SYabin Cui``` 186*01826a49SYabin Cuihello.sh 187*01826a49SYabin Cui--- 188*01826a49SYabin Cui#!/bin/sh 189*01826a49SYabin Cuiecho world >&2 190*01826a49SYabin Cui--- 191*01826a49SYabin Cui 192*01826a49SYabin Cuihello.sh.stderr.exact 193*01826a49SYabin Cui--- 194*01826a49SYabin Cuihello 195*01826a49SYabin Cui--- 196*01826a49SYabin Cui``` 197*01826a49SYabin Cui 198*01826a49SYabin Cui### Setup & teardown scripts 199*01826a49SYabin Cui 200*01826a49SYabin CuiFinally, test writing can be eased with setup and teardown scripts. 201*01826a49SYabin CuiEach directory in the test directory is a test-suite consisting of all tests within that directory (but not sub-directories). 202*01826a49SYabin CuiThis test suite can come with 4 scripts to help test writing: 203*01826a49SYabin Cui 204*01826a49SYabin Cui* `setup_once` 205*01826a49SYabin Cui* `teardown_once` 206*01826a49SYabin Cui* `setup` 207*01826a49SYabin Cui* `teardown` 208*01826a49SYabin Cui 209*01826a49SYabin CuiThe `setup_once` and `teardown_once` are run once before and after all the tests in the suite respectively. 210*01826a49SYabin CuiThey operate in the scratch directory for the test suite, which is the parent directory of each scratch directory for each test case. 211*01826a49SYabin CuiThey can do work that is shared between tests to improve test efficiency. 212*01826a49SYabin CuiFor example, the `dictionaries/setup_once` script builds several dictionaries, for use in the `dictionaries` tests. 213*01826a49SYabin Cui 214*01826a49SYabin CuiThe `setup` and `teardown` scripts run before and after each test case respectively, in the test case's scratch directory. 215*01826a49SYabin CuiThese scripts can do work that is shared between test cases to make tests more succinct. 216*01826a49SYabin CuiFor example, the `dictionaries/setup` script copies the dictionaries built by the `dictionaries/setup_once` script into the test's scratch directory, to make them easier to use, and make sure they aren't accidentally modified. 217*01826a49SYabin Cui 218*01826a49SYabin Cui#### Examples 219*01826a49SYabin Cui 220*01826a49SYabin Cui``` 221*01826a49SYabin Cuibasic/setup 222*01826a49SYabin Cui--- 223*01826a49SYabin Cui#!/bin/sh 224*01826a49SYabin Cui# Create some files for testing with 225*01826a49SYabin Cuidatagen > file 226*01826a49SYabin Cuidatagen > file0 227*01826a49SYabin Cuidatagen > file1 228*01826a49SYabin Cui--- 229*01826a49SYabin Cui 230*01826a49SYabin Cuibasic/test.sh 231*01826a49SYabin Cui--- 232*01826a49SYabin Cui#!/bin/sh 233*01826a49SYabin Cuizstd file file0 file1 234*01826a49SYabin Cui--- 235*01826a49SYabin Cui 236*01826a49SYabin Cuidictionaries/setup_once 237*01826a49SYabin Cui--- 238*01826a49SYabin Cui#!/bin/sh 239*01826a49SYabin Cuiset -e 240*01826a49SYabin Cui 241*01826a49SYabin Cuimkdir files/ dicts/ 242*01826a49SYabin Cuifor i in $(seq 10); do 243*01826a49SYabin Cui datagen -g1000 > files/$i 244*01826a49SYabin Cuidone 245*01826a49SYabin Cui 246*01826a49SYabin Cuizstd --train -r files/ -o dicts/0 247*01826a49SYabin Cui--- 248*01826a49SYabin Cui 249*01826a49SYabin Cuidictionaries/setup 250*01826a49SYabin Cui--- 251*01826a49SYabin Cui#!/bin/sh 252*01826a49SYabin Cui 253*01826a49SYabin Cui# Runs in the test case's scratch directory. 254*01826a49SYabin Cui# The test suite's scratch directory that 255*01826a49SYabin Cui# `setup_once` operates in is the parent directory. 256*01826a49SYabin Cuicp -r ../files ../dicts . 257*01826a49SYabin Cui--- 258*01826a49SYabin Cui``` 259