(std test expect)

Reference

Overview

Snapshot tests: expect-output compares what a test wrote with a text in the test, and –promote updates the text.

(import (std prelude))
(import (std test))
(import (std test expect))

(deftest "printing a card"
  (print-value (Card (rank 12) (suit Hearts)))
  (expect-output """
    (Card (rank 12) (suit Hearts))
    """))

(run-tests)

expect-output compares the output of a test with a text that is written in the test. When they differ, the test fails, and the report shows a line diff. With --promote, the run writes the output into the test file in place of the text, and the test does not fail.

Which tests capture their output. deftest examines its body. When the body has the name expect-output anywhere in it, the output of the test goes to a string port, and current-output-port does not print it. A function that is defined outside the test and calls expect-output does not make the test capture its output. Then expect-output has no output to read, and the test fails.

What is compared. Each expect-output reads what the test wrote since the test started, or since the previous expect-output. Both texts are split into lines. Whitespace at the end of each line is removed, and empty lines at the start and the end of the text are removed. So a final newline, or a carriage return, is not a difference.

The diff. A line that only the expected text has starts with -, a line that only the output has starts with +, and a line that both have starts with a space:

FAIL printing two cards (cards_test.bjo:10)
  cards_test.bjo:13: the output is not the expected text (- expected, + written; --promote updates the text):
     (Card (rank 12) (suit Hearts))
    -(Card (rank 1) (suit Spades))
    +(Card (rank 1) (suit Clubs))

The longest common subsequence of the lines decides which lines both texts have. When the product of the two numbers of lines is more than a million, the diff shows all the expected lines with - and all the written lines with +.

Promotion. With --promote, an expect-output whose text differs records the output, and the test does not fail. At the end of (run-tests), through at-run-end!, the run writes the output into the test file in place of each text that differed, and prints a line for each file that it changed. The text must be a string literal that comes directly after expect-output, because the run looks for it there.

Finding the text. A promotion records the line of its expect-output and the text that the test ran with. The run looks on that line for an (expect-output whose literal still holds that text, and replaces only that literal. So two forms on one line are each found, and a form that was edited after the test was compiled is left alone: the run prints a line for it, and writes nothing in its place.

The new text. Output of one line, without a quote, a backslash or a tab, becomes a plain string: "done". Other output becomes a raw string. Its lines start 2 columns to the right of the column of the (expect-output, and the closing quotes are on a line of their own, in the same column. A raw string has more quotes than the longest run of quotes in the text, and at least three. Output that has no lines becomes "".

The file is changed from its last line to its first, and the forms on one line from the right, so that a change does not move the texts that are still to come. When one expect-output runs more than once in a run, for example in a for-all, the output of its first mismatch is written. run-test alone does not write the file.

Output that no expect-output reads. What the test wrote after its last expect-output is printed when the test ends, so that the prints of a test are not lost.

See also: expect-output, deftest

Reference

Functions

Macros

Functions

expect-output-check!

function ↑ Functions

(: expect-output-check! (-> string int string void))
(expect-output-check! file line wanted)

Compares the output of the running test with a text, and fails the test or records a promotion.

file
The source file of the expect-output.
line
The line of the expect-output.
wanted
The expected text.

It is exported because the template of expect-output names it. Write expect-output, not a call to this function.

When the running test does not capture its output, it fails the test with a message that says so.

See also: expect-output

Macros

expect-output

macro ↑ Macros

(expect-output text)

Passes when what the test wrote since it started, or since the previous expect-output, is the text.

text
A string: the expected output. Write it as a string literal, so that --promote can replace it.
(deftest "a greeting"
  (println "hello")
  (println "world")
  (expect-output """
    hello
    world
    """)
  (println "again")
  (expect-output "again"))

(deftest "prints nothing"
  (expect-output ""))

Write it in the body of a deftest, not in a function that the body calls: deftest captures the output of the test only when its body has the name expect-output.

Lines are compared without the whitespace at their ends, and without the empty lines at the start and the end of the text. On a mismatch, the test fails with a line diff. With --promote, the output is written into the test file in place of the text when the run ends, and the test does not fail. The module tells more.

For the output of one expression, check-output from (std test) is shorter. It captures the output also in a test whose body does not have the name expect-output.

See also: deftest, check-output