Documentation ¶
Overview ¶
Package test provide library for helping with testing.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Assert ¶
Assert compare two interfaces: exp and got for equality. If both parameters are not equal, the function will call print and try to describe the position (type and value) where value are not matched and call Fatalf.
If exp implement the extended reflect.Equaler, then it will use the method IsEqual with got as parameter.
If exp and got is a struct, it will print the first non-matched field in the following format,
!!! Assert: [<name>: ] T.<Field>: expecting <type>(<value>), got <type>(<value>)
If both exp and got types are string and its longer than 50 chars, it will use the text/diff.Text to show the difference between them. The diff output is as follow,
!!! "string not matched" / <desc>: ---- <LINE_NUM> - "<STRING>" ... ++++ <LINE_NUM> + "<STRING>" ... --++ <LINE_NUM> - "<LINE_EXP>" <LINE_NUM> + "<LINE_GOT>" ^<COL_NUM> - "<DELETED_STRING>" ^<COL_NUM> + "<INSERTED_STRING>"
Any lines after "----" indicate the lines that deleted in got (exist in exp but not in got).
Any lines after "++++" indicate the lines that inserted in got (does not exist in exp but exist in got).
Any lines after "--++" indicate that the line between exp and got has words changes in it.
- The "<LINE_NUM> - " print the line in exp.
- The "<LINE_NUM> + " print the line in got.
- The "^<COL_NUM> - " print the position and the string deleted in exp (or string that not exist in got).
- The "^<COL_NUM> + " print the position and the string inserted in got (or string that not exist in exp).
WARNING: this method does not support recursive pointer, for example a node that point to parent and parent that point back to node again.
Example (String) ¶
var ( tw = testWriter{} exp string got string ) exp = `a string` got = `b string` Assert(&tw, ``, exp, got) fmt.Println(tw.String()) exp = `func (tw *testWriter) Fatal(args ...any) { fmt.Fprint(tw, args...) }` got = `func (tw *testWriter) Fatalf(format string, args ...any) { fmt.Fprintf(tw, format, args...) }` tw.Reset() Assert(&tw, ``, exp, got) fmt.Println(tw.String())
Output: !!! Assert: expecting string(a string), got string(b string) !!! strings not matched: --++ 0 - "func (tw *testWriter) Fatal(args ...any) { fmt.Fprint(tw, args...) }" 0 + "func (tw *testWriter) Fatalf(format string, args ...any) { fmt.Fprintf(tw, format, args...) }" ^27 - "(" ^41 - " " ^27 + "f(format string, " ^69 + "f" ^56 + ", format"
Example (Struct) ¶
type ADT struct { BigRat *big.Rat Int int Bytes []byte } var cases = []struct { desc string exp ADT got ADT }{{ desc: `On field struct`, exp: ADT{ BigRat: big.NewRat(123, 456), }, got: ADT{ BigRat: big.NewRat(124, 456), }, }, { desc: `On field int`, exp: ADT{ BigRat: big.NewRat(1, 2), Int: 1, }, got: ADT{ BigRat: big.NewRat(1, 2), Int: 2, }, }, { desc: `On field []byte`, exp: ADT{ Bytes: []byte(`hello, world`), }, got: ADT{ Bytes: []byte(`hello, world!`), }, }, { desc: `On field []byte, same length`, exp: ADT{ Bytes: []byte(`heelo, world!`), }, got: ADT{ Bytes: []byte(`hello, world!`), }, }} var ( tw = testWriter{} ) for _, c := range cases { Assert(&tw, c.desc, c.exp, c.got) fmt.Println(tw.String()) tw.Reset() }
Output: !!! Assert: On field struct: ADT.BigRat: Rat.a: Int.abs: nat[0]: expecting Word(41), got Word(31) !!! Assert: On field int: ADT.Int: expecting int(1), got int(2) !!! Assert: On field []byte: ADT.Bytes: len(): expecting 12, got 13 !!! Assert: On field []byte, same length: ADT.Bytes: [2]: expecting uint8(101), got uint8(108)
Types ¶
type Data ¶ added in v0.40.0
type Data struct { Flag map[string]string Input map[string][]byte Output map[string][]byte // The file name of the data. Name string Desc []byte }
Data contains predefined input and output values that is loaded from file to be used during test.
The data provides zero or more flags, an optional description, zero or more input, and zero or more output.
The data content use the following format,
[FLAG_KEY ":" FLAG_VALUE LF] [LF DESCRIPTION] ">>>" [INPUT_NAME] LF INPUT_CONTENT LF "<<<" [OUTPUT_NAME] LF OUTPUT_CONTENT
The data can contains zero or more flag. A flag is key and value separated by ":". The flag key must not contain spaces.
The data may contain description.
The line that start with "\n>>>" defined the beginning of input. An input can have a name, if its empty it will be set to "default". An input can be defined multiple times, with different names.
The line that start with "\n<<<" defined the beginning of output. An output can have a name, if its empty it will be set to "default". An output also can be defined multiple times, with different names.
All of both input and output content will have one new line truncated at the end. If they expecting new line at the end, add two empty lines at the end of it.
Example ¶
The following code illustrate how to use Data when writing test.
Assume that we are writing a parser that consume []byte. First we pass the input as defined in ">>>" and then we dump the result into bytes.Buffer to be compare with output "<<<".
func TestParse(t *testing.T) { var buf bytes.Buffer tdata, _ := LoadData("testdata/data.txt") opt := tdata.Flag["env"] p, err := Parse(tdata.Input["default"], opt) if err != nil { Assert(t, "Error", tdata.Output["error"], []byte(err.Error()) } fmt.Fprintf(&buf, "%v", p) want := tdata.Output["default"] got := buf.Bytes() Assert(t, tdata.Name, want, got) }
That is the gist, the real application can consume one or more input; or generate one or more output.
func LoadData ¶ added in v0.40.0
LoadData load data from file.
Example ¶
var ( data *Data name string content []byte err error ) // Content of data1_test.txt, // // key: value // Description of test1. // >>> // input. // // <<< // output. data, err = LoadData("testdata/data1_test.txt") if err != nil { log.Fatal(err) } fmt.Printf("%s\n", data.Name) fmt.Printf(" Flags=%v\n", data.Flag) fmt.Printf(" Desc=%s\n", data.Desc) fmt.Println(" Input") for name, content = range data.Input { fmt.Printf(" %s=%s\n", name, content) } fmt.Println(" Output") for name, content = range data.Output { fmt.Printf(" %s=%s\n", name, content) }
Output: data1_test.txt Flags=map[key:value] Desc=Description of test1. Input default=input. Output default=output.
func LoadDataDir ¶ added in v0.40.0
LoadDataDir load all data inside a directory. Only file that has file name suffix "_text.txt" will be loaded.
Example ¶
var ( listData []*Data data *Data err error name string content []byte ) listData, err = LoadDataDir("testdata/") if err != nil { log.Fatal(err) } for _, data = range listData { fmt.Printf("%s\n", data.Name) fmt.Printf(" Flags=%v\n", data.Flag) fmt.Printf(" Desc=%s\n", data.Desc) fmt.Println(" Input") for name, content = range data.Input { fmt.Printf(" %s=%s\n", name, content) } fmt.Println(" Output") for name, content = range data.Output { fmt.Printf(" %s=%s\n", name, content) } }
Output: data1_test.txt Flags=map[key:value] Desc=Description of test1. Input default=input. Output default=output. data2_test.txt Flags=map[] Desc= Input default=another test input. Output default=another test output.
type Writer ¶ added in v0.41.1
type Writer interface { Error(args ...any) Errorf(format string, args ...any) Fatal(args ...any) Fatalf(format string, args ...any) Log(args ...any) Logf(format string, args ...any) }
Writer contains common methods between testing.T and testing.B, a subset of testing.TB that cannot be used do private method.