@@ -45,7 +45,6 @@ import (
4545 "os"
4646 "path/filepath"
4747 "reflect"
48- "runtime"
4948 "strings"
5049 "testing"
5150)
@@ -69,28 +68,31 @@ type I struct {
6968 fail func ()
7069 out io.Writer
7170 colorful bool
71+
72+ helpers map [string ]struct {} // functions to be skipped when writing file/line info
7273}
7374
7475var noColorFlag bool
7576
7677func init () {
77- flag .BoolVar (& noColorFlag , "nocolor" , false , "turns off colors" )
78+ envNoColor := os .Getenv ("IS_NO_COLOR" ) == "true"
79+ flag .BoolVar (& noColorFlag , "nocolor" , envNoColor , "turns off colors" )
7880}
7981
8082// New makes a new testing helper using the specified
8183// T through which failures will be reported.
8284// In strict mode, failures call T.FailNow causing the test
8385// to be aborted. See NewRelaxed for alternative behavior.
8486func New (t T ) * I {
85- return & I {t , t .FailNow , os .Stdout , ! noColorFlag }
87+ return & I {t , t .FailNow , os .Stdout , ! noColorFlag , map [ string ] struct {}{} }
8688}
8789
8890// NewRelaxed makes a new testing helper using the specified
8991// T through which failures will be reported.
9092// In relaxed mode, failures call T.Fail allowing
9193// multiple failures per test.
9294func NewRelaxed (t T ) * I {
93- return & I {t , t .Fail , os .Stdout , ! noColorFlag }
95+ return & I {t , t .Fail , os .Stdout , ! noColorFlag , map [ string ] struct {}{} }
9496}
9597
9698func (is * I ) log (args ... interface {}) {
@@ -146,23 +148,14 @@ func (is *I) True(expression bool) {
146148//
147149// your_test.go:123: Hey Mat != Hi Mat // greeting
148150func (is * I ) Equal (a , b interface {}) {
149- if ! areEqual (a , b ) {
150- if isNil (a ) || isNil (b ) {
151- aLabel := is .valWithType (a )
152- bLabel := is .valWithType (b )
153- if isNil (a ) {
154- aLabel = "<nil>"
155- }
156- if isNil (b ) {
157- bLabel = "<nil>"
158- }
159- is .logf ("%s != %s" , aLabel , bLabel )
160- return
161- }
162- if reflect .ValueOf (a ).Type () == reflect .ValueOf (b ).Type () {
163- is .logf ("%v != %v" , a , b )
164- return
165- }
151+ if areEqual (a , b ) {
152+ return
153+ }
154+ if isNil (a ) || isNil (b ) {
155+ is .logf ("%s != %s" , is .valWithType (a ), is .valWithType (b ))
156+ } else if reflect .ValueOf (a ).Type () == reflect .ValueOf (b ).Type () {
157+ is .logf ("%v != %v" , a , b )
158+ } else {
166159 is .logf ("%s != %s" , is .valWithType (a ), is .valWithType (b ))
167160 }
168161}
@@ -198,6 +191,9 @@ func (is *I) NewRelaxed(t *testing.T) *I {
198191}
199192
200193func (is * I ) valWithType (v interface {}) string {
194+ if isNil (v ) {
195+ return "<nil>"
196+ }
201197 if is .colorful {
202198 return fmt .Sprintf ("%[1]s%[3]T(%[2]s%[3]v%[1]s)%[2]s" , colorType , colorNormal , v )
203199 }
@@ -237,15 +233,12 @@ func isNil(object interface{}) bool {
237233
238234// areEqual gets whether a equals b or not.
239235func areEqual (a , b interface {}) bool {
240- if isNil (a ) || isNil (b ) {
241- if isNil (a ) && ! isNil (b ) {
242- return false
243- }
244- if ! isNil (a ) && isNil (b ) {
245- return false
246- }
236+ if isNil (a ) && isNil (b ) {
247237 return true
248238 }
239+ if isNil (a ) || isNil (b ) {
240+ return false
241+ }
249242 if reflect .DeepEqual (a , b ) {
250243 return true
251244 }
@@ -254,19 +247,6 @@ func areEqual(a, b interface{}) bool {
254247 return aValue == bValue
255248}
256249
257- func callerinfo () (path string , line int , ok bool ) {
258- for i := 0 ; ; i ++ {
259- _ , path , line , ok = runtime .Caller (i )
260- if ! ok {
261- return
262- }
263- if strings .HasSuffix (path , "is.go" ) {
264- continue
265- }
266- return path , line , true
267- }
268- }
269-
270250// loadComment gets the Go comment from the specified line
271251// in the specified file.
272252func loadComment (path string , line int ) (string , bool ) {
@@ -280,7 +260,7 @@ func loadComment(path string, line int) (string, bool) {
280260 for s .Scan () {
281261 if i == line {
282262 text := s .Text ()
283- commentI := strings .Index (text , "//" )
263+ commentI := strings .Index (text , "// " )
284264 if commentI == - 1 {
285265 return "" , false // no comment
286266 }
@@ -339,7 +319,7 @@ func loadArguments(path string, line int) (string, bool) {
339319// and inserts the final newline if needed and indentation tabs for formatting.
340320// this function was copied from the testing framework and modified.
341321func (is * I ) decorate (s string ) string {
342- path , lineNumber , ok := callerinfo () // decorate + log + public function.
322+ path , lineNumber , ok := is . callerinfo () // decorate + log + public function.
343323 file := filepath .Base (path )
344324 if ok {
345325 // Truncate file name at last file name separator.
@@ -362,6 +342,9 @@ func (is *I) decorate(s string) string {
362342 if is .colorful {
363343 buf .WriteString (colorNormal )
364344 }
345+
346+ s = escapeFormatString (s )
347+
365348 lines := strings .Split (s , "\n " )
366349 if l := len (lines ); l > 1 && lines [l - 1 ] == "" {
367350 lines = lines [:l - 1 ]
@@ -384,6 +367,7 @@ func (is *I) decorate(s string) string {
384367 buf .WriteString (colorComment )
385368 }
386369 buf .WriteString (" // " )
370+ comment = escapeFormatString (comment )
387371 buf .WriteString (comment )
388372 if is .colorful {
389373 buf .WriteString (colorNormal )
@@ -393,9 +377,14 @@ func (is *I) decorate(s string) string {
393377 return buf .String ()
394378}
395379
380+ // escapeFormatString escapes strings for use in formatted functions like Sprintf.
381+ func escapeFormatString (fmt string ) string {
382+ return strings .Replace (fmt , "%" , "%%" , - 1 )
383+ }
384+
396385const (
397386 colorNormal = "\u001b [39m"
398- colorComment = "\u001b [32m "
387+ colorComment = "\u001b [31m "
399388 colorFile = "\u001b [90m"
400389 colorType = "\u001b [90m"
401390)
0 commit comments