Merge pull request #181 from henryaj/add-build-for-platform
Add gexec.BuildWithEnvironment
diff --git a/.travis.yml b/.travis.yml
index 8ed1e44..9bc3fd0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,7 @@
language: go
go:
- - 1.5
- - 1.6.2
- - stable
+ - 1.6
+ - 1.7
install:
- go get -v ./...
diff --git a/format/format.go b/format/format.go
index 06355d9..5cd89bc 100644
--- a/format/format.go
+++ b/format/format.go
@@ -6,8 +6,9 @@
import (
"fmt"
"reflect"
- "strings"
"strconv"
+ "strings"
+ "time"
)
// Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
@@ -22,6 +23,24 @@
*/
var UseStringerRepresentation = false
+/*
+Print the content of context objects. By default it will be suppressed.
+
+Set PrintContextObjects = true to enable printing of the context internals.
+*/
+var PrintContextObjects = false
+
+// Ctx interface defined here to keep backwards compatability with go < 1.7
+// It matches the context.Context interface
+type Ctx interface {
+ Deadline() (deadline time.Time, ok bool)
+ Done() <-chan struct{}
+ Err() error
+ Value(key interface{}) interface{}
+}
+
+var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
+
//The default indentation string emitted by the format package
var Indent = " "
@@ -57,6 +76,8 @@
Modify format.MaxDepth to control how deep the recursion is allowed to go
Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of
recursing into the object.
+
+Set PrintContextObjects to true to print the content of objects implementing context.Context
*/
func Object(object interface{}, indentation uint) string {
indent := strings.Repeat(Indent, int(indentation))
@@ -124,6 +145,12 @@
}
}
+ if !PrintContextObjects {
+ if value.Type().Implements(contextType) && indentation > 1 {
+ return "<suppressed context>"
+ }
+ }
+
switch value.Kind() {
case reflect.Bool:
return fmt.Sprintf("%v", value.Bool())
@@ -187,7 +214,7 @@
}
func formatSlice(v reflect.Value, indentation uint) string {
- if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())){
+ if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) {
return formatString(v.Bytes(), indentation)
}
@@ -216,7 +243,7 @@
longest := 0
for i, key := range v.MapKeys() {
value := v.MapIndex(key)
- result[i] = fmt.Sprintf("%s: %s", formatValue(key, 0), formatValue(value, indentation+1))
+ result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1), formatValue(value, indentation+1))
if len(result[i]) > longest {
longest = len(result[i])
}
diff --git a/format/format_test.go b/format/format_test.go
index 1391fe7..4d4b36c 100644
--- a/format/format_test.go
+++ b/format/format_test.go
@@ -2,11 +2,13 @@
import (
"fmt"
+ "strings"
+ "time"
+
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/format"
"github.com/onsi/gomega/types"
- "strings"
)
//recursive struct
@@ -71,6 +73,25 @@
return "string"
}
+type ctx struct {
+}
+
+func (c *ctx) Deadline() (deadline time.Time, ok bool) {
+ return time.Time{}, false
+}
+
+func (c *ctx) Done() <-chan struct{} {
+ return nil
+}
+
+func (c *ctx) Err() error {
+ return nil
+}
+
+func (c *ctx) Value(key interface{}) interface{} {
+ return nil
+}
+
var _ = Describe("Format", func() {
match := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher {
if len(args) > 0 {
@@ -162,19 +183,19 @@
})
Describe("formatting []byte slices", func() {
- Context("when the slice is made of printable bytes", func () {
- It("should present it as string", func() {
- b := []byte("a b c")
- Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`))
- })
- })
- Context("when the slice contains non-printable bytes", func () {
- It("should present it as slice", func() {
- b := []byte("a b c\n\x01\x02\x03\xff\x1bH")
- Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`))
- })
- })
- })
+ Context("when the slice is made of printable bytes", func() {
+ It("should present it as string", func() {
+ b := []byte("a b c")
+ Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`))
+ })
+ })
+ Context("when the slice contains non-printable bytes", func() {
+ It("should present it as slice", func() {
+ b := []byte("a b c\n\x01\x02\x03\xff\x1bH")
+ Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`))
+ })
+ })
+ })
Describe("formatting functions", func() {
It("should give the type and format values correctly", func() {
@@ -429,6 +450,18 @@
m["map"] = m
Ω(Object(m, 1)).Should(ContainSubstring("..."))
})
+
+ It("really should not go crazy...", func() {
+ type complexKey struct {
+ Value map[interface{}]int
+ }
+
+ complexObject := complexKey{}
+ complexObject.Value = make(map[interface{}]int)
+
+ complexObject.Value[&complexObject] = 2
+ Ω(Object(complexObject, 1)).Should(ContainSubstring("..."))
+ })
})
Describe("When instructed to use the Stringer representation", func() {
@@ -452,4 +485,37 @@
})
})
})
+
+ Describe("Printing a context.Context field", func() {
+
+ type structWithContext struct {
+ Context Ctx
+ Value string
+ }
+
+ context := ctx{}
+ objWithContext := structWithContext{Value: "some-value", Context: &context}
+
+ It("Suppresses the content by default", func() {
+ Ω(Object(objWithContext, 1)).Should(ContainSubstring("<suppressed context>"))
+ })
+
+ It("Doesn't supress the context if it's the object being printed", func() {
+ Ω(Object(context, 1)).ShouldNot(MatchRegexp("^.*<suppressed context>$"))
+ })
+
+ Context("PrintContextObjects is set", func() {
+ BeforeEach(func() {
+ PrintContextObjects = true
+ })
+
+ AfterEach(func() {
+ PrintContextObjects = false
+ })
+
+ It("Prints the context", func() {
+ Ω(Object(objWithContext, 1)).ShouldNot(ContainSubstring("<suppressed context>"))
+ })
+ })
+ })
})
diff --git a/matchers/be_numerically_matcher.go b/matchers/be_numerically_matcher.go
index 52f83fe..0c157f6 100644
--- a/matchers/be_numerically_matcher.go
+++ b/matchers/be_numerically_matcher.go
@@ -2,8 +2,9 @@
import (
"fmt"
- "github.com/onsi/gomega/format"
"math"
+
+ "github.com/onsi/gomega/format"
)
type BeNumericallyMatcher struct {
diff --git a/matchers/panic_matcher.go b/matchers/panic_matcher.go
index 75ab251..640f4db 100644
--- a/matchers/panic_matcher.go
+++ b/matchers/panic_matcher.go
@@ -2,11 +2,14 @@
import (
"fmt"
- "github.com/onsi/gomega/format"
"reflect"
+
+ "github.com/onsi/gomega/format"
)
-type PanicMatcher struct{}
+type PanicMatcher struct {
+ object interface{}
+}
func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) {
if actual == nil {
@@ -24,6 +27,7 @@
success = false
defer func() {
if e := recover(); e != nil {
+ matcher.object = e
success = true
}
}()
@@ -38,5 +42,5 @@
}
func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) {
- return format.Message(actual, "not to panic")
+ return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1)))
}
diff --git a/matchers/panic_matcher_test.go b/matchers/panic_matcher_test.go
index 17f3935..6b859a7 100644
--- a/matchers/panic_matcher_test.go
+++ b/matchers/panic_matcher_test.go
@@ -33,4 +33,13 @@
Ω(func() {}).ShouldNot(Panic())
})
})
+
+ Context("when assertion fails", func() {
+ It("should print the object passed to Panic", func() {
+ failuresMessages := InterceptGomegaFailures(func() {
+ Ω(func() { panic("ack!") }).ShouldNot(Panic())
+ })
+ Ω(failuresMessages).Should(ConsistOf(MatchRegexp("not to panic, but panicked with\\s*<string>: ack!")))
+ })
+ })
})