Bläddra i källkod

Add full suite of tests for Formatter.

Dave Collins 13 år sedan
förälder
incheckning
34805dbdb5
1 ändrade filer med 807 tillägg och 0 borttagningar
  1. 807 0
      spew/format_test.go

+ 807 - 0
spew/format_test.go

@@ -0,0 +1,807 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Standard string
+- Nil interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+  exported and unexported fields
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+*/
+
+package spew_test
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/davecgh/go-spew/spew"
+	"testing"
+	"unsafe"
+)
+
+// formatterTest is used to describe a test to be perfomed against NewFormatter.
+type formatterTest struct {
+	format string
+	in     interface{}
+	want   string
+}
+
+// formatterTests houses all of the tests to be performed against NewFormatter.
+var formatterTests = make([]formatterTest, 0)
+
+// addFormatterTest is a helper method to append the passed input and desired
+// result to formatterTests.
+func addFormatterTest(format string, in interface{}, want string) {
+	test := formatterTest{format, in, want}
+	formatterTests = append(formatterTests, test)
+}
+
+func addIntFormatterTests() {
+	// Max int8.
+	v := int8(127)
+	nv := (*int8)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "127"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Max int16.
+	v2 := int16(32767)
+	nv2 := (*int16)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "32767"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+
+	// Max int32.
+	v3 := int32(2147483647)
+	nv3 := (*int32)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3s := "2147483647"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+
+	// Max int64.
+	v4 := int64(9223372036854775807)
+	nv4 := (*int64)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4s := "9223372036854775807"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+
+	// Max int.
+	v5 := int(2147483647)
+	nv5 := (*int)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5s := "2147483647"
+	addFormatterTest("%v", v5, v5s)
+	addFormatterTest("%v", pv5, "<*>"+v5s)
+	addFormatterTest("%v", &pv5, "<**>"+v5s)
+	addFormatterTest("%v", nv5, "<nil>")
+	addFormatterTest("%+v", v5, v5s)
+	addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+	addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%+v", nv5, "<nil>")
+}
+
+func addUintFormatterTests() {
+	// Max uint8.
+	v := uint8(255)
+	nv := (*uint8)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "255"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Max uint16.
+	v2 := uint16(65535)
+	nv2 := (*uint16)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "65535"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+
+	// Max uint32.
+	v3 := uint32(4294967295)
+	nv3 := (*uint32)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3s := "4294967295"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+
+	// Max uint64.
+	v4 := uint64(18446744073709551615)
+	nv4 := (*uint64)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4s := "18446744073709551615"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+
+	// Max uint.
+	v5 := uint(4294967295)
+	nv5 := (*uint)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5s := "4294967295"
+	addFormatterTest("%v", v5, v5s)
+	addFormatterTest("%v", pv5, "<*>"+v5s)
+	addFormatterTest("%v", &pv5, "<**>"+v5s)
+	addFormatterTest("%v", nv5, "<nil>")
+	addFormatterTest("%+v", v5, v5s)
+	addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+	addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%+v", nv5, "<nil>")
+}
+
+func addBoolFormatterTests() {
+	// Boolean true.
+	v := bool(true)
+	nv := (*bool)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "true"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Boolean false.
+	v2 := bool(false)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "false"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFloatFormatterTests() {
+	// Standard float32.
+	v := float32(3.1415)
+	nv := (*float32)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "3.1415"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Standard float64.
+	v2 := float64(3.1415926)
+	nv2 := (*float64)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "3.1415926"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+}
+
+func addComplexFormatterTests() {
+	// Standard complex64.
+	v := complex(float32(6), -2)
+	nv := (*complex64)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "(6-2i)"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Standard complex128.
+	v2 := complex(float64(-6), 2)
+	nv2 := (*complex128)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "(-6+2i)"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+}
+
+func addArrayFormatterTests() {
+	// Array containing standard ints.
+	v := [3]int{1, 2, 3}
+	nv := (*[3]int)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "[1 2 3]"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Array containing type with custom formatter on pointer receiver only.
+	v2 := [3]pstringer{"1", "2", "3"}
+	nv2 := (*[3]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "[stringer 1 stringer 2 stringer 3]"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+}
+
+func addSliceFormatterTests() {
+	// Slice containing standard float32 values.
+	v := []float32{3.14, 6.28, 12.56}
+	nv := (*[]float32)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "[3.14 6.28 12.56]"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Slice containing type with custom formatter on pointer receiver only.
+	v2 := []pstringer{"1", "2", "3"}
+	nv2 := (*[]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "[stringer 1 stringer 2 stringer 3]"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+}
+
+func addStringFormatterTests() {
+	// Standard string.
+	v := "test"
+	nv := (*string)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "test"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+}
+
+func addNilInterfaceFormatterTests() {
+	// Nil interface.
+	var v interface{}
+	nv := (*interface{})(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+}
+
+func addMapFormatterTests() {
+	// Map with string keys and int vals.
+	v := map[string]int{"one": 1}
+	nv := (*map[string]int)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "map[one:1]"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Map with custom formatter type on pointer receiver only keys and vals.
+	v2 := map[pstringer]pstringer{"one": "1"}
+	nv2 := (*map[pstringer]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "map[stringer one:stringer 1]"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+
+	// Map with interface keys and values.
+	v3 := map[interface{}]interface{}{"one": 1}
+	nv3 := (*map[interface{}]interface{})(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3s := "map[one:1]"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+}
+
+func addStructFormatterTests() {
+	// Struct with primitives.
+	type s1 struct {
+		a int8
+		b uint8
+	}
+	v := s1{127, 255}
+	nv := (*s1)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "{127 255}"
+	vs2 := "{a:127 b:255}"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs2)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Struct that contains another struct.
+	type s2 struct {
+		s1 s1
+		b  bool
+	}
+	v2 := s2{s1{127, 255}, true}
+	nv2 := (*s2)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "{{127 255} true}"
+	v2s2 := "{s1:{a:127 b:255} b:true}"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s2)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
+	addFormatterTest("%+v", nv2, "<nil>")
+
+	// Struct that contains custom type with Stringer pointer interface via both
+	// exported and unexported fields.
+	type s3 struct {
+		s pstringer
+		S pstringer
+	}
+	v3 := s3{"test", "test2"}
+	nv3 := (*s3)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3s := "{stringer test stringer test2}"
+	v3s2 := "{s:stringer test S:stringer test2}"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s2)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%+v", nv3, "<nil>")
+}
+
+func addUintptrFormatterTests() {
+	// Null pointer.
+	v := uintptr(0)
+	nv := (*uintptr)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Address of real variable.
+	i := 1
+	v2 := uintptr(unsafe.Pointer(&i))
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := fmt.Sprintf("%p", &i)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addUnsafePointerFormatterTests() {
+	// Null pointer.
+	v := unsafe.Pointer(uintptr(0))
+	nv := (*unsafe.Pointer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Address of real variable.
+	i := 1
+	v2 := unsafe.Pointer(&i)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := fmt.Sprintf("%p", &i)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addChanFormatterTests() {
+	// Nil channel.
+	var v chan int
+	pv := &v
+	nv := (*chan int)(nil)
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Real channel.
+	v2 := make(chan int)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := fmt.Sprintf("%p", v2)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFuncFormatterTests() {
+	// Function with no params and no returns.
+	v := addIntFormatterTests
+	nv := (*func())(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := fmt.Sprintf("%p", v)
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+
+	// Function with param and no returns.
+	v2 := TestFormatter
+	nv2 := (*func(*testing.T))(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := fmt.Sprintf("%p", v2)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+
+	// Function with multiple params and multiple returns.
+	var v3 = func(i int, s string) (b bool, err error) {
+		return true, nil
+	}
+	nv3 := (*func(int, string) (bool, error))(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3s := fmt.Sprintf("%p", v3)
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+}
+
+func addCircularFormatterTests() {
+	// Struct that is circular through self referencing.
+	type circular struct {
+		c *circular
+	}
+	v := circular{nil}
+	v.c = &v
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vs := "{<*>{<*><shown>}}"
+	vs2 := "{<*><shown>}"
+	vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")<shown>}}"
+	vs4 := "{c:<*>(" + vAddr + ")<shown>}"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs2)
+	addFormatterTest("%v", &pv, "<**>"+vs2)
+	addFormatterTest("%+v", v, vs3)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4)
+
+	// Structs that are circular through cross referencing.
+	v2 := xref1{nil}
+	ts2 := xref2{&v2}
+	v2.ps2 = &ts2
+	pv2 := &v2
+	ts2Addr := fmt.Sprintf("%p", &ts2)
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2s := "{<*>{<*>{<*><shown>}}}"
+	v2s2 := "{<*>{<*><shown>}}"
+	v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" +
+		ts2Addr + ")<shown>}}}"
+	v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")<shown>}}"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s2)
+	addFormatterTest("%v", &pv2, "<**>"+v2s2)
+	addFormatterTest("%+v", v2, v2s3)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4)
+
+	// Structs that are indirectly circular.
+	v3 := indirCir1{nil}
+	tic2 := indirCir2{nil}
+	tic3 := indirCir3{&v3}
+	tic2.ps3 = &tic3
+	v3.ps2 = &tic2
+	pv3 := &v3
+	tic2Addr := fmt.Sprintf("%p", &tic2)
+	tic3Addr := fmt.Sprintf("%p", &tic3)
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3s := "{<*>{<*>{<*>{<*><shown>}}}}"
+	v3s2 := "{<*>{<*>{<*><shown>}}}"
+	v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+		v3Addr + "){ps2:<*>(" + tic2Addr + ")<shown>}}}}"
+	v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+		v3Addr + ")<shown>}}}"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s2)
+	addFormatterTest("%v", &pv3, "<**>"+v3s2)
+	addFormatterTest("%+v", v3, v3s3)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4)
+}
+
+// TestFormatter executes all of the tests described by formatterTests.
+func TestFormatter(t *testing.T) {
+	// Setup tests.
+	addIntFormatterTests()
+	addUintFormatterTests()
+	addBoolFormatterTests()
+	addFloatFormatterTests()
+	addComplexFormatterTests()
+	addArrayFormatterTests()
+	addSliceFormatterTests()
+	addStringFormatterTests()
+	addNilInterfaceFormatterTests()
+	addMapFormatterTests()
+	addStructFormatterTests()
+	addUintptrFormatterTests()
+	addUnsafePointerFormatterTests()
+	addChanFormatterTests()
+	addFuncFormatterTests()
+	addCircularFormatterTests()
+
+	t.Logf("Running %d tests", len(formatterTests))
+	for i, test := range formatterTests {
+		buf := new(bytes.Buffer)
+		spew.Fprintf(buf, test.format, test.in)
+		s := buf.String()
+		if test.want != s {
+			t.Errorf("Formatter #%d format: %s got: %s want: %s", i,
+				test.format, s, test.want)
+			continue
+		}
+	}
+}