Documentation ¶
Overview ¶
go-tutl is a Trivial Unit Testing Library (for Go). Example usage:
package duration import ( "testing" u "github.com/TyeMcQueen/go-tutl" _ "github.com/TyeMcQueen/go-tutl/hang" // ^C gives stack dumps. ) func TestDur(t *testing.T) { u.Is("1m 1s", DurationAsText(61), "61", t) got, err := TextAsDuration("1h 5s") u.Is(nil, err, "Error from '1h 5s'", t) u.Is(60*60+5, got, "'1h 5s'", t) got, err = TextAsDuration("3 fortnight") u.Like(err, "Error from '3 fortnight'", t, "(Unknown|Invalid) unit", "*fortnight") }
See also "go doc github.com/TyeMcQueen/go-tutl/hang".
Index ¶
- Constants
- Variables
- func AtInterrupt(f func()) func()
- func Char(c byte) string
- func Circa(digits int, want, got float64, desc string, t TestingT) bool
- func DoubleQuote(s string) string
- func Escape(r rune) string
- func EscapeNewline(b bool)
- func GetPanic(run func()) (failure interface{})
- func HasType(want string, got interface{}, desc string, t TestingT) bool
- func Is(want, got interface{}, desc string, t TestingT) bool
- func IsNot(hate, got interface{}, desc string, t TestingT) bool
- func Like(got interface{}, desc string, t TestingT, match ...string) int
- func ReplaceNewlines(s string) string
- func Rune(r rune) string
- func S(vs ...interface{}) string
- func ShowStackOnInterrupt(show ...bool)
- func V(v interface{}) string
- type FakeTester
- type Options
- func (o Options) Circa(digits int, want, got float64, desc string, t TestingT) bool
- func (o *Options) EscapeNewline(b bool)
- func (o Options) HasType(want string, got interface{}, desc string, t TestingT) bool
- func (o Options) Is(want, got interface{}, desc string, t TestingT) bool
- func (o Options) IsNot(hate, got interface{}, desc string, t TestingT) bool
- func (o Options) Like(got interface{}, desc string, t TestingT, match ...string) int
- func (o *Options) ReplaceNewlines(s string) string
- func (o Options) S(vs ...interface{}) string
- func (o Options) V(v interface{}) string
- type TUTL
- func (u TUTL) Char(c byte) string
- func (u TUTL) Circa(digits int, want, got float64, desc string) bool
- func (u TUTL) DoubleQuote(s string) string
- func (u TUTL) Escape(r rune) string
- func (u *TUTL) EscapeNewline(b bool)
- func (_ TUTL) GetPanic(run func()) interface{}
- func (u TUTL) HasType(want string, got interface{}, desc string) bool
- func (u TUTL) Is(want, got interface{}, desc string) bool
- func (u TUTL) IsNot(hate, got interface{}, desc string) bool
- func (u TUTL) Like(got interface{}, desc string, match ...string) int
- func (u *TUTL) ReplaceNewlines(s string) string
- func (u TUTL) Rune(r rune) string
- func (u TUTL) S(vs ...interface{}) string
- func (u TUTL) SetDigits32(d int)
- func (u TUTL) SetDigits64(d int)
- func (u *TUTL) SetLineWidth(w int)
- func (u *TUTL) SetPathLength(l int)
- func (u TUTL) V(v interface{}) string
- type TestingT
Constants ¶
const MaxDigits32 = 7
const MaxDigits64 = 15
Variables ¶
var Default = Options{ LineWidth: 72, PathLength: 20, Digits32: 5, Digits64: 12, // contains filtered or unexported fields }
The 'tutl.Default' global contains the user preferences to be used unless you make a copy and use it, such as via New() (see Options for more).
var StdoutTester = FakeTester{os.Stdout, false}
The 'tutl.StdoutTester' is a replacement for a '*testing.T' that just writes output to 'os.Stdout'.
Functions ¶
func AtInterrupt ¶
func AtInterrupt(f func()) func()
AtInterrupt registers a function to be called if the test run is interrupted (by the user typing Ctrl-C or whatever sends SIGINT). The function registered first is run last. You must have called ShowStackOnInterrupt() or AtInterrupt() will do nothing useful.
The function passed in is also returned. This can be useful for clean-up code that should be run whether the test run is interrupted or not:
defer tutl.AtInterrupt(cleanup)()
If you want to empower AtInterrupt() even if ShowStackOnInterrupt() has not been enabled, then your code can call:
go tutl.ShowStackOnInterrupt(false)
This does nothing if ShowStackOnInterrupt() had already been called (in particular, it does not disable the showing of stack traces). Otherwise, it does the work that it would normally do except, if a SIGINT is received, it will only run any functions registered via AtInterrupt() but will not show stack traces.
func Char ¶
Char(c) is similar to Rune(rune(c)), except it escapes all byte values of 0x80 and above into 6-character strings like '\x9B' (rather then converting them UTF-8).
func Circa ¶
Circa() tests that the 2nd and 3rd arguments are approximately equal to each other. If they are not, then a diagnostic is displayed which also causes the unit test to fail.
The diagnostic is similar to "Got {got} not {want} for {desc}.\n" where 'want' and 'got' are shown formatted via 'fmt.Sprintf("%.*g", digits, v)'. They are considered equal if that formatting produces the same string for both values. That is, 'want' and 'got' are considered roughly equal if they are the same to 'digits' significant digits. Passing 'digits' as less than 1 or more than 15 is not useful.
Circa() returns whether the test passed, which is useful for skipping tests that would make no sense to run given a prior failure or to display extra debug information only when a test fails.
func DoubleQuote ¶
DoubleQuote() returns the string enclosed in double quotes and with contained \ and " characters escaped.
func Escape ¶
Escape() returns a string containing the passed-in rune, unless it is a control character. Runes '\n', '\r', and '\t' each return a 2-character string (\n, \r, or \t). Other 7-bit control characters are turned into strings like \x1B. The 8-bit control characters are turned into strings like \u009B. EscapeNewline(false) does not affect Escape().
func EscapeNewline ¶
func EscapeNewline(b bool)
After calling EscapeNewline(true), S() will escape '\n' characters. You can call EscapeNewline(false) to restore the default behavior.
func GetPanic ¶ added in v1.1.1
func GetPanic(run func()) (failure interface{})
GetPanic() calls the passed-in function and returns 'nil' or the argument that gets passed to panic() from within it. This can be used in other test functions, for example:
u := tutl.New(t) u.Is(nil, u.GetPanic(func(){ obj.Method(nil) }), "Method panic")
func HasType ¶
HasType() tests that the type of the 2nd argument ('got') is equal to the first argument ('want', a string). That is, it checks that 'want == fmt.Sprintf("%T", got)'. If not, then a diagnostic is displayed which also causes the unit test to fail.
The diagnostic is similar to "Got {got} not {want} for {desc}.\n" where '{got}' is the data type of 'got' and '{want}' is just the 'want' string.
If 'got' is an 'interface' type, then the type string will be the type of the underlying object (or "nil"). If you actually wish to compare the 'interface' type, then place '&' before 'got' and prepend "*" to 'want':
got := GetReader() // Returns io.Reader interface to an *os.File tutl.HasType("*os.File", got, "underlying type is *os.File", t) tutl.HasType("*io.Reader", &got, "interface type is io.Reader", t) // ^ ^ insert these to test interface type
HasType() returns whether the test passed, which is useful for skipping tests that would make no sense to run given a prior failure.
func Is ¶
Is() tests that the first two arguments are converted to the same string by V(). If they are not, then a diagnostic is displayed which also causes the unit test to fail.
The diagnostic is similar to "Got {got} not {want} for {desc}.\n" except that; 1) S() is used for 'got' and 'want' so control characters will be escaped and their values may be in quotes and 2) it will be split onto multiple lines if the values involved are long enough.
Note that you pass 'want' before 'got' when calling Is() because the 'want' value is often a simple constant while 'got' can be a complex call and code is easier to read if you put shorter things first. But the output shows 'got' before 'want' as "Got X not Y" is the shortest way to express that concept in English.
Is() returns whether the test passed, which is useful for skipping tests that would make no sense to run given a prior failure or to display extra debug information only when a test fails.
func IsNot ¶
IsNot() tests that the first two arguments are converted to different strings by V(). If they are not, then a diagnostic is displayed which also causes the unit test to fail. The diagnostic is similar to "Got unwanted {got} for {desc}.\n" except that S() is used for 'got' so control characters will be escaped and their values may be in quotes.
IsNot() returns whether the test passed, which is useful for skipping tests that would make no sense to run given a prior failure.
func Like ¶
Like() is most often used to test error messages (or other complex strings). It lets you perform multiple tests against a single value. Each test checks that the value converts into a string that either contains a specific sub-string (ignoring letter case) or that it matches a regular expression. You must pass at least one string to be matched.
Strings that start with "*" have the "*" stripped before a substring match is performed (ignoring letter case). If a string does not start with a "*", then it must be a valid regular expression that will be matched against the value's string representation.
Except that strings that start with "!" have that stripped before checking for a subsequent "*". The "!" negates the match so that the test will only pass if the string does not match. To specify a regular expression that starts with a "!" character, simply escape it as `\!` or "[!]".
Like() returns the number of matches that failed.
If 'got' is 'nil', the empty string, or becomes the empty string, then no comparisons are done and a single failure is reported (but the number returned is the number of match strings as it is assumed that none of them would have matched the empty string).
func ReplaceNewlines ¶
ReplaceNewlines() returns a string with each newline replaced with either an escaped newline (a \ then an 'n') or with the string "\n...." (so that subsequent lines of a multi-line value are indented to make them easier to distinguish from subsequent lines of a test diagnostic).
func Rune ¶
Rune() returns a string consisting of the rune enclosed in single quotes, except that control characters are escaped [see Escape()].
Note that neither ' nor \ characters are escaped so Char('\”) returns "”'" (3 apostrophes) and Char('\\') returns `'\'` (partly because `'\”` and `'\\'` are rather ugly).
func S ¶
func S(vs ...interface{}) string
S() returns a single string composed by converting each argument into a string and concatenating all of those strings. It is similar to but not identical to 'fmt.Sprint()'. S() never inserts spaces between your values (if you want spaces, it is easy for you to add them). S() puts single quotes around 'byte' (and 'uint8') values. S() treats '[]byte' values like 'string's. S() puts double quotes around '[]byte' and 'error' values (escaping enclosed " and \ characters).
S() escapes control characters except for newlines [but see EscapeNewline()]. S() also escapes non-UTF-8 byte sequences.
If S() is passed a single argument that is a 'string', then it will put double quotes around it and escape any contained " and \ characters.
See V() for how 'float32', 'float64', '[]float32', or '[]float64' values are converted.
Note that S() does not put single quotes around 'rune' values as 'rune' is just an alias for 'int32' so S('x') == S(int32('x')) == "120" while S("x"[0]) == S(byte('x')) == S(uint8('x')) = "'x'".
func ShowStackOnInterrupt ¶
func ShowStackOnInterrupt(show ...bool)
If you have a TestMain() function, then you can add
go tutl.ShowStackOnInterrupt()
to it to allow you to interrupt it (such as via typing Ctrl-C) in order to see stack traces of everything that is running. This is particularly useful if your code has an infinite loop.
See also "go doc github.com/TyeMcQueen/go-tutl/hang".
ShowStackOnInterrupt() can also be used from non-test programs.
ShowStackOnInterrupt(false) has a special meaning; see AtInterrupt().
func V ¶
func V(v interface{}) string
V() just converts a value to a string. It is similar to 'fmt.Sprint(v)'. But it treats '[]byte' values as 'string's. It also (by default) uses fewer significant digits when converting 'float32', 'float64', '[]float32', and '[]float64' values (see Options for details).
Types ¶
type FakeTester ¶
A FakeTester is a replacement for a '*testing.T' so that you can use TUTL's functionality outside of a real 'go test' run.
func (FakeTester) Error ¶
func (out FakeTester) Error(args ...interface{})
func (FakeTester) Errorf ¶
func (out FakeTester) Errorf(format string, args ...interface{})
func (FakeTester) Failed ¶
func (out FakeTester) Failed() bool
func (FakeTester) Helper ¶
func (out FakeTester) Helper()
func (FakeTester) Log ¶
func (out FakeTester) Log(args ...interface{})
func (FakeTester) Logf ¶
func (out FakeTester) Logf(format string, args ...interface{})
type Options ¶
type Options struct { // LineWidth influences when "Got {got} not {want} for {title}" output // gets split onto multiple lines instead. If that string is longer // than LineWidth, then it gets split into "Got ...\nnot ...\n...". // // This also happens if you aren't escaping newlines and either value // contains a newline (and the newlines get indentation added so that // the output is easier to understand). // // If the diagnostic line is no longer than LineWidth but is longer than // LineWidth-PathLength, then a newline gets prepended to it as the // prepended source info would likely cause the diagnostic to wrap. // LineWidth int // PathLength is the maximum expected length of the path to the // *_test.go file being run plus the line number that 'go test' // prepends to each diagnostic. It defaults to 20. // PathLength int // Digits32 specifies how many significant digits to use when comparing // 'float32' values. In particular, if a 'float32' or '[]float32' value // is passed to V(), then no more than Digits32 significant digits are // used in the resulting string. Other data structures that contain // 'float32' values are not impacted. // // If Digits32 is 0, then the default value of 5 is used. If Digits32 // is negative or more than 7, then 'fmt.Sprint()' is used which may // use even 8 digits for some values (such as 1/3) so that 2 'float32' // values that are even very slightly different will produce different // strings (a 'float32' is accurate to only slightly more than 7 digits). // Digits32 int // Digits64 specifies how many significant digits to use when comparing // 'float64' values. In particular, if a 'float64' or '[]float64' value // is passed to V(), then no more than Digits64 significant digits are // used in the resulting string. Other data structures that contain // 'float64' values are not impacted. // // If Digits64 is 0, then the default value of 12 is used. If Digits64 // is negative or more than 16, then 'fmt.Sprint()' is used which may // use up to 16 digits so that 2 'float64' values that are even very // slightly different will produce different strings (a 'float64' is // accurate to only slightly less than 16 digits). // Digits64 int // contains filtered or unexported fields }
Options contains user preference options. The 'tutl.Default' global is the Options used unless you make a copy of it and use the copy.
Calling tutl.New(t) associates such a copy with the returned object so changes to preferences via the returned object don't modify 'Default'.
func TestFoo(t *testing.T) { u := tutl.New(t) u.SetLineWidth(120) u.Is(want, got(), "") // Uses 120-character line width. tutl.Is(want, got(), "", t) // Uses tutl.Default's line width. }
You can modify some options directly via 'tutl.Default', such as:
tutl.Default.LineWidth = 120
func (*Options) EscapeNewline ¶
See tutl.EscapeNewline() for documentation.
func (*Options) ReplaceNewlines ¶
See tutl.ReplaceNewlines() for documentation.
type TUTL ¶
type TUTL struct { TestingT // contains filtered or unexported fields }
TUTL is a type used to allow an alternate calling style, especially for Is() and Like().
func New ¶
A unit test can have a huge number of calls to Is(). Having to remember to pass in the *testing.T argument can be inconvenient. TUTL offers an alternate calling method that replaces the huge number of such extra arguments with a single line of code. This example code:
import ( "testing" u "github.com/TyeMcQueen/go-tutl" ^^ Import alias ) func TestDur(t *testing.T) { u.Is("1m 1s", DurationAsText(61), "61", t) // ^^^ Extra argument u.Like(Valid("3f", "Error from '3f'", t, "(Unknown|Invalid) unit") // ^^^ Extra argument }
would become:
import ( "testing" "github.com/TyeMcQueen/go-tutl" ) func TestDur(t *testing.T) { var u = tutl.New(t) // ^^^^^^^^^^^^^^^^ Added line u.Is("1m 1s", DurationAsText(61), "61") u.Like(Valid("3f", "Error from '3f'", "(Unknown|Invalid) unit") }
Whether to use an import alias or New() (or neither) is mostly a personal preference. Though, using New() also limits the scope of EscapeNewline() and other options.
New() also copies the current settings from the global 'tutl.Default' into the returned object.
func (TUTL) Circa ¶
Same as the non-method tutl.Circa() except the '*testing.T' argument is held in the TUTL object and so does not need to be passed as an argument.
func (TUTL) DoubleQuote ¶
Identical to the non-method tutl.DoubleQuote().
func (*TUTL) EscapeNewline ¶
Same as the EscapeNewline() method on the 'tutl.Default' global, except it only changes the setting for the invoking TUTL object.
func (TUTL) GetPanic ¶ added in v1.1.1
func (_ TUTL) GetPanic(run func()) interface{}
GetPanic() calls the passed-in function and returns 'nil' or the argument that gets passed to panic() from within it. This can be used in other test functions, for example:
u.Is(nil, u.GetPanic(func(){ obj.Method(nil) }), "Method panic")
func (TUTL) HasType ¶
Same as the non-method tutl.HasType() except the '*testing.T' argument is held in the TUTL object and so does not need to be passed as an argument.
func (TUTL) Is ¶
Same as the non-method tutl.Is() except the '*testing.T' argument is held in the TUTL object and so does not need to be passed as an argument.
func (TUTL) IsNot ¶
Same as the non-method tutl.IsNot() except the '*testing.T' argument is held in the TUTL object and so does not need to be passed as an argument.
func (TUTL) Like ¶
Same as the non-method tutl.Like() except the '*testing.T' argument is held in the TUTL object and so does not need to be passed as an argument.
func (*TUTL) ReplaceNewlines ¶
Same as the ReplaceNewlines() method on the 'tutl.Default' global, except it honors the settings from the invoking TUTL object.
func (TUTL) S ¶
Same as the non-method tutl.S() except that it honors the option settings of the invoking TUTL object, not of the 'tutl.Default' global.
func (TUTL) SetDigits32 ¶
SetDigits32() is the same as setting the global 'tutl.Default.Digits32' value, except it only changes the setting for the invoking TUTL object.
func (TUTL) SetDigits64 ¶
SetDigits64() is the same as setting the global 'tutl.Default.Digits64' value, except it only changes the setting for the invoking TUTL object.
func (*TUTL) SetLineWidth ¶
SetLineWidth() is the same as setting the global 'tutl.Default.LineWidth' except it only changes the setting for the invoking TUTL object.
func (*TUTL) SetPathLength ¶
SetPathLength() is the same as setting the global 'tutl.Default.PathLength' except it only changes the setting for the invoking TUTL object.
type TestingT ¶
type TestingT interface { Helper() Error(args ...interface{}) Errorf(format string, args ...interface{}) Log(args ...interface{}) Logf(format string, args ...interface{}) Failed() bool }
TestingT is an interface covering the methods of '*testing.T' that TUTL uses. This makes it easier to test this test library.
Directories ¶
Path | Synopsis |
---|---|
Include: import ( _ "github.com/TyeMcQueen/go-tutl/hang" // ^C gives stack dumps.
|
Include: import ( _ "github.com/TyeMcQueen/go-tutl/hang" // ^C gives stack dumps. |
A couple of simple helper functions to make it easy to get CPU or blocking profile data from your tests.
|
A couple of simple helper functions to make it easy to get CPU or blocking profile data from your tests. |