diff options
| -rw-r--r-- | spew/internal_test.go | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/spew/internal_test.go b/spew/internal_test.go index 7a872e4..05bab97 100644 --- a/spew/internal_test.go +++ b/spew/internal_test.go @@ -26,6 +26,7 @@ import ( "bytes" "reflect" "testing" + "unsafe" ) // dummyFmtState implements a fake fmt.State to use for testing invalid @@ -79,3 +80,78 @@ func TestInvalidReflectValue(t *testing.T) { t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) } } + +// flagRO, flagKindShift and flagKindWidth indicate various bit flags that the +// reflect package uses internally to track kind and state information. +const flagRO = 1 << 0 +const flagKindShift = 4 +const flagKindWidth = 5 + +// changeKind uses unsafe to intentionally change the kind of a reflect.Value to +// the maximum kind value which does not exist. This is needed to test the +// fallback code which punts to the standard fmt library for new types that +// might get added to the language. +func changeKind(v *reflect.Value, readOnly bool) { + rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + + unsafe.Offsetof(reflectValue.flag))) + *rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift) + if readOnly { + *rvf |= flagRO + } else { + *rvf &= ^uintptr(flagRO) + } +} + +// TestAddedReflectValue tests functionaly of the dump and formatter code which +// falls back to the standard fmt library for new types that might get added to +// the language. +func TestAddedReflectValue(t *testing.T) { + i := 1 + + // Dump using a reflect.Value that is exported. + v := reflect.ValueOf(int8(5)) + changeKind(&v, false) + buf := new(bytes.Buffer) + d := dumpState{w: buf, cs: &Config} + d.dump(v) + s := buf.String() + want := "(int8) 5" + if s != want { + t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want) + } + i++ + + // Dump using a reflect.Value that is not exported. + changeKind(&v, true) + buf.Reset() + d.dump(v) + s = buf.String() + want = "(int8) <int8 Value>" + if s != want { + t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want) + } + i++ + + // Formatter using a reflect.Value that is exported. + changeKind(&v, false) + buf2 := new(dummyFmtState) + f := formatState{value: v, cs: &Config, fs: buf2} + f.format(v) + s = buf2.String() + want = "5" + if s != want { + t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want) + } + i++ + + // Formatter using a reflect.Value that is not exported. + changeKind(&v, true) + buf2.Reset() + f = formatState{value: v, cs: &Config, fs: buf2} + f.format(v) + s = buf2.String() + want = "<int8 Value>" + if s != want { + t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want) + } +} |
