pax_global_header00006660000000000000000000000064130052064660014514gustar00rootroot0000000000000052 comment=346938d642f2ec3594ed81d874461961cd0faa76 go-spew-1.1.0/000077500000000000000000000000001300520646600130745ustar00rootroot00000000000000go-spew-1.1.0/.gitignore000066400000000000000000000003741300520646600150700ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe go-spew-1.1.0/.travis.yml000066400000000000000000000006051300520646600152060ustar00rootroot00000000000000language: go go: - 1.5.4 - 1.6.3 - 1.7 install: - go get -v golang.org/x/tools/cmd/cover script: - go test -v -tags=safe ./spew - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov after_success: - go get -v github.com/mattn/goveralls - export PATH=$PATH:$HOME/gopath/bin - goveralls -coverprofile=profile.cov -service=travis-ci go-spew-1.1.0/LICENSE000066400000000000000000000013731300520646600141050ustar00rootroot00000000000000ISC License Copyright (c) 2012-2016 Dave Collins 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. go-spew-1.1.0/README.md000066400000000000000000000157251300520646600143650ustar00rootroot00000000000000go-spew ======= [![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)] (https://travis-ci.org/davecgh/go-spew) [![ISC License] (http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status] (https://img.shields.io/coveralls/davecgh/go-spew.svg)] (https://coveralls.io/r/davecgh/go-spew?branch=master) Go-spew implements a deep pretty printer for Go data structures to aid in debugging. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. See `test_coverage.txt` for the gocov coverage report. Go-spew is licensed under the liberal ISC license, so it may be used in open source or commercial projects. If you're interested in reading about how this package came to life and some of the challenges involved in providing a deep pretty printer, there is a blog post about it [here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/). ## Documentation [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] (http://godoc.org/github.com/davecgh/go-spew/spew) Full `go doc` style documentation for the project can be viewed online without installing this package by using the excellent GoDoc site here: http://godoc.org/github.com/davecgh/go-spew/spew You can also view the documentation locally once the package is installed with the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to http://localhost:6060/pkg/github.com/davecgh/go-spew/spew ## Installation ```bash $ go get -u github.com/davecgh/go-spew/spew ``` ## Quick Start Add this import line to the file you're working in: ```Go import "github.com/davecgh/go-spew/spew" ``` To dump a variable with full newlines, indentation, type, and pointer information use Dump, Fdump, or Sdump: ```Go spew.Dump(myVar1, myVar2, ...) spew.Fdump(someWriter, myVar1, myVar2, ...) str := spew.Sdump(myVar1, myVar2, ...) ``` Alternatively, if you would prefer to use format strings with a compacted inline printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses): ```Go spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) ``` ## Debugging a Web Application Example Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production. ```Go package main import ( "fmt" "html" "net/http" "github.com/davecgh/go-spew/spew" ) func handler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:]) fmt.Fprintf(w, "") } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } ``` ## Sample Dump Output ``` (main.Foo) { unexportedField: (*main.Bar)(0xf84002e210)({ flag: (main.Flag) flagTwo, data: (uintptr) }), ExportedField: (map[interface {}]interface {}) { (string) "one": (bool) true } } ([]uint8) { 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 00000020 31 32 |12| } ``` ## Sample Formatter Output Double pointer to a uint8: ``` %v: <**>5 %+v: <**>(0xf8400420d0->0xf8400420c8)5 %#v: (**uint8)5 %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 ``` Pointer to circular struct with a uint8 field and a pointer to itself: ``` %v: <*>{1 <*>} %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} ``` ## Configuration Options Configuration of spew is handled by fields in the ConfigState type. For convenience, all of the top-level functions use a global state available via the spew.Config global. It is also possible to create a ConfigState instance that provides methods equivalent to the top-level functions. This allows concurrent configuration options. See the ConfigState documentation for more details. ``` * Indent String to use for each indentation level for Dump functions. It is a single space by default. A popular alternative is "\t". * MaxDepth Maximum number of levels to descend into nested data structures. There is no limit by default. * DisableMethods Disables invocation of error and Stringer interface methods. Method invocation is enabled by default. * DisablePointerMethods Disables invocation of error and Stringer interface methods on types which only accept pointer receivers from non-pointer variables. This option relies on access to the unsafe package, so it will not have any effect when running in environments without access to the unsafe package such as Google App Engine or with the "safe" build tag specified. Pointer method invocation is enabled by default. * DisablePointerAddresses DisablePointerAddresses specifies whether to disable the printing of pointer addresses. This is useful when diffing data structures in tests. * DisableCapacities DisableCapacities specifies whether to disable the printing of capacities for arrays, slices, maps and channels. This is useful when diffing data structures in tests. * ContinueOnMethod Enables recursion into types after invoking error and Stringer interface methods. Recursion after method invocation is disabled by default. * SortKeys Specifies map keys should be sorted before being printed. Use this to have a more deterministic, diffable output. Note that only native types (bool, int, uint, floats, uintptr and string) and types which implement error or Stringer interfaces are supported, with other types sorted according to the reflect.Value.String() output which guarantees display stability. Natural map order is used by default. * SpewKeys SpewKeys specifies that, as a last resort attempt, map keys should be spewed to strings and sorted by those strings. This is only considered if SortKeys is true. ``` ## Unsafe Package Dependency This package relies on the unsafe package to perform some of the more advanced features, however it also supports a "limited" mode which allows it to work in environments where the unsafe package is not available. By default, it will operate in this mode on Google App Engine and when compiled with GopherJS. The "safe" build tag may also be specified to force the package to build without using the unsafe package. ## License Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. go-spew-1.1.0/cov_report.sh000066400000000000000000000012221300520646600156070ustar00rootroot00000000000000#!/bin/sh # This script uses gocov to generate a test coverage report. # The gocov tool my be obtained with the following command: # go get github.com/axw/gocov/gocov # # It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. # Check for gocov. if ! type gocov >/dev/null 2>&1; then echo >&2 "This script requires the gocov tool." echo >&2 "You may obtain it with the following command:" echo >&2 "go get github.com/axw/gocov/gocov" exit 1 fi # Only run the cgo tests if gcc is installed. if type gcc >/dev/null 2>&1; then (cd spew && gocov test -tags testcgo | gocov report) else (cd spew && gocov test | gocov report) fi go-spew-1.1.0/spew/000077500000000000000000000000001300520646600140525ustar00rootroot00000000000000go-spew-1.1.0/spew/bypass.go000066400000000000000000000132351300520646600157060ustar00rootroot00000000000000// Copyright (c) 2015-2016 Dave Collins // // 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. // NOTE: Due to the following build constraints, this file will only be compiled // when the code is not running on Google App Engine, compiled by GopherJS, and // "-tags safe" is not added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. // +build !js,!appengine,!safe,!disableunsafe package spew import ( "reflect" "unsafe" ) const ( // UnsafeDisabled is a build-time constant which specifies whether or // not access to the unsafe package is available. UnsafeDisabled = false // ptrSize is the size of a pointer on the current arch. ptrSize = unsafe.Sizeof((*byte)(nil)) ) var ( // offsetPtr, offsetScalar, and offsetFlag are the offsets for the // internal reflect.Value fields. These values are valid before golang // commit ecccf07e7f9d which changed the format. The are also valid // after commit 82f48826c6c7 which changed the format again to mirror // the original format. Code in the init function updates these offsets // as necessary. offsetPtr = uintptr(ptrSize) offsetScalar = uintptr(0) offsetFlag = uintptr(ptrSize * 2) // flagKindWidth and flagKindShift indicate various bits that the // reflect package uses internally to track kind information. // // flagRO indicates whether or not the value field of a reflect.Value is // read-only. // // flagIndir indicates whether the value field of a reflect.Value is // the actual data or a pointer to the data. // // These values are valid before golang commit 90a7c3c86944 which // changed their positions. Code in the init function updates these // flags as necessary. flagKindWidth = uintptr(5) flagKindShift = uintptr(flagKindWidth - 1) flagRO = uintptr(1 << 0) flagIndir = uintptr(1 << 1) ) func init() { // Older versions of reflect.Value stored small integers directly in the // ptr field (which is named val in the older versions). Versions // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named // scalar for this purpose which unfortunately came before the flag // field, so the offset of the flag field is different for those // versions. // // This code constructs a new reflect.Value from a known small integer // and checks if the size of the reflect.Value struct indicates it has // the scalar field. When it does, the offsets are updated accordingly. vv := reflect.ValueOf(0xf00) if unsafe.Sizeof(vv) == (ptrSize * 4) { offsetScalar = ptrSize * 2 offsetFlag = ptrSize * 3 } // Commit 90a7c3c86944 changed the flag positions such that the low // order bits are the kind. This code extracts the kind from the flags // field and ensures it's the correct type. When it's not, the flag // order has been changed to the newer format, so the flags are updated // accordingly. upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) upfv := *(*uintptr)(upf) flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { flagKindShift = 0 flagRO = 1 << 5 flagIndir = 1 << 6 // Commit adf9b30e5594 modified the flags to separate the // flagRO flag into two bits which specifies whether or not the // field is embedded. This causes flagIndir to move over a bit // and means that flagRO is the combination of either of the // original flagRO bit and the new bit. // // This code detects the change by extracting what used to be // the indirect bit to ensure it's set. When it's not, the flag // order has been changed to the newer format, so the flags are // updated accordingly. if upfv&flagIndir == 0 { flagRO = 3 << 5 flagIndir = 1 << 7 } } } // unsafeReflectValue converts the passed reflect.Value into a one that bypasses // the typical safety restrictions preventing access to unaddressable and // unexported data. It works by digging the raw pointer to the underlying // value out of the protected value and generating a new unprotected (unsafe) // reflect.Value to it. // // This allows us to check for implementations of the Stringer and error // interfaces to be used for pretty printing ordinarily unaddressable and // inaccessible values such as unexported struct fields. func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { indirects := 1 vt := v.Type() upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) if rvf&flagIndir != 0 { vt = reflect.PtrTo(v.Type()) indirects++ } else if offsetScalar != 0 { // The value is in the scalar field when it's not one of the // reference types. switch vt.Kind() { case reflect.Uintptr: case reflect.Chan: case reflect.Func: case reflect.Map: case reflect.Ptr: case reflect.UnsafePointer: default: upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetScalar) } } pv := reflect.NewAt(vt, upv) rv = pv for i := 0; i < indirects; i++ { rv = rv.Elem() } return rv } go-spew-1.1.0/spew/bypasssafe.go000066400000000000000000000033061300520646600165430ustar00rootroot00000000000000// Copyright (c) 2015-2016 Dave Collins // // 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. // NOTE: Due to the following build constraints, this file will only be compiled // when the code is running on Google App Engine, compiled by GopherJS, or // "-tags safe" is added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. // +build js appengine safe disableunsafe package spew import "reflect" const ( // UnsafeDisabled is a build-time constant which specifies whether or // not access to the unsafe package is available. UnsafeDisabled = true ) // unsafeReflectValue typically converts the passed reflect.Value into a one // that bypasses the typical safety restrictions preventing access to // unaddressable and unexported data. However, doing this relies on access to // the unsafe package. This is a stub version which simply returns the passed // reflect.Value when the unsafe package is not available. func unsafeReflectValue(v reflect.Value) reflect.Value { return v } go-spew-1.1.0/spew/common.go000066400000000000000000000241741300520646600157010ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew import ( "bytes" "fmt" "io" "reflect" "sort" "strconv" ) // Some constants in the form of bytes to avoid string overhead. This mirrors // the technique used in the fmt package. var ( panicBytes = []byte("(PANIC=") plusBytes = []byte("+") iBytes = []byte("i") trueBytes = []byte("true") falseBytes = []byte("false") interfaceBytes = []byte("(interface {})") commaNewlineBytes = []byte(",\n") newlineBytes = []byte("\n") openBraceBytes = []byte("{") openBraceNewlineBytes = []byte("{\n") closeBraceBytes = []byte("}") asteriskBytes = []byte("*") colonBytes = []byte(":") colonSpaceBytes = []byte(": ") openParenBytes = []byte("(") closeParenBytes = []byte(")") spaceBytes = []byte(" ") pointerChainBytes = []byte("->") nilAngleBytes = []byte("") maxNewlineBytes = []byte("\n") maxShortBytes = []byte("") circularBytes = []byte("") circularShortBytes = []byte("") invalidAngleBytes = []byte("") openBracketBytes = []byte("[") closeBracketBytes = []byte("]") percentBytes = []byte("%") precisionBytes = []byte(".") openAngleBytes = []byte("<") closeAngleBytes = []byte(">") openMapBytes = []byte("map[") closeMapBytes = []byte("]") lenEqualsBytes = []byte("len=") capEqualsBytes = []byte("cap=") ) // hexDigits is used to map a decimal value to a hex digit. var hexDigits = "0123456789abcdef" // catchPanic handles any panics that might occur during the handleMethods // calls. func catchPanic(w io.Writer, v reflect.Value) { if err := recover(); err != nil { w.Write(panicBytes) fmt.Fprintf(w, "%v", err) w.Write(closeParenBytes) } } // handleMethods attempts to call the Error and String methods on the underlying // type the passed reflect.Value represents and outputes the result to Writer w. // // It handles panics in any called methods by catching and displaying the error // as the formatted value. func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { // We need an interface to check if the type implements the error or // Stringer interface. However, the reflect package won't give us an // interface on certain things like unexported struct fields in order // to enforce visibility rules. We use unsafe, when it's available, // to bypass these restrictions since this package does not mutate the // values. if !v.CanInterface() { if UnsafeDisabled { return false } v = unsafeReflectValue(v) } // Choose whether or not to do error and Stringer interface lookups against // the base type or a pointer to the base type depending on settings. // Technically calling one of these methods with a pointer receiver can // mutate the value, however, types which choose to satisify an error or // Stringer interface with a pointer receiver should not be mutating their // state inside these interface methods. if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { v = unsafeReflectValue(v) } if v.CanAddr() { v = v.Addr() } // Is it an error or Stringer? switch iface := v.Interface().(type) { case error: defer catchPanic(w, v) if cs.ContinueOnMethod { w.Write(openParenBytes) w.Write([]byte(iface.Error())) w.Write(closeParenBytes) w.Write(spaceBytes) return false } w.Write([]byte(iface.Error())) return true case fmt.Stringer: defer catchPanic(w, v) if cs.ContinueOnMethod { w.Write(openParenBytes) w.Write([]byte(iface.String())) w.Write(closeParenBytes) w.Write(spaceBytes) return false } w.Write([]byte(iface.String())) return true } return false } // printBool outputs a boolean value as true or false to Writer w. func printBool(w io.Writer, val bool) { if val { w.Write(trueBytes) } else { w.Write(falseBytes) } } // printInt outputs a signed integer value to Writer w. func printInt(w io.Writer, val int64, base int) { w.Write([]byte(strconv.FormatInt(val, base))) } // printUint outputs an unsigned integer value to Writer w. func printUint(w io.Writer, val uint64, base int) { w.Write([]byte(strconv.FormatUint(val, base))) } // printFloat outputs a floating point value using the specified precision, // which is expected to be 32 or 64bit, to Writer w. func printFloat(w io.Writer, val float64, precision int) { w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) } // printComplex outputs a complex value using the specified float precision // for the real and imaginary parts to Writer w. func printComplex(w io.Writer, c complex128, floatPrecision int) { r := real(c) w.Write(openParenBytes) w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) i := imag(c) if i >= 0 { w.Write(plusBytes) } w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) w.Write(iBytes) w.Write(closeParenBytes) } // printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' // prefix to Writer w. func printHexPtr(w io.Writer, p uintptr) { // Null pointer. num := uint64(p) if num == 0 { w.Write(nilAngleBytes) return } // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix buf := make([]byte, 18) // It's simpler to construct the hex string right to left. base := uint64(16) i := len(buf) - 1 for num >= base { buf[i] = hexDigits[num%base] num /= base i-- } buf[i] = hexDigits[num] // Add '0x' prefix. i-- buf[i] = 'x' i-- buf[i] = '0' // Strip unused leading bytes. buf = buf[i:] w.Write(buf) } // valuesSorter implements sort.Interface to allow a slice of reflect.Value // elements to be sorted. type valuesSorter struct { values []reflect.Value strings []string // either nil or same len and values cs *ConfigState } // newValuesSorter initializes a valuesSorter instance, which holds a set of // surrogate keys on which the data should be sorted. It uses flags in // ConfigState to decide if and how to populate those surrogate keys. func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { vs := &valuesSorter{values: values, cs: cs} if canSortSimply(vs.values[0].Kind()) { return vs } if !cs.DisableMethods { vs.strings = make([]string, len(values)) for i := range vs.values { b := bytes.Buffer{} if !handleMethods(cs, &b, vs.values[i]) { vs.strings = nil break } vs.strings[i] = b.String() } } if vs.strings == nil && cs.SpewKeys { vs.strings = make([]string, len(values)) for i := range vs.values { vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) } } return vs } // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted // directly, or whether it should be considered for sorting by surrogate keys // (if the ConfigState allows it). func canSortSimply(kind reflect.Kind) bool { // This switch parallels valueSortLess, except for the default case. switch kind { case reflect.Bool: return true case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: return true case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: return true case reflect.Float32, reflect.Float64: return true case reflect.String: return true case reflect.Uintptr: return true case reflect.Array: return true } return false } // Len returns the number of values in the slice. It is part of the // sort.Interface implementation. func (s *valuesSorter) Len() int { return len(s.values) } // Swap swaps the values at the passed indices. It is part of the // sort.Interface implementation. func (s *valuesSorter) Swap(i, j int) { s.values[i], s.values[j] = s.values[j], s.values[i] if s.strings != nil { s.strings[i], s.strings[j] = s.strings[j], s.strings[i] } } // valueSortLess returns whether the first value should sort before the second // value. It is used by valueSorter.Less as part of the sort.Interface // implementation. func valueSortLess(a, b reflect.Value) bool { switch a.Kind() { case reflect.Bool: return !a.Bool() && b.Bool() case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: return a.Int() < b.Int() case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: return a.Uint() < b.Uint() case reflect.Float32, reflect.Float64: return a.Float() < b.Float() case reflect.String: return a.String() < b.String() case reflect.Uintptr: return a.Uint() < b.Uint() case reflect.Array: // Compare the contents of both arrays. l := a.Len() for i := 0; i < l; i++ { av := a.Index(i) bv := b.Index(i) if av.Interface() == bv.Interface() { continue } return valueSortLess(av, bv) } } return a.String() < b.String() } // Less returns whether the value at index i should sort before the // value at index j. It is part of the sort.Interface implementation. func (s *valuesSorter) Less(i, j int) bool { if s.strings == nil { return valueSortLess(s.values[i], s.values[j]) } return s.strings[i] < s.strings[j] } // sortValues is a sort function that handles both native types and any type that // can be converted to error or Stringer. Other inputs are sorted according to // their Value.String() value to ensure display stability. func sortValues(values []reflect.Value, cs *ConfigState) { if len(values) == 0 { return } sort.Sort(newValuesSorter(values, cs)) } go-spew-1.1.0/spew/common_test.go000066400000000000000000000173721300520646600167420ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew_test import ( "fmt" "reflect" "testing" "github.com/davecgh/go-spew/spew" ) // custom type to test Stinger interface on non-pointer receiver. type stringer string // String implements the Stringer interface for testing invocation of custom // stringers on types with non-pointer receivers. func (s stringer) String() string { return "stringer " + string(s) } // custom type to test Stinger interface on pointer receiver. type pstringer string // String implements the Stringer interface for testing invocation of custom // stringers on types with only pointer receivers. func (s *pstringer) String() string { return "stringer " + string(*s) } // xref1 and xref2 are cross referencing structs for testing circular reference // detection. type xref1 struct { ps2 *xref2 } type xref2 struct { ps1 *xref1 } // indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular // reference for testing detection. type indirCir1 struct { ps2 *indirCir2 } type indirCir2 struct { ps3 *indirCir3 } type indirCir3 struct { ps1 *indirCir1 } // embed is used to test embedded structures. type embed struct { a string } // embedwrap is used to test embedded structures. type embedwrap struct { *embed e *embed } // panicer is used to intentionally cause a panic for testing spew properly // handles them type panicer int func (p panicer) String() string { panic("test panic") } // customError is used to test custom error interface invocation. type customError int func (e customError) Error() string { return fmt.Sprintf("error: %d", int(e)) } // stringizeWants converts a slice of wanted test output into a format suitable // for a test error message. func stringizeWants(wants []string) string { s := "" for i, want := range wants { if i > 0 { s += fmt.Sprintf("want%d: %s", i+1, want) } else { s += "want: " + want } } return s } // testFailed returns whether or not a test failed by checking if the result // of the test is in the slice of wanted strings. func testFailed(result string, wants []string) bool { for _, want := range wants { if result == want { return false } } return true } type sortableStruct struct { x int } func (ss sortableStruct) String() string { return fmt.Sprintf("ss.%d", ss.x) } type unsortableStruct struct { x int } type sortTestCase struct { input []reflect.Value expected []reflect.Value } func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) { getInterfaces := func(values []reflect.Value) []interface{} { interfaces := []interface{}{} for _, v := range values { interfaces = append(interfaces, v.Interface()) } return interfaces } for _, test := range tests { spew.SortValues(test.input, cs) // reflect.DeepEqual cannot really make sense of reflect.Value, // probably because of all the pointer tricks. For instance, // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} // instead. input := getInterfaces(test.input) expected := getInterfaces(test.expected) if !reflect.DeepEqual(input, expected) { t.Errorf("Sort mismatch:\n %v != %v", input, expected) } } } // TestSortValues ensures the sort functionality for relect.Value based sorting // works as intended. func TestSortValues(t *testing.T) { v := reflect.ValueOf a := v("a") b := v("b") c := v("c") embedA := v(embed{"a"}) embedB := v(embed{"b"}) embedC := v(embed{"c"}) tests := []sortTestCase{ // No values. { []reflect.Value{}, []reflect.Value{}, }, // Bools. { []reflect.Value{v(false), v(true), v(false)}, []reflect.Value{v(false), v(false), v(true)}, }, // Ints. { []reflect.Value{v(2), v(1), v(3)}, []reflect.Value{v(1), v(2), v(3)}, }, // Uints. { []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, }, // Floats. { []reflect.Value{v(2.0), v(1.0), v(3.0)}, []reflect.Value{v(1.0), v(2.0), v(3.0)}, }, // Strings. { []reflect.Value{b, a, c}, []reflect.Value{a, b, c}, }, // Array { []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})}, []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})}, }, // Uintptrs. { []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, }, // SortableStructs. { // Note: not sorted - DisableMethods is set. []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, }, // UnsortableStructs. { // Note: not sorted - SpewKeys is false. []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, }, // Invalid. { []reflect.Value{embedB, embedA, embedC}, []reflect.Value{embedB, embedA, embedC}, }, } cs := spew.ConfigState{DisableMethods: true, SpewKeys: false} helpTestSortValues(tests, &cs, t) } // TestSortValuesWithMethods ensures the sort functionality for relect.Value // based sorting works as intended when using string methods. func TestSortValuesWithMethods(t *testing.T) { v := reflect.ValueOf a := v("a") b := v("b") c := v("c") tests := []sortTestCase{ // Ints. { []reflect.Value{v(2), v(1), v(3)}, []reflect.Value{v(1), v(2), v(3)}, }, // Strings. { []reflect.Value{b, a, c}, []reflect.Value{a, b, c}, }, // SortableStructs. { []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, }, // UnsortableStructs. { // Note: not sorted - SpewKeys is false. []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, }, } cs := spew.ConfigState{DisableMethods: false, SpewKeys: false} helpTestSortValues(tests, &cs, t) } // TestSortValuesWithSpew ensures the sort functionality for relect.Value // based sorting works as intended when using spew to stringify keys. func TestSortValuesWithSpew(t *testing.T) { v := reflect.ValueOf a := v("a") b := v("b") c := v("c") tests := []sortTestCase{ // Ints. { []reflect.Value{v(2), v(1), v(3)}, []reflect.Value{v(1), v(2), v(3)}, }, // Strings. { []reflect.Value{b, a, c}, []reflect.Value{a, b, c}, }, // SortableStructs. { []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, }, // UnsortableStructs. { []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})}, }, } cs := spew.ConfigState{DisableMethods: true, SpewKeys: true} helpTestSortValues(tests, &cs, t) } go-spew-1.1.0/spew/config.go000066400000000000000000000310521300520646600156470ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew import ( "bytes" "fmt" "io" "os" ) // ConfigState houses the configuration options used by spew to format and // display values. There is a global instance, Config, that is used to control // all top-level Formatter and Dump functionality. Each ConfigState instance // provides methods equivalent to the top-level functions. // // The zero value for ConfigState provides no indentation. You would typically // want to set it to a space or a tab. // // Alternatively, you can use NewDefaultConfig to get a ConfigState instance // with default settings. See the documentation of NewDefaultConfig for default // values. type ConfigState struct { // Indent specifies the string to use for each indentation level. The // global config instance that all top-level functions use set this to a // single space by default. If you would like more indentation, you might // set this to a tab with "\t" or perhaps two spaces with " ". Indent string // MaxDepth controls the maximum number of levels to descend into nested // data structures. The default, 0, means there is no limit. // // NOTE: Circular data structures are properly detected, so it is not // necessary to set this value unless you specifically want to limit deeply // nested data structures. MaxDepth int // DisableMethods specifies whether or not error and Stringer interfaces are // invoked for types that implement them. DisableMethods bool // DisablePointerMethods specifies whether or not to check for and invoke // error and Stringer interfaces on types which only accept a pointer // receiver when the current type is not a pointer. // // NOTE: This might be an unsafe action since calling one of these methods // with a pointer receiver could technically mutate the value, however, // in practice, types which choose to satisify an error or Stringer // interface with a pointer receiver should not be mutating their state // inside these interface methods. As a result, this option relies on // access to the unsafe package, so it will not have any effect when // running in environments without access to the unsafe package such as // Google App Engine or with the "safe" build tag specified. DisablePointerMethods bool // DisablePointerAddresses specifies whether to disable the printing of // pointer addresses. This is useful when diffing data structures in tests. DisablePointerAddresses bool // DisableCapacities specifies whether to disable the printing of capacities // for arrays, slices, maps and channels. This is useful when diffing // data structures in tests. DisableCapacities bool // ContinueOnMethod specifies whether or not recursion should continue once // a custom error or Stringer interface is invoked. The default, false, // means it will print the results of invoking the custom error or Stringer // interface and return immediately instead of continuing to recurse into // the internals of the data type. // // NOTE: This flag does not have any effect if method invocation is disabled // via the DisableMethods or DisablePointerMethods options. ContinueOnMethod bool // SortKeys specifies map keys should be sorted before being printed. Use // this to have a more deterministic, diffable output. Note that only // native types (bool, int, uint, floats, uintptr and string) and types // that support the error or Stringer interfaces (if methods are // enabled) are supported, with other types sorted according to the // reflect.Value.String() output which guarantees display stability. SortKeys bool // SpewKeys specifies that, as a last resort attempt, map keys should // be spewed to strings and sorted by those strings. This is only // considered if SortKeys is true. SpewKeys bool } // Config is the active configuration of the top-level functions. // The configuration can be changed by modifying the contents of spew.Config. var Config = ConfigState{Indent: " "} // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the formatted string as a value that satisfies error. See NewFormatter // for formatting details. // // This function is shorthand for the following syntax: // // fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { return fmt.Errorf(format, c.convertArgs(a)...) } // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprint(w, c.convertArgs(a)...) } // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(w, format, c.convertArgs(a)...) } // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it // passed with a Formatter interface returned by c.NewFormatter. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprintln(w, c.convertArgs(a)...) } // Print is a wrapper for fmt.Print that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Print(a ...interface{}) (n int, err error) { return fmt.Print(c.convertArgs(a)...) } // Printf is a wrapper for fmt.Printf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { return fmt.Printf(format, c.convertArgs(a)...) } // Println is a wrapper for fmt.Println that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Println(a ...interface{}) (n int, err error) { return fmt.Println(c.convertArgs(a)...) } // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Sprint(a ...interface{}) string { return fmt.Sprint(c.convertArgs(a)...) } // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were // passed with a Formatter interface returned by c.NewFormatter. It returns // the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Sprintf(format string, a ...interface{}) string { return fmt.Sprintf(format, c.convertArgs(a)...) } // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it // were passed with a Formatter interface returned by c.NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) func (c *ConfigState) Sprintln(a ...interface{}) string { return fmt.Sprintln(c.convertArgs(a)...) } /* NewFormatter returns a custom formatter that satisfies the fmt.Formatter interface. As a result, it integrates cleanly with standard fmt package printing functions. The formatter is useful for inline printing of smaller data types similar to the standard %v format specifier. The custom formatter only responds to the %v (most compact), %+v (adds pointer addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb combinations. Any other verbs such as %x and %q will be sent to the the standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). Typically this function shouldn't be called directly. It is much easier to make use of the custom formatter by calling one of the convenience functions such as c.Printf, c.Println, or c.Printf. */ func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { return newFormatter(c, v) } // Fdump formats and displays the passed arguments to io.Writer w. It formats // exactly the same as Dump. func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { fdump(c, w, a...) } /* Dump displays the passed parameters to standard out with newlines, customizable indentation, and additional debug information such as complete types and all pointer addresses used to indirect to the final value. It provides the following features over the built-in printing facilities provided by the fmt package: * Pointers are dereferenced and followed * Circular data structures are detected and handled properly * Custom Stringer/error interfaces are optionally invoked, including on unexported types * Custom types which only implement the Stringer/error interfaces via a pointer receiver are optionally invoked when passing non-pointer variables * Byte arrays and slices are dumped like the hexdump -C command which includes offsets, byte values in hex, and ASCII output The configuration options are controlled by modifying the public members of c. See ConfigState for options documentation. See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to get the formatted result as a string. */ func (c *ConfigState) Dump(a ...interface{}) { fdump(c, os.Stdout, a...) } // Sdump returns a string with the passed arguments formatted exactly the same // as Dump. func (c *ConfigState) Sdump(a ...interface{}) string { var buf bytes.Buffer fdump(c, &buf, a...) return buf.String() } // convertArgs accepts a slice of arguments and returns a slice of the same // length with each argument converted to a spew Formatter interface using // the ConfigState associated with s. func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { formatters = make([]interface{}, len(args)) for index, arg := range args { formatters[index] = newFormatter(c, arg) } return formatters } // NewDefaultConfig returns a ConfigState with the following default settings. // // Indent: " " // MaxDepth: 0 // DisableMethods: false // DisablePointerMethods: false // ContinueOnMethod: false // SortKeys: false func NewDefaultConfig() *ConfigState { return &ConfigState{Indent: " "} } go-spew-1.1.0/spew/doc.go000066400000000000000000000205171300520646600151530ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ /* Package spew implements a deep pretty printer for Go data structures to aid in debugging. A quick overview of the additional features spew provides over the built-in printing facilities for Go data types are as follows: * Pointers are dereferenced and followed * Circular data structures are detected and handled properly * Custom Stringer/error interfaces are optionally invoked, including on unexported types * Custom types which only implement the Stringer/error interfaces via a pointer receiver are optionally invoked when passing non-pointer variables * Byte arrays and slices are dumped like the hexdump -C command which includes offsets, byte values in hex, and ASCII output (only when using Dump style) There are two different approaches spew allows for dumping Go data structures: * Dump style which prints with newlines, customizable indentation, and additional debug information such as types and all pointer addresses used to indirect to the final value * A custom Formatter interface that integrates cleanly with the standard fmt package and replaces %v, %+v, %#v, and %#+v to provide inline printing similar to the default %v while providing the additional functionality outlined above and passing unsupported format verbs such as %x and %q along to fmt Quick Start This section demonstrates how to quickly get started with spew. See the sections below for further details on formatting and configuration options. To dump a variable with full newlines, indentation, type, and pointer information use Dump, Fdump, or Sdump: spew.Dump(myVar1, myVar2, ...) spew.Fdump(someWriter, myVar1, myVar2, ...) str := spew.Sdump(myVar1, myVar2, ...) Alternatively, if you would prefer to use format strings with a compacted inline printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses): spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) Configuration Options Configuration of spew is handled by fields in the ConfigState type. For convenience, all of the top-level functions use a global state available via the spew.Config global. It is also possible to create a ConfigState instance that provides methods equivalent to the top-level functions. This allows concurrent configuration options. See the ConfigState documentation for more details. The following configuration options are available: * Indent String to use for each indentation level for Dump functions. It is a single space by default. A popular alternative is "\t". * MaxDepth Maximum number of levels to descend into nested data structures. There is no limit by default. * DisableMethods Disables invocation of error and Stringer interface methods. Method invocation is enabled by default. * DisablePointerMethods Disables invocation of error and Stringer interface methods on types which only accept pointer receivers from non-pointer variables. Pointer method invocation is enabled by default. * DisablePointerAddresses DisablePointerAddresses specifies whether to disable the printing of pointer addresses. This is useful when diffing data structures in tests. * DisableCapacities DisableCapacities specifies whether to disable the printing of capacities for arrays, slices, maps and channels. This is useful when diffing data structures in tests. * ContinueOnMethod Enables recursion into types after invoking error and Stringer interface methods. Recursion after method invocation is disabled by default. * SortKeys Specifies map keys should be sorted before being printed. Use this to have a more deterministic, diffable output. Note that only native types (bool, int, uint, floats, uintptr and string) and types which implement error or Stringer interfaces are supported with other types sorted according to the reflect.Value.String() output which guarantees display stability. Natural map order is used by default. * SpewKeys Specifies that, as a last resort attempt, map keys should be spewed to strings and sorted by those strings. This is only considered if SortKeys is true. Dump Usage Simply call spew.Dump with a list of variables you want to dump: spew.Dump(myVar1, myVar2, ...) You may also call spew.Fdump if you would prefer to output to an arbitrary io.Writer. For example, to dump to standard error: spew.Fdump(os.Stderr, myVar1, myVar2, ...) A third option is to call spew.Sdump to get the formatted output as a string: str := spew.Sdump(myVar1, myVar2, ...) Sample Dump Output See the Dump example for details on the setup of the types and variables being shown here. (main.Foo) { unexportedField: (*main.Bar)(0xf84002e210)({ flag: (main.Flag) flagTwo, data: (uintptr) }), ExportedField: (map[interface {}]interface {}) (len=1) { (string) (len=3) "one": (bool) true } } Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C command as shown. ([]uint8) (len=32 cap=32) { 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 00000020 31 32 |12| } Custom Formatter Spew provides a custom formatter that implements the fmt.Formatter interface so that it integrates cleanly with standard fmt package printing functions. The formatter is useful for inline printing of smaller data types similar to the standard %v format specifier. The custom formatter only responds to the %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb combinations. Any other verbs such as %x and %q will be sent to the the standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). Custom Formatter Usage The simplest way to make use of the spew custom formatter is to call one of the convenience functions such as spew.Printf, spew.Println, or spew.Printf. The functions have syntax you are most likely already familiar with: spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) spew.Println(myVar, myVar2) spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) See the Index for the full list convenience functions. Sample Formatter Output Double pointer to a uint8: %v: <**>5 %+v: <**>(0xf8400420d0->0xf8400420c8)5 %#v: (**uint8)5 %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 Pointer to circular struct with a uint8 field and a pointer to itself: %v: <*>{1 <*>} %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} See the Printf example for details on the setup of variables being shown here. Errors Since it is possible for custom Stringer/error interfaces to panic, spew detects them and handles them internally by printing the panic information inline with the output. Since spew is intended to provide deep pretty printing capabilities on structures, it intentionally does not return any errors. */ package spew go-spew-1.1.0/spew/dump.go000066400000000000000000000327651300520646600153630ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew import ( "bytes" "encoding/hex" "fmt" "io" "os" "reflect" "regexp" "strconv" "strings" ) var ( // uint8Type is a reflect.Type representing a uint8. It is used to // convert cgo types to uint8 slices for hexdumping. uint8Type = reflect.TypeOf(uint8(0)) // cCharRE is a regular expression that matches a cgo char. // It is used to detect character arrays to hexdump them. cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") // cUnsignedCharRE is a regular expression that matches a cgo unsigned // char. It is used to detect unsigned character arrays to hexdump // them. cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") // cUint8tCharRE is a regular expression that matches a cgo uint8_t. // It is used to detect uint8_t arrays to hexdump them. cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") ) // dumpState contains information about the state of a dump operation. type dumpState struct { w io.Writer depth int pointers map[uintptr]int ignoreNextType bool ignoreNextIndent bool cs *ConfigState } // indent performs indentation according to the depth level and cs.Indent // option. func (d *dumpState) indent() { if d.ignoreNextIndent { d.ignoreNextIndent = false return } d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) } // unpackValue returns values inside of non-nil interfaces when possible. // This is useful for data types like structs, arrays, slices, and maps which // can contain varying types packed inside an interface. func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { if v.Kind() == reflect.Interface && !v.IsNil() { v = v.Elem() } return v } // dumpPtr handles formatting of pointers by indirecting them as necessary. func (d *dumpState) dumpPtr(v reflect.Value) { // Remove pointers at or below the current depth from map used to detect // circular refs. for k, depth := range d.pointers { if depth >= d.depth { delete(d.pointers, k) } } // Keep list of all dereferenced pointers to show later. pointerChain := make([]uintptr, 0) // Figure out how many levels of indirection there are by dereferencing // pointers and unpacking interfaces down the chain while detecting circular // references. nilFound := false cycleFound := false indirects := 0 ve := v for ve.Kind() == reflect.Ptr { if ve.IsNil() { nilFound = true break } indirects++ addr := ve.Pointer() pointerChain = append(pointerChain, addr) if pd, ok := d.pointers[addr]; ok && pd < d.depth { cycleFound = true indirects-- break } d.pointers[addr] = d.depth ve = ve.Elem() if ve.Kind() == reflect.Interface { if ve.IsNil() { nilFound = true break } ve = ve.Elem() } } // Display type information. d.w.Write(openParenBytes) d.w.Write(bytes.Repeat(asteriskBytes, indirects)) d.w.Write([]byte(ve.Type().String())) d.w.Write(closeParenBytes) // Display pointer information. if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { d.w.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { d.w.Write(pointerChainBytes) } printHexPtr(d.w, addr) } d.w.Write(closeParenBytes) } // Display dereferenced value. d.w.Write(openParenBytes) switch { case nilFound == true: d.w.Write(nilAngleBytes) case cycleFound == true: d.w.Write(circularBytes) default: d.ignoreNextType = true d.dump(ve) } d.w.Write(closeParenBytes) } // dumpSlice handles formatting of arrays and slices. Byte (uint8 under // reflection) arrays and slices are dumped in hexdump -C fashion. func (d *dumpState) dumpSlice(v reflect.Value) { // Determine whether this type should be hex dumped or not. Also, // for types which should be hexdumped, try to use the underlying data // first, then fall back to trying to convert them to a uint8 slice. var buf []uint8 doConvert := false doHexDump := false numEntries := v.Len() if numEntries > 0 { vt := v.Index(0).Type() vts := vt.String() switch { // C types that need to be converted. case cCharRE.MatchString(vts): fallthrough case cUnsignedCharRE.MatchString(vts): fallthrough case cUint8tCharRE.MatchString(vts): doConvert = true // Try to use existing uint8 slices and fall back to converting // and copying if that fails. case vt.Kind() == reflect.Uint8: // We need an addressable interface to convert the type // to a byte slice. However, the reflect package won't // give us an interface on certain things like // unexported struct fields in order to enforce // visibility rules. We use unsafe, when available, to // bypass these restrictions since this package does not // mutate the values. vs := v if !vs.CanInterface() || !vs.CanAddr() { vs = unsafeReflectValue(vs) } if !UnsafeDisabled { vs = vs.Slice(0, numEntries) // Use the existing uint8 slice if it can be // type asserted. iface := vs.Interface() if slice, ok := iface.([]uint8); ok { buf = slice doHexDump = true break } } // The underlying data needs to be converted if it can't // be type asserted to a uint8 slice. doConvert = true } // Copy and convert the underlying type if needed. if doConvert && vt.ConvertibleTo(uint8Type) { // Convert and copy each element into a uint8 byte // slice. buf = make([]uint8, numEntries) for i := 0; i < numEntries; i++ { vv := v.Index(i) buf[i] = uint8(vv.Convert(uint8Type).Uint()) } doHexDump = true } } // Hexdump the entire slice as needed. if doHexDump { indent := strings.Repeat(d.cs.Indent, d.depth) str := indent + hex.Dump(buf) str = strings.Replace(str, "\n", "\n"+indent, -1) str = strings.TrimRight(str, d.cs.Indent) d.w.Write([]byte(str)) return } // Recursively call dump for each item. for i := 0; i < numEntries; i++ { d.dump(d.unpackValue(v.Index(i))) if i < (numEntries - 1) { d.w.Write(commaNewlineBytes) } else { d.w.Write(newlineBytes) } } } // dump is the main workhorse for dumping a value. It uses the passed reflect // value to figure out what kind of object we are dealing with and formats it // appropriately. It is a recursive function, however circular data structures // are detected and handled properly. func (d *dumpState) dump(v reflect.Value) { // Handle invalid reflect values immediately. kind := v.Kind() if kind == reflect.Invalid { d.w.Write(invalidAngleBytes) return } // Handle pointers specially. if kind == reflect.Ptr { d.indent() d.dumpPtr(v) return } // Print type information unless already handled elsewhere. if !d.ignoreNextType { d.indent() d.w.Write(openParenBytes) d.w.Write([]byte(v.Type().String())) d.w.Write(closeParenBytes) d.w.Write(spaceBytes) } d.ignoreNextType = false // Display length and capacity if the built-in len and cap functions // work with the value's kind and the len/cap itself is non-zero. valueLen, valueCap := 0, 0 switch v.Kind() { case reflect.Array, reflect.Slice, reflect.Chan: valueLen, valueCap = v.Len(), v.Cap() case reflect.Map, reflect.String: valueLen = v.Len() } if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { d.w.Write(openParenBytes) if valueLen != 0 { d.w.Write(lenEqualsBytes) printInt(d.w, int64(valueLen), 10) } if !d.cs.DisableCapacities && valueCap != 0 { if valueLen != 0 { d.w.Write(spaceBytes) } d.w.Write(capEqualsBytes) printInt(d.w, int64(valueCap), 10) } d.w.Write(closeParenBytes) d.w.Write(spaceBytes) } // Call Stringer/error interfaces if they exist and the handle methods flag // is enabled if !d.cs.DisableMethods { if (kind != reflect.Invalid) && (kind != reflect.Interface) { if handled := handleMethods(d.cs, d.w, v); handled { return } } } switch kind { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. case reflect.Bool: printBool(d.w, v.Bool()) case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: printInt(d.w, v.Int(), 10) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: printUint(d.w, v.Uint(), 10) case reflect.Float32: printFloat(d.w, v.Float(), 32) case reflect.Float64: printFloat(d.w, v.Float(), 64) case reflect.Complex64: printComplex(d.w, v.Complex(), 32) case reflect.Complex128: printComplex(d.w, v.Complex(), 64) case reflect.Slice: if v.IsNil() { d.w.Write(nilAngleBytes) break } fallthrough case reflect.Array: d.w.Write(openBraceNewlineBytes) d.depth++ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { d.indent() d.w.Write(maxNewlineBytes) } else { d.dumpSlice(v) } d.depth-- d.indent() d.w.Write(closeBraceBytes) case reflect.String: d.w.Write([]byte(strconv.Quote(v.String()))) case reflect.Interface: // The only time we should get here is for nil interfaces due to // unpackValue calls. if v.IsNil() { d.w.Write(nilAngleBytes) } case reflect.Ptr: // Do nothing. We should never get here since pointers have already // been handled above. case reflect.Map: // nil maps should be indicated as different than empty maps if v.IsNil() { d.w.Write(nilAngleBytes) break } d.w.Write(openBraceNewlineBytes) d.depth++ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { d.indent() d.w.Write(maxNewlineBytes) } else { numEntries := v.Len() keys := v.MapKeys() if d.cs.SortKeys { sortValues(keys, d.cs) } for i, key := range keys { d.dump(d.unpackValue(key)) d.w.Write(colonSpaceBytes) d.ignoreNextIndent = true d.dump(d.unpackValue(v.MapIndex(key))) if i < (numEntries - 1) { d.w.Write(commaNewlineBytes) } else { d.w.Write(newlineBytes) } } } d.depth-- d.indent() d.w.Write(closeBraceBytes) case reflect.Struct: d.w.Write(openBraceNewlineBytes) d.depth++ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { d.indent() d.w.Write(maxNewlineBytes) } else { vt := v.Type() numFields := v.NumField() for i := 0; i < numFields; i++ { d.indent() vtf := vt.Field(i) d.w.Write([]byte(vtf.Name)) d.w.Write(colonSpaceBytes) d.ignoreNextIndent = true d.dump(d.unpackValue(v.Field(i))) if i < (numFields - 1) { d.w.Write(commaNewlineBytes) } else { d.w.Write(newlineBytes) } } } d.depth-- d.indent() d.w.Write(closeBraceBytes) case reflect.Uintptr: printHexPtr(d.w, uintptr(v.Uint())) case reflect.UnsafePointer, reflect.Chan, reflect.Func: printHexPtr(d.w, v.Pointer()) // There were not any other types at the time this code was written, but // fall back to letting the default fmt package handle it in case any new // types are added. default: if v.CanInterface() { fmt.Fprintf(d.w, "%v", v.Interface()) } else { fmt.Fprintf(d.w, "%v", v.String()) } } } // fdump is a helper function to consolidate the logic from the various public // methods which take varying writers and config states. func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { for _, arg := range a { if arg == nil { w.Write(interfaceBytes) w.Write(spaceBytes) w.Write(nilAngleBytes) w.Write(newlineBytes) continue } d := dumpState{w: w, cs: cs} d.pointers = make(map[uintptr]int) d.dump(reflect.ValueOf(arg)) d.w.Write(newlineBytes) } } // Fdump formats and displays the passed arguments to io.Writer w. It formats // exactly the same as Dump. func Fdump(w io.Writer, a ...interface{}) { fdump(&Config, w, a...) } // Sdump returns a string with the passed arguments formatted exactly the same // as Dump. func Sdump(a ...interface{}) string { var buf bytes.Buffer fdump(&Config, &buf, a...) return buf.String() } /* Dump displays the passed parameters to standard out with newlines, customizable indentation, and additional debug information such as complete types and all pointer addresses used to indirect to the final value. It provides the following features over the built-in printing facilities provided by the fmt package: * Pointers are dereferenced and followed * Circular data structures are detected and handled properly * Custom Stringer/error interfaces are optionally invoked, including on unexported types * Custom types which only implement the Stringer/error interfaces via a pointer receiver are optionally invoked when passing non-pointer variables * Byte arrays and slices are dumped like the hexdump -C command which includes offsets, byte values in hex, and ASCII output The configuration options are controlled by an exported package global, spew.Config. See ConfigState for options documentation. See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to get the formatted result as a string. */ func Dump(a ...interface{}) { fdump(&Config, os.Stdout, a...) } go-spew-1.1.0/spew/dump_test.go000066400000000000000000001017741300520646600164170ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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 - Array containing interfaces - Array containing bytes - Slice containing standard float32 values - Slice containing type with custom formatter on pointer receiver only - Slice containing interfaces - Slice containing bytes - Nil slice - Standard string - Nil interface - Sub-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 - Map with nil interface value - Struct with primitives - Struct that contains another struct - Struct that contains custom type with Stringer pointer interface via both exported and unexported fields - Struct that contains embedded struct and field to same struct - 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 - Type that panics in its Stringer interface */ package spew_test import ( "bytes" "fmt" "testing" "unsafe" "github.com/davecgh/go-spew/spew" ) // dumpTest is used to describe a test to be performed against the Dump method. type dumpTest struct { in interface{} wants []string } // dumpTests houses all of the tests to be performed against the Dump method. var dumpTests = make([]dumpTest, 0) // addDumpTest is a helper method to append the passed input and desired result // to dumpTests func addDumpTest(in interface{}, wants ...string) { test := dumpTest{in, wants} dumpTests = append(dumpTests, test) } func addIntDumpTests() { // Max int8. v := int8(127) nv := (*int8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "int8" vs := "127" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Max int16. v2 := int16(32767) nv2 := (*int16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "int16" v2s := "32767" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // Max int32. v3 := int32(2147483647) nv3 := (*int32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "int32" v3s := "2147483647" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Max int64. v4 := int64(9223372036854775807) nv4 := (*int64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "int64" v4s := "9223372036854775807" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") // Max int. v5 := int(2147483647) nv5 := (*int)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "int" v5s := "2147483647" addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") addDumpTest(nv5, "(*"+v5t+")()\n") } func addUintDumpTests() { // Max uint8. v := uint8(255) nv := (*uint8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uint8" vs := "255" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Max uint16. v2 := uint16(65535) nv2 := (*uint16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // Max uint32. v3 := uint32(4294967295) nv3 := (*uint32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "uint32" v3s := "4294967295" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Max uint64. v4 := uint64(18446744073709551615) nv4 := (*uint64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "uint64" v4s := "18446744073709551615" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") // Max uint. v5 := uint(4294967295) nv5 := (*uint)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "uint" v5s := "4294967295" addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") addDumpTest(nv5, "(*"+v5t+")()\n") } func addBoolDumpTests() { // Boolean true. v := bool(true) nv := (*bool)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "bool" vs := "true" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Boolean false. v2 := bool(false) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "bool" v2s := "false" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") } func addFloatDumpTests() { // Standard float32. v := float32(3.1415) nv := (*float32)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "float32" vs := "3.1415" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Standard float64. v2 := float64(3.1415926) nv2 := (*float64)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "float64" v2s := "3.1415926" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") } func addComplexDumpTests() { // Standard complex64. v := complex(float32(6), -2) nv := (*complex64)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "complex64" vs := "(6-2i)" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Standard complex128. v2 := complex(float64(-6), 2) nv2 := (*complex128)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "complex128" v2s := "(-6+2i)" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") } func addArrayDumpTests() { // Array containing standard ints. v := [3]int{1, 2, 3} vLen := fmt.Sprintf("%d", len(v)) vCap := fmt.Sprintf("%d", cap(v)) nv := (*[3]int)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "int" vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + vt + ") 2,\n (" + vt + ") 3\n}" addDumpTest(v, "([3]"+vt+") "+vs+"\n") addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*[3]"+vt+")()\n") // Array containing type with custom formatter on pointer receiver only. v2i0 := pstringer("1") v2i1 := pstringer("2") v2i2 := pstringer("3") v2 := [3]pstringer{v2i0, v2i1, v2i2} v2i0Len := fmt.Sprintf("%d", len(v2i0)) v2i1Len := fmt.Sprintf("%d", len(v2i1)) v2i2Len := fmt.Sprintf("%d", len(v2i2)) v2Len := fmt.Sprintf("%d", len(v2)) v2Cap := fmt.Sprintf("%d", cap(v2)) nv2 := (*[3]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.pstringer" v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + "stringer 3\n}" v2s := v2sp if spew.UnsafeDisabled { v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" + v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len + ") " + "\"3\"\n}" } addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n") addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n") addDumpTest(nv2, "(*[3]"+v2t+")()\n") // Array containing interfaces. v3i0 := "one" v3 := [3]interface{}{v3i0, int(2), uint(3)} v3i0Len := fmt.Sprintf("%d", len(v3i0)) v3Len := fmt.Sprintf("%d", len(v3)) v3Cap := fmt.Sprintf("%d", cap(v3)) nv3 := (*[3]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[3]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + v3t4 + ") 3\n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Array containing bytes. v4 := [34]byte{ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, } v4Len := fmt.Sprintf("%d", len(v4)) v4Cap := fmt.Sprintf("%d", cap(v4)) nv4 := (*[34]byte)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "[34]uint8" v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + " |............... |\n" + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + " |!\"#$%&'()*+,-./0|\n" + " 00000020 31 32 " + " |12|\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") } func addSliceDumpTests() { // Slice containing standard float32 values. v := []float32{3.14, 6.28, 12.56} vLen := fmt.Sprintf("%d", len(v)) vCap := fmt.Sprintf("%d", cap(v)) nv := (*[]float32)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "float32" vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + vt + ") 6.28,\n (" + vt + ") 12.56\n}" addDumpTest(v, "([]"+vt+") "+vs+"\n") addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*[]"+vt+")()\n") // Slice containing type with custom formatter on pointer receiver only. v2i0 := pstringer("1") v2i1 := pstringer("2") v2i2 := pstringer("3") v2 := []pstringer{v2i0, v2i1, v2i2} v2i0Len := fmt.Sprintf("%d", len(v2i0)) v2i1Len := fmt.Sprintf("%d", len(v2i1)) v2i2Len := fmt.Sprintf("%d", len(v2i2)) v2Len := fmt.Sprintf("%d", len(v2)) v2Cap := fmt.Sprintf("%d", cap(v2)) nv2 := (*[]pstringer)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "spew_test.pstringer" v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + "stringer 3\n}" addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*[]"+v2t+")()\n") // Slice containing interfaces. v3i0 := "one" v3 := []interface{}{v3i0, int(2), uint(3), nil} v3i0Len := fmt.Sprintf("%d", len(v3i0)) v3Len := fmt.Sprintf("%d", len(v3)) v3Cap := fmt.Sprintf("%d", cap(v3)) nv3 := (*[]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3t5 := "interface {}" v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + v3t4 + ") 3,\n (" + v3t5 + ") \n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Slice containing bytes. v4 := []byte{ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, } v4Len := fmt.Sprintf("%d", len(v4)) v4Cap := fmt.Sprintf("%d", cap(v4)) nv4 := (*[]byte)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "[]uint8" v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + " |............... |\n" + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + " |!\"#$%&'()*+,-./0|\n" + " 00000020 31 32 " + " |12|\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") // Nil slice. v5 := []int(nil) nv5 := (*[]int)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "[]int" v5s := "" addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") addDumpTest(nv5, "(*"+v5t+")()\n") } func addStringDumpTests() { // Standard string. v := "test" vLen := fmt.Sprintf("%d", len(v)) nv := (*string)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "string" vs := "(len=" + vLen + ") \"test\"" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") } func addInterfaceDumpTests() { // Nil interface. var v interface{} nv := (*interface{})(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "interface {}" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Sub-interface. v2 := interface{}(uint16(65535)) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") } func addMapDumpTests() { // Map with string keys and int vals. k := "one" kk := "two" m := map[string]int{k: 1, kk: 2} klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up kkLen := fmt.Sprintf("%d", len(kk)) mLen := fmt.Sprintf("%d", len(m)) nilMap := map[string]int(nil) nm := (*map[string]int)(nil) pm := &m mAddr := fmt.Sprintf("%p", pm) pmAddr := fmt.Sprintf("%p", &pm) mt := "map[string]int" mt1 := "string" mt2 := "int" ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + ") \"two\": (" + mt2 + ") 2\n}" ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + ") \"one\": (" + mt2 + ") 1\n}" addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", "(*"+mt+")("+mAddr+")("+ms2+")\n") addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") addDumpTest(nm, "(*"+mt+")()\n") addDumpTest(nilMap, "("+mt+") \n") // Map with custom formatter type on pointer receiver only keys and vals. k2 := pstringer("one") v2 := pstringer("1") m2 := map[pstringer]pstringer{k2: v2} k2Len := fmt.Sprintf("%d", len(k2)) v2Len := fmt.Sprintf("%d", len(v2)) m2Len := fmt.Sprintf("%d", len(m2)) nilMap2 := map[pstringer]pstringer(nil) nm2 := (*map[pstringer]pstringer)(nil) pm2 := &m2 m2Addr := fmt.Sprintf("%p", pm2) pm2Addr := fmt.Sprintf("%p", &pm2) m2t := "map[spew_test.pstringer]spew_test.pstringer" m2t1 := "spew_test.pstringer" m2t2 := "spew_test.pstringer" m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" if spew.UnsafeDisabled { m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len + ") \"1\"\n}" } addDumpTest(m2, "("+m2t+") "+m2s+"\n") addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") addDumpTest(nm2, "(*"+m2t+")()\n") addDumpTest(nilMap2, "("+m2t+") \n") // Map with interface keys and values. k3 := "one" k3Len := fmt.Sprintf("%d", len(k3)) m3 := map[interface{}]interface{}{k3: 1} m3Len := fmt.Sprintf("%d", len(m3)) nilMap3 := map[interface{}]interface{}(nil) nm3 := (*map[interface{}]interface{})(nil) pm3 := &m3 m3Addr := fmt.Sprintf("%p", pm3) pm3Addr := fmt.Sprintf("%p", &pm3) m3t := "map[interface {}]interface {}" m3t1 := "string" m3t2 := "int" m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + "\"one\": (" + m3t2 + ") 1\n}" addDumpTest(m3, "("+m3t+") "+m3s+"\n") addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") addDumpTest(nm3, "(*"+m3t+")()\n") addDumpTest(nilMap3, "("+m3t+") \n") // Map with nil interface value. k4 := "nil" k4Len := fmt.Sprintf("%d", len(k4)) m4 := map[string]interface{}{k4: nil} m4Len := fmt.Sprintf("%d", len(m4)) nilMap4 := map[string]interface{}(nil) nm4 := (*map[string]interface{})(nil) pm4 := &m4 m4Addr := fmt.Sprintf("%p", pm4) pm4Addr := fmt.Sprintf("%p", &pm4) m4t := "map[string]interface {}" m4t1 := "string" m4t2 := "interface {}" m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + " \"nil\": (" + m4t2 + ") \n}" addDumpTest(m4, "("+m4t+") "+m4s+"\n") addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") addDumpTest(nm4, "(*"+m4t+")()\n") addDumpTest(nilMap4, "("+m4t+") \n") } func addStructDumpTests() { // 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) vt := "spew_test.s1" vt2 := "int8" vt3 := "uint8" vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // 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) v2t := "spew_test.s2" v2t2 := "spew_test.s1" v2t3 := "int8" v2t4 := "uint8" v2t5 := "bool" v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // 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) v3t := "spew_test.s3" v3t2 := "spew_test.pstringer" v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + ") (len=5) stringer test2\n}" v3sp := v3s if spew.UnsafeDisabled { v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + v3t2 + ") (len=5) \"test2\"\n}" v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + v3t2 + ") (len=5) stringer test2\n}" } addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") // Struct that contains embedded struct and field to same struct. e := embed{"embedstr"} eLen := fmt.Sprintf("%d", len("embedstr")) v4 := embedwrap{embed: &e, e: &e} nv4 := (*embedwrap)(nil) pv4 := &v4 eAddr := fmt.Sprintf("%p", &e) v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "spew_test.embedwrap" v4t2 := "spew_test.embed" v4t3 := "string" v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + " \"embedstr\"\n })\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") addDumpTest(nv4, "(*"+v4t+")()\n") } func addUintptrDumpTests() { // Null pointer. v := uintptr(0) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uintptr" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") // Address of real variable. i := 1 v2 := uintptr(unsafe.Pointer(&i)) nv2 := (*uintptr)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uintptr" v2s := fmt.Sprintf("%p", &i) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") } func addUnsafePointerDumpTests() { // Null pointer. v := unsafe.Pointer(uintptr(0)) nv := (*unsafe.Pointer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "unsafe.Pointer" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Address of real variable. i := 1 v2 := unsafe.Pointer(&i) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "unsafe.Pointer" v2s := fmt.Sprintf("%p", &i) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv, "(*"+vt+")()\n") } func addChanDumpTests() { // Nil channel. var v chan int pv := &v nv := (*chan int)(nil) vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "chan int" vs := "" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Real channel. v2 := make(chan int) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "chan int" v2s := fmt.Sprintf("%p", v2) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") } func addFuncDumpTests() { // Function with no params and no returns. v := addIntDumpTests nv := (*func())(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "func()" vs := fmt.Sprintf("%p", v) addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") // Function with param and no returns. v2 := TestDump nv2 := (*func(*testing.T))(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "func(*testing.T)" v2s := fmt.Sprintf("%p", v2) addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") addDumpTest(nv2, "(*"+v2t+")()\n") // 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) v3t := "func(int, string) (bool, error)" v3s := fmt.Sprintf("%p", v3) addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") addDumpTest(nv3, "(*"+v3t+")()\n") } func addCircularDumpTests() { // 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) vt := "spew_test.circular" vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + vAddr + ")()\n })\n}" vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") // 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) v2t := "spew_test.xref1" v2t2 := "spew_test.xref2" v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")()\n })\n })\n}" v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + ")(" + v2Addr + ")()\n })\n}" addDumpTest(v2, "("+v2t+") "+v2s+"\n") addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") // 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) v3t := "spew_test.indirCir1" v3t2 := "spew_test.indirCir2" v3t3 := "spew_test.indirCir3" v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")()\n })\n })\n })\n}" v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + ")()\n })\n })\n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n") addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") } func addPanicDumpTests() { // Type that panics in its Stringer interface. v := panicer(127) nv := (*panicer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.panicer" vs := "(PANIC=test panic)127" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") } func addErrorDumpTests() { // Type that has a custom Error interface. v := customError(127) nv := (*customError)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.customError" vs := "error: 127" addDumpTest(v, "("+vt+") "+vs+"\n") addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") addDumpTest(nv, "(*"+vt+")()\n") } // TestDump executes all of the tests described by dumpTests. func TestDump(t *testing.T) { // Setup tests. addIntDumpTests() addUintDumpTests() addBoolDumpTests() addFloatDumpTests() addComplexDumpTests() addArrayDumpTests() addSliceDumpTests() addStringDumpTests() addInterfaceDumpTests() addMapDumpTests() addStructDumpTests() addUintptrDumpTests() addUnsafePointerDumpTests() addChanDumpTests() addFuncDumpTests() addCircularDumpTests() addPanicDumpTests() addErrorDumpTests() addCgoDumpTests() t.Logf("Running %d tests", len(dumpTests)) for i, test := range dumpTests { buf := new(bytes.Buffer) spew.Fdump(buf, test.in) s := buf.String() if testFailed(s, test.wants) { t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) continue } } } func TestDumpSortedKeys(t *testing.T) { cfg := spew.ConfigState{SortKeys: true} s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " + "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " + "(len=1) \"3\"\n" + "}\n" if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2}) expected = "(map[spew_test.stringer]int) (len=3) {\n" + "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" + "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" + "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" + "}\n" if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) expected = "(map[spew_test.pstringer]int) (len=3) {\n" + "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" + "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" + "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" + "}\n" if spew.UnsafeDisabled { expected = "(map[spew_test.pstringer]int) (len=3) {\n" + "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" + "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" + "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" + "}\n" } if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) expected = "(map[spew_test.customError]int) (len=3) {\n" + "(spew_test.customError) error: 1: (int) 1,\n" + "(spew_test.customError) error: 2: (int) 2,\n" + "(spew_test.customError) error: 3: (int) 3\n" + "}\n" if s != expected { t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) } } go-spew-1.1.0/spew/dumpcgo_test.go000066400000000000000000000074401300520646600171030ustar00rootroot00000000000000// Copyright (c) 2013-2016 Dave Collins // // 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. // NOTE: Due to the following build constraints, this file will only be compiled // when both cgo is supported and "-tags testcgo" is added to the go test // command line. This means the cgo tests are only added (and hence run) when // specifially requested. This configuration is used because spew itself // does not require cgo to run even though it does handle certain cgo types // specially. Rather than forcing all clients to require cgo and an external // C compiler just to run the tests, this scheme makes them optional. // +build cgo,testcgo package spew_test import ( "fmt" "github.com/davecgh/go-spew/spew/testdata" ) func addCgoDumpTests() { // C char pointer. v := testdata.GetCgoCharPointer() nv := testdata.GetCgoNullCharPointer() pv := &v vcAddr := fmt.Sprintf("%p", v) vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "*testdata._Ctype_char" vs := "116" addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") addDumpTest(nv, "("+vt+")()\n") // C char array. v2, v2l, v2c := testdata.GetCgoCharArray() v2Len := fmt.Sprintf("%d", v2l) v2Cap := fmt.Sprintf("%d", v2c) v2t := "[6]testdata._Ctype_char" v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + "{\n 00000000 74 65 73 74 32 00 " + " |test2.|\n}" addDumpTest(v2, "("+v2t+") "+v2s+"\n") // C unsigned char array. v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() v3Len := fmt.Sprintf("%d", v3l) v3Cap := fmt.Sprintf("%d", v3c) v3t := "[6]testdata._Ctype_unsignedchar" v3t2 := "[6]testdata._Ctype_uchar" v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + "{\n 00000000 74 65 73 74 33 00 " + " |test3.|\n}" addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n") // C signed char array. v4, v4l, v4c := testdata.GetCgoSignedCharArray() v4Len := fmt.Sprintf("%d", v4l) v4Cap := fmt.Sprintf("%d", v4c) v4t := "[6]testdata._Ctype_schar" v4t2 := "testdata._Ctype_schar" v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + ") 0\n}" addDumpTest(v4, "("+v4t+") "+v4s+"\n") // C uint8_t array. v5, v5l, v5c := testdata.GetCgoUint8tArray() v5Len := fmt.Sprintf("%d", v5l) v5Cap := fmt.Sprintf("%d", v5c) v5t := "[6]testdata._Ctype_uint8_t" v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + "{\n 00000000 74 65 73 74 35 00 " + " |test5.|\n}" addDumpTest(v5, "("+v5t+") "+v5s+"\n") // C typedefed unsigned char array. v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() v6Len := fmt.Sprintf("%d", v6l) v6Cap := fmt.Sprintf("%d", v6c) v6t := "[6]testdata._Ctype_custom_uchar_t" v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + "{\n 00000000 74 65 73 74 36 00 " + " |test6.|\n}" addDumpTest(v6, "("+v6t+") "+v6s+"\n") } go-spew-1.1.0/spew/dumpnocgo_test.go000066400000000000000000000023031300520646600174310ustar00rootroot00000000000000// Copyright (c) 2013 Dave Collins // // 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. // NOTE: Due to the following build constraints, this file will only be compiled // when either cgo is not supported or "-tags testcgo" is not added to the go // test command line. This file intentionally does not setup any cgo tests in // this scenario. // +build !cgo !testcgo package spew_test func addCgoDumpTests() { // Don't add any tests for cgo since this file is only compiled when // there should not be any cgo tests. } go-spew-1.1.0/spew/example_test.go000066400000000000000000000127141300520646600171000ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew_test import ( "fmt" "github.com/davecgh/go-spew/spew" ) type Flag int const ( flagOne Flag = iota flagTwo ) var flagStrings = map[Flag]string{ flagOne: "flagOne", flagTwo: "flagTwo", } func (f Flag) String() string { if s, ok := flagStrings[f]; ok { return s } return fmt.Sprintf("Unknown flag (%d)", int(f)) } type Bar struct { data uintptr } type Foo struct { unexportedField Bar ExportedField map[interface{}]interface{} } // This example demonstrates how to use Dump to dump variables to stdout. func ExampleDump() { // The following package level declarations are assumed for this example: /* type Flag int const ( flagOne Flag = iota flagTwo ) var flagStrings = map[Flag]string{ flagOne: "flagOne", flagTwo: "flagTwo", } func (f Flag) String() string { if s, ok := flagStrings[f]; ok { return s } return fmt.Sprintf("Unknown flag (%d)", int(f)) } type Bar struct { data uintptr } type Foo struct { unexportedField Bar ExportedField map[interface{}]interface{} } */ // Setup some sample data structures for the example. bar := Bar{uintptr(0)} s1 := Foo{bar, map[interface{}]interface{}{"one": true}} f := Flag(5) b := []byte{ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, } // Dump! spew.Dump(s1, f, b) // Output: // (spew_test.Foo) { // unexportedField: (spew_test.Bar) { // data: (uintptr) // }, // ExportedField: (map[interface {}]interface {}) (len=1) { // (string) (len=3) "one": (bool) true // } // } // (spew_test.Flag) Unknown flag (5) // ([]uint8) (len=34 cap=34) { // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| // 00000020 31 32 |12| // } // } // This example demonstrates how to use Printf to display a variable with a // format string and inline formatting. func ExamplePrintf() { // Create a double pointer to a uint 8. ui8 := uint8(5) pui8 := &ui8 ppui8 := &pui8 // Create a circular data type. type circular struct { ui8 uint8 c *circular } c := circular{ui8: 1} c.c = &c // Print! spew.Printf("ppui8: %v\n", ppui8) spew.Printf("circular: %v\n", c) // Output: // ppui8: <**>5 // circular: {1 <*>{1 <*>}} } // This example demonstrates how to use a ConfigState. func ExampleConfigState() { // Modify the indent level of the ConfigState only. The global // configuration is not modified. scs := spew.ConfigState{Indent: "\t"} // Output using the ConfigState instance. v := map[string]int{"one": 1} scs.Printf("v: %v\n", v) scs.Dump(v) // Output: // v: map[one:1] // (map[string]int) (len=1) { // (string) (len=3) "one": (int) 1 // } } // This example demonstrates how to use ConfigState.Dump to dump variables to // stdout func ExampleConfigState_Dump() { // See the top-level Dump example for details on the types used in this // example. // Create two ConfigState instances with different indentation. scs := spew.ConfigState{Indent: "\t"} scs2 := spew.ConfigState{Indent: " "} // Setup some sample data structures for the example. bar := Bar{uintptr(0)} s1 := Foo{bar, map[interface{}]interface{}{"one": true}} // Dump using the ConfigState instances. scs.Dump(s1) scs2.Dump(s1) // Output: // (spew_test.Foo) { // unexportedField: (spew_test.Bar) { // data: (uintptr) // }, // ExportedField: (map[interface {}]interface {}) (len=1) { // (string) (len=3) "one": (bool) true // } // } // (spew_test.Foo) { // unexportedField: (spew_test.Bar) { // data: (uintptr) // }, // ExportedField: (map[interface {}]interface {}) (len=1) { // (string) (len=3) "one": (bool) true // } // } // } // This example demonstrates how to use ConfigState.Printf to display a variable // with a format string and inline formatting. func ExampleConfigState_Printf() { // See the top-level Dump example for details on the types used in this // example. // Create two ConfigState instances and modify the method handling of the // first ConfigState only. scs := spew.NewDefaultConfig() scs2 := spew.NewDefaultConfig() scs.DisableMethods = true // Alternatively // scs := spew.ConfigState{Indent: " ", DisableMethods: true} // scs2 := spew.ConfigState{Indent: " "} // This is of type Flag which implements a Stringer and has raw value 1. f := flagTwo // Dump using the ConfigState instances. scs.Printf("f: %v\n", f) scs2.Printf("f: %v\n", f) // Output: // f: 1 // f: flagTwo } go-spew-1.1.0/spew/format.go000066400000000000000000000261021300520646600156720ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew import ( "bytes" "fmt" "reflect" "strconv" "strings" ) // supportedFlags is a list of all the character flags supported by fmt package. const supportedFlags = "0-+# " // formatState implements the fmt.Formatter interface and contains information // about the state of a formatting operation. The NewFormatter function can // be used to get a new Formatter which can be used directly as arguments // in standard fmt package printing calls. type formatState struct { value interface{} fs fmt.State depth int pointers map[uintptr]int ignoreNextType bool cs *ConfigState } // buildDefaultFormat recreates the original format string without precision // and width information to pass in to fmt.Sprintf in the case of an // unrecognized type. Unless new types are added to the language, this // function won't ever be called. func (f *formatState) buildDefaultFormat() (format string) { buf := bytes.NewBuffer(percentBytes) for _, flag := range supportedFlags { if f.fs.Flag(int(flag)) { buf.WriteRune(flag) } } buf.WriteRune('v') format = buf.String() return format } // constructOrigFormat recreates the original format string including precision // and width information to pass along to the standard fmt package. This allows // automatic deferral of all format strings this package doesn't support. func (f *formatState) constructOrigFormat(verb rune) (format string) { buf := bytes.NewBuffer(percentBytes) for _, flag := range supportedFlags { if f.fs.Flag(int(flag)) { buf.WriteRune(flag) } } if width, ok := f.fs.Width(); ok { buf.WriteString(strconv.Itoa(width)) } if precision, ok := f.fs.Precision(); ok { buf.Write(precisionBytes) buf.WriteString(strconv.Itoa(precision)) } buf.WriteRune(verb) format = buf.String() return format } // unpackValue returns values inside of non-nil interfaces when possible and // ensures that types for values which have been unpacked from an interface // are displayed when the show types flag is also set. // This is useful for data types like structs, arrays, slices, and maps which // can contain varying types packed inside an interface. func (f *formatState) unpackValue(v reflect.Value) reflect.Value { if v.Kind() == reflect.Interface { f.ignoreNextType = false if !v.IsNil() { v = v.Elem() } } return v } // formatPtr handles formatting of pointers by indirecting them as necessary. func (f *formatState) formatPtr(v reflect.Value) { // Display nil if top level pointer is nil. showTypes := f.fs.Flag('#') if v.IsNil() && (!showTypes || f.ignoreNextType) { f.fs.Write(nilAngleBytes) return } // Remove pointers at or below the current depth from map used to detect // circular refs. for k, depth := range f.pointers { if depth >= f.depth { delete(f.pointers, k) } } // Keep list of all dereferenced pointers to possibly show later. pointerChain := make([]uintptr, 0) // Figure out how many levels of indirection there are by derferencing // pointers and unpacking interfaces down the chain while detecting circular // references. nilFound := false cycleFound := false indirects := 0 ve := v for ve.Kind() == reflect.Ptr { if ve.IsNil() { nilFound = true break } indirects++ addr := ve.Pointer() pointerChain = append(pointerChain, addr) if pd, ok := f.pointers[addr]; ok && pd < f.depth { cycleFound = true indirects-- break } f.pointers[addr] = f.depth ve = ve.Elem() if ve.Kind() == reflect.Interface { if ve.IsNil() { nilFound = true break } ve = ve.Elem() } } // Display type or indirection level depending on flags. if showTypes && !f.ignoreNextType { f.fs.Write(openParenBytes) f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) f.fs.Write([]byte(ve.Type().String())) f.fs.Write(closeParenBytes) } else { if nilFound || cycleFound { indirects += strings.Count(ve.Type().String(), "*") } f.fs.Write(openAngleBytes) f.fs.Write([]byte(strings.Repeat("*", indirects))) f.fs.Write(closeAngleBytes) } // Display pointer information depending on flags. if f.fs.Flag('+') && (len(pointerChain) > 0) { f.fs.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { f.fs.Write(pointerChainBytes) } printHexPtr(f.fs, addr) } f.fs.Write(closeParenBytes) } // Display dereferenced value. switch { case nilFound == true: f.fs.Write(nilAngleBytes) case cycleFound == true: f.fs.Write(circularShortBytes) default: f.ignoreNextType = true f.format(ve) } } // format is the main workhorse for providing the Formatter interface. It // uses the passed reflect value to figure out what kind of object we are // dealing with and formats it appropriately. It is a recursive function, // however circular data structures are detected and handled properly. func (f *formatState) format(v reflect.Value) { // Handle invalid reflect values immediately. kind := v.Kind() if kind == reflect.Invalid { f.fs.Write(invalidAngleBytes) return } // Handle pointers specially. if kind == reflect.Ptr { f.formatPtr(v) return } // Print type information unless already handled elsewhere. if !f.ignoreNextType && f.fs.Flag('#') { f.fs.Write(openParenBytes) f.fs.Write([]byte(v.Type().String())) f.fs.Write(closeParenBytes) } f.ignoreNextType = false // Call Stringer/error interfaces if they exist and the handle methods // flag is enabled. if !f.cs.DisableMethods { if (kind != reflect.Invalid) && (kind != reflect.Interface) { if handled := handleMethods(f.cs, f.fs, v); handled { return } } } switch kind { case reflect.Invalid: // Do nothing. We should never get here since invalid has already // been handled above. case reflect.Bool: printBool(f.fs, v.Bool()) case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: printInt(f.fs, v.Int(), 10) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: printUint(f.fs, v.Uint(), 10) case reflect.Float32: printFloat(f.fs, v.Float(), 32) case reflect.Float64: printFloat(f.fs, v.Float(), 64) case reflect.Complex64: printComplex(f.fs, v.Complex(), 32) case reflect.Complex128: printComplex(f.fs, v.Complex(), 64) case reflect.Slice: if v.IsNil() { f.fs.Write(nilAngleBytes) break } fallthrough case reflect.Array: f.fs.Write(openBracketBytes) f.depth++ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { f.fs.Write(maxShortBytes) } else { numEntries := v.Len() for i := 0; i < numEntries; i++ { if i > 0 { f.fs.Write(spaceBytes) } f.ignoreNextType = true f.format(f.unpackValue(v.Index(i))) } } f.depth-- f.fs.Write(closeBracketBytes) case reflect.String: f.fs.Write([]byte(v.String())) case reflect.Interface: // The only time we should get here is for nil interfaces due to // unpackValue calls. if v.IsNil() { f.fs.Write(nilAngleBytes) } case reflect.Ptr: // Do nothing. We should never get here since pointers have already // been handled above. case reflect.Map: // nil maps should be indicated as different than empty maps if v.IsNil() { f.fs.Write(nilAngleBytes) break } f.fs.Write(openMapBytes) f.depth++ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { f.fs.Write(maxShortBytes) } else { keys := v.MapKeys() if f.cs.SortKeys { sortValues(keys, f.cs) } for i, key := range keys { if i > 0 { f.fs.Write(spaceBytes) } f.ignoreNextType = true f.format(f.unpackValue(key)) f.fs.Write(colonBytes) f.ignoreNextType = true f.format(f.unpackValue(v.MapIndex(key))) } } f.depth-- f.fs.Write(closeMapBytes) case reflect.Struct: numFields := v.NumField() f.fs.Write(openBraceBytes) f.depth++ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { f.fs.Write(maxShortBytes) } else { vt := v.Type() for i := 0; i < numFields; i++ { if i > 0 { f.fs.Write(spaceBytes) } vtf := vt.Field(i) if f.fs.Flag('+') || f.fs.Flag('#') { f.fs.Write([]byte(vtf.Name)) f.fs.Write(colonBytes) } f.format(f.unpackValue(v.Field(i))) } } f.depth-- f.fs.Write(closeBraceBytes) case reflect.Uintptr: printHexPtr(f.fs, uintptr(v.Uint())) case reflect.UnsafePointer, reflect.Chan, reflect.Func: printHexPtr(f.fs, v.Pointer()) // There were not any other types at the time this code was written, but // fall back to letting the default fmt package handle it if any get added. default: format := f.buildDefaultFormat() if v.CanInterface() { fmt.Fprintf(f.fs, format, v.Interface()) } else { fmt.Fprintf(f.fs, format, v.String()) } } } // Format satisfies the fmt.Formatter interface. See NewFormatter for usage // details. func (f *formatState) Format(fs fmt.State, verb rune) { f.fs = fs // Use standard formatting for verbs that are not v. if verb != 'v' { format := f.constructOrigFormat(verb) fmt.Fprintf(fs, format, f.value) return } if f.value == nil { if fs.Flag('#') { fs.Write(interfaceBytes) } fs.Write(nilAngleBytes) return } f.format(reflect.ValueOf(f.value)) } // newFormatter is a helper function to consolidate the logic from the various // public methods which take varying config states. func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { fs := &formatState{value: v, cs: cs} fs.pointers = make(map[uintptr]int) return fs } /* NewFormatter returns a custom formatter that satisfies the fmt.Formatter interface. As a result, it integrates cleanly with standard fmt package printing functions. The formatter is useful for inline printing of smaller data types similar to the standard %v format specifier. The custom formatter only responds to the %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb combinations. Any other verbs such as %x and %q will be sent to the the standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). Typically this function shouldn't be called directly. It is much easier to make use of the custom formatter by calling one of the convenience functions such as Printf, Println, or Fprintf. */ func NewFormatter(v interface{}) fmt.Formatter { return newFormatter(&Config, v) } go-spew-1.1.0/spew/format_test.go000066400000000000000000001603001300520646600167300ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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 - Array containing interfaces - Slice containing standard float32 values - Slice containing type with custom formatter on pointer receiver only - Slice containing interfaces - Nil slice - Standard string - Nil interface - Sub-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 - Map with nil interface value - Struct with primitives - Struct that contains another struct - Struct that contains custom type with Stringer pointer interface via both exported and unexported fields - Struct that contains embedded struct and field to same struct - 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 - Type that panics in its Stringer interface - Type that has a custom Error interface - %x passthrough with uint - %#x passthrough with uint - %f passthrough with precision - %f passthrough with width and precision - %d passthrough with width - %q passthrough with string */ package spew_test import ( "bytes" "fmt" "testing" "unsafe" "github.com/davecgh/go-spew/spew" ) // formatterTest is used to describe a test to be performed against NewFormatter. type formatterTest struct { format string in interface{} wants []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{}, wants ...string) { test := formatterTest{format, in, wants} 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) vt := "int8" vs := "127" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Max int16. v2 := int16(32767) nv2 := (*int16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "int16" v2s := "32767" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Max int32. v3 := int32(2147483647) nv3 := (*int32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "int32" v3s := "2147483647" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") // Max int64. v4 := int64(9223372036854775807) nv4 := (*int64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "int64" v4s := "9223372036854775807" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") // Max int. v5 := int(2147483647) nv5 := (*int)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "int" v5s := "2147483647" addFormatterTest("%v", v5, v5s) addFormatterTest("%v", pv5, "<*>"+v5s) addFormatterTest("%v", &pv5, "<**>"+v5s) addFormatterTest("%v", nv5, "") addFormatterTest("%+v", v5, v5s) addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%+v", nv5, "") addFormatterTest("%#v", v5, "("+v5t+")"+v5s) addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") } func addUintFormatterTests() { // Max uint8. v := uint8(255) nv := (*uint8)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uint8" vs := "255" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Max uint16. v2 := uint16(65535) nv2 := (*uint16)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Max uint32. v3 := uint32(4294967295) nv3 := (*uint32)(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "uint32" v3s := "4294967295" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") // Max uint64. v4 := uint64(18446744073709551615) nv4 := (*uint64)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "uint64" v4s := "18446744073709551615" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") // Max uint. v5 := uint(4294967295) nv5 := (*uint)(nil) pv5 := &v5 v5Addr := fmt.Sprintf("%p", pv5) pv5Addr := fmt.Sprintf("%p", &pv5) v5t := "uint" v5s := "4294967295" addFormatterTest("%v", v5, v5s) addFormatterTest("%v", pv5, "<*>"+v5s) addFormatterTest("%v", &pv5, "<**>"+v5s) addFormatterTest("%v", nv5, "") addFormatterTest("%+v", v5, v5s) addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%+v", nv5, "") addFormatterTest("%#v", v5, "("+v5t+")"+v5s) addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") } func addBoolFormatterTests() { // Boolean true. v := bool(true) nv := (*bool)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "bool" vs := "true" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Boolean false. v2 := bool(false) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "bool" 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) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+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) vt := "float32" vs := "3.1415" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Standard float64. v2 := float64(3.1415926) nv2 := (*float64)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "float64" v2s := "3.1415926" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") } func addComplexFormatterTests() { // Standard complex64. v := complex(float32(6), -2) nv := (*complex64)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "complex64" vs := "(6-2i)" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Standard complex128. v2 := complex(float64(-6), 2) nv2 := (*complex128)(nil) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "complex128" v2s := "(-6+2i)" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") } 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) vt := "[3]int" vs := "[1 2 3]" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // 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) v2t := "[3]spew_test.pstringer" v2sp := "[stringer 1 stringer 2 stringer 3]" v2s := v2sp if spew.UnsafeDisabled { v2s = "[1 2 3]" } addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2sp) addFormatterTest("%v", &pv2, "<**>"+v2sp) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Array containing interfaces. v3 := [3]interface{}{"one", int(2), uint(3)} nv3 := (*[3]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[3]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3s := "[one 2 3]" v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") } 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) vt := "[]float32" vs := "[3.14 6.28 12.56]" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // 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) v2t := "[]spew_test.pstringer" v2s := "[stringer 1 stringer 2 stringer 3]" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // Slice containing interfaces. v3 := []interface{}{"one", int(2), uint(3), nil} nv3 := (*[]interface{})(nil) pv3 := &v3 v3Addr := fmt.Sprintf("%p", pv3) pv3Addr := fmt.Sprintf("%p", &pv3) v3t := "[]interface {}" v3t2 := "string" v3t3 := "int" v3t4 := "uint" v3t5 := "interface {}" v3s := "[one 2 3 ]" v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + ")]" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") // Nil slice. var v4 []int nv4 := (*[]int)(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "[]int" v4s := "" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") } func addStringFormatterTests() { // Standard string. v := "test" nv := (*string)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "string" vs := "test" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") } func addInterfaceFormatterTests() { // Nil interface. var v interface{} nv := (*interface{})(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "interface {}" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Sub-interface. v2 := interface{}(uint16(65535)) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uint16" v2s := "65535" 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) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) } func addMapFormatterTests() { // Map with string keys and int vals. v := map[string]int{"one": 1, "two": 2} nilMap := map[string]int(nil) nv := (*map[string]int)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "map[string]int" vs := "map[one:1 two:2]" vs2 := "map[two:2 one:1]" addFormatterTest("%v", v, vs, vs2) addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) addFormatterTest("%+v", nilMap, "") addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs, vs2) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, "<**>("+pvAddr+"->"+vAddr+")"+vs2) addFormatterTest("%+v", nilMap, "") addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) addFormatterTest("%#v", nilMap, "("+vt+")"+"") addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, "(*"+vt+")("+vAddr+")"+vs2) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) addFormatterTest("%#+v", nilMap, "("+vt+")"+"") addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // 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) v2t := "map[spew_test.pstringer]spew_test.pstringer" v2s := "map[stringer one:stringer 1]" if spew.UnsafeDisabled { v2s = "map[one:1]" } addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // 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) v3t := "map[interface {}]interface {}" v3t1 := "string" v3t2 := "int" v3s := "map[one:1]" v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") // Map with nil interface value v4 := map[string]interface{}{"nil": nil} nv4 := (*map[string]interface{})(nil) pv4 := &v4 v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "map[string]interface {}" v4t1 := "interface {}" v4s := "map[nil:]" v4s2 := "map[nil:(" + v4t1 + ")]" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%+v", v4, v4s) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") } 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) vt := "spew_test.s1" vt2 := "int8" vt3 := "uint8" vs := "{127 255}" vs2 := "{a:127 b:255}" vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs2) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs3) addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs3) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // 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) v2t := "spew_test.s2" v2t2 := "spew_test.s1" v2t3 := "int8" v2t4 := "uint8" v2t5 := "bool" v2s := "{{127 255} true}" v2s2 := "{s1:{a:127 b:255} b:true}" v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + v2t5 + ")true}" addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s2) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // 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) v3t := "spew_test.s3" v3t2 := "spew_test.pstringer" v3s := "{stringer test stringer test2}" v3sp := v3s v3s2 := "{s:stringer test S:stringer test2}" v3s2p := v3s2 v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" v3s3p := v3s3 if spew.UnsafeDisabled { v3s = "{test test2}" v3sp = "{test stringer test2}" v3s2 = "{s:test S:test2}" v3s2p = "{s:test S:stringer test2}" v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}" v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}" } addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3sp) addFormatterTest("%v", &pv3, "<**>"+v3sp) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s2) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") // Struct that contains embedded struct and field to same struct. e := embed{"embedstr"} v4 := embedwrap{embed: &e, e: &e} nv4 := (*embedwrap)(nil) pv4 := &v4 eAddr := fmt.Sprintf("%p", &e) v4Addr := fmt.Sprintf("%p", pv4) pv4Addr := fmt.Sprintf("%p", &pv4) v4t := "spew_test.embedwrap" v4t2 := "spew_test.embed" v4t3 := "string" v4s := "{<*>{embedstr} <*>{embedstr}}" v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + "){a:embedstr}}" v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr}}" v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" addFormatterTest("%v", v4, v4s) addFormatterTest("%v", pv4, "<*>"+v4s) addFormatterTest("%v", &pv4, "<**>"+v4s) addFormatterTest("%+v", nv4, "") addFormatterTest("%+v", v4, v4s2) addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) addFormatterTest("%+v", nv4, "") addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") } func addUintptrFormatterTests() { // Null pointer. v := uintptr(0) nv := (*uintptr)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "uintptr" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Address of real variable. i := 1 v2 := uintptr(unsafe.Pointer(&i)) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "uintptr" 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) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+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) vt := "unsafe.Pointer" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Address of real variable. i := 1 v2 := unsafe.Pointer(&i) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "unsafe.Pointer" 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) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+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) vt := "chan int" vs := "" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // Real channel. v2 := make(chan int) pv2 := &v2 v2Addr := fmt.Sprintf("%p", pv2) pv2Addr := fmt.Sprintf("%p", &pv2) v2t := "chan int" 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) addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+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) vt := "func()" vs := fmt.Sprintf("%p", v) addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") // 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) v2t := "func(*testing.T)" v2s := fmt.Sprintf("%p", v2) addFormatterTest("%v", v2, v2s) addFormatterTest("%v", pv2, "<*>"+v2s) addFormatterTest("%v", &pv2, "<**>"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%+v", v2, v2s) addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%+v", nv2, "") addFormatterTest("%#v", v2, "("+v2t+")"+v2s) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") // 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) v3t := "func(int, string) (bool, error)" v3s := fmt.Sprintf("%p", v3) addFormatterTest("%v", v3, v3s) addFormatterTest("%v", pv3, "<*>"+v3s) addFormatterTest("%v", &pv3, "<**>"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%+v", v3, v3s) addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%+v", nv3, "") addFormatterTest("%#v", v3, "("+v3t+")"+v3s) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") } 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) vt := "spew_test.circular" vs := "{<*>{<*>}}" vs2 := "{<*>}" vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" vs4 := "{c:<*>(" + vAddr + ")}" vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" vs6 := "{c:(*" + vt + ")}" vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + ")}}" vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" 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) addFormatterTest("%#v", v, "("+vt+")"+vs5) addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) addFormatterTest("%#+v", v, "("+vt+")"+vs7) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) // 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) v2t := "spew_test.xref1" v2t2 := "spew_test.xref2" v2s := "{<*>{<*>{<*>}}}" v2s2 := "{<*>{<*>}}" v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + ts2Addr + ")}}}" v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + ")}}}" v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + ")}}}" v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + ")(" + v2Addr + ")}}" 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) addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) // 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) v3t := "spew_test.indirCir1" v3t2 := "spew_test.indirCir2" v3t3 := "spew_test.indirCir3" v3s := "{<*>{<*>{<*>{<*>}}}}" v3s2 := "{<*>{<*>{<*>}}}" v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + v3Addr + ")}}}" v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + "){ps2:(*" + v3t2 + ")}}}}" v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + ")}}}" v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + ")(" + tic2Addr + ")}}}}" v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" 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) addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) } func addPanicFormatterTests() { // Type that panics in its Stringer interface. v := panicer(127) nv := (*panicer)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.panicer" vs := "(PANIC=test panic)127" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") } func addErrorFormatterTests() { // Type that has a custom Error interface. v := customError(127) nv := (*customError)(nil) pv := &v vAddr := fmt.Sprintf("%p", pv) pvAddr := fmt.Sprintf("%p", &pv) vt := "spew_test.customError" vs := "error: 127" addFormatterTest("%v", v, vs) addFormatterTest("%v", pv, "<*>"+vs) addFormatterTest("%v", &pv, "<**>"+vs) addFormatterTest("%v", nv, "") addFormatterTest("%+v", v, vs) addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%+v", nv, "") addFormatterTest("%#v", v, "("+vt+")"+vs) addFormatterTest("%#v", pv, "(*"+vt+")"+vs) addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) addFormatterTest("%#v", nv, "(*"+vt+")"+"") addFormatterTest("%#+v", v, "("+vt+")"+vs) addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) addFormatterTest("%#+v", nv, "(*"+vt+")"+"") } func addPassthroughFormatterTests() { // %x passthrough with uint. v := uint(4294967295) pv := &v vAddr := fmt.Sprintf("%x", pv) pvAddr := fmt.Sprintf("%x", &pv) vs := "ffffffff" addFormatterTest("%x", v, vs) addFormatterTest("%x", pv, vAddr) addFormatterTest("%x", &pv, pvAddr) // %#x passthrough with uint. v2 := int(2147483647) pv2 := &v2 v2Addr := fmt.Sprintf("%#x", pv2) pv2Addr := fmt.Sprintf("%#x", &pv2) v2s := "0x7fffffff" addFormatterTest("%#x", v2, v2s) addFormatterTest("%#x", pv2, v2Addr) addFormatterTest("%#x", &pv2, pv2Addr) // %f passthrough with precision. addFormatterTest("%.2f", 3.1415, "3.14") addFormatterTest("%.3f", 3.1415, "3.142") addFormatterTest("%.4f", 3.1415, "3.1415") // %f passthrough with width and precision. addFormatterTest("%5.2f", 3.1415, " 3.14") addFormatterTest("%6.3f", 3.1415, " 3.142") addFormatterTest("%7.4f", 3.1415, " 3.1415") // %d passthrough with width. addFormatterTest("%3d", 127, "127") addFormatterTest("%4d", 127, " 127") addFormatterTest("%5d", 127, " 127") // %q passthrough with string. addFormatterTest("%q", "test", "\"test\"") } // TestFormatter executes all of the tests described by formatterTests. func TestFormatter(t *testing.T) { // Setup tests. addIntFormatterTests() addUintFormatterTests() addBoolFormatterTests() addFloatFormatterTests() addComplexFormatterTests() addArrayFormatterTests() addSliceFormatterTests() addStringFormatterTests() addInterfaceFormatterTests() addMapFormatterTests() addStructFormatterTests() addUintptrFormatterTests() addUnsafePointerFormatterTests() addChanFormatterTests() addFuncFormatterTests() addCircularFormatterTests() addPanicFormatterTests() addErrorFormatterTests() addPassthroughFormatterTests() 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 testFailed(s, test.wants) { t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, stringizeWants(test.wants)) continue } } } type testStruct struct { x int } func (ts testStruct) String() string { return fmt.Sprintf("ts.%d", ts.x) } type testStructP struct { x int } func (ts *testStructP) String() string { return fmt.Sprintf("ts.%d", ts.x) } func TestPrintSortedKeys(t *testing.T) { cfg := spew.ConfigState{SortKeys: true} s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) expected := "map[1:1 2:2 3:3]" if s != expected { t.Errorf("Sorted keys mismatch 1:\n %v %v", s, expected) } s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2}) expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" if s != expected { t.Errorf("Sorted keys mismatch 2:\n %v %v", s, expected) } s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" if spew.UnsafeDisabled { expected = "map[1:1 2:2 3:3]" } if s != expected { t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) } s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) expected = "map[ts.1:1 ts.2:2 ts.3:3]" if s != expected { t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) } if !spew.UnsafeDisabled { s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) expected = "map[ts.1:1 ts.2:2 ts.3:3]" if s != expected { t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) } } s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) expected = "map[error: 1:1 error: 2:2 error: 3:3]" if s != expected { t.Errorf("Sorted keys mismatch 6:\n %v %v", s, expected) } } go-spew-1.1.0/spew/internal_test.go000066400000000000000000000050171300520646600172570ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ /* This test file is part of the spew package rather than than the spew_test package because it needs access to internals to properly test certain cases which are not possible via the public interface since they should never happen. */ package spew import ( "bytes" "reflect" "testing" ) // dummyFmtState implements a fake fmt.State to use for testing invalid // reflect.Value handling. This is necessary because the fmt package catches // invalid values before invoking the formatter on them. type dummyFmtState struct { bytes.Buffer } func (dfs *dummyFmtState) Flag(f int) bool { if f == int('+') { return true } return false } func (dfs *dummyFmtState) Precision() (int, bool) { return 0, false } func (dfs *dummyFmtState) Width() (int, bool) { return 0, false } // TestInvalidReflectValue ensures the dump and formatter code handles an // invalid reflect value properly. This needs access to internal state since it // should never happen in real code and therefore can't be tested via the public // API. func TestInvalidReflectValue(t *testing.T) { i := 1 // Dump invalid reflect value. v := new(reflect.Value) buf := new(bytes.Buffer) d := dumpState{w: buf, cs: &Config} d.dump(*v) s := buf.String() want := "" if s != want { t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) } i++ // Formatter invalid reflect value. buf2 := new(dummyFmtState) f := formatState{value: *v, cs: &Config, fs: buf2} f.format(*v) s = buf2.String() want = "" if s != want { t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) } } // SortValues makes the internal sortValues function available to the test // package. func SortValues(values []reflect.Value, cs *ConfigState) { sortValues(values, cs) } go-spew-1.1.0/spew/internalunsafe_test.go000066400000000000000000000063711300520646600204650ustar00rootroot00000000000000// Copyright (c) 2013-2016 Dave Collins // 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. // NOTE: Due to the following build constraints, this file will only be compiled // when the code is not running on Google App Engine, compiled by GopherJS, and // "-tags safe" is not added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. // +build !js,!appengine,!safe,!disableunsafe /* This test file is part of the spew package rather than than the spew_test package because it needs access to internals to properly test certain cases which are not possible via the public interface since they should never happen. */ package spew import ( "bytes" "reflect" "testing" "unsafe" ) // 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)) + offsetFlag)) *rvf = *rvf | ((1< * * 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. */ package spew import ( "fmt" "io" ) // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the formatted string as a value that satisfies error. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) func Errorf(format string, a ...interface{}) (err error) { return fmt.Errorf(format, convertArgs(a)...) } // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) func Fprint(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprint(w, convertArgs(a)...) } // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(w, format, convertArgs(a)...) } // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it // passed with a default Formatter interface returned by NewFormatter. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { return fmt.Fprintln(w, convertArgs(a)...) } // Print is a wrapper for fmt.Print that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) func Print(a ...interface{}) (n int, err error) { return fmt.Print(convertArgs(a)...) } // Printf is a wrapper for fmt.Printf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) func Printf(format string, a ...interface{}) (n int, err error) { return fmt.Printf(format, convertArgs(a)...) } // Println is a wrapper for fmt.Println that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the number of bytes written and any write error encountered. See // NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) func Println(a ...interface{}) (n int, err error) { return fmt.Println(convertArgs(a)...) } // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) func Sprint(a ...interface{}) string { return fmt.Sprint(convertArgs(a)...) } // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were // passed with a default Formatter interface returned by NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) func Sprintf(format string, a ...interface{}) string { return fmt.Sprintf(format, convertArgs(a)...) } // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it // were passed with a default Formatter interface returned by NewFormatter. It // returns the resulting string. See NewFormatter for formatting details. // // This function is shorthand for the following syntax: // // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) func Sprintln(a ...interface{}) string { return fmt.Sprintln(convertArgs(a)...) } // convertArgs accepts a slice of arguments and returns a slice of the same // length with each argument converted to a default spew Formatter interface. func convertArgs(args []interface{}) (formatters []interface{}) { formatters = make([]interface{}, len(args)) for index, arg := range args { formatters[index] = NewFormatter(arg) } return formatters } go-spew-1.1.0/spew/spew_test.go000066400000000000000000000226511300520646600164240ustar00rootroot00000000000000/* * Copyright (c) 2013-2016 Dave Collins * * 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. */ package spew_test import ( "bytes" "fmt" "io/ioutil" "os" "testing" "github.com/davecgh/go-spew/spew" ) // spewFunc is used to identify which public function of the spew package or // ConfigState a test applies to. type spewFunc int const ( fCSFdump spewFunc = iota fCSFprint fCSFprintf fCSFprintln fCSPrint fCSPrintln fCSSdump fCSSprint fCSSprintf fCSSprintln fCSErrorf fCSNewFormatter fErrorf fFprint fFprintln fPrint fPrintln fSdump fSprint fSprintf fSprintln ) // Map of spewFunc values to names for pretty printing. var spewFuncStrings = map[spewFunc]string{ fCSFdump: "ConfigState.Fdump", fCSFprint: "ConfigState.Fprint", fCSFprintf: "ConfigState.Fprintf", fCSFprintln: "ConfigState.Fprintln", fCSSdump: "ConfigState.Sdump", fCSPrint: "ConfigState.Print", fCSPrintln: "ConfigState.Println", fCSSprint: "ConfigState.Sprint", fCSSprintf: "ConfigState.Sprintf", fCSSprintln: "ConfigState.Sprintln", fCSErrorf: "ConfigState.Errorf", fCSNewFormatter: "ConfigState.NewFormatter", fErrorf: "spew.Errorf", fFprint: "spew.Fprint", fFprintln: "spew.Fprintln", fPrint: "spew.Print", fPrintln: "spew.Println", fSdump: "spew.Sdump", fSprint: "spew.Sprint", fSprintf: "spew.Sprintf", fSprintln: "spew.Sprintln", } func (f spewFunc) String() string { if s, ok := spewFuncStrings[f]; ok { return s } return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) } // spewTest is used to describe a test to be performed against the public // functions of the spew package or ConfigState. type spewTest struct { cs *spew.ConfigState f spewFunc format string in interface{} want string } // spewTests houses the tests to be performed against the public functions of // the spew package and ConfigState. // // These tests are only intended to ensure the public functions are exercised // and are intentionally not exhaustive of types. The exhaustive type // tests are handled in the dump and format tests. var spewTests []spewTest // redirStdout is a helper function to return the standard output from f as a // byte slice. func redirStdout(f func()) ([]byte, error) { tempFile, err := ioutil.TempFile("", "ss-test") if err != nil { return nil, err } fileName := tempFile.Name() defer os.Remove(fileName) // Ignore error origStdout := os.Stdout os.Stdout = tempFile f() os.Stdout = origStdout tempFile.Close() return ioutil.ReadFile(fileName) } func initSpewTests() { // Config states with various settings. scsDefault := spew.NewDefaultConfig() scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true} scsNoCap := &spew.ConfigState{DisableCapacities: true} // Variables for tests on types which implement Stringer interface with and // without a pointer receiver. ts := stringer("test") tps := pstringer("test") type ptrTester struct { s *struct{} } tptr := &ptrTester{s: &struct{}{}} // depthTester is used to test max depth handling for structs, array, slices // and maps. type depthTester struct { ic indirCir1 arr [1]string slice []string m map[string]int } dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, map[string]int{"one": 1}} // Variable for tests on types which implement error interface. te := customError(10) spewTests = []spewTest{ {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, {scsDefault, fCSFprint, "", int16(32767), "32767"}, {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, {scsDefault, fFprint, "", float32(3.14), "3.14"}, {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, {scsDefault, fPrint, "", true, "true"}, {scsDefault, fPrintln, "", false, "false\n"}, {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, {scsNoMethods, fCSFprint, "", ts, "test"}, {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, {scsNoMethods, fCSFprint, "", tps, "test"}, {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, {scsNoPmethods, fCSFprint, "", tps, "test"}, {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + " ic: (spew_test.indirCir1) {\n \n },\n" + " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + " slice: ([]string) (len=1 cap=1) {\n \n },\n" + " m: (map[string]int) (len=1) {\n \n }\n}\n"}, {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + "(len=4) (stringer test) \"test\"\n"}, {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + "(error: 10) 10\n"}, {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"}, {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"}, {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"}, {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"}, } } // TestSpew executes all of the tests described by spewTests. func TestSpew(t *testing.T) { initSpewTests() t.Logf("Running %d tests", len(spewTests)) for i, test := range spewTests { buf := new(bytes.Buffer) switch test.f { case fCSFdump: test.cs.Fdump(buf, test.in) case fCSFprint: test.cs.Fprint(buf, test.in) case fCSFprintf: test.cs.Fprintf(buf, test.format, test.in) case fCSFprintln: test.cs.Fprintln(buf, test.in) case fCSPrint: b, err := redirStdout(func() { test.cs.Print(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fCSPrintln: b, err := redirStdout(func() { test.cs.Println(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fCSSdump: str := test.cs.Sdump(test.in) buf.WriteString(str) case fCSSprint: str := test.cs.Sprint(test.in) buf.WriteString(str) case fCSSprintf: str := test.cs.Sprintf(test.format, test.in) buf.WriteString(str) case fCSSprintln: str := test.cs.Sprintln(test.in) buf.WriteString(str) case fCSErrorf: err := test.cs.Errorf(test.format, test.in) buf.WriteString(err.Error()) case fCSNewFormatter: fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) case fErrorf: err := spew.Errorf(test.format, test.in) buf.WriteString(err.Error()) case fFprint: spew.Fprint(buf, test.in) case fFprintln: spew.Fprintln(buf, test.in) case fPrint: b, err := redirStdout(func() { spew.Print(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fPrintln: b, err := redirStdout(func() { spew.Println(test.in) }) if err != nil { t.Errorf("%v #%d %v", test.f, i, err) continue } buf.Write(b) case fSdump: str := spew.Sdump(test.in) buf.WriteString(str) case fSprint: str := spew.Sprint(test.in) buf.WriteString(str) case fSprintf: str := spew.Sprintf(test.format, test.in) buf.WriteString(str) case fSprintln: str := spew.Sprintln(test.in) buf.WriteString(str) default: t.Errorf("%v #%d unrecognized function", test.f, i) continue } s := buf.String() if test.want != s { t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) continue } } } go-spew-1.1.0/spew/testdata/000077500000000000000000000000001300520646600156635ustar00rootroot00000000000000go-spew-1.1.0/spew/testdata/dumpcgo.go000066400000000000000000000063241300520646600176550ustar00rootroot00000000000000// Copyright (c) 2013 Dave Collins // // 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. // NOTE: Due to the following build constraints, this file will only be compiled // when both cgo is supported and "-tags testcgo" is added to the go test // command line. This code should really only be in the dumpcgo_test.go file, // but unfortunately Go will not allow cgo in test files, so this is a // workaround to allow cgo types to be tested. This configuration is used // because spew itself does not require cgo to run even though it does handle // certain cgo types specially. Rather than forcing all clients to require cgo // and an external C compiler just to run the tests, this scheme makes them // optional. // +build cgo,testcgo package testdata /* #include typedef unsigned char custom_uchar_t; char *ncp = 0; char *cp = "test"; char ca[6] = {'t', 'e', 's', 't', '2', '\0'}; unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'}; signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'}; uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'}; custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'}; */ import "C" // GetCgoNullCharPointer returns a null char pointer via cgo. This is only // used for tests. func GetCgoNullCharPointer() interface{} { return C.ncp } // GetCgoCharPointer returns a char pointer via cgo. This is only used for // tests. func GetCgoCharPointer() interface{} { return C.cp } // GetCgoCharArray returns a char array via cgo and the array's len and cap. // This is only used for tests. func GetCgoCharArray() (interface{}, int, int) { return C.ca, len(C.ca), cap(C.ca) } // GetCgoUnsignedCharArray returns an unsigned char array via cgo and the // array's len and cap. This is only used for tests. func GetCgoUnsignedCharArray() (interface{}, int, int) { return C.uca, len(C.uca), cap(C.uca) } // GetCgoSignedCharArray returns a signed char array via cgo and the array's len // and cap. This is only used for tests. func GetCgoSignedCharArray() (interface{}, int, int) { return C.sca, len(C.sca), cap(C.sca) } // GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and // cap. This is only used for tests. func GetCgoUint8tArray() (interface{}, int, int) { return C.ui8ta, len(C.ui8ta), cap(C.ui8ta) } // GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via // cgo and the array's len and cap. This is only used for tests. func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) { return C.tuca, len(C.tuca), cap(C.tuca) } go-spew-1.1.0/test_coverage.txt000066400000000000000000000104761300520646600164770ustar00rootroot00000000000000 github.com/davecgh/go-spew/spew/dump.go dumpState.dump 100.00% (88/88) github.com/davecgh/go-spew/spew/format.go formatState.format 100.00% (82/82) github.com/davecgh/go-spew/spew/format.go formatState.formatPtr 100.00% (52/52) github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44) github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39) github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30) github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18) github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13) github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12) github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11) github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11) github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10) github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9) github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8) github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7) github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5) github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4) github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4) github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4) github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4) github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3) github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3) github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3) github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3) github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3) github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3) github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1) github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1) github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1) github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1) github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1) github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Sprint 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1) github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1) github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1) github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1) github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505)