mirror of https://github.com/stretchr/testify.git
Prune vendor & update deps
parent
5f831d47b7
commit
33e91307d5
|
@ -10,16 +10,18 @@
|
|||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
revision = "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/objx"
|
||||
packages = ["."]
|
||||
revision = "cbeaeb16a013161a98496fad62933b1d21786672"
|
||||
revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
|
||||
version = "v0.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "6bd8fb1f11a0d3df245fc01bd8853f6dac40b83457e780f7978ca30244647c7b"
|
||||
inputs-digest = "448ddae4702c6aded2555faafd390c537789bb1c483f70b0431e6634f73f2090"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
36
Gopkg.toml
36
Gopkg.toml
|
@ -1,26 +1,16 @@
|
|||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
[prune]
|
||||
unused-packages = true
|
||||
non-go = true
|
||||
go-tests = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
version = ">=1.0.0, <=3.0.0-g6d21280"
|
||||
version = "~1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
version = "~1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/objx"
|
||||
version = "~0.1.0"
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# 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
|
|
@ -1,14 +0,0 @@
|
|||
language: 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
|
|
@ -1,205 +0,0 @@
|
|||
go-spew
|
||||
=======
|
||||
|
||||
[]
|
||||
(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
|
||||
|
||||
[]
|
||||
(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, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", handler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
```
|
||||
|
||||
## Sample Dump Output
|
||||
|
||||
```
|
||||
(main.Foo) {
|
||||
unexportedField: (*main.Bar)(0xf84002e210)({
|
||||
flag: (main.Flag) flagTwo,
|
||||
data: (uintptr) <nil>
|
||||
}),
|
||||
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 <*><shown>}
|
||||
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
||||
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
||||
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
|
||||
```
|
||||
|
||||
## 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.
|
|
@ -1,22 +0,0 @@
|
|||
#!/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
|
|
@ -1,298 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
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)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,99 +0,0 @@
|
|||
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// 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+")(<nil>)\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")
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// 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.
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
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) <nil>
|
||||
// },
|
||||
// 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 <*><shown>}}
|
||||
}
|
||||
|
||||
// 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) <nil>
|
||||
// },
|
||||
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||
// (string) (len=3) "one": (bool) true
|
||||
// }
|
||||
// }
|
||||
// (spew_test.Foo) {
|
||||
// unexportedField: (spew_test.Bar) {
|
||||
// data: (uintptr) <nil>
|
||||
// },
|
||||
// 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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
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 := "<invalid>"
|
||||
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 = "<invalid>"
|
||||
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)
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// 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<<flagKindWidth - 1) << flagKindShift)
|
||||
if readOnly {
|
||||
*rvf |= flagRO
|
||||
} else {
|
||||
*rvf &= ^uintptr(flagRO)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddedReflectValue tests functionaly of the dump and formatter code which
|
||||
// falls back to the standard fmt library for new types that might get added to
|
||||
// the language.
|
||||
func TestAddedReflectValue(t *testing.T) {
|
||||
i := 1
|
||||
|
||||
// Dump using a reflect.Value that is exported.
|
||||
v := reflect.ValueOf(int8(5))
|
||||
changeKind(&v, false)
|
||||
buf := new(bytes.Buffer)
|
||||
d := dumpState{w: buf, cs: &Config}
|
||||
d.dump(v)
|
||||
s := buf.String()
|
||||
want := "(int8) 5"
|
||||
if s != want {
|
||||
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
|
||||
}
|
||||
i++
|
||||
|
||||
// Dump using a reflect.Value that is not exported.
|
||||
changeKind(&v, true)
|
||||
buf.Reset()
|
||||
d.dump(v)
|
||||
s = buf.String()
|
||||
want = "(int8) <int8 Value>"
|
||||
if s != want {
|
||||
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
|
||||
}
|
||||
i++
|
||||
|
||||
// Formatter using a reflect.Value that is exported.
|
||||
changeKind(&v, false)
|
||||
buf2 := new(dummyFmtState)
|
||||
f := formatState{value: v, cs: &Config, fs: buf2}
|
||||
f.format(v)
|
||||
s = buf2.String()
|
||||
want = "5"
|
||||
if s != want {
|
||||
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
|
||||
}
|
||||
i++
|
||||
|
||||
// Formatter using a reflect.Value that is not exported.
|
||||
changeKind(&v, true)
|
||||
buf2.Reset()
|
||||
f = formatState{value: v, cs: &Config, fs: buf2}
|
||||
f.format(v)
|
||||
s = buf2.String()
|
||||
want = "<int8 Value>"
|
||||
if s != want {
|
||||
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
|
||||
}
|
||||
}
|
|
@ -1,320 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
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, "{{<max>} [<max>] [<max>] map[<max>]}"},
|
||||
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
|
||||
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
|
||||
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
|
||||
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
|
||||
" m: (map[string]int) (len=1) {\n <max depth reached>\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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// 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 <stdint.h>
|
||||
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)
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
|
||||
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)
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
- tip
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
go-difflib
|
||||
==========
|
||||
|
||||
[](https://travis-ci.org/pmezard/go-difflib)
|
||||
[](https://godoc.org/github.com/pmezard/go-difflib/difflib)
|
||||
|
||||
Go-difflib is a partial port of python 3 difflib package. Its main goal
|
||||
was to make unified and context diff available in pure Go, mostly for
|
||||
testing purposes.
|
||||
|
||||
The following class and functions (and related tests) have be ported:
|
||||
|
||||
* `SequenceMatcher`
|
||||
* `unified_diff()`
|
||||
* `context_diff()`
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ go get github.com/pmezard/go-difflib/difflib
|
||||
```
|
||||
|
||||
### Quick Start
|
||||
|
||||
Diffs are configured with Unified (or ContextDiff) structures, and can
|
||||
be output to an io.Writer or returned as a string.
|
||||
|
||||
```Go
|
||||
diff := UnifiedDiff{
|
||||
A: difflib.SplitLines("foo\nbar\n"),
|
||||
B: difflib.SplitLines("foo\nbaz\n"),
|
||||
FromFile: "Original",
|
||||
ToFile: "Current",
|
||||
Context: 3,
|
||||
}
|
||||
text, _ := GetUnifiedDiffString(diff)
|
||||
fmt.Printf(text)
|
||||
```
|
||||
|
||||
would output:
|
||||
|
||||
```
|
||||
--- Original
|
||||
+++ Current
|
||||
@@ -1,3 +1,3 @@
|
||||
foo
|
||||
-bar
|
||||
+baz
|
||||
```
|
||||
|
|
@ -559,10 +559,14 @@ type UnifiedDiff struct {
|
|||
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
||||
buf := bufio.NewWriter(writer)
|
||||
defer buf.Flush()
|
||||
w := func(format string, args ...interface{}) error {
|
||||
wf := func(format string, args ...interface{}) error {
|
||||
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
||||
return err
|
||||
}
|
||||
ws := func(s string) error {
|
||||
_, err := buf.WriteString(s)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(diff.Eol) == 0 {
|
||||
diff.Eol = "\n"
|
||||
|
@ -581,26 +585,28 @@ func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
|||
if len(diff.ToDate) > 0 {
|
||||
toDate = "\t" + diff.ToDate
|
||||
}
|
||||
err := w("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = w("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
if diff.FromFile != "" || diff.ToFile != "" {
|
||||
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
first, last := g[0], g[len(g)-1]
|
||||
range1 := formatRangeUnified(first.I1, last.I2)
|
||||
range2 := formatRangeUnified(first.J1, last.J2)
|
||||
if err := w("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
|
||||
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, c := range g {
|
||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||
if c.Tag == 'e' {
|
||||
for _, line := range diff.A[i1:i2] {
|
||||
if err := w(" " + line); err != nil {
|
||||
if err := ws(" " + line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -608,14 +614,14 @@ func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
|||
}
|
||||
if c.Tag == 'r' || c.Tag == 'd' {
|
||||
for _, line := range diff.A[i1:i2] {
|
||||
if err := w("-" + line); err != nil {
|
||||
if err := ws("-" + line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.Tag == 'r' || c.Tag == 'i' {
|
||||
for _, line := range diff.B[j1:j2] {
|
||||
if err := w("+" + line); err != nil {
|
||||
if err := ws("+" + line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -669,12 +675,18 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|||
buf := bufio.NewWriter(writer)
|
||||
defer buf.Flush()
|
||||
var diffErr error
|
||||
w := func(format string, args ...interface{}) {
|
||||
wf := func(format string, args ...interface{}) {
|
||||
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
||||
if diffErr == nil && err != nil {
|
||||
diffErr = err
|
||||
}
|
||||
}
|
||||
ws := func(s string) {
|
||||
_, err := buf.WriteString(s)
|
||||
if diffErr == nil && err != nil {
|
||||
diffErr = err
|
||||
}
|
||||
}
|
||||
|
||||
if len(diff.Eol) == 0 {
|
||||
diff.Eol = "\n"
|
||||
|
@ -700,15 +712,17 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|||
if len(diff.ToDate) > 0 {
|
||||
toDate = "\t" + diff.ToDate
|
||||
}
|
||||
w("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
w("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
if diff.FromFile != "" || diff.ToFile != "" {
|
||||
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
}
|
||||
}
|
||||
|
||||
first, last := g[0], g[len(g)-1]
|
||||
w("***************" + diff.Eol)
|
||||
ws("***************" + diff.Eol)
|
||||
|
||||
range1 := formatRangeContext(first.I1, last.I2)
|
||||
w("*** %s ****%s", range1, diff.Eol)
|
||||
wf("*** %s ****%s", range1, diff.Eol)
|
||||
for _, c := range g {
|
||||
if c.Tag == 'r' || c.Tag == 'd' {
|
||||
for _, cc := range g {
|
||||
|
@ -716,7 +730,7 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|||
continue
|
||||
}
|
||||
for _, line := range diff.A[cc.I1:cc.I2] {
|
||||
w(prefix[cc.Tag] + line)
|
||||
ws(prefix[cc.Tag] + line)
|
||||
}
|
||||
}
|
||||
break
|
||||
|
@ -724,7 +738,7 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|||
}
|
||||
|
||||
range2 := formatRangeContext(first.J1, last.J2)
|
||||
w("--- %s ----%s", range2, diff.Eol)
|
||||
wf("--- %s ----%s", range2, diff.Eol)
|
||||
for _, c := range g {
|
||||
if c.Tag == 'r' || c.Tag == 'i' {
|
||||
for _, cc := range g {
|
||||
|
@ -732,7 +746,7 @@ func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|||
continue
|
||||
}
|
||||
for _, line := range diff.B[cc.J1:cc.J2] {
|
||||
w(prefix[cc.Tag] + line)
|
||||
ws(prefix[cc.Tag] + line)
|
||||
}
|
||||
}
|
||||
break
|
||||
|
|
|
@ -1,352 +0,0 @@
|
|||
package difflib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertAlmostEqual(t *testing.T, a, b float64, places int) {
|
||||
if math.Abs(a-b) > math.Pow10(-places) {
|
||||
t.Errorf("%.7f != %.7f", a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqual(t *testing.T, a, b interface{}) {
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Errorf("%v != %v", a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func splitChars(s string) []string {
|
||||
chars := make([]string, 0, len(s))
|
||||
// Assume ASCII inputs
|
||||
for i := 0; i != len(s); i++ {
|
||||
chars = append(chars, string(s[i]))
|
||||
}
|
||||
return chars
|
||||
}
|
||||
|
||||
func TestSequenceMatcherRatio(t *testing.T) {
|
||||
s := NewMatcher(splitChars("abcd"), splitChars("bcde"))
|
||||
assertEqual(t, s.Ratio(), 0.75)
|
||||
assertEqual(t, s.QuickRatio(), 0.75)
|
||||
assertEqual(t, s.RealQuickRatio(), 1.0)
|
||||
}
|
||||
|
||||
func TestGetOptCodes(t *testing.T) {
|
||||
a := "qabxcd"
|
||||
b := "abycdf"
|
||||
s := NewMatcher(splitChars(a), splitChars(b))
|
||||
w := &bytes.Buffer{}
|
||||
for _, op := range s.GetOpCodes() {
|
||||
fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag),
|
||||
op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2])
|
||||
}
|
||||
result := string(w.Bytes())
|
||||
expected := `d a[0:1], (q) b[0:0] ()
|
||||
e a[1:3], (ab) b[0:2] (ab)
|
||||
r a[3:4], (x) b[2:3] (y)
|
||||
e a[4:6], (cd) b[3:5] (cd)
|
||||
i a[6:6], () b[5:6] (f)
|
||||
`
|
||||
if expected != result {
|
||||
t.Errorf("unexpected op codes: \n%s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupedOpCodes(t *testing.T) {
|
||||
a := []string{}
|
||||
for i := 0; i != 39; i++ {
|
||||
a = append(a, fmt.Sprintf("%02d", i))
|
||||
}
|
||||
b := []string{}
|
||||
b = append(b, a[:8]...)
|
||||
b = append(b, " i")
|
||||
b = append(b, a[8:19]...)
|
||||
b = append(b, " x")
|
||||
b = append(b, a[20:22]...)
|
||||
b = append(b, a[27:34]...)
|
||||
b = append(b, " y")
|
||||
b = append(b, a[35:]...)
|
||||
s := NewMatcher(a, b)
|
||||
w := &bytes.Buffer{}
|
||||
for _, g := range s.GetGroupedOpCodes(-1) {
|
||||
fmt.Fprintf(w, "group\n")
|
||||
for _, op := range g {
|
||||
fmt.Fprintf(w, " %s, %d, %d, %d, %d\n", string(op.Tag),
|
||||
op.I1, op.I2, op.J1, op.J2)
|
||||
}
|
||||
}
|
||||
result := string(w.Bytes())
|
||||
expected := `group
|
||||
e, 5, 8, 5, 8
|
||||
i, 8, 8, 8, 9
|
||||
e, 8, 11, 9, 12
|
||||
group
|
||||
e, 16, 19, 17, 20
|
||||
r, 19, 20, 20, 21
|
||||
e, 20, 22, 21, 23
|
||||
d, 22, 27, 23, 23
|
||||
e, 27, 30, 23, 26
|
||||
group
|
||||
e, 31, 34, 27, 30
|
||||
r, 34, 35, 30, 31
|
||||
e, 35, 38, 31, 34
|
||||
`
|
||||
if expected != result {
|
||||
t.Errorf("unexpected op codes: \n%s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleGetUnifiedDiffString() {
|
||||
a := `one
|
||||
two
|
||||
three
|
||||
four`
|
||||
b := `zero
|
||||
one
|
||||
three
|
||||
four`
|
||||
diff := UnifiedDiff{
|
||||
A: SplitLines(a),
|
||||
B: SplitLines(b),
|
||||
FromFile: "Original",
|
||||
FromDate: "2005-01-26 23:30:50",
|
||||
ToFile: "Current",
|
||||
ToDate: "2010-04-02 10:20:52",
|
||||
Context: 3,
|
||||
}
|
||||
result, _ := GetUnifiedDiffString(diff)
|
||||
fmt.Printf(strings.Replace(result, "\t", " ", -1))
|
||||
// Output:
|
||||
// --- Original 2005-01-26 23:30:50
|
||||
// +++ Current 2010-04-02 10:20:52
|
||||
// @@ -1,4 +1,4 @@
|
||||
// +zero
|
||||
// one
|
||||
// -two
|
||||
// three
|
||||
// four
|
||||
}
|
||||
|
||||
func ExampleGetContextDiffString() {
|
||||
a := `one
|
||||
two
|
||||
three
|
||||
four`
|
||||
b := `zero
|
||||
one
|
||||
tree
|
||||
four`
|
||||
diff := ContextDiff{
|
||||
A: SplitLines(a),
|
||||
B: SplitLines(b),
|
||||
FromFile: "Original",
|
||||
ToFile: "Current",
|
||||
Context: 3,
|
||||
Eol: "\n",
|
||||
}
|
||||
result, _ := GetContextDiffString(diff)
|
||||
fmt.Printf(strings.Replace(result, "\t", " ", -1))
|
||||
// Output:
|
||||
// *** Original
|
||||
// --- Current
|
||||
// ***************
|
||||
// *** 1,4 ****
|
||||
// one
|
||||
// ! two
|
||||
// ! three
|
||||
// four
|
||||
// --- 1,4 ----
|
||||
// + zero
|
||||
// one
|
||||
// ! tree
|
||||
// four
|
||||
}
|
||||
|
||||
func rep(s string, count int) string {
|
||||
return strings.Repeat(s, count)
|
||||
}
|
||||
|
||||
func TestWithAsciiOneInsert(t *testing.T) {
|
||||
sm := NewMatcher(splitChars(rep("b", 100)),
|
||||
splitChars("a"+rep("b", 100)))
|
||||
assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
|
||||
assertEqual(t, sm.GetOpCodes(),
|
||||
[]OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}})
|
||||
assertEqual(t, len(sm.bPopular), 0)
|
||||
|
||||
sm = NewMatcher(splitChars(rep("b", 100)),
|
||||
splitChars(rep("b", 50)+"a"+rep("b", 50)))
|
||||
assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
|
||||
assertEqual(t, sm.GetOpCodes(),
|
||||
[]OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}})
|
||||
assertEqual(t, len(sm.bPopular), 0)
|
||||
}
|
||||
|
||||
func TestWithAsciiOnDelete(t *testing.T) {
|
||||
sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)),
|
||||
splitChars(rep("a", 40)+rep("b", 40)))
|
||||
assertAlmostEqual(t, sm.Ratio(), 0.994, 3)
|
||||
assertEqual(t, sm.GetOpCodes(),
|
||||
[]OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}})
|
||||
}
|
||||
|
||||
func TestWithAsciiBJunk(t *testing.T) {
|
||||
isJunk := func(s string) bool {
|
||||
return s == " "
|
||||
}
|
||||
sm := NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
|
||||
splitChars(rep("a", 44)+rep("b", 40)), true, isJunk)
|
||||
assertEqual(t, sm.bJunk, map[string]struct{}{})
|
||||
|
||||
sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
|
||||
splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
|
||||
assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}})
|
||||
|
||||
isJunk = func(s string) bool {
|
||||
return s == " " || s == "b"
|
||||
}
|
||||
sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
|
||||
splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
|
||||
assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}, "b": struct{}{}})
|
||||
}
|
||||
|
||||
func TestSFBugsRatioForNullSeqn(t *testing.T) {
|
||||
sm := NewMatcher(nil, nil)
|
||||
assertEqual(t, sm.Ratio(), 1.0)
|
||||
assertEqual(t, sm.QuickRatio(), 1.0)
|
||||
assertEqual(t, sm.RealQuickRatio(), 1.0)
|
||||
}
|
||||
|
||||
func TestSFBugsComparingEmptyLists(t *testing.T) {
|
||||
groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1)
|
||||
assertEqual(t, len(groups), 0)
|
||||
diff := UnifiedDiff{
|
||||
FromFile: "Original",
|
||||
ToFile: "Current",
|
||||
Context: 3,
|
||||
}
|
||||
result, err := GetUnifiedDiffString(diff)
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, result, "")
|
||||
}
|
||||
|
||||
func TestOutputFormatRangeFormatUnified(t *testing.T) {
|
||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
||||
//
|
||||
// Each <range> field shall be of the form:
|
||||
// %1d", <beginning line number> if the range contains exactly one line,
|
||||
// and:
|
||||
// "%1d,%1d", <beginning line number>, <number of lines> otherwise.
|
||||
// If a range is empty, its beginning line number shall be the number of
|
||||
// the line just before the range, or 0 if the empty range starts the file.
|
||||
fm := formatRangeUnified
|
||||
assertEqual(t, fm(3, 3), "3,0")
|
||||
assertEqual(t, fm(3, 4), "4")
|
||||
assertEqual(t, fm(3, 5), "4,2")
|
||||
assertEqual(t, fm(3, 6), "4,3")
|
||||
assertEqual(t, fm(0, 0), "0,0")
|
||||
}
|
||||
|
||||
func TestOutputFormatRangeFormatContext(t *testing.T) {
|
||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
||||
//
|
||||
// The range of lines in file1 shall be written in the following format
|
||||
// if the range contains two or more lines:
|
||||
// "*** %d,%d ****\n", <beginning line number>, <ending line number>
|
||||
// and the following format otherwise:
|
||||
// "*** %d ****\n", <ending line number>
|
||||
// The ending line number of an empty range shall be the number of the preceding line,
|
||||
// or 0 if the range is at the start of the file.
|
||||
//
|
||||
// Next, the range of lines in file2 shall be written in the following format
|
||||
// if the range contains two or more lines:
|
||||
// "--- %d,%d ----\n", <beginning line number>, <ending line number>
|
||||
// and the following format otherwise:
|
||||
// "--- %d ----\n", <ending line number>
|
||||
fm := formatRangeContext
|
||||
assertEqual(t, fm(3, 3), "3")
|
||||
assertEqual(t, fm(3, 4), "4")
|
||||
assertEqual(t, fm(3, 5), "4,5")
|
||||
assertEqual(t, fm(3, 6), "4,6")
|
||||
assertEqual(t, fm(0, 0), "0")
|
||||
}
|
||||
|
||||
func TestOutputFormatTabDelimiter(t *testing.T) {
|
||||
diff := UnifiedDiff{
|
||||
A: splitChars("one"),
|
||||
B: splitChars("two"),
|
||||
FromFile: "Original",
|
||||
FromDate: "2005-01-26 23:30:50",
|
||||
ToFile: "Current",
|
||||
ToDate: "2010-04-12 10:20:52",
|
||||
Eol: "\n",
|
||||
}
|
||||
ud, err := GetUnifiedDiffString(diff)
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, SplitLines(ud)[:2], []string{
|
||||
"--- Original\t2005-01-26 23:30:50\n",
|
||||
"+++ Current\t2010-04-12 10:20:52\n",
|
||||
})
|
||||
cd, err := GetContextDiffString(ContextDiff(diff))
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, SplitLines(cd)[:2], []string{
|
||||
"*** Original\t2005-01-26 23:30:50\n",
|
||||
"--- Current\t2010-04-12 10:20:52\n",
|
||||
})
|
||||
}
|
||||
|
||||
func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) {
|
||||
diff := UnifiedDiff{
|
||||
A: splitChars("one"),
|
||||
B: splitChars("two"),
|
||||
FromFile: "Original",
|
||||
ToFile: "Current",
|
||||
Eol: "\n",
|
||||
}
|
||||
ud, err := GetUnifiedDiffString(diff)
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"})
|
||||
|
||||
cd, err := GetContextDiffString(ContextDiff(diff))
|
||||
assertEqual(t, err, nil)
|
||||
assertEqual(t, SplitLines(cd)[:2], []string{"*** Original\n", "--- Current\n"})
|
||||
}
|
||||
|
||||
func TestSplitLines(t *testing.T) {
|
||||
allTests := []struct {
|
||||
input string
|
||||
want []string
|
||||
}{
|
||||
{"foo", []string{"foo\n"}},
|
||||
{"foo\nbar", []string{"foo\n", "bar\n"}},
|
||||
{"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}},
|
||||
}
|
||||
for _, test := range allTests {
|
||||
assertEqual(t, SplitLines(test.input), test.want)
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkSplitLines(b *testing.B, count int) {
|
||||
str := strings.Repeat("foo\n", count)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
n := 0
|
||||
for i := 0; i < b.N; i++ {
|
||||
n += len(SplitLines(str))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSplitLines100(b *testing.B) {
|
||||
benchmarkSplitLines(b, 100)
|
||||
}
|
||||
|
||||
func BenchmarkSplitLines10000(b *testing.B) {
|
||||
benchmarkSplitLines(b, 10000)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
# 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
|
5
vendor/github.com/stretchr/objx/LICENSE.md → vendor/github.com/stretchr/objx/LICENSE
generated
vendored
5
vendor/github.com/stretchr/objx/LICENSE.md → vendor/github.com/stretchr/objx/LICENSE
generated
vendored
|
@ -1,8 +1,7 @@
|
|||
objx - by Mat Ryer and Tyler Bunnell
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014 Stretchr, Inc.
|
||||
Copyright (c) 2017-2018 objx contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
|
@ -1,3 +0,0 @@
|
|||
# objx
|
||||
|
||||
* Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)
|
|
@ -77,13 +77,10 @@ func access(current, selector, value interface{}, isSet, panics bool) interface{
|
|||
index := -1
|
||||
var err error
|
||||
|
||||
// https://github.com/stretchr/objx/issues/12
|
||||
if strings.Contains(thisSel, "[") {
|
||||
|
||||
arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
|
||||
|
||||
if len(arrayMatches) > 0 {
|
||||
|
||||
// Get the key into the map
|
||||
thisSel = arrayMatches[1]
|
||||
|
||||
|
@ -95,7 +92,6 @@ func access(current, selector, value interface{}, isSet, panics bool) interface{
|
|||
// seriously wrong. Panic.
|
||||
panic("objx: Array index is not an integer. Must use array[int].")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,9 +106,8 @@ func access(current, selector, value interface{}, isSet, panics bool) interface{
|
|||
if len(selSegs) <= 1 && isSet {
|
||||
curMSI[thisSel] = value
|
||||
return nil
|
||||
} else {
|
||||
current = curMSI[thisSel]
|
||||
}
|
||||
current = curMSI[thisSel]
|
||||
default:
|
||||
current = nil
|
||||
}
|
||||
|
@ -140,9 +135,7 @@ func access(current, selector, value interface{}, isSet, panics bool) interface{
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
return current
|
||||
|
||||
}
|
||||
|
||||
// intFromInterface converts an interface object to the largest
|
||||
|
@ -174,6 +167,5 @@ func intFromInterface(selector interface{}) int {
|
|||
default:
|
||||
panic("objx: array access argument is not an integer type (this should never happen)")
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAccessorsAccessGetSingleField(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"name": "Tyler"}
|
||||
assert.Equal(t, "Tyler", access(current, "name", nil, false, true))
|
||||
|
||||
}
|
||||
func TestAccessorsAccessGetDeep(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
|
||||
assert.Equal(t, "Tyler", access(current, "name.first", nil, false, true))
|
||||
assert.Equal(t, "Bunnell", access(current, "name.last", nil, false, true))
|
||||
|
||||
}
|
||||
func TestAccessorsAccessGetDeepDeep(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
|
||||
assert.Equal(t, 4, access(current, "one.two.three.four", nil, false, true))
|
||||
|
||||
}
|
||||
func TestAccessorsAccessGetInsideArray(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
|
||||
assert.Equal(t, "Tyler", access(current, "names[0].first", nil, false, true))
|
||||
assert.Equal(t, "Bunnell", access(current, "names[0].last", nil, false, true))
|
||||
assert.Equal(t, "Capitol", access(current, "names[1].first", nil, false, true))
|
||||
assert.Equal(t, "Bollocks", access(current, "names[1].last", nil, false, true))
|
||||
|
||||
assert.Panics(t, func() {
|
||||
access(current, "names[2]", nil, false, true)
|
||||
})
|
||||
assert.Nil(t, access(current, "names[2]", nil, false, false))
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsAccessGetFromArrayWithInt(t *testing.T) {
|
||||
|
||||
current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
|
||||
one := access(current, 0, nil, false, false)
|
||||
two := access(current, 1, nil, false, false)
|
||||
three := access(current, 2, nil, false, false)
|
||||
|
||||
assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
|
||||
assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
|
||||
assert.Nil(t, three)
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsGet(t *testing.T) {
|
||||
|
||||
current := New(map[string]interface{}{"name": "Tyler"})
|
||||
assert.Equal(t, "Tyler", current.Get("name").data)
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsAccessSetSingleField(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"name": "Tyler"}
|
||||
access(current, "name", "Mat", true, false)
|
||||
assert.Equal(t, current["name"], "Mat")
|
||||
|
||||
access(current, "age", 29, true, true)
|
||||
assert.Equal(t, current["age"], 29)
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsAccessSetSingleFieldNotExisting(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{}
|
||||
access(current, "name", "Mat", true, false)
|
||||
assert.Equal(t, current["name"], "Mat")
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsAccessSetDeep(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"name": map[string]interface{}{"first": "Tyler", "last": "Bunnell"}}
|
||||
|
||||
access(current, "name.first", "Mat", true, true)
|
||||
access(current, "name.last", "Ryer", true, true)
|
||||
|
||||
assert.Equal(t, "Mat", access(current, "name.first", nil, false, true))
|
||||
assert.Equal(t, "Ryer", access(current, "name.last", nil, false, true))
|
||||
|
||||
}
|
||||
func TestAccessorsAccessSetDeepDeep(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"one": map[string]interface{}{"two": map[string]interface{}{"three": map[string]interface{}{"four": 4}}}}
|
||||
|
||||
access(current, "one.two.three.four", 5, true, true)
|
||||
|
||||
assert.Equal(t, 5, access(current, "one.two.three.four", nil, false, true))
|
||||
|
||||
}
|
||||
func TestAccessorsAccessSetArray(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"names": []interface{}{"Tyler"}}
|
||||
|
||||
access(current, "names[0]", "Mat", true, true)
|
||||
|
||||
assert.Equal(t, "Mat", access(current, "names[0]", nil, false, true))
|
||||
|
||||
}
|
||||
func TestAccessorsAccessSetInsideArray(t *testing.T) {
|
||||
|
||||
current := map[string]interface{}{"names": []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}}
|
||||
|
||||
access(current, "names[0].first", "Mat", true, true)
|
||||
access(current, "names[0].last", "Ryer", true, true)
|
||||
access(current, "names[1].first", "Captain", true, true)
|
||||
access(current, "names[1].last", "Underpants", true, true)
|
||||
|
||||
assert.Equal(t, "Mat", access(current, "names[0].first", nil, false, true))
|
||||
assert.Equal(t, "Ryer", access(current, "names[0].last", nil, false, true))
|
||||
assert.Equal(t, "Captain", access(current, "names[1].first", nil, false, true))
|
||||
assert.Equal(t, "Underpants", access(current, "names[1].last", nil, false, true))
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsAccessSetFromArrayWithInt(t *testing.T) {
|
||||
|
||||
current := []interface{}{map[string]interface{}{"first": "Tyler", "last": "Bunnell"}, map[string]interface{}{"first": "Capitol", "last": "Bollocks"}}
|
||||
one := access(current, 0, nil, false, false)
|
||||
two := access(current, 1, nil, false, false)
|
||||
three := access(current, 2, nil, false, false)
|
||||
|
||||
assert.Equal(t, "Tyler", one.(map[string]interface{})["first"])
|
||||
assert.Equal(t, "Capitol", two.(map[string]interface{})["first"])
|
||||
assert.Nil(t, three)
|
||||
|
||||
}
|
||||
|
||||
func TestAccessorsSet(t *testing.T) {
|
||||
|
||||
current := New(map[string]interface{}{"name": "Tyler"})
|
||||
current.Set("name", "Mat")
|
||||
assert.Equal(t, "Mat", current.Get("name").data)
|
||||
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
case []{1}:
|
||||
a := object.([]{1})
|
||||
if isSet {
|
||||
a[index] = value.({1})
|
||||
} else {
|
||||
if index >= len(a) {
|
||||
if panics {
|
||||
panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a)))
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return a[index]
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Codegen
|
||||
</title>
|
||||
<style>
|
||||
body {
|
||||
width: 800px;
|
||||
margin: auto;
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
font-family: Courier;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
Template
|
||||
</h2>
|
||||
<p>
|
||||
Use <code>{x}</code> as a placeholder for each argument.
|
||||
</p>
|
||||
<textarea id="template"></textarea>
|
||||
|
||||
<h2>
|
||||
Arguments (comma separated)
|
||||
</h2>
|
||||
<p>
|
||||
One block per line
|
||||
</p>
|
||||
<textarea id="args"></textarea>
|
||||
|
||||
<h2>
|
||||
Output
|
||||
</h2>
|
||||
<input id="go" type="button" value="Generate code" />
|
||||
|
||||
<textarea id="output"></textarea>
|
||||
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
|
||||
$("#go").click(function(){
|
||||
|
||||
var output = ""
|
||||
var template = $("#template").val()
|
||||
var args = $("#args").val()
|
||||
|
||||
// collect the args
|
||||
var argLines = args.split("\n")
|
||||
for (var line in argLines) {
|
||||
|
||||
var argLine = argLines[line];
|
||||
var thisTemp = template
|
||||
|
||||
// get individual args
|
||||
var args = argLine.split(",")
|
||||
|
||||
for (var argI in args) {
|
||||
var argText = args[argI];
|
||||
var argPlaceholder = "{" + argI + "}";
|
||||
|
||||
while (thisTemp.indexOf(argPlaceholder) > -1) {
|
||||
thisTemp = thisTemp.replace(argPlaceholder, argText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
output += thisTemp
|
||||
|
||||
}
|
||||
|
||||
$("#output").val(output);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
{4} ({1} and []{1})
|
||||
--------------------------------------------------
|
||||
*/
|
||||
|
||||
// {4} gets the value as a {1}, returns the optionalDefault
|
||||
// value or a system default object if the value is the wrong type.
|
||||
func (v *Value) {4}(optionalDefault ...{1}) {1} {
|
||||
if s, ok := v.data.({1}); ok {
|
||||
return s
|
||||
}
|
||||
if len(optionalDefault) == 1 {
|
||||
return optionalDefault[0]
|
||||
}
|
||||
return {3}
|
||||
}
|
||||
|
||||
// Must{4} gets the value as a {1}.
|
||||
//
|
||||
// Panics if the object is not a {1}.
|
||||
func (v *Value) Must{4}() {1} {
|
||||
return v.data.({1})
|
||||
}
|
||||
|
||||
// {4}Slice gets the value as a []{1}, returns the optionalDefault
|
||||
// value or nil if the value is not a []{1}.
|
||||
func (v *Value) {4}Slice(optionalDefault ...[]{1}) []{1} {
|
||||
if s, ok := v.data.([]{1}); ok {
|
||||
return s
|
||||
}
|
||||
if len(optionalDefault) == 1 {
|
||||
return optionalDefault[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must{4}Slice gets the value as a []{1}.
|
||||
//
|
||||
// Panics if the object is not a []{1}.
|
||||
func (v *Value) Must{4}Slice() []{1} {
|
||||
return v.data.([]{1})
|
||||
}
|
||||
|
||||
// Is{4} gets whether the object contained is a {1} or not.
|
||||
func (v *Value) Is{4}() bool {
|
||||
_, ok := v.data.({1})
|
||||
return ok
|
||||
}
|
||||
|
||||
// Is{4}Slice gets whether the object contained is a []{1} or not.
|
||||
func (v *Value) Is{4}Slice() bool {
|
||||
_, ok := v.data.([]{1})
|
||||
return ok
|
||||
}
|
||||
|
||||
// Each{4} calls the specified callback for each object
|
||||
// in the []{1}.
|
||||
//
|
||||
// Panics if the object is the wrong type.
|
||||
func (v *Value) Each{4}(callback func(int, {1}) bool) *Value {
|
||||
|
||||
for index, val := range v.Must{4}Slice() {
|
||||
carryon := callback(index, val)
|
||||
if carryon == false {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return v
|
||||
|
||||
}
|
||||
|
||||
// Where{4} uses the specified decider function to select items
|
||||
// from the []{1}. The object contained in the result will contain
|
||||
// only the selected items.
|
||||
func (v *Value) Where{4}(decider func(int, {1}) bool) *Value {
|
||||
|
||||
var selected []{1}
|
||||
|
||||
v.Each{4}(func(index int, val {1}) bool {
|
||||
shouldSelect := decider(index, val)
|
||||
if shouldSelect == false {
|
||||
selected = append(selected, val)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return &Value{data:selected}
|
||||
|
||||
}
|
||||
|
||||
// Group{4} uses the specified grouper function to group the items
|
||||
// keyed by the return of the grouper. The object contained in the
|
||||
// result will contain a map[string][]{1}.
|
||||
func (v *Value) Group{4}(grouper func(int, {1}) string) *Value {
|
||||
|
||||
groups := make(map[string][]{1})
|
||||
|
||||
v.Each{4}(func(index int, val {1}) bool {
|
||||
group := grouper(index, val)
|
||||
if _, ok := groups[group]; !ok {
|
||||
groups[group] = make([]{1}, 0)
|
||||
}
|
||||
groups[group] = append(groups[group], val)
|
||||
return true
|
||||
})
|
||||
|
||||
return &Value{data:groups}
|
||||
|
||||
}
|
||||
|
||||
// Replace{4} uses the specified function to replace each {1}s
|
||||
// by iterating each item. The data in the returned result will be a
|
||||
// []{1} containing the replaced items.
|
||||
func (v *Value) Replace{4}(replacer func(int, {1}) {1}) *Value {
|
||||
|
||||
arr := v.Must{4}Slice()
|
||||
replaced := make([]{1}, len(arr))
|
||||
|
||||
v.Each{4}(func(index int, val {1}) bool {
|
||||
replaced[index] = replacer(index, val)
|
||||
return true
|
||||
})
|
||||
|
||||
return &Value{data:replaced}
|
||||
|
||||
}
|
||||
|
||||
// Collect{4} uses the specified collector function to collect a value
|
||||
// for each of the {1}s in the slice. The data returned will be a
|
||||
// []interface{}.
|
||||
func (v *Value) Collect{4}(collector func(int, {1}) interface{}) *Value {
|
||||
|
||||
arr := v.Must{4}Slice()
|
||||
collected := make([]interface{}, len(arr))
|
||||
|
||||
v.Each{4}(func(index int, val {1}) bool {
|
||||
collected[index] = collector(index, val)
|
||||
return true
|
||||
})
|
||||
|
||||
return &Value{data:collected}
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// TESTS
|
||||
// ************************************************************
|
||||
|
||||
func Test{4}(t *testing.T) {
|
||||
|
||||
val := {1}( {2} )
|
||||
m := map[string]interface{}{"value": val, "nothing": nil}
|
||||
assert.Equal(t, val, New(m).Get("value").{4}())
|
||||
assert.Equal(t, val, New(m).Get("value").Must{4}())
|
||||
assert.Equal(t, {1}({3}), New(m).Get("nothing").{4}())
|
||||
assert.Equal(t, val, New(m).Get("nothing").{4}({2}))
|
||||
|
||||
assert.Panics(t, func() {
|
||||
New(m).Get("age").Must{4}()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test{4}Slice(t *testing.T) {
|
||||
|
||||
val := {1}( {2} )
|
||||
m := map[string]interface{}{"value": []{1}{ val }, "nothing": nil}
|
||||
assert.Equal(t, val, New(m).Get("value").{4}Slice()[0])
|
||||
assert.Equal(t, val, New(m).Get("value").Must{4}Slice()[0])
|
||||
assert.Equal(t, []{1}(nil), New(m).Get("nothing").{4}Slice())
|
||||
assert.Equal(t, val, New(m).Get("nothing").{4}Slice( []{1}{ {1}({2}) } )[0])
|
||||
|
||||
assert.Panics(t, func() {
|
||||
New(m).Get("nothing").Must{4}Slice()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestIs{4}(t *testing.T) {
|
||||
|
||||
var v *Value
|
||||
|
||||
v = &Value{data: {1}({2})}
|
||||
assert.True(t, v.Is{4}())
|
||||
|
||||
v = &Value{data: []{1}{ {1}({2}) }}
|
||||
assert.True(t, v.Is{4}Slice())
|
||||
|
||||
}
|
||||
|
||||
func TestEach{4}(t *testing.T) {
|
||||
|
||||
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
|
||||
count := 0
|
||||
replacedVals := make([]{1}, 0)
|
||||
assert.Equal(t, v, v.Each{4}(func(i int, val {1}) bool {
|
||||
|
||||
count++
|
||||
replacedVals = append(replacedVals, val)
|
||||
|
||||
// abort early
|
||||
if i == 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}))
|
||||
|
||||
assert.Equal(t, count, 3)
|
||||
assert.Equal(t, replacedVals[0], v.Must{4}Slice()[0])
|
||||
assert.Equal(t, replacedVals[1], v.Must{4}Slice()[1])
|
||||
assert.Equal(t, replacedVals[2], v.Must{4}Slice()[2])
|
||||
|
||||
}
|
||||
|
||||
func TestWhere{4}(t *testing.T) {
|
||||
|
||||
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
|
||||
|
||||
selected := v.Where{4}(func(i int, val {1}) bool {
|
||||
return i%2==0
|
||||
}).Must{4}Slice()
|
||||
|
||||
assert.Equal(t, 3, len(selected))
|
||||
|
||||
}
|
||||
|
||||
func TestGroup{4}(t *testing.T) {
|
||||
|
||||
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
|
||||
|
||||
grouped := v.Group{4}(func(i int, val {1}) string {
|
||||
return fmt.Sprintf("%v", i%2==0)
|
||||
}).data.(map[string][]{1})
|
||||
|
||||
assert.Equal(t, 2, len(grouped))
|
||||
assert.Equal(t, 3, len(grouped["true"]))
|
||||
assert.Equal(t, 3, len(grouped["false"]))
|
||||
|
||||
}
|
||||
|
||||
func TestReplace{4}(t *testing.T) {
|
||||
|
||||
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
|
||||
|
||||
rawArr := v.Must{4}Slice()
|
||||
|
||||
replaced := v.Replace{4}(func(index int, val {1}) {1} {
|
||||
if index < len(rawArr)-1 {
|
||||
return rawArr[index+1]
|
||||
}
|
||||
return rawArr[0]
|
||||
})
|
||||
|
||||
replacedArr := replaced.Must{4}Slice()
|
||||
if assert.Equal(t, 6, len(replacedArr)) {
|
||||
assert.Equal(t, replacedArr[0], rawArr[1])
|
||||
assert.Equal(t, replacedArr[1], rawArr[2])
|
||||
assert.Equal(t, replacedArr[2], rawArr[3])
|
||||
assert.Equal(t, replacedArr[3], rawArr[4])
|
||||
assert.Equal(t, replacedArr[4], rawArr[5])
|
||||
assert.Equal(t, replacedArr[5], rawArr[0])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCollect{4}(t *testing.T) {
|
||||
|
||||
v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
|
||||
|
||||
collected := v.Collect{4}(func(index int, val {1}) interface{} {
|
||||
return index
|
||||
})
|
||||
|
||||
collectedArr := collected.MustInterSlice()
|
||||
if assert.Equal(t, 6, len(collectedArr)) {
|
||||
assert.Equal(t, collectedArr[0], 0)
|
||||
assert.Equal(t, collectedArr[1], 1)
|
||||
assert.Equal(t, collectedArr[2], 2)
|
||||
assert.Equal(t, collectedArr[3], 3)
|
||||
assert.Equal(t, collectedArr[4], 4)
|
||||
assert.Equal(t, collectedArr[5], 5)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
Interface,interface{},"something",nil,Inter
|
||||
Map,map[string]interface{},map[string]interface{}{"name":"Tyler"},nil,MSI
|
||||
ObjxMap,(Map),New(1),New(nil),ObjxMap
|
||||
Bool,bool,true,false,Bool
|
||||
String,string,"hello","",Str
|
||||
Int,int,1,0,Int
|
||||
Int8,int8,1,0,Int8
|
||||
Int16,int16,1,0,Int16
|
||||
Int32,int32,1,0,Int32
|
||||
Int64,int64,1,0,Int64
|
||||
Uint,uint,1,0,Uint
|
||||
Uint8,uint8,1,0,Uint8
|
||||
Uint16,uint16,1,0,Uint16
|
||||
Uint32,uint32,1,0,Uint32
|
||||
Uint64,uint64,1,0,Uint64
|
||||
Uintptr,uintptr,1,0,Uintptr
|
||||
Float32,float32,1,0,Float32
|
||||
Float64,float64,1,0,Float64
|
||||
Complex64,complex64,1,0,Complex64
|
||||
Complex128,complex128,1,0,Complex128
|
|
@ -12,15 +12,11 @@ import (
|
|||
// JSON converts the contained object to a JSON string
|
||||
// representation
|
||||
func (m Map) JSON() (string, error) {
|
||||
|
||||
result, err := json.Marshal(m)
|
||||
|
||||
if err != nil {
|
||||
err = errors.New("objx: JSON encode failed with: " + err.Error())
|
||||
}
|
||||
|
||||
return string(result), err
|
||||
|
||||
}
|
||||
|
||||
// MustJSON converts the contained object to a JSON string
|
||||
|
@ -36,7 +32,6 @@ func (m Map) MustJSON() string {
|
|||
// Base64 converts the contained object to a Base64 string
|
||||
// representation of the JSON string representation
|
||||
func (m Map) Base64() (string, error) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
jsonData, err := m.JSON()
|
||||
|
@ -45,11 +40,13 @@ func (m Map) Base64() (string, error) {
|
|||
}
|
||||
|
||||
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
|
||||
encoder.Write([]byte(jsonData))
|
||||
encoder.Close()
|
||||
_, err = encoder.Write([]byte(jsonData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_ = encoder.Close()
|
||||
|
||||
return buf.String(), nil
|
||||
|
||||
}
|
||||
|
||||
// MustBase64 converts the contained object to a Base64 string
|
||||
|
@ -67,16 +64,13 @@ func (m Map) MustBase64() string {
|
|||
// representation of the JSON string representation and signs it
|
||||
// using the provided key.
|
||||
func (m Map) SignedBase64(key string) (string, error) {
|
||||
|
||||
base64, err := m.Base64()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sig := HashWithKey(base64, key)
|
||||
|
||||
return base64 + SignatureSeparator + sig, nil
|
||||
|
||||
}
|
||||
|
||||
// MustSignedBase64 converts the contained object to a Base64 string
|
||||
|
@ -98,14 +92,11 @@ func (m Map) MustSignedBase64(key string) string {
|
|||
// URLValues creates a url.Values object from an Obj. This
|
||||
// function requires that the wrapped object be a map[string]interface{}
|
||||
func (m Map) URLValues() url.Values {
|
||||
|
||||
vals := make(url.Values)
|
||||
|
||||
for k, v := range m {
|
||||
//TODO: can this be done without sprintf?
|
||||
vals.Set(k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConversionJSON(t *testing.T) {
|
||||
|
||||
jsonString := `{"name":"Mat"}`
|
||||
o := MustFromJSON(jsonString)
|
||||
|
||||
result, err := o.JSON()
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, jsonString, result)
|
||||
}
|
||||
|
||||
assert.Equal(t, jsonString, o.MustJSON())
|
||||
|
||||
}
|
||||
|
||||
func TestConversionJSONWithError(t *testing.T) {
|
||||
|
||||
o := MSI()
|
||||
o["test"] = func() {}
|
||||
|
||||
assert.Panics(t, func() {
|
||||
o.MustJSON()
|
||||
})
|
||||
|
||||
_, err := o.JSON()
|
||||
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestConversionBase64(t *testing.T) {
|
||||
|
||||
o := New(map[string]interface{}{"name": "Mat"})
|
||||
|
||||
result, err := o.Base64()
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", result)
|
||||
}
|
||||
|
||||
assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", o.MustBase64())
|
||||
|
||||
}
|
||||
|
||||
func TestConversionBase64WithError(t *testing.T) {
|
||||
|
||||
o := MSI()
|
||||
o["test"] = func() {}
|
||||
|
||||
assert.Panics(t, func() {
|
||||
o.MustBase64()
|
||||
})
|
||||
|
||||
_, err := o.Base64()
|
||||
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestConversionSignedBase64(t *testing.T) {
|
||||
|
||||
o := New(map[string]interface{}{"name": "Mat"})
|
||||
|
||||
result, err := o.SignedBase64("key")
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", result)
|
||||
}
|
||||
|
||||
assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", o.MustSignedBase64("key"))
|
||||
|
||||
}
|
||||
|
||||
func TestConversionSignedBase64WithError(t *testing.T) {
|
||||
|
||||
o := MSI()
|
||||
o["test"] = func() {}
|
||||
|
||||
assert.Panics(t, func() {
|
||||
o.MustSignedBase64("key")
|
||||
})
|
||||
|
||||
_, err := o.SignedBase64("key")
|
||||
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
|
@ -1,72 +1,66 @@
|
|||
// objx - Go package for dealing with maps, slices, JSON and other data.
|
||||
//
|
||||
// Overview
|
||||
//
|
||||
// Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
|
||||
// a powerful `Get` method (among others) that allows you to easily and quickly get
|
||||
// access to data within the map, without having to worry too much about type assertions,
|
||||
// missing data, default values etc.
|
||||
//
|
||||
// Pattern
|
||||
//
|
||||
// Objx uses a preditable pattern to make access data from within `map[string]interface{}'s
|
||||
// easy.
|
||||
//
|
||||
// Call one of the `objx.` functions to create your `objx.Map` to get going:
|
||||
//
|
||||
// m, err := objx.FromJSON(json)
|
||||
//
|
||||
// NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
|
||||
// the rest will be optimistic and try to figure things out without panicking.
|
||||
//
|
||||
// Use `Get` to access the value you're interested in. You can use dot and array
|
||||
// notation too:
|
||||
//
|
||||
// m.Get("places[0].latlng")
|
||||
//
|
||||
// Once you have saught the `Value` you're interested in, you can use the `Is*` methods
|
||||
// to determine its type.
|
||||
//
|
||||
// if m.Get("code").IsStr() { /* ... */ }
|
||||
//
|
||||
// Or you can just assume the type, and use one of the strong type methods to
|
||||
// extract the real value:
|
||||
//
|
||||
// m.Get("code").Int()
|
||||
//
|
||||
// If there's no value there (or if it's the wrong type) then a default value
|
||||
// will be returned, or you can be explicit about the default value.
|
||||
//
|
||||
// Get("code").Int(-1)
|
||||
//
|
||||
// If you're dealing with a slice of data as a value, Objx provides many useful
|
||||
// methods for iterating, manipulating and selecting that data. You can find out more
|
||||
// by exploring the index below.
|
||||
//
|
||||
// Reading data
|
||||
//
|
||||
// A simple example of how to use Objx:
|
||||
//
|
||||
// // use MustFromJSON to make an objx.Map from some JSON
|
||||
// m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
|
||||
//
|
||||
// // get the details
|
||||
// name := m.Get("name").Str()
|
||||
// age := m.Get("age").Int()
|
||||
//
|
||||
// // get their nickname (or use their name if they
|
||||
// // don't have one)
|
||||
// nickname := m.Get("nickname").Str(name)
|
||||
//
|
||||
// Ranging
|
||||
//
|
||||
// Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For
|
||||
// example, to `range` the data, do what you would expect:
|
||||
//
|
||||
// m := objx.MustFromJSON(json)
|
||||
// for key, value := range m {
|
||||
//
|
||||
// /* ... do your magic ... */
|
||||
//
|
||||
// }
|
||||
/*
|
||||
Objx - Go package for dealing with maps, slices, JSON and other data.
|
||||
|
||||
Overview
|
||||
|
||||
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
|
||||
a powerful `Get` method (among others) that allows you to easily and quickly get
|
||||
access to data within the map, without having to worry too much about type assertions,
|
||||
missing data, default values etc.
|
||||
|
||||
Pattern
|
||||
|
||||
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy.
|
||||
Call one of the `objx.` functions to create your `objx.Map` to get going:
|
||||
|
||||
m, err := objx.FromJSON(json)
|
||||
|
||||
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
|
||||
the rest will be optimistic and try to figure things out without panicking.
|
||||
|
||||
Use `Get` to access the value you're interested in. You can use dot and array
|
||||
notation too:
|
||||
|
||||
m.Get("places[0].latlng")
|
||||
|
||||
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
|
||||
|
||||
if m.Get("code").IsStr() { // Your code... }
|
||||
|
||||
Or you can just assume the type, and use one of the strong type methods to extract the real value:
|
||||
|
||||
m.Get("code").Int()
|
||||
|
||||
If there's no value there (or if it's the wrong type) then a default value will be returned,
|
||||
or you can be explicit about the default value.
|
||||
|
||||
Get("code").Int(-1)
|
||||
|
||||
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating,
|
||||
manipulating and selecting that data. You can find out more by exploring the index below.
|
||||
|
||||
Reading data
|
||||
|
||||
A simple example of how to use Objx:
|
||||
|
||||
// Use MustFromJSON to make an objx.Map from some JSON
|
||||
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
|
||||
|
||||
// Get the details
|
||||
name := m.Get("name").Str()
|
||||
age := m.Get("age").Int()
|
||||
|
||||
// Get their nickname (or use their name if they don't have one)
|
||||
nickname := m.Get("nickname").Str(name)
|
||||
|
||||
Ranging
|
||||
|
||||
Since `objx.Map` is a `map[string]interface{}` you can treat it as such.
|
||||
For example, to `range` the data, do what you would expect:
|
||||
|
||||
m := objx.MustFromJSON(json)
|
||||
for key, value := range m {
|
||||
// Your code...
|
||||
}
|
||||
*/
|
||||
package objx
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var fixtures = []struct {
|
||||
// name is the name of the fixture (used for reporting
|
||||
// failures)
|
||||
name string
|
||||
// data is the JSON data to be worked on
|
||||
data string
|
||||
// get is the argument(s) to pass to Get
|
||||
get interface{}
|
||||
// output is the expected output
|
||||
output interface{}
|
||||
}{
|
||||
{
|
||||
name: "Simple get",
|
||||
data: `{"name": "Mat"}`,
|
||||
get: "name",
|
||||
output: "Mat",
|
||||
},
|
||||
{
|
||||
name: "Get with dot notation",
|
||||
data: `{"address": {"city": "Boulder"}}`,
|
||||
get: "address.city",
|
||||
output: "Boulder",
|
||||
},
|
||||
{
|
||||
name: "Deep get with dot notation",
|
||||
data: `{"one": {"two": {"three": {"four": "hello"}}}}`,
|
||||
get: "one.two.three.four",
|
||||
output: "hello",
|
||||
},
|
||||
{
|
||||
name: "Get missing with dot notation",
|
||||
data: `{"one": {"two": {"three": {"four": "hello"}}}}`,
|
||||
get: "one.ten",
|
||||
output: nil,
|
||||
},
|
||||
{
|
||||
name: "Get with array notation",
|
||||
data: `{"tags": ["one", "two", "three"]}`,
|
||||
get: "tags[1]",
|
||||
output: "two",
|
||||
},
|
||||
{
|
||||
name: "Get with array and dot notation",
|
||||
data: `{"types": { "tags": ["one", "two", "three"]}}`,
|
||||
get: "types.tags[1]",
|
||||
output: "two",
|
||||
},
|
||||
{
|
||||
name: "Get with array and dot notation - field after array",
|
||||
data: `{"tags": [{"name":"one"}, {"name":"two"}, {"name":"three"}]}`,
|
||||
get: "tags[1].name",
|
||||
output: "two",
|
||||
},
|
||||
{
|
||||
name: "Complex get with array and dot notation",
|
||||
data: `{"tags": [{"list": [{"one":"pizza"}]}]}`,
|
||||
get: "tags[0].list[0].one",
|
||||
output: "pizza",
|
||||
},
|
||||
{
|
||||
name: "Get field from within string should be nil",
|
||||
data: `{"name":"Tyler"}`,
|
||||
get: "name.something",
|
||||
output: nil,
|
||||
},
|
||||
{
|
||||
name: "Get field from within string (using array accessor) should be nil",
|
||||
data: `{"numbers":["one", "two", "three"]}`,
|
||||
get: "numbers[0].nope",
|
||||
output: nil,
|
||||
},
|
||||
}
|
||||
|
||||
func TestFixtures(t *testing.T) {
|
||||
|
||||
for _, fixture := range fixtures {
|
||||
|
||||
m := MustFromJSON(fixture.data)
|
||||
|
||||
// get the value
|
||||
t.Logf("Running get fixture: \"%s\" (%v)", fixture.name, fixture)
|
||||
value := m.Get(fixture.get.(string))
|
||||
|
||||
// make sure it matches
|
||||
assert.Equal(t, fixture.output, value.data,
|
||||
"Get fixture \"%s\" failed: %v", fixture.name, fixture,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -27,7 +27,7 @@ func (m Map) Value() *Value {
|
|||
}
|
||||
|
||||
// Nil represents a nil Map.
|
||||
var Nil Map = New(nil)
|
||||
var Nil = New(nil)
|
||||
|
||||
// New creates a new Map containing the map[string]interface{} in the data argument.
|
||||
// If the data argument is not a map[string]interface, New attempts to call the
|
||||
|
@ -49,7 +49,7 @@ func New(data interface{}) Map {
|
|||
//
|
||||
// Panics
|
||||
//
|
||||
// Panics if any key arugment is non-string or if there are an odd number of arguments.
|
||||
// Panics if any key argument is non-string or if there are an odd number of arguments.
|
||||
//
|
||||
// Example
|
||||
//
|
||||
|
@ -60,16 +60,13 @@ func New(data interface{}) Map {
|
|||
// // creates an Map equivalent to
|
||||
// m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
|
||||
func MSI(keyAndValuePairs ...interface{}) Map {
|
||||
|
||||
newMap := make(map[string]interface{})
|
||||
keyAndValuePairsLen := len(keyAndValuePairs)
|
||||
|
||||
if keyAndValuePairsLen%2 != 0 {
|
||||
panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
|
||||
}
|
||||
|
||||
for i := 0; i < keyAndValuePairsLen; i = i + 2 {
|
||||
|
||||
key := keyAndValuePairs[i]
|
||||
value := keyAndValuePairs[i+1]
|
||||
|
||||
|
@ -78,11 +75,8 @@ func MSI(keyAndValuePairs ...interface{}) Map {
|
|||
if !keyStringOK {
|
||||
panic("objx: MSI must follow 'string, interface{}' pattern. " + keyString + " is not a valid key.")
|
||||
}
|
||||
|
||||
newMap[keyString] = value
|
||||
|
||||
}
|
||||
|
||||
return New(newMap)
|
||||
}
|
||||
|
||||
|
@ -94,11 +88,9 @@ func MSI(keyAndValuePairs ...interface{}) Map {
|
|||
// Panics if the JSON is invalid.
|
||||
func MustFromJSON(jsonString string) Map {
|
||||
o, err := FromJSON(jsonString)
|
||||
|
||||
if err != nil {
|
||||
panic("objx: MustFromJSON failed with error: " + err.Error())
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
|
@ -107,16 +99,12 @@ func MustFromJSON(jsonString string) Map {
|
|||
//
|
||||
// Returns an error if the JSON is invalid.
|
||||
func FromJSON(jsonString string) (Map, error) {
|
||||
|
||||
var data interface{}
|
||||
err := json.Unmarshal([]byte(jsonString), &data)
|
||||
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
return New(data), nil
|
||||
|
||||
}
|
||||
|
||||
// FromBase64 creates a new Obj containing the data specified
|
||||
|
@ -124,14 +112,11 @@ func FromJSON(jsonString string) (Map, error) {
|
|||
//
|
||||
// The string is an encoded JSON string returned by Base64
|
||||
func FromBase64(base64String string) (Map, error) {
|
||||
|
||||
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
|
||||
|
||||
decoded, err := ioutil.ReadAll(decoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return FromJSON(string(decoded))
|
||||
}
|
||||
|
||||
|
@ -140,13 +125,10 @@ func FromBase64(base64String string) (Map, error) {
|
|||
//
|
||||
// The string is an encoded JSON string returned by Base64
|
||||
func MustFromBase64(base64String string) Map {
|
||||
|
||||
result, err := FromBase64(base64String)
|
||||
|
||||
if err != nil {
|
||||
panic("objx: MustFromBase64 failed with error: " + err.Error())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -157,14 +139,13 @@ func MustFromBase64(base64String string) Map {
|
|||
func FromSignedBase64(base64String, key string) (Map, error) {
|
||||
parts := strings.Split(base64String, SignatureSeparator)
|
||||
if len(parts) != 2 {
|
||||
return nil, errors.New("objx: Signed base64 string is malformed.")
|
||||
return nil, errors.New("objx: Signed base64 string is malformed")
|
||||
}
|
||||
|
||||
sig := HashWithKey(parts[0], key)
|
||||
if parts[1] != sig {
|
||||
return nil, errors.New("objx: Signature for base64 data does not match.")
|
||||
return nil, errors.New("objx: Signature for base64 data does not match")
|
||||
}
|
||||
|
||||
return FromBase64(parts[0])
|
||||
}
|
||||
|
||||
|
@ -173,13 +154,10 @@ func FromSignedBase64(base64String, key string) (Map, error) {
|
|||
//
|
||||
// The string is an encoded JSON string returned by Base64
|
||||
func MustFromSignedBase64(base64String, key string) Map {
|
||||
|
||||
result, err := FromSignedBase64(base64String, key)
|
||||
|
||||
if err != nil {
|
||||
panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -188,9 +166,7 @@ func MustFromSignedBase64(base64String, key string) Map {
|
|||
//
|
||||
// For queries with multiple values, the first value is selected.
|
||||
func FromURLQuery(query string) (Map, error) {
|
||||
|
||||
vals, err := url.ParseQuery(query)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -199,7 +175,6 @@ func FromURLQuery(query string) (Map, error) {
|
|||
for k, vals := range vals {
|
||||
m[k] = vals[0]
|
||||
}
|
||||
|
||||
return New(m), nil
|
||||
}
|
||||
|
||||
|
@ -210,13 +185,9 @@ func FromURLQuery(query string) (Map, error) {
|
|||
//
|
||||
// Panics if it encounters an error
|
||||
func MustFromURLQuery(query string) Map {
|
||||
|
||||
o, err := FromURLQuery(query)
|
||||
|
||||
if err != nil {
|
||||
panic("objx: MustFromURLQuery failed with error: " + err.Error())
|
||||
}
|
||||
|
||||
return o
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package objx
|
||||
|
||||
var TestMap map[string]interface{} = map[string]interface{}{
|
||||
"name": "Tyler",
|
||||
"address": map[string]interface{}{
|
||||
"city": "Salt Lake City",
|
||||
"state": "UT",
|
||||
},
|
||||
"numbers": []interface{}{"one", "two", "three", "four", "five"},
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Convertable struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (c *Convertable) MSI() map[string]interface{} {
|
||||
return map[string]interface{}{"name": c.name}
|
||||
}
|
||||
|
||||
type Unconvertable struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func TestMapCreation(t *testing.T) {
|
||||
|
||||
o := New(nil)
|
||||
assert.Nil(t, o)
|
||||
|
||||
o = New("Tyler")
|
||||
assert.Nil(t, o)
|
||||
|
||||
unconvertable := &Unconvertable{name: "Tyler"}
|
||||
o = New(unconvertable)
|
||||
assert.Nil(t, o)
|
||||
|
||||
convertable := &Convertable{name: "Tyler"}
|
||||
o = New(convertable)
|
||||
if assert.NotNil(t, convertable) {
|
||||
assert.Equal(t, "Tyler", o["name"], "Tyler")
|
||||
}
|
||||
|
||||
o = MSI()
|
||||
if assert.NotNil(t, o) {
|
||||
assert.NotNil(t, o)
|
||||
}
|
||||
|
||||
o = MSI("name", "Tyler")
|
||||
if assert.NotNil(t, o) {
|
||||
if assert.NotNil(t, o) {
|
||||
assert.Equal(t, o["name"], "Tyler")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMapMustFromJSONWithError(t *testing.T) {
|
||||
|
||||
_, err := FromJSON(`"name":"Mat"}`)
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromJSON(t *testing.T) {
|
||||
|
||||
o := MustFromJSON(`{"name":"Mat"}`)
|
||||
|
||||
if assert.NotNil(t, o) {
|
||||
if assert.NotNil(t, o) {
|
||||
assert.Equal(t, "Mat", o["name"])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromJSONWithError(t *testing.T) {
|
||||
|
||||
var m Map
|
||||
|
||||
assert.Panics(t, func() {
|
||||
m = MustFromJSON(`"name":"Mat"}`)
|
||||
})
|
||||
|
||||
assert.Nil(t, m)
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromBase64String(t *testing.T) {
|
||||
|
||||
base64String := "eyJuYW1lIjoiTWF0In0="
|
||||
|
||||
o, err := FromBase64(base64String)
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, o.Get("name").Str(), "Mat")
|
||||
}
|
||||
|
||||
assert.Equal(t, MustFromBase64(base64String).Get("name").Str(), "Mat")
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromBase64StringWithError(t *testing.T) {
|
||||
|
||||
base64String := "eyJuYW1lIjoiTWFasd0In0="
|
||||
|
||||
_, err := FromBase64(base64String)
|
||||
|
||||
assert.Error(t, err)
|
||||
|
||||
assert.Panics(t, func() {
|
||||
MustFromBase64(base64String)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromSignedBase64String(t *testing.T) {
|
||||
|
||||
base64String := "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
|
||||
|
||||
o, err := FromSignedBase64(base64String, "key")
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, o.Get("name").Str(), "Mat")
|
||||
}
|
||||
|
||||
assert.Equal(t, MustFromSignedBase64(base64String, "key").Get("name").Str(), "Mat")
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromSignedBase64StringWithError(t *testing.T) {
|
||||
|
||||
base64String := "eyJuYW1lasdIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
|
||||
|
||||
_, err := FromSignedBase64(base64String, "key")
|
||||
|
||||
assert.Error(t, err)
|
||||
|
||||
assert.Panics(t, func() {
|
||||
MustFromSignedBase64(base64String, "key")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestMapFromURLQuery(t *testing.T) {
|
||||
|
||||
m, err := FromURLQuery("name=tyler&state=UT")
|
||||
if assert.NoError(t, err) && assert.NotNil(t, m) {
|
||||
assert.Equal(t, "tyler", m.Get("name").Str())
|
||||
assert.Equal(t, "UT", m.Get("state").Str())
|
||||
}
|
||||
|
||||
}
|
|
@ -2,11 +2,10 @@ package objx
|
|||
|
||||
// Exclude returns a new Map with the keys in the specified []string
|
||||
// excluded.
|
||||
func (d Map) Exclude(exclude []string) Map {
|
||||
|
||||
func (m Map) Exclude(exclude []string) Map {
|
||||
excluded := make(Map)
|
||||
for k, v := range d {
|
||||
var shouldInclude bool = true
|
||||
for k, v := range m {
|
||||
var shouldInclude = true
|
||||
for _, toExclude := range exclude {
|
||||
if k == toExclude {
|
||||
shouldInclude = false
|
||||
|
@ -17,7 +16,6 @@ func (d Map) Exclude(exclude []string) Map {
|
|||
excluded[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return excluded
|
||||
}
|
||||
|
||||
|
@ -38,19 +36,16 @@ func (m Map) Merge(merge Map) Map {
|
|||
return m.Copy().MergeHere(merge)
|
||||
}
|
||||
|
||||
// Merge blends the specified map with this map and returns the current map.
|
||||
// MergeHere blends the specified map with this map and returns the current map.
|
||||
//
|
||||
// Keys that appear in both will be selected from the specified map. The original map
|
||||
// Keys that appear in both will be selected from the specified map. The original map
|
||||
// will be modified. This method requires that
|
||||
// the wrapped object be a map[string]interface{}
|
||||
func (m Map) MergeHere(merge Map) Map {
|
||||
|
||||
for k, v := range merge {
|
||||
m[k] = v
|
||||
}
|
||||
|
||||
return m
|
||||
|
||||
}
|
||||
|
||||
// Transform builds a new Obj giving the transformer a chance
|
||||
|
@ -71,11 +66,9 @@ func (m Map) Transform(transformer func(key string, value interface{}) (string,
|
|||
// This method requires that the wrapped object be a map[string]interface{}
|
||||
func (m Map) TransformKeys(mapping map[string]string) Map {
|
||||
return m.Transform(func(key string, value interface{}) (string, interface{}) {
|
||||
|
||||
if newKey, ok := mapping[key]; ok {
|
||||
return newKey, value
|
||||
}
|
||||
|
||||
return key, value
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExclude(t *testing.T) {
|
||||
|
||||
d := make(Map)
|
||||
d["name"] = "Mat"
|
||||
d["age"] = 29
|
||||
d["secret"] = "ABC"
|
||||
|
||||
excluded := d.Exclude([]string{"secret"})
|
||||
|
||||
assert.Equal(t, d["name"], excluded["name"])
|
||||
assert.Equal(t, d["age"], excluded["age"])
|
||||
assert.False(t, excluded.Has("secret"), "secret should be excluded")
|
||||
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
|
||||
d1 := make(map[string]interface{})
|
||||
d1["name"] = "Tyler"
|
||||
d1["location"] = "UT"
|
||||
|
||||
d1Obj := New(d1)
|
||||
d2Obj := d1Obj.Copy()
|
||||
|
||||
d2Obj["name"] = "Mat"
|
||||
|
||||
assert.Equal(t, d1Obj.Get("name").Str(), "Tyler")
|
||||
assert.Equal(t, d2Obj.Get("name").Str(), "Mat")
|
||||
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
|
||||
d := make(map[string]interface{})
|
||||
d["name"] = "Mat"
|
||||
|
||||
d1 := make(map[string]interface{})
|
||||
d1["name"] = "Tyler"
|
||||
d1["location"] = "UT"
|
||||
|
||||
dObj := New(d)
|
||||
d1Obj := New(d1)
|
||||
|
||||
merged := dObj.Merge(d1Obj)
|
||||
|
||||
assert.Equal(t, merged.Get("name").Str(), d1Obj.Get("name").Str())
|
||||
assert.Equal(t, merged.Get("location").Str(), d1Obj.Get("location").Str())
|
||||
assert.Empty(t, dObj.Get("location").Str())
|
||||
|
||||
}
|
||||
|
||||
func TestMergeHere(t *testing.T) {
|
||||
|
||||
d := make(map[string]interface{})
|
||||
d["name"] = "Mat"
|
||||
|
||||
d1 := make(map[string]interface{})
|
||||
d1["name"] = "Tyler"
|
||||
d1["location"] = "UT"
|
||||
|
||||
dObj := New(d)
|
||||
d1Obj := New(d1)
|
||||
|
||||
merged := dObj.MergeHere(d1Obj)
|
||||
|
||||
assert.Equal(t, dObj, merged, "With MergeHere, it should return the first modified map")
|
||||
assert.Equal(t, merged.Get("name").Str(), d1Obj.Get("name").Str())
|
||||
assert.Equal(t, merged.Get("location").Str(), d1Obj.Get("location").Str())
|
||||
assert.Equal(t, merged.Get("location").Str(), dObj.Get("location").Str())
|
||||
}
|
|
@ -9,6 +9,9 @@ import (
|
|||
// key.
|
||||
func HashWithKey(data, key string) string {
|
||||
hash := sha1.New()
|
||||
hash.Write([]byte(data + ":" + key))
|
||||
_, err := hash.Write([]byte(data + ":" + key))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHashWithKey(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "0ce84d8d01f2c7b6e0882b784429c54d280ea2d9", HashWithKey("abc", "def"))
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimpleExample(t *testing.T) {
|
||||
|
||||
// build a map from a JSON object
|
||||
o := MustFromJSON(`{"name":"Mat","foods":["indian","chinese"], "location":{"county":"hobbiton","city":"the shire"}}`)
|
||||
|
||||
// Map can be used as a straight map[string]interface{}
|
||||
assert.Equal(t, o["name"], "Mat")
|
||||
|
||||
// Get an Value object
|
||||
v := o.Get("name")
|
||||
assert.Equal(t, v, &Value{data: "Mat"})
|
||||
|
||||
// Test the contained value
|
||||
assert.False(t, v.IsInt())
|
||||
assert.False(t, v.IsBool())
|
||||
assert.True(t, v.IsStr())
|
||||
|
||||
// Get the contained value
|
||||
assert.Equal(t, v.Str(), "Mat")
|
||||
|
||||
// Get a default value if the contained value is not of the expected type or does not exist
|
||||
assert.Equal(t, 1, v.Int(1))
|
||||
|
||||
// Get a value by using array notation
|
||||
assert.Equal(t, "indian", o.Get("foods[0]").Data())
|
||||
|
||||
// Set a value by using array notation
|
||||
o.Set("foods[0]", "italian")
|
||||
assert.Equal(t, "italian", o.Get("foods[0]").Str())
|
||||
|
||||
// Get a value by using dot notation
|
||||
assert.Equal(t, "hobbiton", o.Get("location.county").Str())
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHas(t *testing.T) {
|
||||
|
||||
m := New(TestMap)
|
||||
|
||||
assert.True(t, m.Has("name"))
|
||||
assert.True(t, m.Has("address.state"))
|
||||
assert.True(t, m.Has("numbers[4]"))
|
||||
|
||||
assert.False(t, m.Has("address.state.nope"))
|
||||
assert.False(t, m.Has("address.nope"))
|
||||
assert.False(t, m.Has("nope"))
|
||||
assert.False(t, m.Has("numbers[5]"))
|
||||
|
||||
m = nil
|
||||
assert.False(t, m.Has("nothing"))
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,10 @@
|
|||
package objx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Value provides methods for extracting interface{} data in various
|
||||
// types.
|
||||
type Value struct {
|
||||
|
@ -11,3 +16,41 @@ type Value struct {
|
|||
func (v *Value) Data() interface{} {
|
||||
return v.data
|
||||
}
|
||||
|
||||
// String returns the value always as a string
|
||||
func (v *Value) String() string {
|
||||
switch {
|
||||
case v.IsStr():
|
||||
return v.Str()
|
||||
case v.IsBool():
|
||||
return strconv.FormatBool(v.Bool())
|
||||
case v.IsFloat32():
|
||||
return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32)
|
||||
case v.IsFloat64():
|
||||
return strconv.FormatFloat(v.Float64(), 'f', -1, 64)
|
||||
case v.IsInt():
|
||||
return strconv.FormatInt(int64(v.Int()), 10)
|
||||
case v.IsInt():
|
||||
return strconv.FormatInt(int64(v.Int()), 10)
|
||||
case v.IsInt8():
|
||||
return strconv.FormatInt(int64(v.Int8()), 10)
|
||||
case v.IsInt16():
|
||||
return strconv.FormatInt(int64(v.Int16()), 10)
|
||||
case v.IsInt32():
|
||||
return strconv.FormatInt(int64(v.Int32()), 10)
|
||||
case v.IsInt64():
|
||||
return strconv.FormatInt(v.Int64(), 10)
|
||||
case v.IsUint():
|
||||
return strconv.FormatUint(uint64(v.Uint()), 10)
|
||||
case v.IsUint8():
|
||||
return strconv.FormatUint(uint64(v.Uint8()), 10)
|
||||
case v.IsUint16():
|
||||
return strconv.FormatUint(uint64(v.Uint16()), 10)
|
||||
case v.IsUint32():
|
||||
return strconv.FormatUint(uint64(v.Uint32()), 10)
|
||||
case v.IsUint64():
|
||||
return strconv.FormatUint(v.Uint64(), 10)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#v", v.Data())
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
package objx
|
Loading…
Reference in New Issue