Add and remove dependencies

This commit is contained in:
Harshavardhana 2015-07-01 00:16:17 -07:00
parent 4addf7a996
commit 188785a886
64 changed files with 2075 additions and 11577 deletions

16
Godeps/Godeps.json generated
View File

@ -21,6 +21,10 @@
"ImportPath": "github.com/gorilla/mux",
"Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf"
},
{
"ImportPath": "github.com/gorilla/rpc/v2",
"Rev": "f6dbf92d77c723632269bf29154cc91f2507693b"
},
{
"ImportPath": "github.com/minio/check",
"Rev": "67f8c16c6c27bb03c82e41c2be533ace00035ab4"
@ -29,18 +33,6 @@
"ImportPath": "github.com/minio/cli",
"Comment": "1.2.0-112-g823349c",
"Rev": "823349ce91e76834a4af0119d5bbc58fd4d2c6b0"
},
{
"ImportPath": "github.com/stretchr/objx",
"Rev": "cbeaeb16a013161a98496fad62933b1d21786672"
},
{
"ImportPath": "github.com/stretchr/testify/assert",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
},
{
"ImportPath": "github.com/stretchr/testify/mock",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
}
]
}

View File

@ -0,0 +1,27 @@
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,6 @@
rpc
===
gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of an object through HTTP requests.
Read the full documentation here: http://www.gorillatoolkit.org/pkg/rpc

View File

@ -0,0 +1,90 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"compress/flate"
"compress/gzip"
"io"
"net/http"
"strings"
"unicode"
)
// gzipWriter writes and closes the gzip writer.
type gzipWriter struct {
w *gzip.Writer
}
func (gw *gzipWriter) Write(p []byte) (n int, err error) {
defer gw.w.Close()
return gw.w.Write(p)
}
// gzipEncoder implements the gzip compressed http encoder.
type gzipEncoder struct {
}
func (enc *gzipEncoder) Encode(w http.ResponseWriter) io.Writer {
w.Header().Set("Content-Encoding", "gzip")
return &gzipWriter{gzip.NewWriter(w)}
}
// flateWriter writes and closes the flate writer.
type flateWriter struct {
w *flate.Writer
}
func (fw *flateWriter) Write(p []byte) (n int, err error) {
defer fw.w.Close()
return fw.w.Write(p)
}
// flateEncoder implements the flate compressed http encoder.
type flateEncoder struct {
}
func (enc *flateEncoder) Encode(w http.ResponseWriter) io.Writer {
fw, err := flate.NewWriter(w, flate.DefaultCompression)
if err != nil {
return w
}
w.Header().Set("Content-Encoding", "deflate")
return &flateWriter{fw}
}
// CompressionSelector generates the compressed http encoder.
type CompressionSelector struct {
}
// acceptedEnc returns the first compression type in "Accept-Encoding" header
// field of the request.
func acceptedEnc(req *http.Request) string {
encHeader := req.Header.Get("Accept-Encoding")
if encHeader == "" {
return ""
}
encTypes := strings.FieldsFunc(encHeader, func(r rune) bool {
return unicode.IsSpace(r) || r == ','
})
for _, enc := range encTypes {
if enc == "gzip" || enc == "deflate" {
return enc
}
}
return ""
}
// Select method selects the correct compression encoder based on http HEADER.
func (_ *CompressionSelector) Select(r *http.Request) Encoder {
switch acceptedEnc(r) {
case "gzip":
return &gzipEncoder{}
case "flate":
return &flateEncoder{}
}
return DefaultEncoder
}

81
Godeps/_workspace/src/github.com/gorilla/rpc/v2/doc.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package gorilla/rpc is a foundation for RPC over HTTP services, providing
access to the exported methods of an object through HTTP requests.
This package derives from the standard net/rpc package but uses a single HTTP
request per call instead of persistent connections. Other differences
compared to net/rpc:
- Multiple codecs can be registered in the same server.
- A codec is chosen based on the "Content-Type" header from the request.
- Service methods also receive http.Request as parameter.
- This package can be used on Google App Engine.
Let's setup a server and register a codec and service:
import (
"http"
"github.com/gorilla/rpc/v2"
"github.com/gorilla/rpc/v2/json"
)
func init() {
s := rpc.NewServer()
s.RegisterCodec(json.NewCodec(), "application/json")
s.RegisterService(new(HelloService), "")
http.Handle("/rpc", s)
}
This server handles requests to the "/rpc" path using a JSON codec.
A codec is tied to a content type. In the example above, the JSON codec is
registered to serve requests with "application/json" as the value for the
"Content-Type" header. If the header includes a charset definition, it is
ignored; only the media-type part is taken into account.
A service can be registered using a name. If the name is empty, like in the
example above, it will be inferred from the service type.
That's all about the server setup. Now let's define a simple service:
type HelloArgs struct {
Who string
}
type HelloReply struct {
Message string
}
type HelloService struct {}
func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error {
reply.Message = "Hello, " + args.Who + "!"
return nil
}
The example above defines a service with a method "HelloService.Say" and
the arguments and reply related to that method.
The service must be exported (begin with an upper case letter) or local
(defined in the package registering the service).
When a service is registered, the server inspects the service methods
and make available the ones that follow these rules:
- The method name is exported.
- The method has three arguments: *http.Request, *args, *reply.
- All three arguments are pointers.
- The second and third arguments are exported or local.
- The method has return type error.
All other methods are ignored.
Gorilla has packages with common RPC codecs. Check out their documentation:
JSON: http://gorilla-web.appspot.com/pkg/rpc/json
*/
package rpc

View File

@ -0,0 +1,43 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"io"
"net/http"
)
// Encoder interface contains the encoder for http response.
// Eg. gzip, flate compressions.
type Encoder interface {
Encode(w http.ResponseWriter) io.Writer
}
type encoder struct {
}
func (_ *encoder) Encode(w http.ResponseWriter) io.Writer {
return w
}
var DefaultEncoder = &encoder{}
// EncoderSelector interface provides a way to select encoder using the http
// request. Typically people can use this to check HEADER of the request and
// figure out client capabilities.
// Eg. "Accept-Encoding" tells about supported compressions.
type EncoderSelector interface {
Select(r *http.Request) Encoder
}
type encoderSelector struct {
}
func (_ *encoderSelector) Select(_ *http.Request) Encoder {
return DefaultEncoder
}
var DefaultEncoderSelector = &encoderSelector{}

View File

@ -0,0 +1,57 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012-2013 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"encoding/json"
"io"
"math/rand"
)
// ----------------------------------------------------------------------------
// Request and Response
// ----------------------------------------------------------------------------
// clientRequest represents a JSON-RPC request sent by a client.
type clientRequest struct {
// A String containing the name of the method to be invoked.
Method string `json:"method"`
// Object to pass as request parameter to the method.
Params [1]interface{} `json:"params"`
// The request id. This can be of any type. It is used to match the
// response with the request that it is replying to.
Id uint64 `json:"id"`
}
// clientResponse represents a JSON-RPC response returned to a client.
type clientResponse struct {
Result *json.RawMessage `json:"result"`
Error interface{} `json:"error"`
Id uint64 `json:"id"`
}
// EncodeClientRequest encodes parameters for a JSON-RPC client request.
func EncodeClientRequest(method string, args interface{}) ([]byte, error) {
c := &clientRequest{
Method: method,
Params: [1]interface{}{args},
Id: uint64(rand.Int63()),
}
return json.Marshal(c)
}
// DecodeClientResponse decodes the response body of a client request into
// the interface reply.
func DecodeClientResponse(r io.Reader, reply interface{}) error {
var c clientResponse
if err := json.NewDecoder(r).Decode(&c); err != nil {
return err
}
if c.Error != nil {
return &Error{Data: c.Error}
}
return json.Unmarshal(*c.Result, reply)
}

View File

@ -0,0 +1,58 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package gorilla/rpc/json provides a codec for JSON-RPC over HTTP services.
To register the codec in a RPC server:
import (
"http"
"github.com/gorilla/rpc/v2"
"github.com/gorilla/rpc/v2/json"
)
func init() {
s := rpc.NewServer()
s.RegisterCodec(json.NewCodec(), "application/json")
// [...]
http.Handle("/rpc", s)
}
A codec is tied to a content type. In the example above, the server will use
the JSON codec for requests with "application/json" as the value for the
"Content-Type" header.
This package follows the JSON-RPC 1.0 specification:
http://json-rpc.org/wiki/specification
Request format is:
method:
The name of the method to be invoked, as a string in dotted notation
as in "Service.Method".
params:
An array with a single object to pass as argument to the method.
id:
The request id, a uint. It is used to match the response with the
request that it is replying to.
Response format is:
result:
The Object that was returned by the invoked method,
or null in case there was an error invoking the method.
error:
An Error object if there was an error invoking the method,
or null if there was no error.
id:
The same id as the request it is responding to.
Check the gorilla/rpc documentation for more details:
http://gorilla-web.appspot.com/pkg/rpc
*/
package json

View File

@ -0,0 +1,117 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"github.com/gorilla/rpc/v2"
)
var (
ErrResponseError = errors.New("response error")
ErrResponseJsonError = &Error{Data: map[string]interface{}{
"stackstrace": map[string]interface{}{"0": "foo()"},
"error": "a message",
}}
)
type Service1Request struct {
A int
B int
}
type Service1Response struct {
Result int
}
type Service1 struct {
}
func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error {
res.Result = req.A * req.B
return nil
}
func (t *Service1) ResponseError(r *http.Request, req *Service1Request, res *Service1Response) error {
return ErrResponseError
}
func (t *Service1) ResponseJsonError(r *http.Request, req *Service1Request, res *Service1Response) error {
return ErrResponseJsonError
}
func execute(t *testing.T, s *rpc.Server, method string, req, res interface{}) error {
if !s.HasMethod(method) {
t.Fatal("Expected to be registered:", method)
}
buf, _ := EncodeClientRequest(method, req)
body := bytes.NewBuffer(buf)
r, _ := http.NewRequest("POST", "http://localhost:8080/", body)
r.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
s.ServeHTTP(w, r)
return DecodeClientResponse(w.Body, res)
}
func executeRaw(t *testing.T, s *rpc.Server, req json.RawMessage) (int, *bytes.Buffer) {
r, _ := http.NewRequest("POST", "http://localhost:8080/", bytes.NewBuffer(req))
r.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
s.ServeHTTP(w, r)
return w.Code, w.Body
}
func field(name string, blob json.RawMessage) (v interface{}, ok bool) {
var obj map[string]interface{}
if err := json.Unmarshal(blob, &obj); err != nil {
return nil, false
}
v, ok = obj[name]
return
}
func TestService(t *testing.T) {
s := rpc.NewServer()
s.RegisterCodec(NewCodec(), "application/json")
s.RegisterService(new(Service1), "")
var res Service1Response
if err := execute(t, s, "Service1.Multiply", &Service1Request{4, 2}, &res); err != nil {
t.Error("Expected err to be nil, but got", err)
}
if res.Result != 8 {
t.Error("Expected res.Result to be 8, but got", res.Result)
}
if err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err == nil {
t.Errorf("Expected to get %q, but got nil", ErrResponseError)
} else if err.Error() != ErrResponseError.Error() {
t.Errorf("Expected to get %q, but got %q", ErrResponseError, err)
}
if code, res := executeRaw(t, s, json.RawMessage(`{"method":"Service1.Multiply","params":null,"id":5}`)); code != 400 {
t.Error("Expected response code to be 400, but got", code)
} else if v, ok := field("result", res.Bytes()); !ok || v != nil {
t.Errorf("Expected ok to be true and v to be nil, but got %v and %v", ok, v)
}
if err := execute(t, s, "Service1.ResponseJsonError", &Service1Request{4, 2}, &res); err == nil {
t.Errorf("Expected to get %q, but got nil", ErrResponseError)
} else if jsonErr, ok := err.(*Error); !ok {
t.Error("Expected err to be of a *json.Error type")
} else if !reflect.DeepEqual(jsonErr.Data, ErrResponseJsonError.Data) {
t.Errorf("Expected jsonErr to be %q, but got %q", ErrResponseJsonError, jsonErr)
}
}

View File

@ -0,0 +1,155 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/gorilla/rpc/v2"
)
var null = json.RawMessage([]byte("null"))
// An Error is a wrapper for a JSON interface value. It can be used by either
// a service's handler func to write more complex JSON data to an error field
// of a server's response, or by a client to read it.
type Error struct {
Data interface{}
}
func (e *Error) Error() string {
return fmt.Sprintf("%v", e.Data)
}
// ----------------------------------------------------------------------------
// Request and Response
// ----------------------------------------------------------------------------
// serverRequest represents a JSON-RPC request received by the server.
type serverRequest struct {
// A String containing the name of the method to be invoked.
Method string `json:"method"`
// An Array of objects to pass as arguments to the method.
Params *json.RawMessage `json:"params"`
// The request id. This can be of any type. It is used to match the
// response with the request that it is replying to.
Id *json.RawMessage `json:"id"`
}
// serverResponse represents a JSON-RPC response returned by the server.
type serverResponse struct {
// The Object that was returned by the invoked method. This must be null
// in case there was an error invoking the method.
Result interface{} `json:"result"`
// An Error object if there was an error invoking the method. It must be
// null if there was no error.
Error interface{} `json:"error"`
// This must be the same id as the request it is responding to.
Id *json.RawMessage `json:"id"`
}
// ----------------------------------------------------------------------------
// Codec
// ----------------------------------------------------------------------------
// NewCodec returns a new JSON Codec.
func NewCodec() *Codec {
return &Codec{}
}
// Codec creates a CodecRequest to process each request.
type Codec struct {
}
// NewRequest returns a CodecRequest.
func (c *Codec) NewRequest(r *http.Request) rpc.CodecRequest {
return newCodecRequest(r)
}
// ----------------------------------------------------------------------------
// CodecRequest
// ----------------------------------------------------------------------------
// newCodecRequest returns a new CodecRequest.
func newCodecRequest(r *http.Request) rpc.CodecRequest {
// Decode the request body and check if RPC method is valid.
req := new(serverRequest)
err := json.NewDecoder(r.Body).Decode(req)
r.Body.Close()
return &CodecRequest{request: req, err: err}
}
// CodecRequest decodes and encodes a single request.
type CodecRequest struct {
request *serverRequest
err error
}
// Method returns the RPC method for the current request.
//
// The method uses a dotted notation as in "Service.Method".
func (c *CodecRequest) Method() (string, error) {
if c.err == nil {
return c.request.Method, nil
}
return "", c.err
}
// ReadRequest fills the request object for the RPC method.
func (c *CodecRequest) ReadRequest(args interface{}) error {
if c.err == nil {
if c.request.Params != nil {
// JSON params is array value. RPC params is struct.
// Unmarshal into array containing the request struct.
params := [1]interface{}{args}
c.err = json.Unmarshal(*c.request.Params, &params)
} else {
c.err = errors.New("rpc: method request ill-formed: missing params field")
}
}
return c.err
}
// WriteResponse encodes the response and writes it to the ResponseWriter.
func (c *CodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}) {
if c.request.Id != nil {
// Id is null for notifications and they don't have a response.
res := &serverResponse{
Result: reply,
Error: &null,
Id: c.request.Id,
}
c.writeServerResponse(w, 200, res)
}
}
func (c *CodecRequest) WriteError(w http.ResponseWriter, _ int, err error) {
res := &serverResponse{
Result: &null,
Id: c.request.Id,
}
if jsonErr, ok := err.(*Error); ok {
res.Error = jsonErr.Data
} else {
res.Error = err.Error()
}
c.writeServerResponse(w, 400, res)
}
func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, status int, res *serverResponse) {
b, err := json.Marshal(res)
if err == nil {
w.WriteHeader(status)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(b)
} else {
// Not sure in which case will this happen. But seems harmless.
rpc.WriteError(w, 400, err.Error())
}
}

View File

@ -0,0 +1,75 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json2
import (
"encoding/json"
"io"
"math/rand"
)
// ----------------------------------------------------------------------------
// Request and Response
// ----------------------------------------------------------------------------
// clientRequest represents a JSON-RPC request sent by a client.
type clientRequest struct {
// JSON-RPC protocol.
Version string `json:"jsonrpc"`
// A String containing the name of the method to be invoked.
Method string `json:"method"`
// Object to pass as request parameter to the method.
Params interface{} `json:"params"`
// The request id. This can be of any type. It is used to match the
// response with the request that it is replying to.
Id uint64 `json:"id"`
}
// clientResponse represents a JSON-RPC response returned to a client.
type clientResponse struct {
Version string `json:"jsonrpc"`
Result *json.RawMessage `json:"result"`
Error *json.RawMessage `json:"error"`
}
// EncodeClientRequest encodes parameters for a JSON-RPC client request.
func EncodeClientRequest(method string, args interface{}) ([]byte, error) {
c := &clientRequest{
Version: "2.0",
Method: method,
Params: args,
Id: uint64(rand.Int63()),
}
return json.Marshal(c)
}
// DecodeClientResponse decodes the response body of a client request into
// the interface reply.
func DecodeClientResponse(r io.Reader, reply interface{}) error {
var c clientResponse
if err := json.NewDecoder(r).Decode(&c); err != nil {
return err
}
if c.Error != nil {
jsonErr := &Error{}
if err := json.Unmarshal(*c.Error, jsonErr); err != nil {
return &Error{
Code: E_SERVER,
Message: string(*c.Error),
}
}
return jsonErr
}
if c.Result == nil {
return ErrNullResult
}
return json.Unmarshal(*c.Result, reply)
}

View File

@ -0,0 +1,39 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json2
import (
"errors"
)
type ErrorCode int
const (
E_PARSE ErrorCode = -32700
E_INVALID_REQ ErrorCode = -32600
E_NO_METHOD ErrorCode = -32601
E_BAD_PARAMS ErrorCode = -32602
E_INTERNAL ErrorCode = -32603
E_SERVER ErrorCode = -32000
)
var ErrNullResult = errors.New("result is null")
type Error struct {
// A Number that indicates the error type that occurred.
Code ErrorCode `json:"code"` /* required */
// A String providing a short description of the error.
// The message SHOULD be limited to a concise single sentence.
Message string `json:"message"` /* required */
// A Primitive or Structured value that contains additional information about the error.
Data interface{} `json:"data"` /* optional */
}
func (e *Error) Error() string {
return e.Message
}

View File

@ -0,0 +1,161 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json2
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"testing"
"github.com/gorilla/rpc/v2"
)
// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
Code int // the HTTP response code from WriteHeader
HeaderMap http.Header // the HTTP response headers
Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
Flushed bool
}
// NewRecorder returns an initialized ResponseRecorder.
func NewRecorder() *ResponseRecorder {
return &ResponseRecorder{
HeaderMap: make(http.Header),
Body: new(bytes.Buffer),
}
}
// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
const DefaultRemoteAddr = "1.2.3.4"
// Header returns the response headers.
func (rw *ResponseRecorder) Header() http.Header {
return rw.HeaderMap
}
// Write always succeeds and writes to rw.Body, if not nil.
func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
if rw.Body != nil {
rw.Body.Write(buf)
}
if rw.Code == 0 {
rw.Code = http.StatusOK
}
return len(buf), nil
}
// WriteHeader sets rw.Code.
func (rw *ResponseRecorder) WriteHeader(code int) {
rw.Code = code
}
// Flush sets rw.Flushed to true.
func (rw *ResponseRecorder) Flush() {
rw.Flushed = true
}
// ----------------------------------------------------------------------------
var ErrResponseError = errors.New("response error")
type Service1Request struct {
A int
B int
}
type Service1BadRequest struct {
V string `json:"jsonrpc"`
M string `json:"method"`
ID uint64 `json:"id"`
}
type Service1Response struct {
Result int
}
type Service1 struct {
}
func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error {
res.Result = req.A * req.B
return nil
}
func (t *Service1) ResponseError(r *http.Request, req *Service1Request, res *Service1Response) error {
return ErrResponseError
}
func execute(t *testing.T, s *rpc.Server, method string, req, res interface{}) error {
if !s.HasMethod(method) {
t.Fatal("Expected to be registered:", method)
}
buf, _ := EncodeClientRequest(method, req)
body := bytes.NewBuffer(buf)
r, _ := http.NewRequest("POST", "http://localhost:8080/", body)
r.Header.Set("Content-Type", "application/json")
w := NewRecorder()
s.ServeHTTP(w, r)
return DecodeClientResponse(w.Body, res)
}
func executeRaw(t *testing.T, s *rpc.Server, req interface{}, res interface{}) error {
j, _ := json.Marshal(req)
r, _ := http.NewRequest("POST", "http://localhost:8080/", bytes.NewBuffer(j))
r.Header.Set("Content-Type", "application/json")
w := NewRecorder()
s.ServeHTTP(w, r)
return DecodeClientResponse(w.Body, res)
}
func TestService(t *testing.T) {
s := rpc.NewServer()
s.RegisterCodec(NewCodec(), "application/json")
s.RegisterService(new(Service1), "")
var res Service1Response
if err := execute(t, s, "Service1.Multiply", &Service1Request{4, 2}, &res); err != nil {
t.Error("Expected err to be nil, but got:", err)
}
if res.Result != 8 {
t.Errorf("Wrong response: %v.", res.Result)
}
if err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err == nil {
t.Errorf("Expected to get %q, but got nil", ErrResponseError)
} else if err.Error() != ErrResponseError.Error() {
t.Errorf("Expected to get %q, but got %q", ErrResponseError, err)
}
if err := executeRaw(t, s, &Service1BadRequest{"2.0", "Service1.Multiply", 1}, &res); err == nil {
t.Errorf("Expected error but error in nil")
}
}
func TestDecodeNullResult(t *testing.T) {
data := `{"jsonrpc": "2.0", "id": 12345, "result": null}`
reader := bytes.NewReader([]byte(data))
var result interface{}
err := DecodeClientResponse(reader, &result)
if err != ErrNullResult {
t.Error("Expected err no be ErrNullResult, but got:", err)
}
if result != nil {
t.Error("Expected result to be nil, but got:", result)
}
}

View File

@ -0,0 +1,190 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json2
import (
"encoding/json"
"net/http"
"github.com/gorilla/rpc/v2"
)
var null = json.RawMessage([]byte("null"))
var Version = "2.0"
// ----------------------------------------------------------------------------
// Request and Response
// ----------------------------------------------------------------------------
// serverRequest represents a JSON-RPC request received by the server.
type serverRequest struct {
// JSON-RPC protocol.
Version string `json:"jsonrpc"`
// A String containing the name of the method to be invoked.
Method string `json:"method"`
// A Structured value to pass as arguments to the method.
Params *json.RawMessage `json:"params"`
// The request id. MUST be a string, number or null.
// Our implementation will not do type checking for id.
// It will be copied as it is.
Id *json.RawMessage `json:"id"`
}
// serverResponse represents a JSON-RPC response returned by the server.
type serverResponse struct {
// JSON-RPC protocol.
Version string `json:"jsonrpc"`
// The Object that was returned by the invoked method. This must be null
// in case there was an error invoking the method.
// As per spec the member will be omitted if there was an error.
Result interface{} `json:"result,omitempty"`
// An Error object if there was an error invoking the method. It must be
// null if there was no error.
// As per spec the member will be omitted if there was no error.
Error *Error `json:"error,omitempty"`
// This must be the same id as the request it is responding to.
Id *json.RawMessage `json:"id"`
}
// ----------------------------------------------------------------------------
// Codec
// ----------------------------------------------------------------------------
// NewcustomCodec returns a new JSON Codec based on passed encoder selector.
func NewCustomCodec(encSel rpc.EncoderSelector) *Codec {
return &Codec{encSel: encSel}
}
// NewCodec returns a new JSON Codec.
func NewCodec() *Codec {
return NewCustomCodec(rpc.DefaultEncoderSelector)
}
// Codec creates a CodecRequest to process each request.
type Codec struct {
encSel rpc.EncoderSelector
}
// NewRequest returns a CodecRequest.
func (c *Codec) NewRequest(r *http.Request) rpc.CodecRequest {
return newCodecRequest(r, c.encSel.Select(r))
}
// ----------------------------------------------------------------------------
// CodecRequest
// ----------------------------------------------------------------------------
// newCodecRequest returns a new CodecRequest.
func newCodecRequest(r *http.Request, encoder rpc.Encoder) rpc.CodecRequest {
// Decode the request body and check if RPC method is valid.
req := new(serverRequest)
err := json.NewDecoder(r.Body).Decode(req)
if err != nil {
err = &Error{
Code: E_PARSE,
Message: err.Error(),
Data: req,
}
}
if req.Version != Version {
err = &Error{
Code: E_INVALID_REQ,
Message: "jsonrpc must be " + Version,
Data: req,
}
}
r.Body.Close()
return &CodecRequest{request: req, err: err, encoder: encoder}
}
// CodecRequest decodes and encodes a single request.
type CodecRequest struct {
request *serverRequest
err error
encoder rpc.Encoder
}
// Method returns the RPC method for the current request.
//
// The method uses a dotted notation as in "Service.Method".
func (c *CodecRequest) Method() (string, error) {
if c.err == nil {
return c.request.Method, nil
}
return "", c.err
}
// ReadRe<quest fills the request object for the RPC method.
func (c *CodecRequest) ReadRequest(args interface{}) error {
if c.err == nil {
if c.request.Params != nil {
// JSON params structured object. Unmarshal to the args object.
err := json.Unmarshal(*c.request.Params, args)
if err != nil {
c.err = &Error{
Code: E_INVALID_REQ,
Message: err.Error(),
Data: c.request.Params,
}
}
} else {
c.err = &Error{
Code: E_INVALID_REQ,
Message: "rpc: method request ill-formed: missing params field",
}
}
}
return c.err
}
// WriteResponse encodes the response and writes it to the ResponseWriter.
func (c *CodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}) {
res := &serverResponse{
Version: Version,
Result: reply,
Id: c.request.Id,
}
c.writeServerResponse(w, res)
}
func (c *CodecRequest) WriteError(w http.ResponseWriter, status int, err error) {
jsonErr, ok := err.(*Error)
if !ok {
jsonErr = &Error{
Code: E_SERVER,
Message: err.Error(),
}
}
res := &serverResponse{
Version: Version,
Error: jsonErr,
Id: c.request.Id,
}
c.writeServerResponse(w, res)
}
func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, res *serverResponse) {
// Id is null for notifications and they don't have a response.
if c.request.Id != nil {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
encoder := json.NewEncoder(c.encoder.Encode(w))
err := encoder.Encode(res)
// Not sure in which case will this happen. But seems harmless.
if err != nil {
rpc.WriteError(w, 400, err.Error())
}
}
}
type EmptyResponse struct {
}

View File

@ -0,0 +1,10 @@
Counter (TestApp)
=================
1) Build
$ go build counter.go
$ ./counter
2) Navigate to localhost:65534 on the browser to access the app.

View File

@ -0,0 +1,50 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2013 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"flag"
"log"
"net/http"
"github.com/gorilla/rpc/v2"
"github.com/gorilla/rpc/v2/json2"
)
type Counter struct {
Count int
}
type IncrReq struct {
Delta int
}
// Notification.
func (c *Counter) Incr(r *http.Request, req *IncrReq, res *json2.EmptyResponse) error {
log.Printf("<- Incr %+v", *req)
c.Count += req.Delta
return nil
}
type GetReq struct {
}
func (c *Counter) Get(r *http.Request, req *GetReq, res *Counter) error {
log.Printf("<- Get %+v", *req)
*res = *c
log.Printf("-> %v", *res)
return nil
}
func main() {
address := flag.String("address", ":65534", "")
s := rpc.NewServer()
s.RegisterCodec(json2.NewCustomCodec(&rpc.CompressionSelector{}), "application/json")
s.RegisterService(new(Counter), "")
http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("./"))))
http.Handle("/jsonrpc/", s)
log.Fatal(http.ListenAndServe(*address, nil))
}

View File

@ -0,0 +1,64 @@
function log(m, label) {
msg = $("<li><span>" + m + "</span></li>");
msg.find("span").addClass(label);
out = $("#output");
out.append(msg);
out.animate({"scrollTop": out[0].scrollHeight}, "fast");
}
$(document).ready(function() {
$("#incr").click(function() {
req = {
method : "Counter.Incr",
params : {delta: 1},
};
log("<- " + JSON.stringify(req), "secondary label");
$.jsonrpc(req);
});
$("#get").click(function() {
req = {
method : "Counter.Get",
params : {},
};
log("<- " + JSON.stringify(req), "label");
$.jsonrpc(req, {
success : function(result) {
$("#get").addClass("success");
setTimeout(function() {
$("#get").removeClass("success");
}, 2000);
log("-> " + JSON.stringify(result), "success label");
},
error : function(error) {
$("#get").addClass("alert");
setTimeout(function() {
$("#get").removeClass("alert");
}, 2000);
log("-> " + JSON.stringify(error), "alert label");
},
});
});
$("#nan").click(function() {
req = {
method : "Counter.Nan",
params : {},
};
log("<- " + JSON.stringify(req), "label");
$.jsonrpc(req, {
success : function(result) {
$("#nan").addClass("success");
setTimeout(function() {
$("#nan").removeClass("success");
}, 2000);
log("-> " + JSON.stringify(result), "success label");
},
error : function(error) {
$("#nan").addClass("alert");
setTimeout(function() {
$("#nan").removeClass("alert");
}, 2000);
log("-> " + JSON.stringify(error), "alert label");
},
});
});
});

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.9.1.js"></script>
<link href="//cdn.jsdelivr.net/foundation/4.1.2/css/foundation.min.css" rel='stylesheet' type='text/css'>
<link href="//fonts.googleapis.com/css?family=Inconsolata" rel='stylesheet' type='text/css'>
<script src="jquery.jsonrpc.js"></script>
<script src="counter.js"></script>
<title>Counter</title>
<style>
body {
font-family: 'Inconsolata', sans-serif;
}
</style>
</head>
<body style="padding:20px">
<div class="row">
<div class="large-1 columns"><a id="incr" href="#" class="small secondary button">Incr</a></div>
<div class="large-1 columns"><a id="get" href="#" class="small button">Get&nbsp</a></div>
<div class="large-1 columns"><a id="nan" href="#" class="small button">Nan&nbsp</a></div>
<div class="large-9 columns"></div>
</div>
<div class="row">
<div class="large-12 columns panel">
<ul id="output" style="height:600px;overflow:scroll;list-style-type:none;">
</ul>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,158 @@
/*
* jQuery JSON-RPC Plugin
*
* @version: 0.3(2012-05-17)
* @author hagino3000 <http://twitter.com/hagino3000> (Takashi Nishibayashi)
* @author alanjds <http://twitter.com/alanjds> (Alan Justino da Silva)
*
* A JSON-RPC 2.0 implementation for jQuery.
* JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol.
* Read more in the <http://groups.google.com/group/json-rpc/web/json-rpc-2-0>
*
* Requires json2.js<http://www.json.org/json2.js> if browser has not window.JSON.
*
* Usage:
* $.jsonrpc(data [, callbacks [, debug]]);
*
* where data = {url: '/rpc/', method:'simplefunc', params:['posi', 'tional']}
* or data = {url: '/rpc/', method:'complexfunc', params:{nam:'ed', par:'ams'}}
* and callbacks = {success: successFunc, error: errorFunc}
*
* Setting no callback produces a JSON-RPC Notification.
* 'data' accepts 'timeout' keyword too, who sets the $.ajax request timeout.
* Setting 'debug' to true prints responses to Firebug's console.info
*
* Examples:
* // A RPC call with named parameters
* $.jsonrpc({
* url : '/rpc',
* method : 'createUser',
* params : {name : 'John Smith', userId : '1000'}
* }, {
* success : function(result) {
* //doSomething
* },
* error : function(error) {
* //doSomething
* }
* });
*
* // Once set defaultUrl, url option is no need
* $.jsonrpc.defaultUrl = '/rpc';
*
* // A Notification
* $.jsonrpc({
* method : 'notify',
* params : {action : 'logout', userId : '1000'}
* });
*
* // A Notification using console to debug and with timeout set
* $.jsonrpc({
* method : 'notify',
* params : {action : 'logout', userId : '1000'},
* debug : true,
* timeout : 500,
* });
*
* // Set DataFilter. It is useful for buggy API that returns sometimes not json but html (when 500, 403..).
* $.jsonrpc({
* method : 'getUser',
* dataFilter : function(data, type) {
* try {
* return JSON.parse(data);
* } catch(e) {
* return {error : {message : 'Cannot parse response', data : data}};
* }
* }, function(result){ doSomething... }
* }, {
* success : handleSuccess
* error : handleFailure
* });
*
* This document is licensed as free software under the terms of the
* MIT License: http://www.opensource.org/licenses/mit-license.php
*/
(function($) {
var rpcid = 1,
emptyFn = function() {};
$.jsonrpc = $.jsonrpc || function(data, callbacks, debug) {
debug = debug || false;
var postdata = {
jsonrpc: '2.0',
method: data.method || '',
params: data.params || {}
};
if (callbacks) {
postdata.id = data.id || rpcid++;
} else {
callbacks = emptyFn;
}
if (typeof(callbacks) === 'function') {
callbacks = {
success: callbacks,
error: callbacks
};
}
var dataFilter = data.dataFilter;
var ajaxopts = {
url: data.url || $.jsonrpc.defaultUrl,
contentType: 'application/json',
dataType: 'text',
dataFilter: function(data, type) {
if (dataFilter) {
return dataFilter(data);
} else {
if (data != "") return JSON.parse(data);
}
},
type: 'POST',
processData: false,
data: JSON.stringify(postdata),
success: function(resp) {
if (resp && !resp.error) {
return callbacks.success && callbacks.success(resp.result);
} else if (resp && resp.error) {
return callbacks.error && callbacks.error(resp.error);
} else {
return callbacks.error && callbacks.error(resp);
}
},
error: function(xhr, status, error) {
if (error === 'timeout') {
callbacks.error({
status: status,
code: 0,
message: 'Request Timeout'
});
return;
}
// If response code is 404, 400, 500, server returns error object
try {
var res = JSON.parse(xhr.responseText);
callbacks.error(res.error);
} catch (e) {
callbacks.error({
status: status,
code: 0,
message: error
});
}
}
};
if (data.timeout) {
ajaxopts['timeout'] = data.timeout;
}
$.ajax(ajaxopts);
return $;
}
$.jsonrpc.defaultUrl = $.jsonrpc.defaultUrl || '/jsonrpc/';
})(jQuery);

164
Godeps/_workspace/src/github.com/gorilla/rpc/v2/map.go generated vendored Normal file
View File

@ -0,0 +1,164 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"fmt"
"net/http"
"reflect"
"strings"
"sync"
"unicode"
"unicode/utf8"
)
var (
// Precompute the reflect.Type of error and http.Request
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
typeOfRequest = reflect.TypeOf((*http.Request)(nil)).Elem()
)
// ----------------------------------------------------------------------------
// service
// ----------------------------------------------------------------------------
type service struct {
name string // name of service
rcvr reflect.Value // receiver of methods for the service
rcvrType reflect.Type // type of the receiver
methods map[string]*serviceMethod // registered methods
}
type serviceMethod struct {
method reflect.Method // receiver method
argsType reflect.Type // type of the request argument
replyType reflect.Type // type of the response argument
}
// ----------------------------------------------------------------------------
// serviceMap
// ----------------------------------------------------------------------------
// serviceMap is a registry for services.
type serviceMap struct {
mutex sync.Mutex
services map[string]*service
}
// register adds a new service using reflection to extract its methods.
func (m *serviceMap) register(rcvr interface{}, name string) error {
// Setup service.
s := &service{
name: name,
rcvr: reflect.ValueOf(rcvr),
rcvrType: reflect.TypeOf(rcvr),
methods: make(map[string]*serviceMethod),
}
if name == "" {
s.name = reflect.Indirect(s.rcvr).Type().Name()
if !isExported(s.name) {
return fmt.Errorf("rpc: type %q is not exported", s.name)
}
}
if s.name == "" {
return fmt.Errorf("rpc: no service name for type %q",
s.rcvrType.String())
}
// Setup methods.
for i := 0; i < s.rcvrType.NumMethod(); i++ {
method := s.rcvrType.Method(i)
mtype := method.Type
// Method must be exported.
if method.PkgPath != "" {
continue
}
// Method needs four ins: receiver, *http.Request, *args, *reply.
if mtype.NumIn() != 4 {
continue
}
// First argument must be a pointer and must be http.Request.
reqType := mtype.In(1)
if reqType.Kind() != reflect.Ptr || reqType.Elem() != typeOfRequest {
continue
}
// Second argument must be a pointer and must be exported.
args := mtype.In(2)
if args.Kind() != reflect.Ptr || !isExportedOrBuiltin(args) {
continue
}
// Third argument must be a pointer and must be exported.
reply := mtype.In(3)
if reply.Kind() != reflect.Ptr || !isExportedOrBuiltin(reply) {
continue
}
// Method needs one out: error.
if mtype.NumOut() != 1 {
continue
}
if returnType := mtype.Out(0); returnType != typeOfError {
continue
}
s.methods[method.Name] = &serviceMethod{
method: method,
argsType: args.Elem(),
replyType: reply.Elem(),
}
}
if len(s.methods) == 0 {
return fmt.Errorf("rpc: %q has no exported methods of suitable type",
s.name)
}
// Add to the map.
m.mutex.Lock()
defer m.mutex.Unlock()
if m.services == nil {
m.services = make(map[string]*service)
} else if _, ok := m.services[s.name]; ok {
return fmt.Errorf("rpc: service already defined: %q", s.name)
}
m.services[s.name] = s
return nil
}
// get returns a registered service given a method name.
//
// The method name uses a dotted notation as in "Service.Method".
func (m *serviceMap) get(method string) (*service, *serviceMethod, error) {
parts := strings.Split(method, ".")
if len(parts) != 2 {
err := fmt.Errorf("rpc: service/method request ill-formed: %q", method)
return nil, nil, err
}
m.mutex.Lock()
service := m.services[parts[0]]
m.mutex.Unlock()
if service == nil {
err := fmt.Errorf("rpc: can't find service %q", method)
return nil, nil, err
}
serviceMethod := service.methods[parts[1]]
if serviceMethod == nil {
err := fmt.Errorf("rpc: can't find method %q", method)
return nil, nil, err
}
return service, serviceMethod, nil
}
// isExported returns true of a string is an exported (upper case) name.
func isExported(name string) bool {
rune, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(rune)
}
// isExportedOrBuiltin returns true if a type is exported or a builtin.
func isExportedOrBuiltin(t reflect.Type) bool {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// PkgPath will be non-empty even for an exported type,
// so we need to check the type name as well.
return isExported(t.Name()) || t.PkgPath() == ""
}

View File

@ -0,0 +1,48 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package gorilla/rpc/protorpc provides a codec for ProtoRPC over HTTP services.
To register the codec in a RPC server:
import (
"http"
"github.com/gorilla/rpc/v2"
"github.com/gorilla/rpc/v2/protorpc"
)
func init() {
s := rpc.NewServer()
s.RegisterCodec(protorpc.NewCodec(), "application/json")
// [...]
http.Handle("/rpc", s)
}
A codec is tied to a content type. In the example above, the server
will use the ProtoRPC codec for requests with "application/json" as
the value for the "Content-Type" header.
This package implement ProtoRPC, based on the JSON-RPC transport, it
differs in that it uses HTTP as its envelope.
Example:
POST /Service.Method
Request:
{
"requestField1": "value1",
"requestField2": "value2",
}
Response:
{
"responseField1": "value1",
"responseField2": "value2",
}
Check the gorilla/rpc documentation for more details:
http://gorilla-web.appspot.com/pkg/rpc
*/
package protorpc

View File

@ -0,0 +1,87 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protorpc
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/rpc/v2"
)
var ErrResponseError = errors.New("response error")
type Service1Request struct {
A int
B int
}
type Service1BadRequest struct {
}
type Service1Response struct {
Result int
ErrorMessage string `json:"error_message"`
}
type Service1 struct {
}
func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error {
res.Result = req.A * req.B
return nil
}
func (t *Service1) ResponseError(r *http.Request, req *Service1Request, res *Service1Response) error {
return ErrResponseError
}
func execute(t *testing.T, s *rpc.Server, method string, req, res interface{}) (int, error) {
if !s.HasMethod(method) {
t.Fatal("Expected to be registered:", method)
}
buf, _ := json.Marshal(req)
body := bytes.NewBuffer(buf)
r, _ := http.NewRequest("POST", "http://localhost:8080/"+method, body)
r.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
s.ServeHTTP(w, r)
err := json.NewDecoder(w.Body).Decode(res)
return w.Code, err
}
func TestService(t *testing.T) {
s := rpc.NewServer()
s.RegisterCodec(NewCodec(), "application/json")
s.RegisterService(new(Service1), "")
var res Service1Response
if _, err := execute(t, s, "Service1.Multiply", &Service1Request{4, 2}, &res); err != nil {
t.Error("Expected err to be nil, but got:", err)
}
if res.Result != 8 {
t.Error("Expected res.Result to be 8, but got:", res.Result)
}
if res.ErrorMessage != "" {
t.Error("Expected error_message to be empty, but got:", res.ErrorMessage)
}
if code, err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err != nil || code != 400 {
t.Errorf("Expected code to be 400 and error to be nil, but got %v (%v)", code, err)
}
if res.ErrorMessage == "" {
t.Errorf("Expected error_message to be %q, but got %q", ErrResponseError, res.ErrorMessage)
}
if code, _ := execute(t, s, "Service1.Multiply", nil, &res); code != 400 {
t.Error("Expected http response code 400, but got", code)
}
}

View File

@ -0,0 +1,147 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protorpc
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"github.com/gorilla/rpc/v2"
)
var null = json.RawMessage([]byte("null"))
// ----------------------------------------------------------------------------
// Request and Response
// ----------------------------------------------------------------------------
// serverRequest represents a ProtoRPC request received by the server.
type serverRequest struct {
// A String containing the name of the method to be invoked.
Method string `json:"method"`
// An Array of objects to pass as arguments to the method.
Params *json.RawMessage `json:"params"`
// The request id. This can be of any type. It is used to match the
// response with the request that it is replying to.
Id *json.RawMessage `json:"id"`
}
// serverResponse represents a ProtoRPC response returned by the server.
type serverResponse struct {
// The Object that was returned by the invoked method. This must be null
// in case there was an error invoking the method.
Result interface{} `json:"result"`
// An Error object if there was an error invoking the method. It must be
// null if there was no error.
Error interface{} `json:"error"`
// This must be the same id as the request it is responding to.
Id *json.RawMessage `json:"id"`
}
// ----------------------------------------------------------------------------
// Codec
// ----------------------------------------------------------------------------
// NewCodec returns a new ProtoRPC Codec.
func NewCodec() *Codec {
return &Codec{}
}
// Codec creates a CodecRequest to process each request.
type Codec struct {
}
// NewRequest returns a CodecRequest.
func (c *Codec) NewRequest(r *http.Request) rpc.CodecRequest {
return newCodecRequest(r)
}
// ----------------------------------------------------------------------------
// CodecRequest
// ----------------------------------------------------------------------------
// newCodecRequest returns a new CodecRequest.
func newCodecRequest(r *http.Request) rpc.CodecRequest {
// Decode the request body and check if RPC method is valid.
req := new(serverRequest)
path := r.URL.Path
index := strings.LastIndex(path, "/")
if index < 0 {
return &CodecRequest{request: req, err: fmt.Errorf("rpc: no method: %s", path)}
}
req.Method = path[index+1:]
err := json.NewDecoder(r.Body).Decode(&req.Params)
r.Body.Close()
var errr error
if err != io.EOF {
errr = err
}
return &CodecRequest{request: req, err: errr}
}
// CodecRequest decodes and encodes a single request.
type CodecRequest struct {
request *serverRequest
err error
}
// Method returns the RPC method for the current request.
//
// The method uses a dotted notation as in "Service.Method".
func (c *CodecRequest) Method() (string, error) {
if c.err == nil {
return c.request.Method, nil
}
return "", c.err
}
// ReadRequest fills the request object for the RPC method.
func (c *CodecRequest) ReadRequest(args interface{}) error {
if c.err == nil {
if c.request.Params != nil {
c.err = json.Unmarshal(*c.request.Params, args)
} else {
c.err = errors.New("rpc: method request ill-formed: missing params field")
}
}
return c.err
}
// WriteResponse encodes the response and writes it to the ResponseWriter.
func (c *CodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}) {
res := &serverResponse{
Result: reply,
Error: &null,
Id: c.request.Id,
}
c.writeServerResponse(w, 200, res)
}
func (c *CodecRequest) WriteError(w http.ResponseWriter, status int, err error) {
res := &serverResponse{
Result: &struct {
ErrorMessage interface{} `json:"error_message"`
}{err.Error()},
Id: c.request.Id,
}
c.writeServerResponse(w, status, res)
}
func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, status int, res *serverResponse) {
b, err := json.Marshal(res.Result)
if err == nil {
w.WriteHeader(status)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(b)
} else {
// Not sure in which case will this happen. But seems harmless.
rpc.WriteError(w, 400, err.Error())
}
}

View File

@ -0,0 +1,158 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"fmt"
"net/http"
"reflect"
"strings"
)
// ----------------------------------------------------------------------------
// Codec
// ----------------------------------------------------------------------------
// Codec creates a CodecRequest to process each request.
type Codec interface {
NewRequest(*http.Request) CodecRequest
}
// CodecRequest decodes a request and encodes a response using a specific
// serialization scheme.
type CodecRequest interface {
// Reads the request and returns the RPC method name.
Method() (string, error)
// Reads the request filling the RPC method args.
ReadRequest(interface{}) error
// Writes the response using the RPC method reply.
WriteResponse(http.ResponseWriter, interface{})
// Writes an error produced by the server.
WriteError(w http.ResponseWriter, status int, err error)
}
// ----------------------------------------------------------------------------
// Server
// ----------------------------------------------------------------------------
// NewServer returns a new RPC server.
func NewServer() *Server {
return &Server{
codecs: make(map[string]Codec),
services: new(serviceMap),
}
}
// Server serves registered RPC services using registered codecs.
type Server struct {
codecs map[string]Codec
services *serviceMap
}
// RegisterCodec adds a new codec to the server.
//
// Codecs are defined to process a given serialization scheme, e.g., JSON or
// XML. A codec is chosen based on the "Content-Type" header from the request,
// excluding the charset definition.
func (s *Server) RegisterCodec(codec Codec, contentType string) {
s.codecs[strings.ToLower(contentType)] = codec
}
// RegisterService adds a new service to the server.
//
// The name parameter is optional: if empty it will be inferred from
// the receiver type name.
//
// Methods from the receiver will be extracted if these rules are satisfied:
//
// - The receiver is exported (begins with an upper case letter) or local
// (defined in the package registering the service).
// - The method name is exported.
// - The method has three arguments: *http.Request, *args, *reply.
// - All three arguments are pointers.
// - The second and third arguments are exported or local.
// - The method has return type error.
//
// All other methods are ignored.
func (s *Server) RegisterService(receiver interface{}, name string) error {
return s.services.register(receiver, name)
}
// HasMethod returns true if the given method is registered.
//
// The method uses a dotted notation as in "Service.Method".
func (s *Server) HasMethod(method string) bool {
if _, _, err := s.services.get(method); err == nil {
return true
}
return false
}
// ServeHTTP
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
WriteError(w, 405, "rpc: POST method required, received "+r.Method)
return
}
contentType := r.Header.Get("Content-Type")
idx := strings.Index(contentType, ";")
if idx != -1 {
contentType = contentType[:idx]
}
codec := s.codecs[strings.ToLower(contentType)]
if codec == nil {
WriteError(w, 415, "rpc: unrecognized Content-Type: "+contentType)
return
}
// Create a new codec request.
codecReq := codec.NewRequest(r)
// Get service method to be called.
method, errMethod := codecReq.Method()
if errMethod != nil {
codecReq.WriteError(w, 400, errMethod)
return
}
serviceSpec, methodSpec, errGet := s.services.get(method)
if errGet != nil {
codecReq.WriteError(w, 400, errGet)
return
}
// Decode the args.
args := reflect.New(methodSpec.argsType)
if errRead := codecReq.ReadRequest(args.Interface()); errRead != nil {
codecReq.WriteError(w, 400, errRead)
return
}
// Call the service method.
reply := reflect.New(methodSpec.replyType)
errValue := methodSpec.method.Func.Call([]reflect.Value{
serviceSpec.rcvr,
reflect.ValueOf(r),
args,
reply,
})
// Cast the result to error if needed.
var errResult error
errInter := errValue[0].Interface()
if errInter != nil {
errResult = errInter.(error)
}
// Prevents Internet Explorer from MIME-sniffing a response away
// from the declared content-type
w.Header().Set("x-content-type-options", "nosniff")
// Encode the response.
if errResult == nil {
codecReq.WriteResponse(w, reply.Interface())
} else {
codecReq.WriteError(w, 400, errResult)
}
}
func WriteError(w http.ResponseWriter, status int, msg string) {
w.WriteHeader(status)
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprint(w, msg)
}

View File

@ -0,0 +1,54 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rpc
import (
"net/http"
"testing"
)
type Service1Request struct {
A int
B int
}
type Service1Response struct {
Result int
}
type Service1 struct {
}
func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error {
res.Result = req.A * req.B
return nil
}
type Service2 struct {
}
func TestRegisterService(t *testing.T) {
var err error
s := NewServer()
service1 := new(Service1)
service2 := new(Service2)
// Inferred name.
err = s.RegisterService(service1, "")
if err != nil || !s.HasMethod("Service1.Multiply") {
t.Errorf("Expected to be registered: Service1.Multiply")
}
// Provided name.
err = s.RegisterService(service1, "Foo")
if err != nil || !s.HasMethod("Foo.Multiply") {
t.Errorf("Expected to be registered: Foo.Multiply")
}
// No methods.
err = s.RegisterService(service2, "")
if err == nil {
t.Errorf("Expected error on service2")
}
}

View File

@ -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

View File

@ -1,23 +0,0 @@
objx - by Mat Ryer and Tyler Bunnell
The MIT License (MIT)
Copyright (c) 2014 Stretchr, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,3 +0,0 @@
# objx
* Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)

View File

@ -1,179 +0,0 @@
package objx
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// arrayAccesRegexString is the regex used to extract the array number
// from the access path
const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
// arrayAccesRegex is the compiled arrayAccesRegexString
var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
// Get gets the value using the specified selector and
// returns it inside a new Obj object.
//
// If it cannot find the value, Get will return a nil
// value inside an instance of Obj.
//
// Get can only operate directly on map[string]interface{} and []interface.
//
// Example
//
// To access the title of the third chapter of the second book, do:
//
// o.Get("books[1].chapters[2].title")
func (m Map) Get(selector string) *Value {
rawObj := access(m, selector, nil, false, false)
return &Value{data: rawObj}
}
// Set sets the value using the specified selector and
// returns the object on which Set was called.
//
// Set can only operate directly on map[string]interface{} and []interface
//
// Example
//
// To set the title of the third chapter of the second book, do:
//
// o.Set("books[1].chapters[2].title","Time to Go")
func (m Map) Set(selector string, value interface{}) Map {
access(m, selector, value, true, false)
return m
}
// access accesses the object using the selector and performs the
// appropriate action.
func access(current, selector, value interface{}, isSet, panics bool) interface{} {
switch selector.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
if array, ok := current.([]interface{}); ok {
index := intFromInterface(selector)
if index >= len(array) {
if panics {
panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
}
return nil
}
return array[index]
}
return nil
case string:
selStr := selector.(string)
selSegs := strings.SplitN(selStr, PathSeparator, 2)
thisSel := selSegs[0]
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]
// Get the index into the array at the key
index, err = strconv.Atoi(arrayMatches[2])
if err != nil {
// This should never happen. If it does, something has gone
// seriously wrong. Panic.
panic("objx: Array index is not an integer. Must use array[int].")
}
}
}
if curMap, ok := current.(Map); ok {
current = map[string]interface{}(curMap)
}
// get the object in question
switch current.(type) {
case map[string]interface{}:
curMSI := current.(map[string]interface{})
if len(selSegs) <= 1 && isSet {
curMSI[thisSel] = value
return nil
} else {
current = curMSI[thisSel]
}
default:
current = nil
}
if current == nil && panics {
panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
}
// do we need to access the item of an array?
if index > -1 {
if array, ok := current.([]interface{}); ok {
if index < len(array) {
current = array[index]
} else {
if panics {
panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
}
current = nil
}
}
}
if len(selSegs) > 1 {
current = access(current, selSegs[1], value, isSet, panics)
}
}
return current
}
// intFromInterface converts an interface object to the largest
// representation of an unsigned integer using a type switch and
// assertions
func intFromInterface(selector interface{}) int {
var value int
switch selector.(type) {
case int:
value = selector.(int)
case int8:
value = int(selector.(int8))
case int16:
value = int(selector.(int16))
case int32:
value = int(selector.(int32))
case int64:
value = int(selector.(int64))
case uint:
value = int(selector.(uint))
case uint8:
value = int(selector.(uint8))
case uint16:
value = int(selector.(uint16))
case uint32:
value = int(selector.(uint32))
case uint64:
value = int(selector.(uint64))
default:
panic("objx: array access argument is not an integer type (this should never happen)")
}
return value
}

View File

@ -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)
}

View File

@ -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]
}
}

View File

@ -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>

View File

@ -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)
}
}

View File

@ -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

View File

@ -1,13 +0,0 @@
package objx
const (
// PathSeparator is the character used to separate the elements
// of the keypath.
//
// For example, `location.address.city`
PathSeparator string = "."
// SignatureSeparator is the character that is used to
// separate the Base64 string from the security signature.
SignatureSeparator = "_"
)

View File

@ -1,117 +0,0 @@
package objx
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/url"
)
// 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
// representation and panics if there is an error
func (m Map) MustJSON() string {
result, err := m.JSON()
if err != nil {
panic(err.Error())
}
return result
}
// 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()
if err != nil {
return "", err
}
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
encoder.Write([]byte(jsonData))
encoder.Close()
return buf.String(), nil
}
// MustBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and panics
// if there is an error
func (m Map) MustBase64() string {
result, err := m.Base64()
if err != nil {
panic(err.Error())
}
return result
}
// SignedBase64 converts the contained object to a Base64 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
// representation of the JSON string representation and signs it
// using the provided key and panics if there is an error
func (m Map) MustSignedBase64(key string) string {
result, err := m.SignedBase64(key)
if err != nil {
panic(err.Error())
}
return result
}
/*
URL Query
------------------------------------------------
*/
// 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
}
// URLQuery gets an encoded URL query representing the given
// Obj. This function requires that the wrapped object be a
// map[string]interface{}
func (m Map) URLQuery() (string, error) {
return m.URLValues().Encode(), nil
}

View File

@ -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)
}

View File

@ -1,72 +0,0 @@
// 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 ... */
//
// }
package objx

View File

@ -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,
)
}
}

View File

@ -1,222 +0,0 @@
package objx
import (
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"net/url"
"strings"
)
// MSIConvertable is an interface that defines methods for converting your
// custom types to a map[string]interface{} representation.
type MSIConvertable interface {
// MSI gets a map[string]interface{} (msi) representing the
// object.
MSI() map[string]interface{}
}
// Map provides extended functionality for working with
// untyped data, in particular map[string]interface (msi).
type Map map[string]interface{}
// Value returns the internal value instance
func (m Map) Value() *Value {
return &Value{data: m}
}
// Nil represents a nil Map.
var Nil Map = 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
// MSI() method on the MSIConvertable interface to create one.
func New(data interface{}) Map {
if _, ok := data.(map[string]interface{}); !ok {
if converter, ok := data.(MSIConvertable); ok {
data = converter.MSI()
} else {
return nil
}
}
return Map(data.(map[string]interface{}))
}
// MSI creates a map[string]interface{} and puts it inside a new Map.
//
// The arguments follow a key, value pattern.
//
// Panics
//
// Panics if any key arugment is non-string or if there are an odd number of arguments.
//
// Example
//
// To easily create Maps:
//
// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
//
// // 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]
// make sure the key is a string
keyString, keyStringOK := key.(string)
if !keyStringOK {
panic("objx: MSI must follow 'string, interface{}' pattern. " + keyString + " is not a valid key.")
}
newMap[keyString] = value
}
return New(newMap)
}
// ****** Conversion Constructors
// MustFromJSON creates a new Map containing the data specified in the
// jsonString.
//
// 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
}
// FromJSON creates a new Map containing the data specified in the
// jsonString.
//
// 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
// in the Base64 string.
//
// 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))
}
// MustFromBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an 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
}
// FromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by SignedBase64
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.")
}
sig := HashWithKey(parts[0], key)
if parts[1] != sig {
return nil, errors.New("objx: Signature for base64 data does not match.")
}
return FromBase64(parts[0])
}
// MustFromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an 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
}
// FromURLQuery generates a new Obj by parsing the specified
// query.
//
// 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
}
m := make(map[string]interface{})
for k, vals := range vals {
m[k] = vals[0]
}
return New(m), nil
}
// MustFromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
//
// 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
}

View File

@ -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"},
}

View File

@ -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())
}
}

View File

@ -1,81 +0,0 @@
package objx
// Exclude returns a new Map with the keys in the specified []string
// excluded.
func (d Map) Exclude(exclude []string) Map {
excluded := make(Map)
for k, v := range d {
var shouldInclude bool = true
for _, toExclude := range exclude {
if k == toExclude {
shouldInclude = false
break
}
}
if shouldInclude {
excluded[k] = v
}
}
return excluded
}
// Copy creates a shallow copy of the Obj.
func (m Map) Copy() Map {
copied := make(map[string]interface{})
for k, v := range m {
copied[k] = v
}
return New(copied)
}
// Merge blends the specified map with a copy of this map and returns the result.
//
// Keys that appear in both will be selected from the specified map.
// This method requires that the wrapped object be a map[string]interface{}
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.
//
// 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
// to change the keys and values as it goes. This method requires that
// the wrapped object be a map[string]interface{}
func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
newMap := make(map[string]interface{})
for k, v := range m {
modifiedKey, modifiedVal := transformer(k, v)
newMap[modifiedKey] = modifiedVal
}
return New(newMap)
}
// TransformKeys builds a new map using the specified key mapping.
//
// Unspecified keys will be unaltered.
// 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
})
}

View File

@ -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())
}

View File

@ -1,14 +0,0 @@
package objx
import (
"crypto/sha1"
"encoding/hex"
)
// HashWithKey hashes the specified string using the security
// key.
func HashWithKey(data, key string) string {
hash := sha1.New()
hash.Write([]byte(data + ":" + key))
return hex.EncodeToString(hash.Sum(nil))
}

View File

@ -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"))
}

View File

@ -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())
}

View File

@ -1,17 +0,0 @@
package objx
// Has gets whether there is something at the specified selector
// or not.
//
// If m is nil, Has will always return false.
func (m Map) Has(selector string) bool {
if m == nil {
return false
}
return !m.Get(selector).IsNil()
}
// IsNil gets whether the data is nil or not.
func (v *Value) IsNil() bool {
return v == nil || v.data == nil
}

View File

@ -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

View File

@ -1,13 +0,0 @@
package objx
// Value provides methods for extracting interface{} data in various
// types.
type Value struct {
// data contains the raw data being managed by this Value
data interface{}
}
// Data returns the raw data contained by this Value
func (v *Value) Data() interface{} {
return v.data
}

View File

@ -1 +0,0 @@
package objx

View File

@ -1,805 +0,0 @@
package assert
import (
"bufio"
"bytes"
"fmt"
"reflect"
"regexp"
"runtime"
"strings"
"time"
)
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Errorf(format string, args ...interface{})
}
// Comparison a custom function that returns true on success and false on failure
type Comparison func() (success bool)
/*
Helper functions
*/
// ObjectsAreEqual determines if two objects are considered equal.
//
// This function does no assertion of any kind.
func ObjectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
if reflect.DeepEqual(expected, actual) {
return true
}
// Last ditch effort
if fmt.Sprintf("%#v", expected) == fmt.Sprintf("%#v", actual) {
return true
}
return false
}
func ObjectsAreEqualValues(expected, actual interface{}) bool {
if ObjectsAreEqual(expected, actual) {
return true
}
actualType := reflect.TypeOf(actual)
expectedValue := reflect.ValueOf(expected)
if expectedValue.Type().ConvertibleTo(actualType) {
// Attempt comparison after type conversion
if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
return true
}
}
return false
}
/* CallerInfo is necessary because the assert functions use the testing object
internally, causing it to print the file:line of the assert method, rather than where
the problem actually occured in calling code.*/
// CallerInfo returns a string containing the file and line number of the assert call
// that failed.
func CallerInfo() string {
file := ""
line := 0
ok := false
for i := 0; ; i++ {
_, file, line, ok = runtime.Caller(i)
if !ok {
return ""
}
parts := strings.Split(file, "/")
dir := parts[len(parts)-2]
file = parts[len(parts)-1]
if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
break
}
}
return fmt.Sprintf("%s:%d", file, line)
}
// getWhitespaceString returns a string that is long enough to overwrite the default
// output from the go testing framework.
func getWhitespaceString() string {
_, file, line, ok := runtime.Caller(1)
if !ok {
return ""
}
parts := strings.Split(file, "/")
file = parts[len(parts)-1]
return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line)))
}
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
if len(msgAndArgs) == 0 || msgAndArgs == nil {
return ""
}
if len(msgAndArgs) == 1 {
return msgAndArgs[0].(string)
}
if len(msgAndArgs) > 1 {
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
}
return ""
}
// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's
// test printing (see inner comment for specifics)
func indentMessageLines(message string, tabs int) string {
outBuf := new(bytes.Buffer)
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
if i != 0 {
outBuf.WriteRune('\n')
}
for ii := 0; ii < tabs; ii++ {
outBuf.WriteRune('\t')
// Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter
// by 1 prematurely.
if ii == 0 && i > 0 {
ii++
}
}
outBuf.WriteString(scanner.Text())
}
return outBuf.String()
}
// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
message := messageFromMsgAndArgs(msgAndArgs...)
if len(message) > 0 {
t.Errorf("\r%s\r\tLocation:\t%s\n"+
"\r\tError:%s\n"+
"\r\tMessages:\t%s\n\r",
getWhitespaceString(),
CallerInfo(),
indentMessageLines(failureMessage, 2),
message)
} else {
t.Errorf("\r%s\r\tLocation:\t%s\n"+
"\r\tError:%s\n\r",
getWhitespaceString(),
CallerInfo(),
indentMessageLines(failureMessage, 2))
}
return false
}
// Implements asserts that an object is implemented by the specified interface.
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
interfaceType := reflect.TypeOf(interfaceObject).Elem()
if !reflect.TypeOf(object).Implements(interfaceType) {
return Fail(t, fmt.Sprintf("Object must implement %v", interfaceType), msgAndArgs...)
}
return true
}
// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
}
return true
}
// Equal asserts that two objects are equal.
//
// assert.Equal(t, 123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if !ObjectsAreEqual(expected, actual) {
return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
" != %#v (actual)", expected, actual), msgAndArgs...)
}
return true
}
// EqualValues asserts that two objects are equal or convertable to the same types
// and equal.
//
// assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if !ObjectsAreEqualValues(expected, actual) {
return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
" != %#v (actual)", expected, actual), msgAndArgs...)
}
return true
}
// Exactly asserts that two objects are equal is value and type.
//
// assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
aType := reflect.TypeOf(expected)
bType := reflect.TypeOf(actual)
if aType != bType {
return Fail(t, "Types expected to match exactly", "%v != %v", aType, bType)
}
return Equal(t, expected, actual, msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
//
// assert.NotNil(t, err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
success := true
if object == nil {
success = false
} else {
value := reflect.ValueOf(object)
kind := value.Kind()
if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
success = false
}
}
if !success {
Fail(t, "Expected not to be nil.", msgAndArgs...)
}
return success
}
// isNil checks if a specified object is nil or not, without Failing.
func isNil(object interface{}) bool {
if object == nil {
return true
}
value := reflect.ValueOf(object)
kind := value.Kind()
if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
return true
}
return false
}
// Nil asserts that the specified object is nil.
//
// assert.Nil(t, err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if isNil(object) {
return true
}
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
}
var zeros = []interface{}{
int(0),
int8(0),
int16(0),
int32(0),
int64(0),
uint(0),
uint8(0),
uint16(0),
uint32(0),
uint64(0),
float32(0),
float64(0),
}
// isEmpty gets whether the specified object is considered empty or not.
func isEmpty(object interface{}) bool {
if object == nil {
return true
} else if object == "" {
return true
} else if object == false {
return true
}
for _, v := range zeros {
if object == v {
return true
}
}
objValue := reflect.ValueOf(object)
switch objValue.Kind() {
case reflect.Map:
fallthrough
case reflect.Slice, reflect.Chan:
{
return (objValue.Len() == 0)
}
case reflect.Ptr:
{
switch object.(type) {
case *time.Time:
return object.(*time.Time).IsZero()
default:
return false
}
}
}
return false
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// assert.Empty(t, obj)
//
// Returns whether the assertion was successful (true) or not (false).
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
pass := isEmpty(object)
if !pass {
Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
}
return pass
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// if assert.NotEmpty(t, obj) {
// assert.Equal(t, "two", obj[1])
// }
//
// Returns whether the assertion was successful (true) or not (false).
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
pass := !isEmpty(object)
if !pass {
Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
}
return pass
}
// getLen try to get length of object.
// return (false, 0) if impossible.
func getLen(x interface{}) (ok bool, length int) {
v := reflect.ValueOf(x)
defer func() {
if e := recover(); e != nil {
ok = false
}
}()
return true, v.Len()
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// assert.Len(t, mySlice, 3, "The size of slice is not 3")
//
// Returns whether the assertion was successful (true) or not (false).
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
ok, l := getLen(object)
if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
}
if l != length {
return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
}
return true
}
// True asserts that the specified value is true.
//
// assert.True(t, myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if value != true {
return Fail(t, "Should be true", msgAndArgs...)
}
return true
}
// False asserts that the specified value is true.
//
// assert.False(t, myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if value != false {
return Fail(t, "Should be false", msgAndArgs...)
}
return true
}
// NotEqual asserts that the specified values are NOT equal.
//
// assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if ObjectsAreEqual(expected, actual) {
return Fail(t, "Should not be equal", msgAndArgs...)
}
return true
}
// containsElement try loop over the list check if the list includes the element.
// return (false, false) if impossible.
// return (true, false) if element was not found.
// return (true, true) if element was found.
func includeElement(list interface{}, element interface{}) (ok, found bool) {
listValue := reflect.ValueOf(list)
elementValue := reflect.ValueOf(element)
defer func() {
if e := recover(); e != nil {
ok = false
found = false
}
}()
if reflect.TypeOf(list).Kind() == reflect.String {
return true, strings.Contains(listValue.String(), elementValue.String())
}
for i := 0; i < listValue.Len(); i++ {
if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
return true, true
}
}
return true, false
}
// Contains asserts that the specified string or list(array, slice...) contains the
// specified substring or element.
//
// assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
// assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
//
// Returns whether the assertion was successful (true) or not (false).
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
ok, found := includeElement(s, contains)
if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
}
if !found {
return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
}
return true
}
// NotContains asserts that the specified string or list(array, slice...) does NOT contain the
// specified substring or element.
//
// assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
// assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
ok, found := includeElement(s, contains)
if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
}
if found {
return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
}
return true
}
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
result := comp()
if !result {
Fail(t, "Condition failed!", msgAndArgs...)
}
return result
}
// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
// methods, and represents a simple func that takes no arguments, and returns nothing.
type PanicTestFunc func()
// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
func didPanic(f PanicTestFunc) (bool, interface{}) {
didPanic := false
var message interface{}
func() {
defer func() {
if message = recover(); message != nil {
didPanic = true
}
}()
// call the target function
f()
}()
return didPanic, message
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// assert.Panics(t, func(){
// GoCrazy()
// }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
}
return true
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// assert.NotPanics(t, func(){
// RemainCalm()
// }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
}
return true
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
//
// Returns whether the assertion was successful (true) or not (false).
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
dt := expected.Sub(actual)
if dt < -delta || dt > delta {
return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
}
return true
}
func toFloat(x interface{}) (float64, bool) {
var xf float64
xok := true
switch xn := x.(type) {
case uint8:
xf = float64(xn)
case uint16:
xf = float64(xn)
case uint32:
xf = float64(xn)
case uint64:
xf = float64(xn)
case int:
xf = float64(xn)
case int8:
xf = float64(xn)
case int16:
xf = float64(xn)
case int32:
xf = float64(xn)
case int64:
xf = float64(xn)
case float32:
xf = float64(xn)
case float64:
xf = float64(xn)
default:
xok = false
}
return xf, xok
}
// InDelta asserts that the two numerals are within delta of each other.
//
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
af, aok := toFloat(expected)
bf, bok := toFloat(actual)
if !aok || !bok {
return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
}
dt := af - bf
if dt < -delta || dt > delta {
return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
}
return true
}
// min(|expected|, |actual|) * epsilon
func calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {
af, aok := toFloat(expected)
bf, bok := toFloat(actual)
if !aok || !bok {
// invalid input
return 0
}
if af < 0 {
af = -af
}
if bf < 0 {
bf = -bf
}
var delta float64
if af < bf {
delta = af * epsilon
} else {
delta = bf * epsilon
}
return delta
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
delta := calcEpsilonDelta(expected, actual, epsilon)
return InDelta(t, expected, actual, delta, msgAndArgs...)
}
/*
Errors
*/
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if assert.NoError(t, err) {
// assert.Equal(t, actualObj, expectedObj)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
if isNil(err) {
return true
}
return Fail(t, fmt.Sprintf("No error is expected but got %v", err), msgAndArgs...)
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if assert.Error(t, err, "An error was expected") {
// assert.Equal(t, err, expectedError)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
message := messageFromMsgAndArgs(msgAndArgs...)
return NotNil(t, err, "An error is expected but got nil. %s", message)
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// if assert.Error(t, err, "An error was expected") {
// assert.Equal(t, err, expectedError)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
message := messageFromMsgAndArgs(msgAndArgs...)
if !NotNil(t, theError, "An error is expected but got nil. %s", message) {
return false
}
s := "An error with value \"%s\" is expected but got \"%s\". %s"
return Equal(t, theError.Error(), errString,
s, errString, theError.Error(), message)
}
// matchRegexp return true if a specified regexp matches a string.
func matchRegexp(rx interface{}, str interface{}) bool {
var r *regexp.Regexp
if rr, ok := rx.(*regexp.Regexp); ok {
r = rr
} else {
r = regexp.MustCompile(fmt.Sprint(rx))
}
return (r.FindStringIndex(fmt.Sprint(str)) != nil)
}
// Regexp asserts that a specified regexp matches a string.
//
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
match := matchRegexp(rx, str)
if !match {
Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
}
return match
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
match := matchRegexp(rx, str)
if match {
Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
}
return !match
}

View File

@ -1,768 +0,0 @@
package assert
import (
"errors"
"regexp"
"testing"
"time"
)
// AssertionTesterInterface defines an interface to be used for testing assertion methods
type AssertionTesterInterface interface {
TestMethod()
}
// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
type AssertionTesterConformingObject struct {
}
func (a *AssertionTesterConformingObject) TestMethod() {
}
// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
type AssertionTesterNonConformingObject struct {
}
func TestObjectsAreEqual(t *testing.T) {
if !ObjectsAreEqual("Hello World", "Hello World") {
t.Error("objectsAreEqual should return true")
}
if !ObjectsAreEqual(123, 123) {
t.Error("objectsAreEqual should return true")
}
if !ObjectsAreEqual(123.5, 123.5) {
t.Error("objectsAreEqual should return true")
}
if !ObjectsAreEqual([]byte("Hello World"), []byte("Hello World")) {
t.Error("objectsAreEqual should return true")
}
if !ObjectsAreEqual(nil, nil) {
t.Error("objectsAreEqual should return true")
}
if ObjectsAreEqual(map[int]int{5: 10}, map[int]int{10: 20}) {
t.Error("objectsAreEqual should return false")
}
if ObjectsAreEqual('x', "x") {
t.Error("objectsAreEqual should return false")
}
if ObjectsAreEqual("x", 'x') {
t.Error("objectsAreEqual should return false")
}
if ObjectsAreEqual(0, 0.1) {
t.Error("objectsAreEqual should return false")
}
if ObjectsAreEqual(0.1, 0) {
t.Error("objectsAreEqual should return false")
}
if ObjectsAreEqual(uint32(10), int32(10)) {
t.Error("objectsAreEqual should return false")
}
if !ObjectsAreEqualValues(uint32(10), int32(10)) {
t.Error("ObjectsAreEqualValues should return true")
}
}
func TestImplements(t *testing.T) {
mockT := new(testing.T)
if !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
}
if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
}
}
func TestIsType(t *testing.T) {
mockT := new(testing.T)
if !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
}
if IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
}
}
func TestEqual(t *testing.T) {
mockT := new(testing.T)
if !Equal(mockT, "Hello World", "Hello World") {
t.Error("Equal should return true")
}
if !Equal(mockT, 123, 123) {
t.Error("Equal should return true")
}
if !Equal(mockT, 123.5, 123.5) {
t.Error("Equal should return true")
}
if !Equal(mockT, []byte("Hello World"), []byte("Hello World")) {
t.Error("Equal should return true")
}
if !Equal(mockT, nil, nil) {
t.Error("Equal should return true")
}
if !Equal(mockT, int32(123), int32(123)) {
t.Error("Equal should return true")
}
if !Equal(mockT, uint64(123), uint64(123)) {
t.Error("Equal should return true")
}
funcA := func() int { return 42 }
if !Equal(mockT, funcA, funcA) {
t.Error("Equal should return true")
}
}
func TestNotNil(t *testing.T) {
mockT := new(testing.T)
if !NotNil(mockT, new(AssertionTesterConformingObject)) {
t.Error("NotNil should return true: object is not nil")
}
if NotNil(mockT, nil) {
t.Error("NotNil should return false: object is nil")
}
}
func TestNil(t *testing.T) {
mockT := new(testing.T)
if !Nil(mockT, nil) {
t.Error("Nil should return true: object is nil")
}
if Nil(mockT, new(AssertionTesterConformingObject)) {
t.Error("Nil should return false: object is not nil")
}
}
func TestTrue(t *testing.T) {
mockT := new(testing.T)
if !True(mockT, true) {
t.Error("True should return true")
}
if True(mockT, false) {
t.Error("True should return false")
}
}
func TestFalse(t *testing.T) {
mockT := new(testing.T)
if !False(mockT, false) {
t.Error("False should return true")
}
if False(mockT, true) {
t.Error("False should return false")
}
}
func TestExactly(t *testing.T) {
mockT := new(testing.T)
a := float32(1)
b := float64(1)
c := float32(1)
d := float32(2)
if Exactly(mockT, a, b) {
t.Error("Exactly should return false")
}
if Exactly(mockT, a, d) {
t.Error("Exactly should return false")
}
if !Exactly(mockT, a, c) {
t.Error("Exactly should return true")
}
if Exactly(mockT, nil, a) {
t.Error("Exactly should return false")
}
if Exactly(mockT, a, nil) {
t.Error("Exactly should return false")
}
}
func TestNotEqual(t *testing.T) {
mockT := new(testing.T)
if !NotEqual(mockT, "Hello World", "Hello World!") {
t.Error("NotEqual should return true")
}
if !NotEqual(mockT, 123, 1234) {
t.Error("NotEqual should return true")
}
if !NotEqual(mockT, 123.5, 123.55) {
t.Error("NotEqual should return true")
}
if !NotEqual(mockT, []byte("Hello World"), []byte("Hello World!")) {
t.Error("NotEqual should return true")
}
if !NotEqual(mockT, nil, new(AssertionTesterConformingObject)) {
t.Error("NotEqual should return true")
}
funcA := func() int { return 23 }
funcB := func() int { return 42 }
if !NotEqual(mockT, funcA, funcB) {
t.Error("NotEqual should return true")
}
if NotEqual(mockT, "Hello World", "Hello World") {
t.Error("NotEqual should return false")
}
if NotEqual(mockT, 123, 123) {
t.Error("NotEqual should return false")
}
if NotEqual(mockT, 123.5, 123.5) {
t.Error("NotEqual should return false")
}
if NotEqual(mockT, []byte("Hello World"), []byte("Hello World")) {
t.Error("NotEqual should return false")
}
if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
t.Error("NotEqual should return false")
}
}
type A struct {
Name, Value string
}
func TestContains(t *testing.T) {
mockT := new(testing.T)
list := []string{"Foo", "Bar"}
complexList := []*A{
{"b", "c"},
{"d", "e"},
{"g", "h"},
{"j", "k"},
}
if !Contains(mockT, "Hello World", "Hello") {
t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
}
if Contains(mockT, "Hello World", "Salut") {
t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
}
if !Contains(mockT, list, "Bar") {
t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Bar\"")
}
if Contains(mockT, list, "Salut") {
t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
}
if !Contains(mockT, complexList, &A{"g", "h"}) {
t.Error("Contains should return true: complexList contains {\"g\", \"h\"}")
}
if Contains(mockT, complexList, &A{"g", "e"}) {
t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
}
}
func TestNotContains(t *testing.T) {
mockT := new(testing.T)
list := []string{"Foo", "Bar"}
if !NotContains(mockT, "Hello World", "Hello!") {
t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
}
if NotContains(mockT, "Hello World", "Hello") {
t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
}
if !NotContains(mockT, list, "Foo!") {
t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
}
if NotContains(mockT, list, "Foo") {
t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
}
}
func Test_includeElement(t *testing.T) {
list1 := []string{"Foo", "Bar"}
list2 := []int{1, 2}
ok, found := includeElement("Hello World", "World")
True(t, ok)
True(t, found)
ok, found = includeElement(list1, "Foo")
True(t, ok)
True(t, found)
ok, found = includeElement(list1, "Bar")
True(t, ok)
True(t, found)
ok, found = includeElement(list2, 1)
True(t, ok)
True(t, found)
ok, found = includeElement(list2, 2)
True(t, ok)
True(t, found)
ok, found = includeElement(list1, "Foo!")
True(t, ok)
False(t, found)
ok, found = includeElement(list2, 3)
True(t, ok)
False(t, found)
ok, found = includeElement(list2, "1")
True(t, ok)
False(t, found)
ok, found = includeElement(1433, "1")
False(t, ok)
False(t, found)
}
func TestCondition(t *testing.T) {
mockT := new(testing.T)
if !Condition(mockT, func() bool { return true }, "Truth") {
t.Error("Condition should return true")
}
if Condition(mockT, func() bool { return false }, "Lie") {
t.Error("Condition should return false")
}
}
func TestDidPanic(t *testing.T) {
if funcDidPanic, _ := didPanic(func() {
panic("Panic!")
}); !funcDidPanic {
t.Error("didPanic should return true")
}
if funcDidPanic, _ := didPanic(func() {
}); funcDidPanic {
t.Error("didPanic should return false")
}
}
func TestPanics(t *testing.T) {
mockT := new(testing.T)
if !Panics(mockT, func() {
panic("Panic!")
}) {
t.Error("Panics should return true")
}
if Panics(mockT, func() {
}) {
t.Error("Panics should return false")
}
}
func TestNotPanics(t *testing.T) {
mockT := new(testing.T)
if !NotPanics(mockT, func() {
}) {
t.Error("NotPanics should return true")
}
if NotPanics(mockT, func() {
panic("Panic!")
}) {
t.Error("NotPanics should return false")
}
}
func TestEqual_Funcs(t *testing.T) {
type f func() int
f1 := func() int { return 1 }
f2 := func() int { return 2 }
f1Copy := f1
Equal(t, f1Copy, f1, "Funcs are the same and should be considered equal")
NotEqual(t, f1, f2, "f1 and f2 are different")
}
func TestNoError(t *testing.T) {
mockT := new(testing.T)
// start with a nil error
var err error
True(t, NoError(mockT, err), "NoError should return True for nil arg")
// now set an error
err = errors.New("some error")
False(t, NoError(mockT, err), "NoError with error should return False")
}
func TestError(t *testing.T) {
mockT := new(testing.T)
// start with a nil error
var err error
False(t, Error(mockT, err), "Error should return False for nil arg")
// now set an error
err = errors.New("some error")
True(t, Error(mockT, err), "Error with error should return True")
}
func TestEqualError(t *testing.T) {
mockT := new(testing.T)
// start with a nil error
var err error
False(t, EqualError(mockT, err, ""),
"EqualError should return false for nil arg")
// now set an error
err = errors.New("some error")
False(t, EqualError(mockT, err, "Not some error"),
"EqualError should return false for different error string")
True(t, EqualError(mockT, err, "some error"),
"EqualError should return true")
}
func Test_isEmpty(t *testing.T) {
chWithValue := make(chan struct{}, 1)
chWithValue <- struct{}{}
True(t, isEmpty(""))
True(t, isEmpty(nil))
True(t, isEmpty([]string{}))
True(t, isEmpty(0))
True(t, isEmpty(int32(0)))
True(t, isEmpty(int64(0)))
True(t, isEmpty(false))
True(t, isEmpty(map[string]string{}))
True(t, isEmpty(new(time.Time)))
True(t, isEmpty(make(chan struct{})))
False(t, isEmpty("something"))
False(t, isEmpty(errors.New("something")))
False(t, isEmpty([]string{"something"}))
False(t, isEmpty(1))
False(t, isEmpty(true))
False(t, isEmpty(map[string]string{"Hello": "World"}))
False(t, isEmpty(chWithValue))
}
func TestEmpty(t *testing.T) {
mockT := new(testing.T)
chWithValue := make(chan struct{}, 1)
chWithValue <- struct{}{}
True(t, Empty(mockT, ""), "Empty string is empty")
True(t, Empty(mockT, nil), "Nil is empty")
True(t, Empty(mockT, []string{}), "Empty string array is empty")
True(t, Empty(mockT, 0), "Zero int value is empty")
True(t, Empty(mockT, false), "False value is empty")
True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty")
False(t, Empty(mockT, "something"), "Non Empty string is not empty")
False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty")
False(t, Empty(mockT, 1), "Non-zero int value is not empty")
False(t, Empty(mockT, true), "True value is not empty")
False(t, Empty(mockT, chWithValue), "Channel with values is not empty")
}
func TestNotEmpty(t *testing.T) {
mockT := new(testing.T)
chWithValue := make(chan struct{}, 1)
chWithValue <- struct{}{}
False(t, NotEmpty(mockT, ""), "Empty string is empty")
False(t, NotEmpty(mockT, nil), "Nil is empty")
False(t, NotEmpty(mockT, []string{}), "Empty string array is empty")
False(t, NotEmpty(mockT, 0), "Zero int value is empty")
False(t, NotEmpty(mockT, false), "False value is empty")
False(t, NotEmpty(mockT, make(chan struct{})), "Channel without values is empty")
True(t, NotEmpty(mockT, "something"), "Non Empty string is not empty")
True(t, NotEmpty(mockT, errors.New("something")), "Non nil object is not empty")
True(t, NotEmpty(mockT, []string{"something"}), "Non empty string array is not empty")
True(t, NotEmpty(mockT, 1), "Non-zero int value is not empty")
True(t, NotEmpty(mockT, true), "True value is not empty")
True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty")
}
func Test_getLen(t *testing.T) {
falseCases := []interface{}{
nil,
0,
true,
false,
'A',
struct{}{},
}
for _, v := range falseCases {
ok, l := getLen(v)
False(t, ok, "Expected getLen fail to get length of %#v", v)
Equal(t, 0, l, "getLen should return 0 for %#v", v)
}
ch := make(chan int, 5)
ch <- 1
ch <- 2
ch <- 3
trueCases := []struct {
v interface{}
l int
}{
{[]int{1, 2, 3}, 3},
{[...]int{1, 2, 3}, 3},
{"ABC", 3},
{map[int]int{1: 2, 2: 4, 3: 6}, 3},
{ch, 3},
{[]int{}, 0},
{map[int]int{}, 0},
{make(chan int), 0},
{[]int(nil), 0},
{map[int]int(nil), 0},
{(chan int)(nil), 0},
}
for _, c := range trueCases {
ok, l := getLen(c.v)
True(t, ok, "Expected getLen success to get length of %#v", c.v)
Equal(t, c.l, l)
}
}
func TestLen(t *testing.T) {
mockT := new(testing.T)
False(t, Len(mockT, nil, 0), "nil does not have length")
False(t, Len(mockT, 0, 0), "int does not have length")
False(t, Len(mockT, true, 0), "true does not have length")
False(t, Len(mockT, false, 0), "false does not have length")
False(t, Len(mockT, 'A', 0), "Rune does not have length")
False(t, Len(mockT, struct{}{}, 0), "Struct does not have length")
ch := make(chan int, 5)
ch <- 1
ch <- 2
ch <- 3
cases := []struct {
v interface{}
l int
}{
{[]int{1, 2, 3}, 3},
{[...]int{1, 2, 3}, 3},
{"ABC", 3},
{map[int]int{1: 2, 2: 4, 3: 6}, 3},
{ch, 3},
{[]int{}, 0},
{map[int]int{}, 0},
{make(chan int), 0},
{[]int(nil), 0},
{map[int]int(nil), 0},
{(chan int)(nil), 0},
}
for _, c := range cases {
True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
}
cases = []struct {
v interface{}
l int
}{
{[]int{1, 2, 3}, 4},
{[...]int{1, 2, 3}, 2},
{"ABC", 2},
{map[int]int{1: 2, 2: 4, 3: 6}, 4},
{ch, 2},
{[]int{}, 1},
{map[int]int{}, 1},
{make(chan int), 1},
{[]int(nil), 1},
{map[int]int(nil), 1},
{(chan int)(nil), 1},
}
for _, c := range cases {
False(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
}
}
func TestWithinDuration(t *testing.T) {
mockT := new(testing.T)
a := time.Now()
b := a.Add(10 * time.Second)
True(t, WithinDuration(mockT, a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
True(t, WithinDuration(mockT, b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
False(t, WithinDuration(mockT, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
False(t, WithinDuration(mockT, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
False(t, WithinDuration(mockT, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
False(t, WithinDuration(mockT, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
False(t, WithinDuration(mockT, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
False(t, WithinDuration(mockT, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
}
func TestInDelta(t *testing.T) {
mockT := new(testing.T)
True(t, InDelta(mockT, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
True(t, InDelta(mockT, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
True(t, InDelta(mockT, 1, 2, 1), "|1 - 2| <= 1")
False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail")
cases := []struct {
a, b interface{}
delta float64
}{
{uint8(2), uint8(1), 1},
{uint16(2), uint16(1), 1},
{uint32(2), uint32(1), 1},
{uint64(2), uint64(1), 1},
{int(2), int(1), 1},
{int8(2), int8(1), 1},
{int16(2), int16(1), 1},
{int32(2), int32(1), 1},
{int64(2), int64(1), 1},
{float32(2), float32(1), 1},
{float64(2), float64(1), 1},
}
for _, tc := range cases {
True(t, InDelta(mockT, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
}
}
func TestInEpsilon(t *testing.T) {
mockT := new(testing.T)
cases := []struct {
a, b interface{}
epsilon float64
}{
{uint8(2), uint16(2), .001},
{2.1, 2.2, 0.1},
{2.2, 2.1, 0.1},
{-2.1, -2.2, 0.1},
{-2.2, -2.1, 0.1},
{uint64(100), uint8(101), 0.01},
{0.1, -0.1, 2},
}
for _, tc := range cases {
True(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
}
cases = []struct {
a, b interface{}
epsilon float64
}{
{uint8(2), int16(-2), .001},
{uint64(100), uint8(102), 0.01},
{2.1, 2.2, 0.001},
{2.2, 2.1, 0.001},
{2.1, -2.2, 1},
{2.1, "bla-bla", 0},
{0.1, -0.1, 1.99},
}
for _, tc := range cases {
False(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
}
}
func TestRegexp(t *testing.T) {
mockT := new(testing.T)
cases := []struct {
rx, str string
}{
{"^start", "start of the line"},
{"end$", "in the end"},
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
}
for _, tc := range cases {
True(t, Regexp(mockT, tc.rx, tc.str))
True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
False(t, NotRegexp(mockT, tc.rx, tc.str))
False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
}
cases = []struct {
rx, str string
}{
{"^asdfastart", "Not the start of the line"},
{"end$", "in the end."},
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
}
for _, tc := range cases {
False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
True(t, NotRegexp(mockT, tc.rx, tc.str))
True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
}
}

View File

@ -1,150 +0,0 @@
// A set of comprehensive testing tools for use with the normal Go testing system.
//
// Example Usage
//
// The following is a complete example using assert in a standard test function:
// import (
// "testing"
// "github.com/stretchr/testify/assert"
// )
//
// func TestSomething(t *testing.T) {
//
// var a string = "Hello"
// var b string = "Hello"
//
// assert.Equal(t, a, b, "The two words should be the same.")
//
// }
//
// if you assert many times, use the below:
//
// import (
// "testing"
// "github.com/stretchr/testify/assert"
// )
//
// func TestSomething(t *testing.T) {
// assert := assert.New(t)
//
// var a string = "Hello"
// var b string = "Hello"
//
// assert.Equal(a, b, "The two words should be the same.")
// }
//
// Assertions
//
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
// testing framework. This allows the assertion funcs to write the failings and other details to
// the correct place.
//
// Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs.
//
// Here is an overview of the assert functions:
//
// assert.Equal(t, expected, actual [, message [, format-args])
//
// assert.NotEqual(t, notExpected, actual [, message [, format-args]])
//
// assert.True(t, actualBool [, message [, format-args]])
//
// assert.False(t, actualBool [, message [, format-args]])
//
// assert.Nil(t, actualObject [, message [, format-args]])
//
// assert.NotNil(t, actualObject [, message [, format-args]])
//
// assert.Empty(t, actualObject [, message [, format-args]])
//
// assert.NotEmpty(t, actualObject [, message [, format-args]])
//
// assert.Len(t, actualObject, expectedLength, [, message [, format-args]])
//
// assert.Error(t, errorObject [, message [, format-args]])
//
// assert.NoError(t, errorObject [, message [, format-args]])
//
// assert.EqualError(t, theError, errString [, message [, format-args]])
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
// assert.IsType(t, expectedObject, actualObject [, message [, format-args]])
//
// assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.Panics(t, func(){
//
// // call code that should panic
//
// } [, message [, format-args]])
//
// assert.NotPanics(t, func(){
//
// // call code that should not panic
//
// } [, message [, format-args]])
//
// assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
//
// assert.InDelta(t, numA, numB, delta, [, message [, format-args]])
//
// assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
//
// assert package contains Assertions object. it has assertion methods.
//
// Here is an overview of the assert functions:
// assert.Equal(expected, actual [, message [, format-args])
//
// assert.NotEqual(notExpected, actual [, message [, format-args]])
//
// assert.True(actualBool [, message [, format-args]])
//
// assert.False(actualBool [, message [, format-args]])
//
// assert.Nil(actualObject [, message [, format-args]])
//
// assert.NotNil(actualObject [, message [, format-args]])
//
// assert.Empty(actualObject [, message [, format-args]])
//
// assert.NotEmpty(actualObject [, message [, format-args]])
//
// assert.Len(actualObject, expectedLength, [, message [, format-args]])
//
// assert.Error(errorObject [, message [, format-args]])
//
// assert.NoError(errorObject [, message [, format-args]])
//
// assert.EqualError(theError, errString [, message [, format-args]])
//
// assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
// assert.IsType(expectedObject, actualObject [, message [, format-args]])
//
// assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])
//
// assert.Panics(func(){
//
// // call code that should panic
//
// } [, message [, format-args]])
//
// assert.NotPanics(func(){
//
// // call code that should not panic
//
// } [, message [, format-args]])
//
// assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])
//
// assert.InDelta(numA, numB, delta, [, message [, format-args]])
//
// assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])
package assert

View File

@ -1,10 +0,0 @@
package assert
import (
"errors"
)
// AnError is an error instance useful for testing. If the code does not care
// about error specifics, and only needs to return the error for example, this
// error should be used to make the test code more readable.
var AnError = errors.New("assert.AnError general error for testing")

View File

@ -1,262 +0,0 @@
package assert
import "time"
type Assertions struct {
t TestingT
}
func New(t TestingT) *Assertions {
return &Assertions{
t: t,
}
}
// Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
return Fail(a.t, failureMessage, msgAndArgs...)
}
// Implements asserts that an object is implemented by the specified interface.
//
// assert.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
return Implements(a.t, interfaceObject, object, msgAndArgs...)
}
// IsType asserts that the specified objects are of the same type.
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
return IsType(a.t, expectedType, object, msgAndArgs...)
}
// Equal asserts that two objects are equal.
//
// assert.Equal(123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) bool {
return Equal(a.t, expected, actual, msgAndArgs...)
}
// EqualValues asserts that two objects are equal or convertable to the same types
// and equal.
//
// assert.EqualValues(uint32(123), int32(123), "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualValues(expected, actual interface{}, msgAndArgs ...interface{}) bool {
return EqualValues(a.t, expected, actual, msgAndArgs...)
}
// Exactly asserts that two objects are equal is value and type.
//
// assert.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) bool {
return Exactly(a.t, expected, actual, msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
//
// assert.NotNil(err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
return NotNil(a.t, object, msgAndArgs...)
}
// Nil asserts that the specified object is nil.
//
// assert.Nil(err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
return Nil(a.t, object, msgAndArgs...)
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or a
// slice with len == 0.
//
// assert.Empty(obj)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
return Empty(a.t, object, msgAndArgs...)
}
// Empty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or a
// slice with len == 0.
//
// if assert.NotEmpty(obj) {
// assert.Equal("two", obj[1])
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
return NotEmpty(a.t, object, msgAndArgs...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// assert.Len(mySlice, 3, "The size of slice is not 3")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
return Len(a.t, object, length, msgAndArgs...)
}
// True asserts that the specified value is true.
//
// assert.True(myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
return True(a.t, value, msgAndArgs...)
}
// False asserts that the specified value is true.
//
// assert.False(myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
return False(a.t, value, msgAndArgs...)
}
// NotEqual asserts that the specified values are NOT equal.
//
// assert.NotEqual(obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool {
return NotEqual(a.t, expected, actual, msgAndArgs...)
}
// Contains asserts that the specified string contains the specified substring.
//
// assert.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) bool {
return Contains(a.t, s, contains, msgAndArgs...)
}
// NotContains asserts that the specified string does NOT contain the specified substring.
//
// assert.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) bool {
return NotContains(a.t, s, contains, msgAndArgs...)
}
// Uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
return Condition(a.t, comp, msgAndArgs...)
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// assert.Panics(func(){
// GoCrazy()
// }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
return Panics(a.t, f, msgAndArgs...)
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// assert.NotPanics(func(){
// RemainCalm()
// }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
return NotPanics(a.t, f, msgAndArgs...)
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// assert.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
}
// InDelta asserts that the two numerals are within delta of each other.
//
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if assert.NoError(err) {
// assert.Equal(actualObj, expectedObj)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) bool {
return NoError(a.t, theError, msgAndArgs...)
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if assert.Error(err, "An error was expected") {
// assert.Equal(err, expectedError)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Error(theError error, msgAndArgs ...interface{}) bool {
return Error(a.t, theError, msgAndArgs...)
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// if assert.Error(err, "An error was expected") {
// assert.Equal(err, expectedError)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
return EqualError(a.t, theError, errString, msgAndArgs...)
}
// Regexp asserts that a specified regexp matches a string.
//
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
return Regexp(a.t, rx, str, msgAndArgs...)
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
return NotRegexp(a.t, rx, str, msgAndArgs...)
}

View File

@ -1,526 +0,0 @@
package assert
import (
"errors"
"regexp"
"testing"
"time"
)
func TestImplementsWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
}
if assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
}
}
func TestIsTypeWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
}
if assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
}
}
func TestEqualWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.Equal("Hello World", "Hello World") {
t.Error("Equal should return true")
}
if !assert.Equal(123, 123) {
t.Error("Equal should return true")
}
if !assert.Equal(123.5, 123.5) {
t.Error("Equal should return true")
}
if !assert.Equal([]byte("Hello World"), []byte("Hello World")) {
t.Error("Equal should return true")
}
if !assert.Equal(nil, nil) {
t.Error("Equal should return true")
}
}
func TestEqualValuesWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.EqualValues(uint32(10), int32(10)) {
t.Error("EqualValues should return true")
}
}
func TestNotNilWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.NotNil(new(AssertionTesterConformingObject)) {
t.Error("NotNil should return true: object is not nil")
}
if assert.NotNil(nil) {
t.Error("NotNil should return false: object is nil")
}
}
func TestNilWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.Nil(nil) {
t.Error("Nil should return true: object is nil")
}
if assert.Nil(new(AssertionTesterConformingObject)) {
t.Error("Nil should return false: object is not nil")
}
}
func TestTrueWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.True(true) {
t.Error("True should return true")
}
if assert.True(false) {
t.Error("True should return false")
}
}
func TestFalseWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.False(false) {
t.Error("False should return true")
}
if assert.False(true) {
t.Error("False should return false")
}
}
func TestExactlyWrapper(t *testing.T) {
assert := New(new(testing.T))
a := float32(1)
b := float64(1)
c := float32(1)
d := float32(2)
if assert.Exactly(a, b) {
t.Error("Exactly should return false")
}
if assert.Exactly(a, d) {
t.Error("Exactly should return false")
}
if !assert.Exactly(a, c) {
t.Error("Exactly should return true")
}
if assert.Exactly(nil, a) {
t.Error("Exactly should return false")
}
if assert.Exactly(a, nil) {
t.Error("Exactly should return false")
}
}
func TestNotEqualWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.NotEqual("Hello World", "Hello World!") {
t.Error("NotEqual should return true")
}
if !assert.NotEqual(123, 1234) {
t.Error("NotEqual should return true")
}
if !assert.NotEqual(123.5, 123.55) {
t.Error("NotEqual should return true")
}
if !assert.NotEqual([]byte("Hello World"), []byte("Hello World!")) {
t.Error("NotEqual should return true")
}
if !assert.NotEqual(nil, new(AssertionTesterConformingObject)) {
t.Error("NotEqual should return true")
}
}
func TestContainsWrapper(t *testing.T) {
assert := New(new(testing.T))
list := []string{"Foo", "Bar"}
if !assert.Contains("Hello World", "Hello") {
t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
}
if assert.Contains("Hello World", "Salut") {
t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
}
if !assert.Contains(list, "Foo") {
t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
}
if assert.Contains(list, "Salut") {
t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
}
}
func TestNotContainsWrapper(t *testing.T) {
assert := New(new(testing.T))
list := []string{"Foo", "Bar"}
if !assert.NotContains("Hello World", "Hello!") {
t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
}
if assert.NotContains("Hello World", "Hello") {
t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
}
if !assert.NotContains(list, "Foo!") {
t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
}
if assert.NotContains(list, "Foo") {
t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
}
}
func TestConditionWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.Condition(func() bool { return true }, "Truth") {
t.Error("Condition should return true")
}
if assert.Condition(func() bool { return false }, "Lie") {
t.Error("Condition should return false")
}
}
func TestDidPanicWrapper(t *testing.T) {
if funcDidPanic, _ := didPanic(func() {
panic("Panic!")
}); !funcDidPanic {
t.Error("didPanic should return true")
}
if funcDidPanic, _ := didPanic(func() {
}); funcDidPanic {
t.Error("didPanic should return false")
}
}
func TestPanicsWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.Panics(func() {
panic("Panic!")
}) {
t.Error("Panics should return true")
}
if assert.Panics(func() {
}) {
t.Error("Panics should return false")
}
}
func TestNotPanicsWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.NotPanics(func() {
}) {
t.Error("NotPanics should return true")
}
if assert.NotPanics(func() {
panic("Panic!")
}) {
t.Error("NotPanics should return false")
}
}
func TestEqualWrapper_Funcs(t *testing.T) {
assert := New(t)
type f func() int
var f1 f = func() int { return 1 }
var f2 f = func() int { return 2 }
var f1_copy f = f1
assert.Equal(f1_copy, f1, "Funcs are the same and should be considered equal")
assert.NotEqual(f1, f2, "f1 and f2 are different")
}
func TestNoErrorWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
// start with a nil error
var err error = nil
assert.True(mockAssert.NoError(err), "NoError should return True for nil arg")
// now set an error
err = errors.New("Some error")
assert.False(mockAssert.NoError(err), "NoError with error should return False")
}
func TestErrorWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
// start with a nil error
var err error = nil
assert.False(mockAssert.Error(err), "Error should return False for nil arg")
// now set an error
err = errors.New("Some error")
assert.True(mockAssert.Error(err), "Error with error should return True")
}
func TestEqualErrorWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
// start with a nil error
var err error
assert.False(mockAssert.EqualError(err, ""),
"EqualError should return false for nil arg")
// now set an error
err = errors.New("some error")
assert.False(mockAssert.EqualError(err, "Not some error"),
"EqualError should return false for different error string")
assert.True(mockAssert.EqualError(err, "some error"),
"EqualError should return true")
}
func TestEmptyWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
assert.True(mockAssert.Empty(""), "Empty string is empty")
assert.True(mockAssert.Empty(nil), "Nil is empty")
assert.True(mockAssert.Empty([]string{}), "Empty string array is empty")
assert.True(mockAssert.Empty(0), "Zero int value is empty")
assert.True(mockAssert.Empty(false), "False value is empty")
assert.False(mockAssert.Empty("something"), "Non Empty string is not empty")
assert.False(mockAssert.Empty(errors.New("something")), "Non nil object is not empty")
assert.False(mockAssert.Empty([]string{"something"}), "Non empty string array is not empty")
assert.False(mockAssert.Empty(1), "Non-zero int value is not empty")
assert.False(mockAssert.Empty(true), "True value is not empty")
}
func TestNotEmptyWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
assert.False(mockAssert.NotEmpty(""), "Empty string is empty")
assert.False(mockAssert.NotEmpty(nil), "Nil is empty")
assert.False(mockAssert.NotEmpty([]string{}), "Empty string array is empty")
assert.False(mockAssert.NotEmpty(0), "Zero int value is empty")
assert.False(mockAssert.NotEmpty(false), "False value is empty")
assert.True(mockAssert.NotEmpty("something"), "Non Empty string is not empty")
assert.True(mockAssert.NotEmpty(errors.New("something")), "Non nil object is not empty")
assert.True(mockAssert.NotEmpty([]string{"something"}), "Non empty string array is not empty")
assert.True(mockAssert.NotEmpty(1), "Non-zero int value is not empty")
assert.True(mockAssert.NotEmpty(true), "True value is not empty")
}
func TestLenWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
assert.False(mockAssert.Len(nil, 0), "nil does not have length")
assert.False(mockAssert.Len(0, 0), "int does not have length")
assert.False(mockAssert.Len(true, 0), "true does not have length")
assert.False(mockAssert.Len(false, 0), "false does not have length")
assert.False(mockAssert.Len('A', 0), "Rune does not have length")
assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length")
ch := make(chan int, 5)
ch <- 1
ch <- 2
ch <- 3
cases := []struct {
v interface{}
l int
}{
{[]int{1, 2, 3}, 3},
{[...]int{1, 2, 3}, 3},
{"ABC", 3},
{map[int]int{1: 2, 2: 4, 3: 6}, 3},
{ch, 3},
{[]int{}, 0},
{map[int]int{}, 0},
{make(chan int), 0},
{[]int(nil), 0},
{map[int]int(nil), 0},
{(chan int)(nil), 0},
}
for _, c := range cases {
assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l)
}
}
func TestWithinDurationWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
a := time.Now()
b := a.Add(10 * time.Second)
assert.True(mockAssert.WithinDuration(a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
assert.True(mockAssert.WithinDuration(b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
assert.False(mockAssert.WithinDuration(a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
assert.False(mockAssert.WithinDuration(b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
assert.False(mockAssert.WithinDuration(a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
assert.False(mockAssert.WithinDuration(b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
assert.False(mockAssert.WithinDuration(a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
assert.False(mockAssert.WithinDuration(b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
}
func TestInDeltaWrapper(t *testing.T) {
assert := New(new(testing.T))
True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
True(t, assert.InDelta(1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
True(t, assert.InDelta(1, 2, 1), "|1 - 2| <= 1")
False(t, assert.InDelta(1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
False(t, assert.InDelta(2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
False(t, assert.InDelta("", nil, 1), "Expected non numerals to fail")
cases := []struct {
a, b interface{}
delta float64
}{
{uint8(2), uint8(1), 1},
{uint16(2), uint16(1), 1},
{uint32(2), uint32(1), 1},
{uint64(2), uint64(1), 1},
{int(2), int(1), 1},
{int8(2), int8(1), 1},
{int16(2), int16(1), 1},
{int32(2), int32(1), 1},
{int64(2), int64(1), 1},
{float32(2), float32(1), 1},
{float64(2), float64(1), 1},
}
for _, tc := range cases {
True(t, assert.InDelta(tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
}
}
func TestInEpsilonWrapper(t *testing.T) {
assert := New(new(testing.T))
cases := []struct {
a, b interface{}
epsilon float64
}{
{uint8(2), uint16(2), .001},
{2.1, 2.2, 0.1},
{2.2, 2.1, 0.1},
{-2.1, -2.2, 0.1},
{-2.2, -2.1, 0.1},
{uint64(100), uint8(101), 0.01},
{0.1, -0.1, 2},
}
for _, tc := range cases {
True(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
}
cases = []struct {
a, b interface{}
epsilon float64
}{
{uint8(2), int16(-2), .001},
{uint64(100), uint8(102), 0.01},
{2.1, 2.2, 0.001},
{2.2, 2.1, 0.001},
{2.1, -2.2, 1},
{2.1, "bla-bla", 0},
{0.1, -0.1, 1.99},
}
for _, tc := range cases {
False(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
}
}
func TestRegexpWrapper(t *testing.T) {
assert := New(new(testing.T))
cases := []struct {
rx, str string
}{
{"^start", "start of the line"},
{"end$", "in the end"},
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
}
for _, tc := range cases {
True(t, assert.Regexp(tc.rx, tc.str))
True(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
False(t, assert.NotRegexp(tc.rx, tc.str))
False(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
}
cases = []struct {
rx, str string
}{
{"^asdfastart", "Not the start of the line"},
{"end$", "in the end."},
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
}
for _, tc := range cases {
False(t, assert.Regexp(tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
True(t, assert.NotRegexp(tc.rx, tc.str))
True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
}
}

View File

@ -1,157 +0,0 @@
package assert
import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
)
// httpCode is a helper that returns HTTP code of the response. It returns -1
// if building a new request fails.
func httpCode(handler http.HandlerFunc, mode, url string, values url.Values) int {
w := httptest.NewRecorder()
req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
if err != nil {
return -1
}
handler(w, req)
return w.Code
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values)
if code == -1 {
return false
}
return code >= http.StatusOK && code <= http.StatusPartialContent
}
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values)
if code == -1 {
return false
}
return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
}
// HTTPError asserts that a specified handler returns an error status code.
//
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {
code := httpCode(handler, mode, url, values)
if code == -1 {
return false
}
return code >= http.StatusBadRequest
}
// HttpBody is a helper that returns HTTP body of the response. It returns
// empty string if building a new request fails.
func HttpBody(handler http.HandlerFunc, mode, url string, values url.Values) string {
w := httptest.NewRecorder()
req, err := http.NewRequest(mode, url+"?"+values.Encode(), nil)
if err != nil {
return ""
}
handler(w, req)
return w.Body.String()
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
body := HttpBody(handler, mode, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
if !contains {
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
}
return contains
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
body := HttpBody(handler, mode, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
if contains {
Fail(t, "Expected response body for %s to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)
}
return !contains
}
//
// Assertions Wrappers
//
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, values url.Values) bool {
return HTTPSuccess(a.t, handler, mode, url, values)
}
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// assert.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, values url.Values) bool {
return HTTPRedirect(a.t, handler, mode, url, values)
}
// HTTPError asserts that a specified handler returns an error status code.
//
// assert.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, values url.Values) bool {
return HTTPError(a.t, handler, mode, url, values)
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
return HTTPBodyContains(a.t, handler, mode, url, values, str)
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {
return HTTPBodyNotContains(a.t, handler, mode, url, values, str)
}

View File

@ -1,86 +0,0 @@
package assert
import (
"fmt"
"net/http"
"net/url"
"testing"
)
func httpOK(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func httpRedirect(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTemporaryRedirect)
}
func httpError(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}
func TestHTTPStatuses(t *testing.T) {
assert := New(t)
mockT := new(testing.T)
assert.Equal(HTTPSuccess(mockT, httpOK, "GET", "/", nil), true)
assert.Equal(HTTPSuccess(mockT, httpRedirect, "GET", "/", nil), false)
assert.Equal(HTTPSuccess(mockT, httpError, "GET", "/", nil), false)
assert.Equal(HTTPRedirect(mockT, httpOK, "GET", "/", nil), false)
assert.Equal(HTTPRedirect(mockT, httpRedirect, "GET", "/", nil), true)
assert.Equal(HTTPRedirect(mockT, httpError, "GET", "/", nil), false)
assert.Equal(HTTPError(mockT, httpOK, "GET", "/", nil), false)
assert.Equal(HTTPError(mockT, httpRedirect, "GET", "/", nil), false)
assert.Equal(HTTPError(mockT, httpError, "GET", "/", nil), true)
}
func TestHTTPStatusesWrapper(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
assert.Equal(mockAssert.HTTPSuccess(httpOK, "GET", "/", nil), true)
assert.Equal(mockAssert.HTTPSuccess(httpRedirect, "GET", "/", nil), false)
assert.Equal(mockAssert.HTTPSuccess(httpError, "GET", "/", nil), false)
assert.Equal(mockAssert.HTTPRedirect(httpOK, "GET", "/", nil), false)
assert.Equal(mockAssert.HTTPRedirect(httpRedirect, "GET", "/", nil), true)
assert.Equal(mockAssert.HTTPRedirect(httpError, "GET", "/", nil), false)
assert.Equal(mockAssert.HTTPError(httpOK, "GET", "/", nil), false)
assert.Equal(mockAssert.HTTPError(httpRedirect, "GET", "/", nil), false)
assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true)
}
func httpHelloName(w http.ResponseWriter, r *http.Request) {
name := r.FormValue("name")
w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
}
func TestHttpBody(t *testing.T) {
assert := New(t)
mockT := new(testing.T)
assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
}
func TestHttpBodyWrappers(t *testing.T) {
assert := New(t)
mockAssert := New(new(testing.T))
assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
}

View File

@ -1,43 +0,0 @@
// Provides a system by which it is possible to mock your objects and verify calls are happening as expected.
//
// Example Usage
//
// The mock package provides an object, Mock, that tracks activity on another object. It is usually
// embedded into a test object as shown below:
//
// type MyTestObject struct {
// // add a Mock object instance
// mock.Mock
//
// // other fields go here as normal
// }
//
// When implementing the methods of an interface, you wire your functions up
// to call the Mock.Called(args...) method, and return the appropriate values.
//
// For example, to mock a method that saves the name and age of a person and returns
// the year of their birth or an error, you might write this:
//
// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
// args := o.Called(firstname, lastname, age)
// return args.Int(0), args.Error(1)
// }
//
// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
// index position. Given this argument list:
//
// (12, true, "Something")
//
// You could read them out strongly typed like this:
//
// args.Int(0)
// args.Bool(1)
// args.String(2)
//
// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
//
// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
//
// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
// cases you should check for nil first.
package mock

View File

@ -1,510 +0,0 @@
package mock
import (
"fmt"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
"reflect"
"runtime"
"strings"
"sync"
)
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Logf(format string, args ...interface{})
Errorf(format string, args ...interface{})
}
/*
Call
*/
// Call represents a method call and is used for setting expectations,
// as well as recording activity.
type Call struct {
// The name of the method that was or will be called.
Method string
// Holds the arguments of the method.
Arguments Arguments
// Holds the arguments that should be returned when
// this method is called.
ReturnArguments Arguments
// The number of times to return the return arguments when setting
// expectations. 0 means to always return the value.
Repeatability int
}
// Mock is the workhorse used to track activity on another object.
// For an example of its usage, refer to the "Example Usage" section at the top of this document.
type Mock struct {
// The method name that is currently
// being referred to by the On method.
onMethodName string
// An array of the arguments that are
// currently being referred to by the On method.
onMethodArguments Arguments
// Represents the calls that are expected of
// an object.
ExpectedCalls []Call
// Holds the calls that were made to this mocked object.
Calls []Call
// TestData holds any data that might be useful for testing. Testify ignores
// this data completely allowing you to do whatever you like with it.
testData objx.Map
mutex sync.Mutex
}
// TestData holds any data that might be useful for testing. Testify ignores
// this data completely allowing you to do whatever you like with it.
func (m *Mock) TestData() objx.Map {
if m.testData == nil {
m.testData = make(objx.Map)
}
return m.testData
}
/*
Setting expectations
*/
// On starts a description of an expectation of the specified method
// being called.
//
// Mock.On("MyMethod", arg1, arg2)
func (m *Mock) On(methodName string, arguments ...interface{}) *Mock {
m.onMethodName = methodName
m.onMethodArguments = arguments
return m
}
// Return finishes a description of an expectation of the method (and arguments)
// specified in the most recent On method call.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2)
func (m *Mock) Return(returnArguments ...interface{}) *Mock {
m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0})
return m
}
// Once indicates that that the mock should only return the value once.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
func (m *Mock) Once() {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1
}
// Twice indicates that that the mock should only return the value twice.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
func (m *Mock) Twice() {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2
}
// Times indicates that that the mock should only return the indicated number
// of times.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
func (m *Mock) Times(i int) {
m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i
}
/*
Recording and responding to activity
*/
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
for i, call := range m.ExpectedCalls {
if call.Method == method && call.Repeatability > -1 {
_, diffCount := call.Arguments.Diff(arguments)
if diffCount == 0 {
return i, &call
}
}
}
return -1, nil
}
func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
diffCount := 0
var closestCall *Call = nil
for _, call := range m.ExpectedCalls {
if call.Method == method {
_, tempDiffCount := call.Arguments.Diff(arguments)
if tempDiffCount < diffCount || diffCount == 0 {
diffCount = tempDiffCount
closestCall = &call
}
}
}
if closestCall == nil {
return false, nil
}
return true, closestCall
}
func callString(method string, arguments Arguments, includeArgumentValues bool) string {
var argValsString string = ""
if includeArgumentValues {
var argVals []string
for argIndex, arg := range arguments {
argVals = append(argVals, fmt.Sprintf("%d: %v", argIndex, arg))
}
argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
}
return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString)
}
// Called tells the mock object that a method has been called, and gets an array
// of arguments to return. Panics if the call is unexpected (i.e. not preceeded by
// appropriate .On .Return() calls)
func (m *Mock) Called(arguments ...interface{}) Arguments {
defer m.mutex.Unlock()
m.mutex.Lock()
// get the calling function's name
pc, _, _, ok := runtime.Caller(1)
if !ok {
panic("Couldn't get the caller information")
}
functionPath := runtime.FuncForPC(pc).Name()
parts := strings.Split(functionPath, ".")
functionName := parts[len(parts)-1]
found, call := m.findExpectedCall(functionName, arguments...)
switch {
case found < 0:
// we have to fail here - because we don't know what to do
// as the return arguments. This is because:
//
// a) this is a totally unexpected call to this method,
// b) the arguments are not what was expected, or
// c) the developer has forgotten to add an accompanying On...Return pair.
closestFound, closestCall := m.findClosestCall(functionName, arguments...)
if closestFound {
panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true)))
} else {
panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
}
case call.Repeatability == 1:
call.Repeatability = -1
m.ExpectedCalls[found] = *call
case call.Repeatability > 1:
call.Repeatability -= 1
m.ExpectedCalls[found] = *call
}
// add the call
m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0})
return call.ReturnArguments
}
/*
Assertions
*/
// AssertExpectationsForObjects asserts that everything specified with On and Return
// of the specified objects was in fact called as expected.
//
// Calls may have occurred in any order.
func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
var success bool = true
for _, obj := range testObjects {
mockObj := obj.(Mock)
success = success && mockObj.AssertExpectations(t)
}
return success
}
// AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool {
var somethingMissing bool = false
var failedExpectations int = 0
// iterate through each expectation
for _, expectedCall := range m.ExpectedCalls {
switch {
case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments):
somethingMissing = true
failedExpectations++
t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
case expectedCall.Repeatability > 0:
somethingMissing = true
failedExpectations++
default:
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
}
}
if somethingMissing {
t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(m.ExpectedCalls)-failedExpectations, len(m.ExpectedCalls), failedExpectations, assert.CallerInfo())
}
return !somethingMissing
}
// AssertNumberOfCalls asserts that the method was called expectedCalls times.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
var actualCalls int = 0
for _, call := range m.Calls {
if call.Method == methodName {
actualCalls++
}
}
return assert.Equal(t, actualCalls, expectedCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
}
// AssertCalled asserts that the method was called.
func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) {
t.Logf("%s", m.ExpectedCalls)
return false
}
return true
}
// AssertNotCalled asserts that the method was not called.
func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) {
t.Logf("%s", m.ExpectedCalls)
return false
}
return true
}
func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
for _, call := range m.Calls {
if call.Method == methodName {
_, differences := Arguments(expected).Diff(call.Arguments)
if differences == 0 {
// found the expected call
return true
}
}
}
// we didn't find the expected call
return false
}
/*
Arguments
*/
// Arguments holds an array of method arguments or return values.
type Arguments []interface{}
const (
// The "any" argument. Used in Diff and Assert when
// the argument being tested shouldn't be taken into consideration.
Anything string = "mock.Anything"
)
// AnythingOfTypeArgument is a string that contains the type of an argument
// for use when type checking. Used in Diff and Assert.
type AnythingOfTypeArgument string
// AnythingOfType returns an AnythingOfTypeArgument object containing the
// name of the type to check for. Used in Diff and Assert.
//
// For example:
// Assert(t, AnythingOfType("string"), AnythingOfType("int"))
func AnythingOfType(t string) AnythingOfTypeArgument {
return AnythingOfTypeArgument(t)
}
// Get Returns the argument at the specified index.
func (args Arguments) Get(index int) interface{} {
if index+1 > len(args) {
panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args)))
}
return args[index]
}
// Is gets whether the objects match the arguments specified.
func (args Arguments) Is(objects ...interface{}) bool {
for i, obj := range args {
if obj != objects[i] {
return false
}
}
return true
}
// Diff gets a string describing the differences between the arguments
// and the specified objects.
//
// Returns the diff string and number of differences found.
func (args Arguments) Diff(objects []interface{}) (string, int) {
var output string = "\n"
var differences int
var maxArgCount int = len(args)
if len(objects) > maxArgCount {
maxArgCount = len(objects)
}
for i := 0; i < maxArgCount; i++ {
var actual, expected interface{}
if len(objects) <= i {
actual = "(Missing)"
} else {
actual = objects[i]
}
if len(args) <= i {
expected = "(Missing)"
} else {
expected = args[i]
}
if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
// type checking
if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
// not match
differences++
output = fmt.Sprintf("%s\t%d: \u274C type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual)
}
} else {
// normal checking
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
// match
output = fmt.Sprintf("%s\t%d: \u2705 %s == %s\n", output, i, actual, expected)
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: \u274C %s != %s\n", output, i, actual, expected)
}
}
}
if differences == 0 {
return "No differences.", differences
}
return output, differences
}
// Assert compares the arguments with the specified objects and fails if
// they do not exactly match.
func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
// get the differences
diff, diffCount := args.Diff(objects)
if diffCount == 0 {
return true
}
// there are differences... report them...
t.Logf(diff)
t.Errorf("%sArguments do not match.", assert.CallerInfo())
return false
}
// String gets the argument at the specified index. Panics if there is no argument, or
// if the argument is of the wrong type.
//
// If no index is provided, String() returns a complete string representation
// of the arguments.
func (args Arguments) String(indexOrNil ...int) string {
if len(indexOrNil) == 0 {
// normal String() method - return a string representation of the args
var argsStr []string
for _, arg := range args {
argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
}
return strings.Join(argsStr, ",")
} else if len(indexOrNil) == 1 {
// Index has been specified - get the argument at that index
var index int = indexOrNil[0]
var s string
var ok bool
if s, ok = args.Get(index).(string); !ok {
panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index)))
}
return s
}
panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil)))
}
// Int gets the argument at the specified index. Panics if there is no argument, or
// if the argument is of the wrong type.
func (args Arguments) Int(index int) int {
var s int
var ok bool
if s, ok = args.Get(index).(int); !ok {
panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
}
return s
}
// Error gets the argument at the specified index. Panics if there is no argument, or
// if the argument is of the wrong type.
func (args Arguments) Error(index int) error {
obj := args.Get(index)
var s error
var ok bool
if obj == nil {
return nil
}
if s, ok = obj.(error); !ok {
panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
}
return s
}
// Bool gets the argument at the specified index. Panics if there is no argument, or
// if the argument is of the wrong type.
func (args Arguments) Bool(index int) bool {
var s bool
var ok bool
if s, ok = args.Get(index).(bool); !ok {
panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
}
return s
}

View File

@ -1,669 +0,0 @@
package mock
import (
"errors"
"github.com/stretchr/testify/assert"
"testing"
)
/*
Test objects
*/
// ExampleInterface represents an example interface.
type ExampleInterface interface {
TheExampleMethod(a, b, c int) (int, error)
}
// TestExampleImplementation is a test implementation of ExampleInterface
type TestExampleImplementation struct {
Mock
}
func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
args := i.Called(a, b, c)
return args.Int(0), errors.New("Whoops")
}
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
i.Called(yesorno)
}
type ExampleType struct{}
func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
args := i.Called(et)
return args.Error(0)
}
/*
Mock
*/
func Test_Mock_TestData(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
if assert.NotNil(t, mockedService.TestData()) {
mockedService.TestData().Set("something", 123)
assert.Equal(t, 123, mockedService.TestData().Get("something").Data())
}
}
func Test_Mock_On(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod"), &mockedService.Mock)
assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
}
func Test_Mock_On_WithArgs(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", 1, 2, 3), &mockedService.Mock)
assert.Equal(t, "TheExampleMethod", mockedService.onMethodName)
assert.Equal(t, 1, mockedService.onMethodArguments[0])
assert.Equal(t, 2, mockedService.onMethodArguments[1])
assert.Equal(t, 3, mockedService.onMethodArguments[2])
}
func Test_Mock_Return(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true), &mockedService.Mock)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 0, call.Repeatability)
}
}
func Test_Mock_Return_Once(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Once()
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 1, call.Repeatability)
}
}
func Test_Mock_Return_Twice(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Twice()
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 2, call.Repeatability)
}
}
func Test_Mock_Return_Times(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).Times(5)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 1, call.ReturnArguments[0])
assert.Equal(t, "two", call.ReturnArguments[1])
assert.Equal(t, true, call.ReturnArguments[2])
assert.Equal(t, 5, call.Repeatability)
}
}
func Test_Mock_Return_Nothing(t *testing.T) {
// make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
assert.Equal(t, mockedService.On("TheExampleMethod", "A", "B", true).Return(), &mockedService.Mock)
// ensure the call was created
if assert.Equal(t, 1, len(mockedService.ExpectedCalls)) {
call := mockedService.ExpectedCalls[0]
assert.Equal(t, "TheExampleMethod", call.Method)
assert.Equal(t, "A", call.Arguments[0])
assert.Equal(t, "B", call.Arguments[1])
assert.Equal(t, true, call.Arguments[2])
assert.Equal(t, 0, len(call.ReturnArguments))
}
}
func Test_Mock_findExpectedCall(t *testing.T) {
m := new(Mock)
m.On("One", 1).Return("one")
m.On("Two", 2).Return("two")
m.On("Two", 3).Return("three")
f, c := m.findExpectedCall("Two", 3)
if assert.Equal(t, 2, f) {
if assert.NotNil(t, c) {
assert.Equal(t, "Two", c.Method)
assert.Equal(t, 3, c.Arguments[0])
assert.Equal(t, "three", c.ReturnArguments[0])
}
}
}
func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) {
m := new(Mock)
m.On("One", 1).Return("one")
m.On("Two", 2).Return("two")
m.On("Two", 3).Return("three")
f, _ := m.findExpectedCall("Two")
assert.Equal(t, -1, f)
}
func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
m := new(Mock)
m.On("One", 1).Return("one")
m.On("Two", 2).Return("two").Once()
m.On("Two", 3).Return("three").Twice()
m.On("Two", 3).Return("three").Times(8)
f, c := m.findExpectedCall("Two", 3)
if assert.Equal(t, 2, f) {
if assert.NotNil(t, c) {
assert.Equal(t, "Two", c.Method)
assert.Equal(t, 3, c.Arguments[0])
assert.Equal(t, "three", c.ReturnArguments[0])
}
}
}
func Test_callString(t *testing.T) {
assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false))
}
func Test_Mock_Called(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_Called", 1, 2, 3).Return(5, "6", true)
returnArguments := mockedService.Called(1, 2, 3)
if assert.Equal(t, 1, len(mockedService.Calls)) {
assert.Equal(t, "Test_Mock_Called", mockedService.Calls[0].Method)
assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
}
if assert.Equal(t, 3, len(returnArguments)) {
assert.Equal(t, 5, returnArguments[0])
assert.Equal(t, "6", returnArguments[1])
assert.Equal(t, true, returnArguments[2])
}
}
func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(5, "6", true).Once()
mockedService.On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).Return(-1, "hi", false)
returnArguments1 := mockedService.Called(1, 2, 3)
returnArguments2 := mockedService.Called(1, 2, 3)
if assert.Equal(t, 2, len(mockedService.Calls)) {
assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[0].Method)
assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[1].Method)
assert.Equal(t, 1, mockedService.Calls[1].Arguments[0])
assert.Equal(t, 2, mockedService.Calls[1].Arguments[1])
assert.Equal(t, 3, mockedService.Calls[1].Arguments[2])
}
if assert.Equal(t, 3, len(returnArguments1)) {
assert.Equal(t, 5, returnArguments1[0])
assert.Equal(t, "6", returnArguments1[1])
assert.Equal(t, true, returnArguments1[2])
}
if assert.Equal(t, 3, len(returnArguments2)) {
assert.Equal(t, -1, returnArguments2[0])
assert.Equal(t, "hi", returnArguments2[1])
assert.Equal(t, false, returnArguments2[2])
}
}
func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod", 1, 2, 3).Return(5, "6", true).Times(4)
mockedService.TheExampleMethod(1, 2, 3)
mockedService.TheExampleMethod(1, 2, 3)
mockedService.TheExampleMethod(1, 2, 3)
mockedService.TheExampleMethod(1, 2, 3)
assert.Panics(t, func() {
mockedService.TheExampleMethod(1, 2, 3)
})
}
func Test_Mock_Called_Unexpected(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
// make sure it panics if no expectation was made
assert.Panics(t, func() {
mockedService.Called(1, 2, 3)
}, "Calling unexpected method should panic")
}
func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
var mockedService1 *TestExampleImplementation = new(TestExampleImplementation)
var mockedService2 *TestExampleImplementation = new(TestExampleImplementation)
var mockedService3 *TestExampleImplementation = new(TestExampleImplementation)
mockedService1.On("Test_AssertExpectationsForObjects_Helper", 1).Return()
mockedService2.On("Test_AssertExpectationsForObjects_Helper", 2).Return()
mockedService3.On("Test_AssertExpectationsForObjects_Helper", 3).Return()
mockedService1.Called(1)
mockedService2.Called(2)
mockedService3.Called(3)
assert.True(t, AssertExpectationsForObjects(t, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
}
func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
var mockedService1 *TestExampleImplementation = new(TestExampleImplementation)
var mockedService2 *TestExampleImplementation = new(TestExampleImplementation)
var mockedService3 *TestExampleImplementation = new(TestExampleImplementation)
mockedService1.On("Test_AssertExpectationsForObjects_Helper_Failed", 1).Return()
mockedService2.On("Test_AssertExpectationsForObjects_Helper_Failed", 2).Return()
mockedService3.On("Test_AssertExpectationsForObjects_Helper_Failed", 3).Return()
mockedService1.Called(1)
mockedService3.Called(3)
tt := new(testing.T)
assert.False(t, AssertExpectationsForObjects(tt, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
}
func Test_Mock_AssertExpectations(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertExpectations", 1, 2, 3).Return(5, 6, 7)
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.Called(1, 2, 3)
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.TheExampleMethod3(&ExampleType{})
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertExpectations_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Twice()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.Called(1, 2, 3)
assert.False(t, mockedService.AssertExpectations(tt))
mockedService.Called(1, 2, 3)
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 1, 2, 3).Return(5, 6, 7)
mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 4, 5, 6).Return(5, 6, 7)
args1 := mockedService.Called(1, 2, 3)
assert.Equal(t, 5, args1.Int(0))
assert.Equal(t, 6, args1.Int(1))
assert.Equal(t, 7, args1.Int(2))
args2 := mockedService.Called(4, 5, 6)
assert.Equal(t, 5, args2.Int(0))
assert.Equal(t, 6, args2.Int(1))
assert.Equal(t, 7, args2.Int(2))
}
func Test_Mock_AssertNumberOfCalls(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertNumberOfCalls", 1, 2, 3).Return(5, 6, 7)
mockedService.Called(1, 2, 3)
assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 1))
mockedService.Called(1, 2, 3)
assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 2))
}
func Test_Mock_AssertCalled(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertCalled", 1, 2, 3).Return(5, 6, 7)
mockedService.Called(1, 2, 3)
assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled", 1, 2, 3))
}
func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything).Return()
mockedService.Called(1, "two", []uint8("three"))
assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled_WithAnythingOfTypeArgument", AnythingOfType("int"), AnythingOfType("string"), AnythingOfType("[]uint8")))
}
func Test_Mock_AssertCalled_WithArguments(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertCalled_WithArguments", 1, 2, 3).Return(5, 6, 7)
mockedService.Called(1, 2, 3)
tt := new(testing.T)
assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 1, 2, 3))
assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 2, 3, 4))
}
func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Once()
mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4).Return(5, 6, 7).Once()
mockedService.Called(1, 2, 3)
mockedService.Called(2, 3, 4)
tt := new(testing.T)
assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3))
assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4))
assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 3, 4, 5))
}
func Test_Mock_AssertNotCalled(t *testing.T) {
var mockedService *TestExampleImplementation = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertNotCalled", 1, 2, 3).Return(5, 6, 7)
mockedService.Called(1, 2, 3)
assert.True(t, mockedService.AssertNotCalled(t, "Test_Mock_NotCalled"))
}
/*
Arguments helper methods
*/
func Test_Arguments_Get(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.Equal(t, "string", args.Get(0).(string))
assert.Equal(t, 123, args.Get(1).(int))
assert.Equal(t, true, args.Get(2).(bool))
}
func Test_Arguments_Is(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.True(t, args.Is("string", 123, true))
assert.False(t, args.Is("wrong", 456, false))
}
func Test_Arguments_Diff(t *testing.T) {
var args Arguments = []interface{}{"Hello World", 123, true}
var diff string
var count int
diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
assert.Equal(t, 2, count)
assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`)
assert.Contains(t, diff, `false != %!s(bool=true)`)
}
func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
var diff string
var count int
diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
assert.Equal(t, 3, count)
assert.Contains(t, diff, `extra != (Missing)`)
}
func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
var count int
_, count = args.Diff([]interface{}{"string", Anything, true})
assert.Equal(t, 0, count)
}
func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) {
var args Arguments = []interface{}{"string", Anything, true}
var count int
_, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 0, count)
}
func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) {
var args Arguments = []interface{}{"string", AnythingOfType("int"), true}
var count int
_, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 0, count)
}
func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
var args Arguments = []interface{}{"string", AnythingOfType("string"), true}
var count int
var diff string
diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 1, count)
assert.Contains(t, diff, `string != type int - %!s(int=123)`)
}
func Test_Arguments_Assert(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.True(t, args.Assert(t, "string", 123, true))
}
func Test_Arguments_String_Representation(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.Equal(t, `string,int,bool`, args.String())
}
func Test_Arguments_String(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.Equal(t, "string", args.String(0))
}
func Test_Arguments_Error(t *testing.T) {
var err error = errors.New("An Error")
var args Arguments = []interface{}{"string", 123, true, err}
assert.Equal(t, err, args.Error(3))
}
func Test_Arguments_Error_Nil(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true, nil}
assert.Equal(t, nil, args.Error(3))
}
func Test_Arguments_Int(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.Equal(t, 123, args.Int(1))
}
func Test_Arguments_Bool(t *testing.T) {
var args Arguments = []interface{}{"string", 123, true}
assert.Equal(t, true, args.Bool(2))
}