diff options
| author | Teddy Wing | 2015-06-06 19:25:17 -0400 |
|---|---|---|
| committer | Teddy Wing | 2015-06-06 19:25:17 -0400 |
| commit | 1135764727f3dc525d0f674c784edbc81cc786f3 (patch) | |
| tree | 5c402c88d3a07a3cde84237ead5829bda28f3e25 /vendor/_nuts/github.com | |
| download | New-House-on-the-Block-1135764727f3dc525d0f674c784edbc81cc786f3.tar.bz2 | |
Initial commit. Install coinbase-go.
* Use nut for vendored dependencies
* Install coinbase-go to interact with the Coinbase API
Diffstat (limited to 'vendor/_nuts/github.com')
105 files changed, 16646 insertions, 0 deletions
diff --git a/vendor/_nuts/github.com/codegangsta/inject/.gitignore b/vendor/_nuts/github.com/codegangsta/inject/.gitignore new file mode 100644 index 0000000..df3df8a --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/.gitignore @@ -0,0 +1,2 @@ +inject +inject.test diff --git a/vendor/_nuts/github.com/codegangsta/inject/LICENSE b/vendor/_nuts/github.com/codegangsta/inject/LICENSE new file mode 100644 index 0000000..eb68a0e --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jeremy Saenz + +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. diff --git a/vendor/_nuts/github.com/codegangsta/inject/README.md b/vendor/_nuts/github.com/codegangsta/inject/README.md new file mode 100644 index 0000000..679abe0 --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/README.md @@ -0,0 +1,92 @@ +# inject +-- + import "github.com/codegangsta/inject" + +Package inject provides utilities for mapping and injecting dependencies in +various ways. + +Language Translations: +* [简体中文](translations/README_zh_cn.md) + +## Usage + +#### func InterfaceOf + +```go +func InterfaceOf(value interface{}) reflect.Type +``` +InterfaceOf dereferences a pointer to an Interface type. It panics if value is +not an pointer to an interface. + +#### type Applicator + +```go +type Applicator interface { + // Maps dependencies in the Type map to each field in the struct + // that is tagged with 'inject'. Returns an error if the injection + // fails. + Apply(interface{}) error +} +``` + +Applicator represents an interface for mapping dependencies to a struct. + +#### type Injector + +```go +type Injector interface { + Applicator + Invoker + TypeMapper + // SetParent sets the parent of the injector. If the injector cannot find a + // dependency in its Type map it will check its parent before returning an + // error. + SetParent(Injector) +} +``` + +Injector represents an interface for mapping and injecting dependencies into +structs and function arguments. + +#### func New + +```go +func New() Injector +``` +New returns a new Injector. + +#### type Invoker + +```go +type Invoker interface { + // Invoke attempts to call the interface{} provided as a function, + // providing dependencies for function arguments based on Type. Returns + // a slice of reflect.Value representing the returned values of the function. + // Returns an error if the injection fails. + Invoke(interface{}) ([]reflect.Value, error) +} +``` + +Invoker represents an interface for calling functions via reflection. + +#### type TypeMapper + +```go +type TypeMapper interface { + // Maps the interface{} value based on its immediate type from reflect.TypeOf. + Map(interface{}) TypeMapper + // Maps the interface{} value based on the pointer of an Interface provided. + // This is really only useful for mapping a value as an interface, as interfaces + // cannot at this time be referenced directly without a pointer. + MapTo(interface{}, interface{}) TypeMapper + // Provides a possibility to directly insert a mapping based on type and value. + // This makes it possible to directly map type arguments not possible to instantiate + // with reflect like unidirectional channels. + Set(reflect.Type, reflect.Value) TypeMapper + // Returns the Value that is mapped to the current type. Returns a zeroed Value if + // the Type has not been mapped. + Get(reflect.Type) reflect.Value +} +``` + +TypeMapper represents an interface for mapping interface{} values based on type. diff --git a/vendor/_nuts/github.com/codegangsta/inject/inject.go b/vendor/_nuts/github.com/codegangsta/inject/inject.go new file mode 100644 index 0000000..3ff713c --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/inject.go @@ -0,0 +1,187 @@ +// Package inject provides utilities for mapping and injecting dependencies in various ways. +package inject + +import ( + "fmt" + "reflect" +) + +// Injector represents an interface for mapping and injecting dependencies into structs +// and function arguments. +type Injector interface { + Applicator + Invoker + TypeMapper + // SetParent sets the parent of the injector. If the injector cannot find a + // dependency in its Type map it will check its parent before returning an + // error. + SetParent(Injector) +} + +// Applicator represents an interface for mapping dependencies to a struct. +type Applicator interface { + // Maps dependencies in the Type map to each field in the struct + // that is tagged with 'inject'. Returns an error if the injection + // fails. + Apply(interface{}) error +} + +// Invoker represents an interface for calling functions via reflection. +type Invoker interface { + // Invoke attempts to call the interface{} provided as a function, + // providing dependencies for function arguments based on Type. Returns + // a slice of reflect.Value representing the returned values of the function. + // Returns an error if the injection fails. + Invoke(interface{}) ([]reflect.Value, error) +} + +// TypeMapper represents an interface for mapping interface{} values based on type. +type TypeMapper interface { + // Maps the interface{} value based on its immediate type from reflect.TypeOf. + Map(interface{}) TypeMapper + // Maps the interface{} value based on the pointer of an Interface provided. + // This is really only useful for mapping a value as an interface, as interfaces + // cannot at this time be referenced directly without a pointer. + MapTo(interface{}, interface{}) TypeMapper + // Provides a possibility to directly insert a mapping based on type and value. + // This makes it possible to directly map type arguments not possible to instantiate + // with reflect like unidirectional channels. + Set(reflect.Type, reflect.Value) TypeMapper + // Returns the Value that is mapped to the current type. Returns a zeroed Value if + // the Type has not been mapped. + Get(reflect.Type) reflect.Value +} + +type injector struct { + values map[reflect.Type]reflect.Value + parent Injector +} + +// InterfaceOf dereferences a pointer to an Interface type. +// It panics if value is not an pointer to an interface. +func InterfaceOf(value interface{}) reflect.Type { + t := reflect.TypeOf(value) + + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + if t.Kind() != reflect.Interface { + panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)") + } + + return t +} + +// New returns a new Injector. +func New() Injector { + return &injector{ + values: make(map[reflect.Type]reflect.Value), + } +} + +// Invoke attempts to call the interface{} provided as a function, +// providing dependencies for function arguments based on Type. +// Returns a slice of reflect.Value representing the returned values of the function. +// Returns an error if the injection fails. +// It panics if f is not a function +func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) { + t := reflect.TypeOf(f) + + var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func + for i := 0; i < t.NumIn(); i++ { + argType := t.In(i) + val := inj.Get(argType) + if !val.IsValid() { + return nil, fmt.Errorf("Value not found for type %v", argType) + } + + in[i] = val + } + + return reflect.ValueOf(f).Call(in), nil +} + +// Maps dependencies in the Type map to each field in the struct +// that is tagged with 'inject'. +// Returns an error if the injection fails. +func (inj *injector) Apply(val interface{}) error { + v := reflect.ValueOf(val) + + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + return nil // Should not panic here ? + } + + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + structField := t.Field(i) + if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") { + ft := f.Type() + v := inj.Get(ft) + if !v.IsValid() { + return fmt.Errorf("Value not found for type %v", ft) + } + + f.Set(v) + } + + } + + return nil +} + +// Maps the concrete value of val to its dynamic type using reflect.TypeOf, +// It returns the TypeMapper registered in. +func (i *injector) Map(val interface{}) TypeMapper { + i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) + return i +} + +func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { + i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) + return i +} + +// Maps the given reflect.Type to the given reflect.Value and returns +// the Typemapper the mapping has been registered in. +func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper { + i.values[typ] = val + return i +} + +func (i *injector) Get(t reflect.Type) reflect.Value { + val := i.values[t] + + if val.IsValid() { + return val + } + + // no concrete types found, try to find implementors + // if t is an interface + if t.Kind() == reflect.Interface { + for k, v := range i.values { + if k.Implements(t) { + val = v + break + } + } + } + + // Still no type found, try to look it up on the parent + if !val.IsValid() && i.parent != nil { + val = i.parent.Get(t) + } + + return val + +} + +func (i *injector) SetParent(parent Injector) { + i.parent = parent +} diff --git a/vendor/_nuts/github.com/codegangsta/inject/inject_test.go b/vendor/_nuts/github.com/codegangsta/inject/inject_test.go new file mode 100644 index 0000000..4b315b8 --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/inject_test.go @@ -0,0 +1,159 @@ +package inject_test + +import ( + "fmt" + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/codegangsta/inject" + "reflect" + "testing" +) + +type SpecialString interface { +} + +type TestStruct struct { + Dep1 string `inject:"t" json:"-"` + Dep2 SpecialString `inject` + Dep3 string +} + +type Greeter struct { + Name string +} + +func (g *Greeter) String() string { + return "Hello, My name is" + g.Name +} + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if a != b { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func Test_InjectorInvoke(t *testing.T) { + injector := inject.New() + expect(t, injector == nil, false) + + dep := "some dependency" + injector.Map(dep) + dep2 := "another dep" + injector.MapTo(dep2, (*SpecialString)(nil)) + dep3 := make(chan *SpecialString) + dep4 := make(chan *SpecialString) + typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem()) + typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem()) + injector.Set(typRecv, reflect.ValueOf(dep3)) + injector.Set(typSend, reflect.ValueOf(dep4)) + + _, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) { + expect(t, d1, dep) + expect(t, d2, dep2) + expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem()) + expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem()) + expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir) + expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir) + }) + + expect(t, err, nil) +} + +func Test_InjectorInvokeReturnValues(t *testing.T) { + injector := inject.New() + expect(t, injector == nil, false) + + dep := "some dependency" + injector.Map(dep) + dep2 := "another dep" + injector.MapTo(dep2, (*SpecialString)(nil)) + + result, err := injector.Invoke(func(d1 string, d2 SpecialString) string { + expect(t, d1, dep) + expect(t, d2, dep2) + return "Hello world" + }) + + expect(t, result[0].String(), "Hello world") + expect(t, err, nil) +} + +func Test_InjectorApply(t *testing.T) { + injector := inject.New() + + injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil)) + + s := TestStruct{} + err := injector.Apply(&s) + expect(t, err, nil) + + expect(t, s.Dep1, "a dep") + expect(t, s.Dep2, "another dep") + expect(t, s.Dep3, "") +} + +func Test_InterfaceOf(t *testing.T) { + iType := inject.InterfaceOf((*SpecialString)(nil)) + expect(t, iType.Kind(), reflect.Interface) + + iType = inject.InterfaceOf((**SpecialString)(nil)) + expect(t, iType.Kind(), reflect.Interface) + + // Expecting nil + defer func() { + rec := recover() + refute(t, rec, nil) + }() + iType = inject.InterfaceOf((*testing.T)(nil)) +} + +func Test_InjectorSet(t *testing.T) { + injector := inject.New() + typ := reflect.TypeOf("string") + typSend := reflect.ChanOf(reflect.SendDir, typ) + typRecv := reflect.ChanOf(reflect.RecvDir, typ) + + // instantiating unidirectional channels is not possible using reflect + // http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064 + chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0) + chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0) + + injector.Set(typSend, chanSend) + injector.Set(typRecv, chanRecv) + + expect(t, injector.Get(typSend).IsValid(), true) + expect(t, injector.Get(typRecv).IsValid(), true) + expect(t, injector.Get(chanSend.Type()).IsValid(), false) +} + +func Test_InjectorGet(t *testing.T) { + injector := inject.New() + + injector.Map("some dependency") + + expect(t, injector.Get(reflect.TypeOf("string")).IsValid(), true) + expect(t, injector.Get(reflect.TypeOf(11)).IsValid(), false) +} + +func Test_InjectorSetParent(t *testing.T) { + injector := inject.New() + injector.MapTo("another dep", (*SpecialString)(nil)) + + injector2 := inject.New() + injector2.SetParent(injector) + + expect(t, injector2.Get(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true) +} + +func TestInjectImplementors(t *testing.T) { + injector := inject.New() + g := &Greeter{"Jeremy"} + injector.Map(g) + + expect(t, injector.Get(inject.InterfaceOf((*fmt.Stringer)(nil))).IsValid(), true) +} diff --git a/vendor/_nuts/github.com/codegangsta/inject/translations/README_zh_cn.md b/vendor/_nuts/github.com/codegangsta/inject/translations/README_zh_cn.md new file mode 100644 index 0000000..0ac3d3f --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/translations/README_zh_cn.md @@ -0,0 +1,85 @@ +# inject +-- + import "github.com/codegangsta/inject" + +inject包提供了多种对实体的映射和依赖注入方式。 + +## 用法 + +#### func InterfaceOf + +```go +func InterfaceOf(value interface{}) reflect.Type +``` +函数InterfaceOf返回指向接口类型的指针。如果传入的value值不是指向接口的指针,将抛出一个panic异常。 + +#### type Applicator + +```go +type Applicator interface { + // 在Type map中维持对结构体中每个域的引用并用'inject'来标记 + // 如果注入失败将会返回一个error. + Apply(interface{}) error +} +``` + +Applicator接口表示到结构体的依赖映射关系。 + +#### type Injector + +```go +type Injector interface { + Applicator + Invoker + TypeMapper + // SetParent用来设置父injector. 如果在当前injector的Type map中找不到依赖, + // 将会继续从它的父injector中找,直到返回error. + SetParent(Injector) +} +``` + +Injector接口表示对结构体、函数参数的映射和依赖注入。 + +#### func New + +```go +func New() Injector +``` +New创建并返回一个Injector. + +#### type Invoker + +```go +type Invoker interface { + // Invoke尝试将interface{}作为一个函数来调用,并基于Type为函数提供参数。 + // 它将返回reflect.Value的切片,其中存放原函数的返回值。 + // 如果注入失败则返回error. + Invoke(interface{}) ([]reflect.Value, error) +} +``` + +Invoker接口表示通过反射进行函数调用。 + +#### type TypeMapper + +```go +type TypeMapper interface { + // 基于调用reflect.TypeOf得到的类型映射interface{}的值。 + Map(interface{}) TypeMapper + // 基于提供的接口的指针映射interface{}的值。 + // 该函数仅用来将一个值映射为接口,因为接口无法不通过指针而直接引用到。 + MapTo(interface{}, interface{}) TypeMapper + // 为直接插入基于类型和值的map提供一种可能性。 + // 它使得这一类直接映射成为可能:无法通过反射直接实例化的类型参数,如单向管道。 + Set(reflect.Type, reflect.Value) TypeMapper + // 返回映射到当前类型的Value. 如果Type没被映射,将返回对应的零值。 + Get(reflect.Type) reflect.Value +} +``` + +TypeMapper接口用来表示基于类型到接口值的映射。 + + +## 译者 + +张强 (qqbunny@yeah.net)
\ No newline at end of file diff --git a/vendor/_nuts/github.com/codegangsta/inject/update_readme.sh b/vendor/_nuts/github.com/codegangsta/inject/update_readme.sh new file mode 100644 index 0000000..497f9a5 --- /dev/null +++ b/vendor/_nuts/github.com/codegangsta/inject/update_readme.sh @@ -0,0 +1,3 @@ +#!/bin/bash +go get github.com/robertkrimen/godocdown/godocdown +godocdown > README.md diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/Authenticator.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/Authenticator.go new file mode 100644 index 0000000..f5b68ea --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/Authenticator.go @@ -0,0 +1,13 @@ +package coinbase + +import ( + "net/http" +) + +// Authenticator is an interface that objects can implement in order to act as the +// authentication mechanism for RPC requests to Coinbase +type authenticator interface { + getBaseUrl() string + getClient() *http.Client + authenticate(req *http.Request, endpoint string, params []byte) error +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/README.md b/vendor/_nuts/github.com/fabioberger/coinbase-go/README.md new file mode 100644 index 0000000..e301cf0 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/README.md @@ -0,0 +1,527 @@ +[](https://godoc.org/github.com/fabioberger/coinbase-go) + +# Coinbase Go Client Library + +An easy way to buy, send, and accept [bitcoin](http://en.wikipedia.org/wiki/Bitcoin) through the [Coinbase API](https://coinbase.com/docs/api/overview). + +This library supports both the [API key authentication method](https://coinbase.com/docs/api/overview) and OAuth. The below examples use an API key - for instructions on how to use OAuth, see [OAuth Authentication](#oauth-authentication). + +A detailed step-by-step tutorial on how to use this library can be found at [this blog](http://fabioberger.com/blog/2014/11/06/building-a-coinbase-app-in-go/). + +## Installation + +Make sure you have set the environment variable $GOPATH + +```bash +export GOPATH="path/to/your/go/folder" +``` + +Obtain the latest version of the Coinbase Go library with: + +```bash +go get github.com/fabioberger/coinbase-go +``` + +Then, add the following to your Go project: + +```go +import ( + "github.com/fabioberger/coinbase-go" +) +``` + +## Usage + +Start by [enabling an API Key on your account](https://coinbase.com/settings/api). + +Next, create an instance of the client using the `ApiKeyClient` method: + +```go +c := coinbase.ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) +``` + +Notice here that we did not hard code the API key into our codebase, but set it in an environment variable instead. This is just one example, but keeping your credentials separate from your code base is a good [security practice](https://coinbase.com/docs/api/overview#security). Here is a [step-by-step guide](http://fabioberger.com/blog/2014/11/06/building-a-coinbase-app-in-go/#env) on how to add these environment variables to your shell config file. + +Now you can call methods on `c` similar to the ones described in the [API reference](https://coinbase.com/api/doc). For example: + +```go +balance, err := c.GetBalance() +if err != nil { + log.Fatal(err) +} +fmt.Printf("Balance is %f BTC", balance) +``` + +A working API key example is available in example/ApiKeyExample.go. To run it, execute: + +`go run ./example/ApiKeyExample.go` + +## Error Handling + +All errors generated at runtime will be returned to the calling client method. Any API request for which Coinbase returns an error encoded in a JSON response will be parsed and returned by the client method as a Golang error struct. Lastly, it is important to note that for HTTP requests, if the response code returned is not '200 OK', an error will be returned to the client method detailing the response code that was received. + +## Examples + +### Get user information + +```go +user, err := c.GetUser() +if err != nil { + log.Fatal(err) +} +fmt.Println(user.Name) +// 'User One' +fmt.Println(user.Email) +// 'user1@example.com' +``` + +### Check your balance + +```go +amount, err := c.GetBalance() +if err != nil { + log.Fatal(err) +} +fmt.Printf("Balance is %f BTC", amount) +// 'Balance is 24.229801 BTC' +``` + +### Send bitcoin + +`func (c Client) SendMoney(params *TransactionParams) (*transactionConfirmation, error) ` + +```go +params := &coinbase.TransactionParams{ + To: "1HHNtsSVWuJXzTZrAmq71busSKLHzgm4Wb", + Amount: "0.0026", + Notes: "Thanks for the coffee!", + } +confirmation, err := c.SendMoney(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(confirmation.Transaction.Status) +// 'pending' +fmt.Println(confirmation.Transaction.Id) +// '518d8567ed3ddcd4fd000034' +``` + +The "To" parameter can also be a bitcoin address and the "Notes" parameter can be a note or description of the transaction. Descriptions are only visible on Coinbase (not on the general bitcoin network). + +You can also send money in a number of currencies (see `GetCurrencies()`). The amount will be automatically converted to the correct BTC amount using the current exchange rate. + +All possible transaction parameters are detailed below: + +```go +type TransactionParams struct { + To string + From string + Amount string + AmountString string + AmountCurrencyIso string + Notes string + UserFee string + ReferrerId string + Idem string + InstantBuy bool + OrderId string +} +``` +Note that parameters are equivalent to those of the coinbase API except in camelcase rather then with underscores between words (Golang standard). This can also be assumed for accessing return values. For detailed information on each parameter, check out the ['send_money' documentation](https://www.coinbase.com/api/doc/1.0/transactions/send_money.html) + +### Request bitcoin + +This will send an email to the recipient, requesting payment, and give them an easy way to pay. + +```go +params := &coinbase.TransactionParams{ + From: "client@example.com", //Who are you requesting Bitcoins from + Amount: "2.5", + Notes: "contractor hours in January (website redesign for 50 BTC)", +} +confirmation, err := c.RequestMoney(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(confirmation.Transaction.Request) +// 'true' +fmt.Println(confirmation.Transaction.Id) +// '518d8567ed3ddcd4fd000034' + + +success, err := c.ResendRequest("501a3554f8182b2754000003") +if err != nil { + log.Fatal(err) +} +fmt.Println(success) +// 'true' + + +success, err := c.CancelRequest("501a3554f8182b2754000003") +if err != nil { + log.Fatal(err) +} +fmt.Println(success) +// 'true' + + +// From the other account: +success, err := c.CompleteRequest("501a3554f8182b2754000003") +if err != nil { + log.Fatal(err) +} +fmt.Println(success) +// 'true' +``` + +### List your current transactions + +Sorted in descending order by timestamp, 30 per page. You can pass an integer as the first param to page through results, for example `c.GetTransactions(2)` would grab the second page. + +```go +response, err := c.GetTransactions(1) +if err != nil { + log.Fatal(err) +} +fmt.Println(response.CurrentPage) +// '1' +fmt.Println(response.NumPages) +// '2' +fmt.Println(response.Transactions[0].Id) +// '5018f833f8182b129c00002f' +``` + +Transactions will always have an `id` attribute which is the primary way to identity them through the Coinbase api. They will also have a `hsh` (bitcoin hash) attribute once they've been broadcast to the network (usually within a few seconds). + +### Check bitcoin prices + +Check the buy or sell price by passing a `quantity` of bitcoin that you'd like to buy or sell. The price can be given with or without the Coinbase's fee of 1% and the bank transfer fee of $0.15. + +```go +price, err := c.GetBuyPrice(1) +if err != nil { + log.Fatal(err) +} +fmt.Println(price.Subtotal.Amount) // Subtotal does not include fees +// '303.00' +fmt.Println(price.Total.Amount) // Total includes coinbase & bank fee +// '306.18' + +price, err = c.GetSellPrice(1) +if err != nil { + log.Fatal(err) +} +fmt.Println(price.Subtotal.Amount) // Subtotal is current market price +// '9.90' +fmt.Println(price.Total.Amount) // Total is amount you will receive (after fees) +// '9.65' +``` + +### Buy or sell bitcoin + +Buying and selling bitcoin requires you to [link and verify a bank account](https://coinbase.com/payment_methods) through the web interface first. + +Then you can call `buy` or `sell` and pass a `quantity` of bitcoin you want to buy. + +On a buy, coinbase will debit your bank account and the bitcoin will arrive in your Coinbase account four business days later (this is shown as the `payoutDate` below). This is how long it takes for the bank transfer to complete and verify, although they are working on shortening this window. In some cases, they may not be able to guarantee a price, and buy requests will fail. In that case, set the second parameter (`agreeBtcAmountVaries`) to true in order to purchase bitcoin at the future market price when your money arrives. + +On a sell they will credit your bank account in a similar way and it will arrive within two business days. + + func (c Client) Buy(amount float64, agreeBtcAmountVaries bool) (*transfer, error) + +```go +transfer, err := c.Buy(1.0, true) +if err != nil { + log.Fatal(err) +} +fmt.Println(transfer.Code) +// '6H7GYLXZ' +fmt.Println(transfer.Btc.Amount) +// '1.00000000' +fmt.Println(transfer.Total.Amount) +// '$361.55' +fmt.Println(transfer.PayoutDate) +// '2013-02-01T18:00:00-08:00' (ISO 8601 format - can be parsed with time.Parse(transfer.PayoutDate, "2013-06-05T14:10:43.678Z")) +``` + +```go +transfer, err := c.Sell(1.0, true) +if err != nil { + log.Fatal(err) +} +fmt.Println(transfer.Code) +// '6H7GYLXZ' +fmt.Println(transfer.Btc.Amount) +// '1.00000000' +fmt.Println(transfer.Total.Amount) +// '$361.55' +fmt.Println(transfer.PayoutDate) +// '2013-02-01T18:00:00-08:00' (ISO 8601 format - can be parsed with time.Parse(transfer.PayoutDate, "2013-06-05T14:10:43.678Z")) +``` + +### Create a payment button + +This will create the code for a payment button (and modal window) that you can use to accept bitcoin on your website. You can read [more about payment buttons here and try a demo](https://coinbase.com/docs/merchant_tools/payment_buttons). + +The allowed ButtonParams are: + +```go +type Button struct { + Name string + PriceString string + PriceCurrencyIso string + Type string + Subscription bool + Repeat string + Style string + Text string + Description string + Custom string + CustomSecure bool + CallbackUrl string + SuccessUrl string + CancelUrl string + InfoUrl string + AutoRedirect bool + AutoRedirectSuccess bool + AutoRedirectCancel bool + VariablePrice bool + ChoosePrice bool + IncludeAddress bool + IncludeEmail bool + Price1 string + Price2 string + Price3 string + Price4 string + Price5 string +} +``` +The `custom` param will get passed through in [callbacks](https://coinbase.com/docs/merchant_tools/callbacks) to your site. The list of valid `options` [are described here](https://coinbase.com/api/doc/1.0/buttons/create.html). + +For detailed information on each parameter, check out the ['buttons' documentation](https://www.coinbase.com/api/doc/1.0/buttons/create.html) + +```go +params := &coinbase.Button{ + Name: "test", + Type: "buy_now", + Subscription: false, + PriceString: "1.23", + PriceCurrencyIso: "USD", + Custom: "Order123", + CallbackUrl: "http://www.example.com/my_custom_button_callback", + Description: "Sample Description", + Style: "custom_large", + IncludeEmail: true, + } +button, err := c.CreateButton(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(button.Code) +// '93865b9cae83706ae59220c013bc0afd' +fmt.Println(button.EmbedHtml) +// '<div class=\"coinbase-button\" data-code=\"93865b9cae83706ae59220c013bc0afd\"></div><script src=\"https://coinbase.com/assets/button.js\" type=\"text/javascript\"></script>' +``` + +### Exchange rates and currency utilities + +You can fetch a list of all supported currencies and ISO codes with the `GetCurrencies()` method. + +```go +currencies, err := c.GetCurrencies() +if err != nil { + log.Fatal() +} +fmt.Println(currencies[0].Name) +// 'Afghan Afghani (AFN)' +``` + +`GetExchangeRates()` will return a list of exchange rates. + +```go +exchanges, err := c.GetExchangeRates() +if err != nil { + log.Fatal(err) +} +fmt.Println(exchanges["btc_to_cad"]) +// '117.13892' +``` + +`GetExchangeRate(from string, to string)` will return a single exchange rate + +```go +exchange, err := c.GetExchangeRate("btc", "usd") +if err != nil { + log.Fatal(err) +} +fmt.Println(exchange) +// 117.13892 +``` + +### Create a new user + +```go +user, err := c.CreateUser("test@email.com", "password") +if err != nil { + log.Fatal(err) +} +fmt.Println(user.Email) +// 'newuser@example.com' +fmt.Println(user.ReceiveAddress) +// 'mpJKwdmJKYjiyfNo26eRp4j6qGwuUUnw9x' +``` + +A receive address is returned also in case you need to send the new user a payment right away. + +### Get autocomplete contacts + +This will return a list of contacts the user has previously sent to or received from. Useful for auto completion. By default, 30 contacts are returned at a time; use the `$page` and `$limit` parameters to adjust how pagination works. + +The allowed ContactsParams are: + +```go +type ContactsParams struct { + Page int + Limit int + Query string +} +``` + +```go +params := &coinbase.ContactsParams{ + Page: 1, + Limit: 5, + Query: "user", +} +contacts, err := c.GetContacts(params) +if err != nil { + log.Fatal(err) +} +fmt.Println(strings.Join(contacts.Emails, ",")) +// 'user1@example.com, user2@example.com' +``` + +## Adding new methods + +You can see a [list of method calls here](https://github.com/fabioberger/coinbase-go/blob/master/coinbase.go) and how they are implemented. They are all wrappers around the [Coinbase JSON API](https://coinbase.com/api/doc). + +If there are any methods listed in the [API Reference](https://coinbase.com/api/doc) that don't have an explicit function name in the library, you can also call `Get`, `Post`, `Put`, or `Delete` with a `path`, `params` and holder struct for a quick implementation. Holder should be a pointer to some data structure that correctly reflects the structure of the returned JSON response. The library will attempt to unmarshal the response from the server into holder. For example: + +```go +balance := map[string]string{} // Holder struct depends on JSON format returned from API +if err := c.Get("account/balance", nil, &balance); err != nil { + log.Fatal(err) +} +fmt.Println(balance) +// map[amount:36.62800000 currency:BTC] +``` + +Or feel free to add a new wrapper method and submit a pull request. + +# OAuth Authentication + +For an indepth tutorial on how to implement OAuth Authentication, visit this [step-by-step tutorial](http://fabioberger.com/blog/2014/11/06/building-a-coinbase-app-in-go/#oauth). + +## Higher Level Overview + +To authenticate with OAuth, first create an OAuth application at [https://coinbase.com/oauth/applications](https://coinbase.com/oauth/applications). +When a user wishes to connect their Coinbase account, redirect them to a URL created with `func (o OAuth) CreateAuthorizeUrl(scope []string) string`: + +```go +o, err := coinbase.OAuthService(YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL) +if err != nil { + log.Fatal(err) +} +scope := []string{"all",} +header("Location: " . o.CreateAuthorizeUrl(scope)); +``` + +After the user has authorized your application, they will be redirected back to the redirect URL specified above. A `code` parameter will be included - pass this into `GetTokens` to receive a set of tokens: + +```go +query := req.URL.Query() +code := query.Get("code") +tokens, err := o.GetTokens(code, "authorization_code") +if err != nil { + log.Fatal(err) +} +``` + +Store these tokens safely, and use them to make Coinbase API requests in the future. For example: + +```go +c := coinbase.OAuthClient(tokens) +amount, err := c.GetBalance() +if err != nil { + log.Fatal(err) +} +``` + +A full example implementation is available in the `example` directory. In order to run this example implementation, you will need to install the following dependency: + +```bash +go get github.com/go-martini/martini +``` + +You will also need to set your coinbase application client_id and client_secret as environment variables by adding these environment variables to your bash config file (i.e ~/.bashrc, ~/.bash_profile, etc...) and reload them: + +```bash +export COINBASE_CLIENT_ID="YOUR_CLIENT_ID" +``` +```bash +export COINBASE_CLIENT_SECRET="YOUR_CLIENT_SECRET" +``` + +```bash +source ~/.bash_profile +``` + +The last step we need to take is to generate a cert and key pair in order to run our OAuth server over SSL. To do this, run the following command from within the example directory: + +```bash +go run $(go env GOROOT)/src/pkg/crypto/tls/generate_cert.go --host="localhost" +``` + +Once you have done this, run the example: + +```bash +go run OAuthExample.go +``` + + +## Security notes + +If someone gains access to your API Key they will have complete control of your Coinbase account. This includes the abillity to send all of your bitcoins elsewhere. + +For this reason, API access is disabled on all Coinbase accounts by default. If you decide to enable API key access you should take precautions to store your API key securely in your application. How to do this is application specific, but it's something you should [research](http://programmers.stackexchange.com/questions/65601/is-it-smart-to-store-application-keys-ids-etc-directly-inside-an-application) if you have never done this before. + +## Testing + +In order to run the tests for this library, you will first need to install the Testify/Assert dependency with the following command: + + ```bash + go get github.com/stretchr/testify/assert + ``` + +Then run all tests by executing the following in your command line: + + go test . -v + + +For environment specific test use : + +Endpoint(Live) : + + go test . -v -test.run=TestEndpoint + +Sandbox : + + go test . -v -test.run=TestSandbox + +Mock : + + go test . -v -test.run=TestMock + + + + diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/api_key_authentication.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/api_key_authentication.go new file mode 100644 index 0000000..534e2dd --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/api_key_authentication.go @@ -0,0 +1,74 @@ +package coinbase + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "net/http" + "strconv" + "time" +) + +// ApiKeyAuthentication Struct implements the Authentication interface and takes +// care of authenticating RPC requests for clients with a Key & Secret pair +type apiKeyAuthentication struct { + Key string + Secret string + BaseUrl string + Client http.Client +} + +// ApiKeyAuthWithEnv instantiates ApiKeyAuthentication with the API key & secret & environment (Live or Sandbox) +func apiKeyAuthWithEnv(key string, secret string, sandbox bool) *apiKeyAuthentication { + baseUrl := "https://api.coinbase.com/v1/" // Live Url + + // Check if should use sandbox + if sandbox { + baseUrl = "https://api.sandbox.coinbase.com/v1/" // Sandbox Url + } + a := apiKeyAuthentication{ + Key: key, + Secret: secret, + BaseUrl: baseUrl, + Client: http.Client{ + Transport: &http.Transport{ + Dial: dialTimeout, + }, + }, + } + return &a +} + +// ApiKeyAuth instantiates ApiKeyAuthentication with the API key & secret +// TODO: Maybe remove this (not sure if it would break backwards compatability) +func apiKeyAuth(key string, secret string) *apiKeyAuthentication { + return apiKeyAuthWithEnv(key, secret, false) +} + +// API Key + Secret authentication requires a request header of the HMAC SHA-256 +// signature of the "message" as well as an incrementing nonce and the API key +func (a apiKeyAuthentication) authenticate(req *http.Request, endpoint string, params []byte) error { + + nonce := strconv.FormatInt(time.Now().UTC().UnixNano(), 10) + message := nonce + endpoint + string(params) //As per Coinbase Documentation + + req.Header.Set("ACCESS_KEY", a.Key) + + h := hmac.New(sha256.New, []byte(a.Secret)) + h.Write([]byte(message)) + + signature := hex.EncodeToString(h.Sum(nil)) + + req.Header.Set("ACCESS_SIGNATURE", signature) + req.Header.Set("ACCESS_NONCE", nonce) + + return nil +} + +func (a apiKeyAuthentication) getBaseUrl() string { + return a.BaseUrl +} + +func (a apiKeyAuthentication) getClient() *http.Client { + return &a.Client +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/ca-coinbase.crt b/vendor/_nuts/github.com/fabioberger/coinbase-go/ca-coinbase.crt new file mode 100644 index 0000000..6a117f4 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/ca-coinbase.crt @@ -0,0 +1,629 @@ +## DigiCert High Assurance EV Root CA +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +## DigiCert Assured ID Root CA +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +## DigiCert Global Root CA +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +## DigiCert Assured ID Root G2 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +## DigiCert Assured ID Root G3 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +## DigiCert Global Root G2 +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +## DigiCert Global Root G3 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +## DigiCert Trusted Root G4 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA - G2 +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 +pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 +13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk +U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY +oJ2daZH9 +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i +2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ +2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ +-----END CERTIFICATE----- + +## VeriSign Class 3 Primary CA - G5 +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +## VeriSign Class 3 Public Primary CA - G4 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +## VeriSign Class 2 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy +aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp +Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp +Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g +Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU +J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO +JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY +wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o +koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN +qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E +Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe +xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u +7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI +sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP +cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- + +## VeriSign Class 2 Public Primary CA - G2 +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns +YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y +aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe +Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj +IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx +KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM +HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw +DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC +AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji +nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX +rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn +jBJ7xUS0rg== +-----END CERTIFICATE----- + +## VeriSign Class 1 Public Primary CA +-----BEGIN CERTIFICATE----- +MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 +NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD +VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp +bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N +H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR +4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN +BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo +EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 +FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx +lA== +-----END CERTIFICATE----- + +## VeriSign Class 1 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 +nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO +8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV +ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb +PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 +6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr +n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a +qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 +wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs +pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 +E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- + +## VeriSign Universal Root CA +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +## VeriSign Class 4 Public Primary CA - G3 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 +GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ ++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd +U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm +NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY +ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ +ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 +CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq +g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c +2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ +bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +## GeoTrust Global CA +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +## GeoTrust Primary Certification Authority +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +## GeoTrust Primary Certification Authority – G2 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +## GeoTrust Primary Certification Authority – G3 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +## GeoTrust Universal CA +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +## GeoTrust Global CA2 +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs +IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A +PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 +Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL +TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL +5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 +S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe +2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap +EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td +EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv +/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN +A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 +abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF +I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz +4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +## GeoTrust Universal CA2 +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/client_oauth_authentication.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/client_oauth_authentication.go new file mode 100644 index 0000000..b8f924c --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/client_oauth_authentication.go @@ -0,0 +1,60 @@ +package coinbase + +import ( + "errors" + "net/http" + "time" +) + +// ClientOAuthAuthentication Struct implements the Authentication interface +// and takes care of authenticating OAuth RPC requests on behalf of a client +// (i.e GetBalance()) +type clientOAuthAuthentication struct { + Tokens *oauthTokens + BaseUrl string + Client http.Client +} + +// ClientOAuth instantiates ClientOAuthAuthentication with the client OAuth tokens +func clientOAuth(tokens *oauthTokens) *clientOAuthAuthentication { + return clientOAuthWithEnv(tokens, false) +} + +// ClientOAuthWithEnv instantiates ClientOAuthAuthentication with the client OAuth tokens and the specified environment +func clientOAuthWithEnv(tokens *oauthTokens, sandbox bool) *clientOAuthAuthentication { + baseUrl := "https://api.coinbase.com/v1/" // Live Url + + // Check if should use sandbox + if sandbox { + baseUrl = "https://api.sandbox.coinbase.com/v1/" // Sandbox Url + } + a := clientOAuthAuthentication{ + Tokens: tokens, + BaseUrl: baseUrl, + Client: http.Client{ + Transport: &http.Transport{ + Dial: dialTimeout, + }, + }, + } + return &a +} + +// Client OAuth authentication requires us to attach an unexpired OAuth token to +// the request header +func (a clientOAuthAuthentication) authenticate(req *http.Request, endpoint string, params []byte) error { + // Ensure tokens havent expired + if time.Now().UTC().Unix() > a.Tokens.ExpireTime { + return errors.New("The OAuth tokens are expired. Use refreshTokens to refresh them") + } + req.Header.Set("Authorization", "Bearer "+a.Tokens.AccessToken) + return nil +} + +func (a clientOAuthAuthentication) getBaseUrl() string { + return a.BaseUrl +} + +func (a clientOAuthAuthentication) getClient() *http.Client { + return &a.Client +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/coinbase.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/coinbase.go new file mode 100644 index 0000000..2f5fdb9 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/coinbase.go @@ -0,0 +1,460 @@ +// Coinbase-go is a convenient Go wrapper for the Coinbase API +package coinbase + +import ( + "errors" + "strconv" + "strings" +) + +// Client is the struct from which all API requests are made +type Client struct { + rpc rpc +} + +// ApiKeyClient instantiates the client with ApiKey Authentication +func ApiKeyClient(key string, secret string) Client { + c := Client{ + rpc: rpc{ + auth: apiKeyAuthWithEnv(key, secret, false), + mock: false, + }, + } + return c +} + +// ApiKeyClientSandbox instantiates the client with ApiKey Authentication for Coinbase Sandbox +func ApiKeyClientSandbox(key string, secret string) Client { + c := Client{ + rpc: rpc{ + auth: apiKeyAuthWithEnv(key, secret, true), + mock: false, + }, + } + return c +} + +// OAuthClient instantiates the client with OAuth Authentication +func OAuthClient(tokens *oauthTokens) Client { + c := Client{ + rpc: rpc{ + auth: clientOAuthWithEnv(tokens, false), + mock: false, + }, + } + return c +} + +// OAuthClientSandbox instantiates the client with OAuth Authentication for Coinbase Sandbox +func OAuthClientSandbox(tokens *oauthTokens) Client { + c := Client{ + rpc: rpc{ + auth: clientOAuthWithEnv(tokens, true), + mock: false, + }, + } + return c +} + +// ApiKeyClientTest instantiates Testing ApiKeyClient. All client methods execute +// normally except responses are returned from a test_data/ file instead of the coinbase API +func apiKeyClientTest(key string, secret string) Client { + c := ApiKeyClient(key, secret) + c.rpc.mock = true + return c +} + +// Get sends a GET request and marshals response data into holder +func (c Client) Get(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("GET", path, params, &holder) +} + +// Post sends a POST request and marshals response data into holder +func (c Client) Post(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("POST", path, params, &holder) +} + +// Delete sends a DELETE request and marshals response data into holder +func (c Client) Delete(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("DELETE", path, params, &holder) +} + +// Put sends a PUT request and marshals response data into holder +func (c Client) Put(path string, params interface{}, holder interface{}) error { + return c.rpc.Request("PUT", path, params, &holder) +} + +// GetBalance returns current balance in BTC +func (c Client) GetBalance() (float64, error) { + balance := map[string]string{} + if err := c.Get("account/balance", nil, &balance); err != nil { + return 0.0, err + } + balanceFloat, err := strconv.ParseFloat(balance["amount"], 64) + if err != nil { + return 0, err + } + return balanceFloat, nil +} + +// GetReceiveAddress returns clients current bitcoin receive address +func (c Client) GetReceiveAddress() (string, error) { + holder := map[string]interface{}{} + if err := c.Get("account/receive_address", nil, &holder); err != nil { + return "", err + } + return holder["address"].(string), nil +} + +// GetAllAddresses returns bitcoin addresses associated with client account +func (c Client) GetAllAddresses(params *AddressesParams) (*addresses, error) { + holder := addressesHolder{} + if err := c.Get("addresses", params, &holder); err != nil { + return nil, err + } + addresses := addresses{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, addr := range holder.Addresses { + addresses.Addresses = append(addresses.Addresses, addr.Address) + } + return &addresses, nil +} + +// GenerateReceiveAddress generates and returns a new bitcoin receive address +func (c Client) GenerateReceiveAddress(params *AddressParams) (string, error) { + holder := map[string]interface{}{} + if err := c.Post("account/generate_receive_address", params, &holder); err != nil { + return "", err + } + return holder["address"].(string), nil +} + +// SendMoney to either a bitcoin or email address +func (c Client) SendMoney(params *TransactionParams) (*transactionConfirmation, error) { + return c.transactionRequest("POST", "send_money", params) +} + +// RequestMoney from either a bitcoin or email address +func (c Client) RequestMoney(params *TransactionParams) (*transactionConfirmation, error) { + return c.transactionRequest("POST", "request_money", params) +} + +func (c Client) transactionRequest(method string, kind string, params *TransactionParams) (*transactionConfirmation, error) { + finalParams := &struct { + Transaction *TransactionParams `json:"transaction"` + }{ + Transaction: params, + } + holder := transactionHolder{} + var err error + if method == "POST" { + err = c.Post("transactions/"+kind, finalParams, &holder) + } else if method == "PUT" { + err = c.Put("transactions/"+kind, finalParams, &holder) + } + if err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, kind); err != nil { + return nil, err + } + confirmation := transactionConfirmation{ + Transaction: holder.Transaction, + Transfer: holder.Transfer, + } + return &confirmation, nil +} + +// ResendRequest resends a transaction request referenced by id +func (c Client) ResendRequest(id string) (bool, error) { + holder := map[string]interface{}{} + if err := c.Put("transactions/"+id+"/resend_request", nil, &holder); err != nil { + return false, err + } + if holder["success"].(bool) { + return true, nil + } + return false, nil +} + +// CancelRequest cancels a transaction request referenced by id +func (c Client) CancelRequest(id string) (bool, error) { + holder := map[string]interface{}{} + if err := c.Delete("transactions/"+id+"/cancel_request", nil, &holder); err != nil { + return false, err + } + if holder["success"].(bool) { + return true, nil + } + return false, nil +} + +// CompleteRequest completes a money request referenced by id +func (c Client) CompleteRequest(id string) (*transactionConfirmation, error) { + return c.transactionRequest("PUT", id+"/complete_request", nil) +} + +// CreateButton gets a new payment button including EmbedHtml as a field on button struct +func (c Client) CreateButton(params *Button) (*Button, error) { + finalParams := &struct { + Button *Button `json:"button"` + }{ + Button: params, + } + holder := buttonHolder{} + if err := c.Post("buttons", finalParams, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "CreateButton"); err != nil { + return nil, err + } + button := holder.Button + button.EmbedHtml = "<div class=\"coinbase-button\" data-code=\"" + button.Code + "\"></div><script src=\"https://coinbase.com/assets/button.js\" type=\"text/javascript\"></script>" + return &button, nil +} + +// CreateOrderFromButtonCode creates an order for a given button code +func (c Client) CreateOrderFromButtonCode(buttonCode string) (*order, error) { + holder := orderHolder{} + if err := c.Post("buttons/"+buttonCode+"/create_order", nil, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "CreateOrderFromButtonCode"); err != nil { + return nil, err + } + return &holder.Order, nil +} + +// CreateUser creates a new user given an email and password +func (c Client) CreateUser(email string, password string) (*user, error) { + params := map[string]interface{}{ + "user[email]": email, + "user[password]": password, + } + holder := userHolder{} + if err := c.Post("users", params, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "CreateUser"); err != nil { + return nil, err + } + return &holder.User, nil +} + +// Buy an amount of BTC and bypass rate limits by setting agreeBtcAmountVaries to true +func (c Client) Buy(amount float64, agreeBtcAmountVaries bool) (*transfer, error) { + params := map[string]interface{}{ + "qty": amount, + "agree_btc_amount_varies": agreeBtcAmountVaries, + } + holder := transferHolder{} + if err := c.Post("buys", params, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "Buy"); err != nil { + return nil, err + } + return &holder.Transfer, nil +} + +// Sell an amount of BTC +func (c Client) Sell(amount float64) (*transfer, error) { + params := map[string]interface{}{ + "qty": amount, + } + holder := transferHolder{} + if err := c.Post("sells", params, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "Sell"); err != nil { + return nil, err + } + return &holder.Transfer, nil +} + +// GetContacts gets a users contacts +func (c Client) GetContacts(params *ContactsParams) (*contactsHolder, error) { + holder := contactsHolder{} + if err := c.Get("contacts", params, &holder); err != nil { + return nil, err + } + for _, contact := range holder.Contacts { + if contact.Contact.Email != "" { + holder.Emails = append(holder.Emails, contact.Contact.Email) + } + } + return &holder, nil +} + +// GetCurrencies gets all currency names and ISO's +func (c Client) GetCurrencies() ([]currency, error) { + holder := [][]string{} + if err := c.Get("currencies", nil, &holder); err != nil { + return nil, err + } + finalData := []currency{} + for _, curr := range holder { + class := currency{ + Name: curr[0], + Iso: curr[1], + } + finalData = append(finalData, class) + } + return finalData, nil +} + +// GetExchangeRates gets the current exchange rates +func (c Client) GetExchangeRates() (map[string]string, error) { + holder := map[string]string{} + if err := c.Get("currencies/exchange_rates", nil, &holder); err != nil { + return nil, err + } + return holder, nil +} + +// GetExchangeRate gets the exchange rate between two specified currencies +func (c Client) GetExchangeRate(from string, to string) (float64, error) { + exchanges, err := c.GetExchangeRates() + if err != nil { + return 0.0, err + } + key := from + "_to_" + to + if exchanges[key] == "" { + return 0.0, errors.New("The exchange rate does not exist for this currency pair") + } + exchangeFloat, err := strconv.ParseFloat(exchanges[key], 64) + if err != nil { + return 0.0, err + } + return exchangeFloat, nil +} + +// GetTransactions gets transactions associated with an account +func (c Client) GetTransactions(page int) (*transactions, error) { + params := map[string]int{ + "page": page, + } + holder := transactionsHolder{} + if err := c.Get("transactions", params, &holder); err != nil { + return nil, err + } + transactions := transactions{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, tx := range holder.Transactions { + transactions.Transactions = append(transactions.Transactions, tx.Transaction) + } + return &transactions, nil +} + +// GetOrders gets orders associated with an account +func (c Client) GetOrders(page int) (*orders, error) { + holder := ordersHolder{} + params := map[string]int{ + "page": page, + } + if err := c.Get("orders", params, &holder); err != nil { + return nil, err + } + orders := orders{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, o := range holder.Orders { + orders.Orders = append(orders.Orders, o.Order) + } + return &orders, nil +} + +// GetTransfers get transfers associated with an account +func (c Client) GetTransfers(page int) (*transfers, error) { + params := map[string]int{ + "page": page, + } + holder := transfersHolder{} + if err := c.Get("transfers", params, &holder); err != nil { + return nil, err + } + transfers := transfers{ + paginationStats: holder.paginationStats, + } + // Remove one layer of nesting + for _, t := range holder.Transfers { + transfers.Transfers = append(transfers.Transfers, t.Transfer) + } + return &transfers, nil +} + +// GetBuyPrice gets the current BTC buy price +func (c Client) GetBuyPrice(qty int) (*pricesHolder, error) { + return c.getPrice("buy", qty) +} + +// GetSellPrice gets the current BTC sell price +func (c Client) GetSellPrice(qty int) (*pricesHolder, error) { + return c.getPrice("sell", qty) +} + +func (c Client) getPrice(kind string, qty int) (*pricesHolder, error) { + params := map[string]int{ + "qty": qty, + } + holder := pricesHolder{} + if err := c.Get("prices/"+kind, params, &holder); err != nil { + return nil, err + } + return &holder, nil +} + +// GetTransaction gets a particular transaction referenced by id +func (c Client) GetTransaction(id string) (*transaction, error) { + holder := transactionHolder{} + if err := c.Get("transactions/"+id, nil, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "GetTransaction"); err != nil { + return nil, err + } + return &holder.Transaction, nil +} + +// GetOrder gets a particular order referenced by id +func (c Client) GetOrder(id string) (*order, error) { + holder := orderHolder{} + if err := c.Get("orders/"+id, nil, &holder); err != nil { + return nil, err + } + if err := checkApiErrors(holder.response, "GetOrder"); err != nil { + return nil, err + } + return &holder.Order, nil +} + +// GetUser gets the user associated with the authentication +func (c Client) GetUser() (*user, error) { + holder := usersHolder{} + if err := c.Get("users", nil, &holder); err != nil { + return nil, err + } + return &holder.Users[0].User, nil +} + +// checkApiErrors checks for errors returned by coinbase API JSON response +// i.e { "success": false, "errors": ["Button with code code123456 does not exist"], ...} +func checkApiErrors(resp response, method string) error { + if resp.Success == false { // Return errors received from API here + err := " in " + method + "()" + if resp.Errors != nil { + err = strings.Join(resp.Errors, ",") + err + return errors.New(err) + } + if resp.Error != "" { // Return errors received from API here + err = resp.Error + err + return errors.New(err) + } + } + return nil +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/endpoint_api_test.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/endpoint_api_test.go new file mode 100644 index 0000000..ce0e1b6 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/endpoint_api_test.go @@ -0,0 +1,151 @@ +package coinbase + +import ( + "fmt" + "log" + "os" + "testing" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/stretchr/testify/assert" +) + +// Initialize the client without mock mode enabled on rpc. +// All calls hit the coinbase API and tests focus on checking +// format of the response and validity of sent requests +func initClient() Client { + return ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) +} + +// About Endpoint Tests: +//All Endpoint Tests actually call the Coinbase API and check the return values +// with type assertions. This was done because of the varying specific values +// returned depending on the API Key and Secret pair used when running the tests. +// Endpoint tests do not include tests that could be run an arbitrary amount of times +// i.e buy, sell, etc... + +func TestEndpointGetBalance(t *testing.T) { + c := initClient() + amount, err := c.GetBalance() + if err != nil { + log.Fatal(err) + } + assert.IsType(t, 1.1, amount) +} + +func TestEndpointGetReceiveAddress(t *testing.T) { + t.Skip("Skipping GetReceiveAddressEndpoint in order not to create excessive amounts of receive addresses during testing.") + c := initClient() + params := &AddressParams{ + CallbackUrl: "http://www.wealthlift.com", + Label: "My Test Address", + } + address, err := c.GenerateReceiveAddress(params) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", address) +} + +func TestEndpointGetAllAddresses(t *testing.T) { + c := initClient() + params := &AddressesParams{ + Page: 1, + Limit: 5, + } + addresses, err := c.GetAllAddresses(params) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", addresses.Addresses[0].CreatedAt) + assert.IsType(t, "string", addresses.Addresses[0].Address) +} + +func TestEndpointCreateButton(t *testing.T) { + c := initClient() + params := &Button{ + Name: "test", + Type: "buy_now", + Subscription: false, + PriceString: "1.23", + PriceCurrencyIso: "USD", + Custom: "Order123", + CallbackUrl: "http://www.example.com/my_custom_button_callback", + Description: "Sample Description", + Style: "custom_large", + IncludeEmail: true, + } + data, err := c.CreateButton(params) + if err != nil { + if fmt.Sprint(err) != "You have not filled out your merchant profile. Please enter your information in the Profile section. in CreateButton()" { + log.Fatal(err) + } + t.Skip("Skip this test since user hasn't filled out their merchant profile yet.") + } + assert.IsType(t, "string", data.EmbedHtml) + assert.IsType(t, "string", data.Type) +} + +func TestEndpointGetCurrencies(t *testing.T) { + c := initClient() + data, err := c.GetCurrencies() + if err != nil { + log.Fatal() + } + assert.IsType(t, "string", data[0].Name) +} + +func TestEndpointGetExchangeRates(t *testing.T) { + c := initClient() + data, err := c.GetExchangeRates() + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", data["btc_to_usd"]) +} + +func TestEndpointGetExchangeRate(t *testing.T) { + c := initClient() + data, err := c.GetExchangeRate("btc", "usd") + if err != nil { + log.Fatal(err) + } + assert.IsType(t, 0.0, data) +} + +func TestEndpointGetTransactions(t *testing.T) { + c := initClient() + data, err := c.GetTransactions(1) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, int64(1), data.TotalCount) + assert.IsType(t, "string", data.Transactions[0].Hsh) +} + +func TestEndpointGetBuyPrice(t *testing.T) { + c := initClient() + data, err := c.GetBuyPrice(1) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", data.Subtotal.Currency) + assert.IsType(t, "string", data.Total.Amount) +} + +func TestEndpointGetSellPrice(t *testing.T) { + c := initClient() + data, err := c.GetSellPrice(1) + if err != nil { + log.Fatal(err) + } + assert.IsType(t, "string", data.Subtotal.Currency) + assert.IsType(t, "string", data.Total.Amount) +} + +func TestEndpointGetTransaction(t *testing.T) { + c := initClient() + _, err := c.GetTransaction("5446968682a19ab940000004") + if err != nil { + assert.IsType(t, "string", err.Error()) + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/ApiKeyExample.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/ApiKeyExample.go new file mode 100644 index 0000000..5830b73 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/ApiKeyExample.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "log" + "os" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/fabioberger/coinbase-go" +) + +func main() { + // Instantiate a ApiKeyClient with key and secret set at environment variables + c := coinbase.ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) + + balance, err := c.GetBalance() + if err != nil { + log.Fatal(err) + } + fmt.Printf("Balance is %f BTC", balance) + +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/OAuthExample.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/OAuthExample.go new file mode 100644 index 0000000..c8697f2 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/OAuthExample.go @@ -0,0 +1,72 @@ +package main + +import ( + "log" + "net/http" + "os" + "strconv" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/fabioberger/coinbase-go" + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/go-martini/martini" +) + +var o *coinbase.OAuth + +func main() { + m := martini.New() + m.Use(martini.Logger()) + m.Use(martini.Recovery()) + m.Use(martini.Static("public")) + r := martini.NewRouter() + m.MapTo(r, (*martini.Routes)(nil)) + m.Action(r.Handle) + + // Instantiate OAuthService with the OAuth App Client Id & Secret from the Environment Variables + o, err := coinbase.OAuthService(os.Getenv("COINBASE_CLIENT_ID"), os.Getenv("COINBASE_CLIENT_SECRET"), "https://localhost:8443/tokens") + if err != nil { + panic(err) + return + } + + // At https://localhost:8443/ we will display an "authorize" link + r.Get("/", func() string { + authorizeUrl := o.CreateAuthorizeUrl([]string{ + "user", + "balance", + }) + link := "<a href='" + authorizeUrl + "'>authorize</a>" + return link + }) + + // AuthorizeUrl redirects to https://localhost:8443/tokens with 'code' in its + // query params. If you dont have SSL enabled, replace 'https' with 'http' + // and reload the page. If successful, the user's balance will show + r.Get("/tokens", func(res http.ResponseWriter, req *http.Request) string { + // Get the tokens given the 'code' query param + tokens, err := o.NewTokensFromRequest(req) // Will use 'code' query param from req + if err != nil { + return err.Error() + } + // instantiate the OAuthClient + c := coinbase.OAuthClient(tokens) + amount, err := c.GetBalance() + if err != nil { + return err.Error() + } + return strconv.FormatFloat(amount, 'f', 6, 64) + }) + + // HTTP + go func() { + if err := http.ListenAndServe(":8080", m); err != nil { + log.Fatal(err) + } + }() + + // HTTPS + // To generate a development cert and key, run the following from your *nix terminal: + // go run $(go env GOROOT)/src/pkg/crypto/tls/generate_cert.go --host="localhost" + if err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", m); err != nil { + log.Fatal(err) + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/cert.pem b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/cert.pem new file mode 100644 index 0000000..3bb7c24 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9TCCAd+gAwIBAgIQAa1gzEkBj0oAqnmjI0uchzALBgkqhkiG9w0BAQswEjEQ +MA4GA1UEChMHQWNtZSBDbzAeFw0xNDExMDcyMTU2NThaFw0xNTExMDcyMTU2NTha +MBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCvCNMPOGV5/OCekfp7I6BOhWdnHedXE9CqiopA3yjv4Gpu2WOS0m/2Irr4 +qGTiFvh9JOZw1XrfcpPlTM5XzoP6MtV+XZP57xgt9hPhwnoAb9X0iN+j9AIkoLXi +alPhZK2poo9QVfQdoDtIUwZPrX0WmlARaf31/uLDvzKxC3uwWbvi/mebg2XnEFhA +K1uPHBXveTbN0PwCXXoOI4F7rnBsXbORNnm5sBS8c3Va0ZetG65gFRjWx/hsvGsA +9dJWyjvaPEzz0bSvVnfQxf0Yybe/sXPn+l9rXMZ+P+LmeUjmPo2KFO135PPYHSCd +BkTGNtMImDk8NdgrsvqMgSjb+sxHAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIAoDAT +BgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxv +Y2FsaG9zdDALBgkqhkiG9w0BAQsDggEBAKBf63MpQY+wmo6oH4dIHvziNwjrsOuZ +SK1d7TB0v67BcTAdKG2fX4eOfUVSVocKoki/OYqbjO7CmVDY972UQnQkN2QaEg/c +8LMX/Z3kC51xBD5y2vztpXgdPSAo6vAPWJCtNVqlRIRDuExDZwEeQ7icZo2jguD4 +GAkpbXJ4OKBXPG+iy+dMFbnEIAaKedSnFU92blrPqa1cMBb0scFli7Klxuu1eHsD +cixGtpI+cBw9X1phl2M09eAdCG618qDXqO/2d5rjcbQ+BFfQjv11HUrKbZKjd6HV +cAOvXdl6Xa8jyr/RMlk2wx1SZlsjw3NqK698VuRLBLPK7rDukxs7V1s= +-----END CERTIFICATE----- diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/example/key.pem b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/key.pem new file mode 100644 index 0000000..36de1cd --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/example/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArwjTDzhlefzgnpH6eyOgToVnZx3nVxPQqoqKQN8o7+Bqbtlj +ktJv9iK6+Khk4hb4fSTmcNV633KT5UzOV86D+jLVfl2T+e8YLfYT4cJ6AG/V9Ijf +o/QCJKC14mpT4WStqaKPUFX0HaA7SFMGT619FppQEWn99f7iw78ysQt7sFm74v5n +m4Nl5xBYQCtbjxwV73k2zdD8Al16DiOBe65wbF2zkTZ5ubAUvHN1WtGXrRuuYBUY +1sf4bLxrAPXSVso72jxM89G0r1Z30MX9GMm3v7Fz5/pfa1zGfj/i5nlI5j6NihTt +d+Tz2B0gnQZExjbTCJg5PDXYK7L6jIEo2/rMRwIDAQABAoIBABRCrzuZyZU/QjjY +qOfMDehI5Nk4yuh3cLXs52fu7OwnS+qc2zvJhBA3oPDbfSH2irjhppL1Aw4OUzQ9 +mbzsOLajX7cK2fAaTvAzBcYiHsEiMN/nYAu4WO8ocyVMLX1vi/KQ0In6CRHM1E/g +3GAosswE/LOnUzBAWrtRzGpV6/FToK6VoSwx0MPW/9v99NIo74u35CuiPZAKyEuw +rIqH1BhTez1Mrfy88Knpxm0+bIRzvIDYyno9ZaBcTqFNI1iN53SatwM4AcU4XVzO +TJtZ2kT9pvyMqXOSA16J2hCh3GNQEBjmI28NFCZ3j6LVTZNsq5cWc55p4gaFvxgV +YsLQPwECgYEA3esqFBptLBXam739CPsh31yMKcPSMP1fkC12S5vZNeEa1kFOCGG2 +A4y6n+vq0tTU1yXvYTVWYnkdqodTE3ASsAvbfeDNzlxinupK1jaOBs8MSBJ4ELJv +OOW/cOC5v6GWlAspuc1sRhho90anTJSg+8FRN4op2k5CVJkGZY/ZE4cCgYEAyepj +SLYaT354xE3hWniEHF1bEV/mUf7WnxRpK4He2+n3wn29AGFk/u9AakmvKbeIv7hQ +ql4FzelLxRPulfGKhzMSU+b5vg6T65+xTQdn+q5etaW8azJMR/34OYPCeLFfK3m2 +v6xYCgbZ0aan2Q4TaSNv82ziMuaPKvwrf3XgMUECgYAuRnV1z7ToNn5pb4quLr/3 +dbL8morgEFW3GOPMDGmU5KXV+7Qr50QvJU9dPbKv2BWx74UlPhwPWLYo8yMNsJcV +AsP4UcJYv8cI4E5OsP2YyeADv2YuBSdQNAhhn1rcbPObV2CSEBX93+UzexYzz+Jp +3Pv0mujzTtJiFa7Rytc3TQKBgFfwdGNTpGvg2jos7SwY9vjfk+0iRk6J3fGU0yU2 +v9gps1WKq8lBodoCW5yvENHrdGyDmuZIYuDGbdCcmLnHZBz0GlRecYDcGoJxn6e7 +xQaB8Q/N6h0J3/0u2HA8OXOVVKy7quMZ7ZIYX7+WhN3c6olM/NIZJv8iOVJwV4WA +0i7BAoGBAImvMo7AWoPP2ht5F/jloaktDOAw9zqyzIpGcHAN1irGluBdthf1VkD4 +C3snqtzBs4tJukNXBVpUQwwwSRFWmOIxuDxFJmW2DmIIE+GdU3WHNGuK+/1RrK/i +H3O8n5w+fP83vevr5HOR6+esodUS+padDZYCglAkpnruBI/i63Df +-----END RSA PRIVATE KEY----- diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/holders.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/holders.go new file mode 100644 index 0000000..42979cc --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/holders.go @@ -0,0 +1,112 @@ +package coinbase + +// Holders includes all the structs used for marshaling JSON responses from the coinbase API + +// The holder used to marshal the JSON request returned in GetTokens +type tokensHolder struct { + AccessToken string `json:"access_token,omitempty"` + TokenType string `json:"token_type,omitempty"` + ExpiresIn int64 `json:"expires_in,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + Scope string `json:"scope,omitempty"` +} + +// addressesHolder used to marshal the JSON request returned in GetAllAddresses +type addressesHolder struct { + paginationStats + Addresses []struct { + Address address `json:"address,omitempty"` + } `json:"addresses,omitempty"` +} + +// orderHolder used to marshal the JSON request returned in CreateOrderFromButtonCode and GetOrder +type orderHolder struct { + response + Order order `json:"order,omitempty"` +} + +// orderHolders used to marshal the JSON request returned in GetOrders +type ordersHolder struct { + paginationStats + Orders []struct { + Order order `json:"order,omitempty"` + } `json:"orders,omitempty"` +} + +// buttonHolder used to marshal the JSON request returned in CreateButton +type buttonHolder struct { + response + Button Button `json:"button,omitempty"` +} + +// transfersHolder used to marshal the JSON request returned in GetTransfers +type transfersHolder struct { + paginationStats + Transfers []struct { + Transfer transfer `json:"transfer,omitempty"` + } `json:"transfers,omitempty"` +} + +// transferHolder used to marshal the JSON request returned in Buy & Sell +type transferHolder struct { + response + Transfer transfer `json:"transfer,omitempty"` +} + +// pricesHolder used to marshal the JSON request returned in GetBuyPrice & GetSellPrice +type pricesHolder struct { + Subtotal amount `json:"subtotal,omitempty"` + Fees []struct { + Coinbase amount `json:"coinbase,omitempty"` + Bank amount `json:"bank,omitempty"` + } `json:"fees,omitempty"` + Total amount `json:"total,omitempty"` +} + +// usersHolder used to marshal the JSON request returned in GetUser +type usersHolder struct { + response + Users []struct { + User user `json:"user,omitempty"` + } `json:"users,omitempty"` +} + +// userHolder used to marshal the JSON request returned in CreateUser +type userHolder struct { + response + User user `json:"user,omitempty"` + Oauth oauth `json:"oauth,omitempty"` +} + +// The sub-structure of a response denominating its success and/or errors +type response struct { + Success bool `json:"success"` + Errors []string `json:"errors"` + Error string `json:"error"` +} + +// contactsHolder used to marshal the JSON request returned in GetContacts +type contactsHolder struct { + paginationStats + Contacts []contact `json:"contacts,omitempty"` + Emails []string `json:"emails,omitempty"` // Add for convenience +} + +// transactionHolder used to marshal the JSON request returned in SendMoney, RequestMoney, +// GetTransaction +type transactionHolder struct { + response + Transaction transaction `json:"transaction"` + Transfer transfer `json:"transfer"` +} + +// transactionsHolder used to marshal the JSON request returned in GetTransactions +type transactionsHolder struct { + paginationStats + CurrentUser user `json:"current_user,omitempty"` + Balance amount `json:"balance,omitempty"` + NativeBalance amount `json:"native_balance,omitempty"` + Transactions []struct { + Transaction transaction `json:"transaction,omitempty"` + } `json:"transactions,omitempty"` +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/mock_api_test.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/mock_api_test.go new file mode 100644 index 0000000..30f190f --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/mock_api_test.go @@ -0,0 +1,255 @@ +package coinbase + +import ( + "log" + "os" + "testing" +) + +// Initialize the client with mock mode enabled on rpc +// All calls return the corresponding json response from the test_data files +func initTestClient() Client { + return apiKeyClientTest(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET")) +} + +// About Mock Tests: +// All Mock Tests simulate requests to the coinbase API by returning the expected +// return values from a file under the test_data folder. The values received from +// the file are compared with the expected value given the marshaling of the JSON +// executed correctly. + +func TestMockGetBalanceParse(t *testing.T) { + c := initTestClient() + amount, err := c.GetBalance() + if err != nil { + log.Fatal(err) + } + compareFloat(t, "GetBalanceParse", 36.62800000, amount) +} + +func TestMockGetReceiveAddressParse(t *testing.T) { + c := initTestClient() + params := &AddressParams{} + address, err := c.GenerateReceiveAddress(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetReceiveAddressParse", "muVu2JZo8PbewBHRp6bpqFvVD87qvqEHWA", address) +} + +func TestMockGetAllAddressesParse(t *testing.T) { + c := initTestClient() + params := &AddressesParams{} + addresses, err := c.GetAllAddresses(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetAllAddressesParse", "2013-05-09T23:07:08-07:00", addresses.Addresses[0].CreatedAt) + compareString(t, "GetAllAddressesParse", "mwigfecvyG4MZjb6R5jMbmNcs7TkzhUaCj", addresses.Addresses[1].Address) + compareInt(t, "GetAllAddressesParse", 1, int64(addresses.NumPages)) +} + +func TestMockCreateButtonParse(t *testing.T) { + c := initTestClient() + params := &Button{} + data, err := c.CreateButton(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "CreateButtonParse", "93865b9cae83706ae59220c013bc0afd", data.Code) + compareString(t, "CreateButtonParse", "Sample description", data.Description) +} + +func TestMockSendMoneyParse(t *testing.T) { + c := initTestClient() + params := &TransactionParams{} + data, err := c.SendMoney(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "SendMoneyParse", "-1.23400000", data.Transaction.Amount.Amount) + compareString(t, "SendMoneyParse", "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare", data.Transaction.RecipientAddress) +} + +func TestMockRequestMoneyParse(t *testing.T) { + c := initTestClient() + params := &TransactionParams{} + data, err := c.RequestMoney(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "RequestMoneyParse", "1.23400000", data.Transaction.Amount.Amount) + compareString(t, "RequestMoneyParse", "5011f33df8182b142400000e", data.Transaction.Recipient.Id) +} + +func TestMockResendRequestParse(t *testing.T) { + c := initTestClient() + data, err := c.ResendRequest("ID") + if err != nil { + log.Fatal(err) + } + compareBool(t, "ResendRequestParse", true, data) +} + +func TestMockCancelRequestParse(t *testing.T) { + c := initTestClient() + data, err := c.CancelRequest("ID") + if err != nil { + log.Fatal(err) + } + compareBool(t, "CancelRequestParse", false, data) +} + +func TestMockCompleteRequestParse(t *testing.T) { + c := initTestClient() + data, err := c.CompleteRequest("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "CancelRequestParse", "503c46a3f8182b106500009b", data.Transaction.Id) +} + +func TestMockCreateOrderFromButtonCodeParse(t *testing.T) { + c := initTestClient() + data, err := c.CreateOrderFromButtonCode("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "CreateOrderFromButtonCodeParse", "7RTTRDVP", data.Id) + compareString(t, "CreateOrderFromButtonCodeParse", "new", data.Status) +} + +func TestMockCreateUserParse(t *testing.T) { + c := initTestClient() + data, err := c.CreateUser("test@email.com", "password") + if err != nil { + log.Fatal(err) + } + compareString(t, "CreateUser", "newuser@example.com", data.Email) + compareString(t, "CreateUser", "501a3d22f8182b2754000011", data.Id) +} + +func TestMockBuyParse(t *testing.T) { + c := initTestClient() + data, err := c.Buy(1000.0, true) + if err != nil { + log.Fatal(err) + } + compareString(t, "Buys", "2013-01-28T16:08:58-08:00", data.CreatedAt) + compareString(t, "Buys", "USD", data.Fees.Bank.CurrencyIso) + compareString(t, "Buys", "13.55", data.Subtotal.Amount) +} + +func TestMockSellParse(t *testing.T) { + c := initTestClient() + data, err := c.Sell(1000.0) + if err != nil { + log.Fatal(err) + } + compareString(t, "Sells", "2013-01-28T16:32:35-08:00", data.CreatedAt) + compareString(t, "Sells", "USD", data.Fees.Bank.CurrencyIso) + compareString(t, "Sells", "13.50", data.Subtotal.Amount) +} + +func TestMockGetContactsParse(t *testing.T) { + c := initTestClient() + params := &ContactsParams{ + Page: 1, + Limit: 5, + } + data, err := c.GetContacts(params) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetContacts", "user1@example.com", data.Emails[0]) +} + +func TestMockGetTransactionsParse(t *testing.T) { + c := initTestClient() + data, err := c.GetTransactions(1) + if err != nil { + log.Fatal(err) + } + compareInt(t, "GetTransactions", 2, data.TotalCount) + compareString(t, "GetTransactions", "5018f833f8182b129c00002f", data.Transactions[0].Id) + compareString(t, "GetTransactions", "-1.00000000", data.Transactions[1].Amount.Amount) +} + +func TestMockGetOrdersParse(t *testing.T) { + c := initTestClient() + data, err := c.GetOrders(1) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetOrders", "buy_now", data.Orders[0].Button.Type) + compareInt(t, "GetOrders", int64(0), int64(data.Orders[0].Transaction.Confirmations)) +} + +func TestMockGetTransfersParse(t *testing.T) { + c := initTestClient() + data, err := c.GetTransfers(1) + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransfers", "BTC", data.Transfers[0].Btc.Currency) + compareInt(t, "GetTransfers", int64(1), int64(data.NumPages)) +} + +func TestMockGetTransaction(t *testing.T) { + c := initTestClient() + data, err := c.GetTransaction("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransaction", "5018f833f8182b129c00002f", data.Id) + compareString(t, "GetTransaction", "BTC", data.Amount.Currency) + compareString(t, "GetTransaction", "User One", data.Recipient.Name) +} + +func TestMockGetOrder(t *testing.T) { + c := initTestClient() + data, err := c.GetOrder("ID") + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransaction", "A7C52JQT", data.Id) + compareString(t, "GetTransaction", "BTC", data.TotalBtc.CurrencyIso) + compareString(t, "GetTransaction", "test", data.Button.Name) +} + +func TestMockGetUser(t *testing.T) { + c := initTestClient() + data, err := c.GetUser() + if err != nil { + log.Fatal(err) + } + compareString(t, "GetTransaction", "512db383f8182bd24d000001", data.Id) + compareString(t, "GetTransaction", "49.76000000", data.Balance.Amount) + compareString(t, "GetTransaction", "Company Name, Inc.", data.Merchant.CompanyName) +} + +func compareFloat(t *testing.T, prefix string, expected float64, got float64) { + if expected != got { + t.Errorf(`%s + Expected %0.32f + but got %0.32f`, prefix, expected, got) + } +} + +func compareInt(t *testing.T, prefix string, expected int64, got int64) { + if expected != got { + t.Errorf("%s Expected %d but got %d", prefix, expected, got) + } +} + +func compareString(t *testing.T, prefix string, expected string, got string) { + if expected != got { + t.Errorf("%s Expected '%s' but got '%s'", prefix, expected, got) + } +} + +func compareBool(t *testing.T, prefix string, expected bool, got bool) { + if expected != got { + t.Errorf("%s Expected '%t' but got '%t'", prefix, expected, got) + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/oauth.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/oauth.go new file mode 100644 index 0000000..92bda03 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/oauth.go @@ -0,0 +1,101 @@ +package coinbase + +import ( + "net/http" + "net/url" + "strings" + "time" +) + +// OAuth handles all service oauth related functionality (i.e GetTokens(), RefreshTokens() +type OAuth struct { + ClientId string + ClientSecret string + RedirectUri string + Rpc rpc +} + +// OAuthService Instantiates OAuth Struct in order to send service related OAuth requests +func OAuthService(clientId string, clientSecret string, redirectUri string) (*OAuth, error) { + certFilePath := basePath + "/ca-coinbase.crt" + serviceAuth, err := serviceOAuth(certFilePath) + if err != nil { + return nil, err + } + o := OAuth{ + ClientId: clientId, + ClientSecret: clientSecret, + RedirectUri: redirectUri, + Rpc: rpc{ + auth: serviceAuth, + mock: false, + }, + } + return &o, nil +} + +// CreateAuthorizeUrl create the Authorize Url used to redirect users for +// coinbase app authorization. The scope parameter includes the specific +// permissions one wants to ask from the user +func (o OAuth) CreateAuthorizeUrl(scope []string) string { + Url, _ := url.Parse("https://coinbase.com") + Url.Path += "/oauth/authorize" + + parameters := url.Values{} + parameters.Add("response_type", "code") + parameters.Add("client_id", o.ClientId) + parameters.Add("redirect_uri", o.RedirectUri) + parameters.Add("scope", strings.Join(scope, " ")) + Url.RawQuery = parameters.Encode() + + return Url.String() +} + +// RefreshTokens refreshes a users existing OAuth tokens +func (o OAuth) RefreshTokens(oldTokens map[string]interface{}) (*oauthTokens, error) { + refresh_token := oldTokens["refresh_token"].(string) + return o.GetTokens(refresh_token, "refresh_token") +} + +// NewTokens generates new tokens for an OAuth user +func (o OAuth) NewTokens(code string) (*oauthTokens, error) { + return o.GetTokens(code, "authorization_code") +} + +// NewTokensRequest generates new tokens for OAuth user given an http request +// containing the query parameter 'code' +func (o OAuth) NewTokensFromRequest(req *http.Request) (*oauthTokens, error) { + query := req.URL.Query() + code := query.Get("code") + return o.GetTokens(code, "authorization_code") +} + +// GetTokens gets tokens for an OAuth user specifying a grantType (i.e authorization_code) +func (o OAuth) GetTokens(code string, grantType string) (*oauthTokens, error) { + + postVars := map[string]string{ + "grant_type": grantType, + "redirect_uri": o.RedirectUri, + "client_id": o.ClientId, + "client_secret": o.ClientSecret, + } + + if grantType == "refresh_token" { + postVars["refresh_token"] = code + } else { + postVars["code"] = code + } + holder := tokensHolder{} + err := o.Rpc.Request("POST", "oauth/token", postVars, &holder) + if err != nil { + return nil, err + } + + tokens := oauthTokens{ + AccessToken: holder.AccessToken, + RefreshToken: holder.RefreshToken, + ExpireTime: time.Now().UTC().Unix() + holder.ExpiresIn, + } + + return &tokens, nil +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/params.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/params.go new file mode 100644 index 0000000..3d2db60 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/params.go @@ -0,0 +1,253 @@ +package coinbase + +// Params includes all the struct parameters that are required for specific API requests +// By defining a specific param struct, a developer can know which parameters are allowed +// for a given request. Also included here are the return object structs returned by +// specific API calls + +// Parameter Struct for GET /api/v1/addresses Requests +type AddressesParams struct { + Page int64 `json:"page,omitempty"` + Limit int64 `json:"limit,omitempty"` + AccountId string `json:"account_id,omitempty"` + Query string `json:"query,omitempty"` +} + +// Parameter Struct for POST /api/v1/account/generate_receive_address Requests +type AddressParams struct { + Label string `json:"label,omitempty"` + CallbackUrl string `json:"callback_url,omitempty"` +} + +// Parameter Struct for POST /api/v1/transactions/(request_money,send_money) Requests +type TransactionParams struct { + To string `json:"to,omitempty"` + From string `json:"from,omitempty"` + Amount string `json:"amount,omitempty"` + AmountString string `json:"amount_string,omitempty"` + AmountCurrencyIso string `json:"amount_currency_iso,omitempty"` + Notes string `json:"notes,omitempty"` + UserFee string `json:"user_fee,omitempty"` + ReferrerId string `json:"refferer_id,omitempty"` + Idem string `json:"idem,omitempty"` + InstantBuy bool `json:"instant_buy,omitempty"` + OrderId string `json:"order_id,omitempty"` +} + +// Parameter Struct for GET /api/v1/contacts Requests +type ContactsParams struct { + Page int64 `json:"page,omitempty"` + Limit int64 `json:"limit,omitempty"` + Query string `json:"query,omitempty"` +} + +// The OAuth Tokens Struct returned from OAuth Authentication +type oauthTokens struct { + AccessToken string + RefreshToken string + ExpireTime int64 +} + +// The return response from SendMoney, RequestMoney, CompleteRequest +type transactionConfirmation struct { + Transaction transaction + Transfer transfer +} + +// The return response from GetAllAddresses +type addresses struct { + paginationStats + Addresses []address +} + +// The structure for one returned address from GetAllAddresses +type address struct { + Address string `json:"address,omitempty"` + CallbackUrl string `json:"callback_url,omitempty"` + Label string `json:"label,omitempty"` + CreatedAt string `json:"created_at,omitempty"` +} + +// The sub-structure of a response denominating a currency +type currency struct { + Name string `json:"name,omitempty"` + Iso string `json:"iso,omitempty"` +} + +// The sub-structure of a response denominating a contact +type contact struct { + Contact struct { + Email string `json:"email,omitempty"` + } `json:"contact,omitempty"` +} + +// The return response from CreateButton +type Button struct { + Name string `json:"name,omitempty"` + PriceString string `json:"price_string,omitempty"` + PriceCurrencyIso string `json:"price_currency_iso,omitempty"` + Type string `json:"type,omitempty"` + Subscription bool `json:"subscription,omitempty"` + Repeat string `json:"repeat,omitempty"` + Style string `json:"style,omitempty"` + Text string `json:"text,omitempty"` + Description string `json:"description,omitempty"` + Custom string `json:"custom,omitempty"` + CustomSecure bool `json:"custom_secure,omitempty"` + CallbackUrl string `json:"callback_url,omitempty"` + SuccessUrl string `json:"success_url,omitempty"` + CancelUrl string `json:"cancel_url,omitempty"` + InfoUrl string `json:"info_url,omitempty"` + AutoRedirect bool `json:"auto_redirect,omitempty"` + AutoRedirectSuccess bool `json:"auto_redirect_success,omitempty"` + AutoRedirectCancel bool `json:"auto_redirect_cancel,omitempty"` + VariablePrice bool `json:"variable_price,omitempty"` + ChoosePrice bool `json:"choose_price,omitempty"` + IncludeAddress bool `json:"include_address,omitempty"` + IncludeEmail bool `json:"include_email,omitempty"` + Price1 string `json:"price1,omitempty"` + Price2 string `json:"price2,omitempty"` + Price3 string `json:"price3,omitempty"` + Price4 string `json:"price4,omitempty"` + Price5 string `json:"price5,omitempty"` + Code string `json:"code,omitempty"` + Price fee `json:"price,omitempty"` + Id string `json:"id,omitempty"` + EmbedHtml string `json:"embed_html"` //Added embed_html for convenience +} + +// The return response from GetUser and CreateUser +type user struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` + ReceiveAddress string `json:"receive_address,omitempty"` + TimeZone string `json:"timezone,omitempty"` + NativeCurrency string `json:"native_currency,omitempty"` + Balance amount `json:"balance,omitempty"` + Merchant merchant `json:"merchant,omitempty"` + BuyLevel int64 `json:"buy_level,omitempty"` + SellLevel int64 `json:"sell_level,omitempty"` + BuyLimit amount `json:"buy_limit,omitempty"` + SellLimit amount `json:"sell_limit,omitempty"` +} + +// The sub-structure of a response denominating a merchant +type merchant struct { + CompanyName string `json:"company_name,omitempty"` + Logo struct { + Small string `json:"small,omitempty"` + Medium string `json:"medium,omitempty"` + Url string `json:"url,omitempty"` + } `json:"logo,omitempty"` +} + +// The sub-structure of a response denominating the oauth data +type oauth struct { + AccessToken string `json:"access_token,omitempty"` + TokenType string `json:"token_type,omitempty"` + ExpiresIn int64 `json:"expires_in,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + Scope string `json:"scope,omitempty"` +} + +// The sub-structure of a response denominating pagination stats +type paginationStats struct { + TotalCount int64 `json:"total_count,omitempty"` + NumPages int64 `json:"num_pages,omitempty"` + CurrentPage int64 `json:"current_page,omitempty"` +} + +// The return response from GetTransfers +type transfers struct { + paginationStats + Transfers []transfer +} + +// The sub-structure of a response denominating a transfer +type transfer struct { + Id string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Code string `json:"code,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Fees fees `json:"fees,omitempty"` + Status string `json:"status,omitempty"` + PayoutDate string `json:"payout_date,omitempty"` + Btc amount `json:"btc,omitempty"` + Subtotal amount `json:"subtotal,omitempty"` + Total amount `json:"total,omitempty"` + Description string `json:"description,omitempty"` + TransactionId string `json:"transaction_id,omitempty"` +} + +// The sub-structure of a response denominating an amount +type amount struct { + Amount string `json:"amount,omitempty"` + Currency string `json:"currency,omitempty"` +} + +// The sub-structure of a response denominating a fee +type fee struct { + Cents float64 `json:"cents,omitempty"` + CurrencyIso string `json:"currency_iso,omitempty"` +} + +// The sub-structure of a response denominating fees +type fees struct { + Coinbase fee `json:"coinbase,omitempty"` + Bank fee `json:"bank,omitempty"` +} + +// The sub-structure of a response denominating a transaction actor +type transactionActor struct { + Id string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` +} + +// The return response from GetTransactions +type transactions struct { + paginationStats + Transactions []transaction +} + +// The sub-structure of a response denominating a transaction +type transaction struct { + Id string `json:"id,omitempty"` + CreateAt string `json:"create_at,omitempty"` + Hsh string `json:"hsh,omitempty"` + Notes string `json:"notes,omitempty"` + Idem string `json:"idem,omitempty"` + Amount amount `json:"amount,omitempty"` + Request bool `json:"request,omitempty"` + Status string `json:"status,omitempty"` + Sender transactionActor `json:"sender,omitempty"` + Recipient transactionActor `json:"recipient,omitempty"` + RecipientAddress string `json:"recipient_address,omitempty"` + Type string `json:"type,omitempty"` + Signed bool `json:"signed,omitempty"` + SignaturesRequired int64 `json:"signature_required,omitempty"` + SignaturesPresent int64 `json:"signatures_present,omitempty"` + SignaturesNeeded int64 `json:"signatures_needed,omitempty"` + Hash string `json:"hash,omitempty"` + Confirmations int64 `json:"confirmations,omitempty"` +} + +// The return response from GetOrders +type orders struct { + paginationStats + Orders []order +} + +// The sub-structure of a response denominating an order +type order struct { + Id string `json:"id,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Status string `json:"status,omitempty"` + TotalBtc fee `json:"total_btc,omitempty"` + TotalNative fee `json:"total_native,omitempty"` + Custom string `json:"custom,omitempty"` + ReceiveAddress string `json:"receive_address,omitempty"` + Button Button `json:"button,omitempty"` + Transaction transaction `json:"transaction,omitempty"` +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/rpc.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/rpc.go new file mode 100644 index 0000000..2fc25e1 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/rpc.go @@ -0,0 +1,107 @@ +package coinbase + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strings" +) + +// basePath needed for reading mock JSON files in simulateRequest and for +// referencing ca-coinbase.crt in OAuthService. Must be fixed path because +// relative path changes depending on where library called +var basePath string = os.Getenv("GOPATH") + "/src/github.com/fabioberger/coinbase-go" + +// Rpc handles the remote procedure call requests +type rpc struct { + auth authenticator + mock bool +} + +// Request sends a request with params marshaled into a JSON payload in the body +// The response value is marshaled from JSON into the specified holder struct +func (r rpc) Request(method string, endpoint string, params interface{}, holder interface{}) error { + + jsonParams, err := json.Marshal(params) + if err != nil { + return err + } + + request, err := r.createRequest(method, endpoint, jsonParams) + if err != nil { + return err + } + + var data []byte + if r.mock == true { // Mock mode: Replace actual request with expected JSON from file + data, err = r.simulateRequest(endpoint, method) + } else { + data, err = r.executeRequest(request) + } + if err != nil { + return err + } + if err := json.Unmarshal(data, &holder); err != nil { + return err + } + + return nil +} + +// CreateRequest formats a request with all the necessary headers +func (r rpc) createRequest(method string, endpoint string, params []byte) (*http.Request, error) { + + endpoint = r.auth.getBaseUrl() + endpoint //BaseUrl depends on Auth type used + + req, err := http.NewRequest(method, endpoint, bytes.NewBuffer(params)) + if err != nil { + return nil, err + } + + // Authenticate the request + r.auth.authenticate(req, endpoint, params) + + req.Header.Set("User-Agent", "CoinbaseGo/v1") + req.Header.Set("Content-Type", "application/json") + + return req, nil +} + +// executeRequest takes a prepared http.Request and returns the body of the response +// If the response is not of HTTP Code 200, an error is returned +func (r rpc) executeRequest(req *http.Request) ([]byte, error) { + resp, err := r.auth.getClient().Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + buf := new(bytes.Buffer) + buf.ReadFrom(resp.Body) + bytes := buf.Bytes() + if resp.StatusCode != 200 { + if len(bytes) == 0 { // Log response body for debugging purposes + log.Printf("Response body was empty") + } else { + log.Printf("Response body:\n\t%s\n", bytes) + } + return nil, fmt.Errorf("%s %s failed. Response code was %s", req.Method, req.URL, resp.Status) + } + return bytes, nil +} + +// simulateRequest simulates a request by returning a sample JSON from file +func (r rpc) simulateRequest(endpoint string, method string) ([]byte, error) { + // Test files conform to replacing '/' in endpoint with '_' + fileName := strings.Replace(endpoint, "/", "_", -1) + // file names also have method type prepended to ensure uniqueness + filePath := basePath + "/test_data/" + method + "_" + fileName + ".json" + data, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, err + } + return data, nil +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/service_oauth_authentication.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/service_oauth_authentication.go new file mode 100644 index 0000000..a02faea --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/service_oauth_authentication.go @@ -0,0 +1,54 @@ +package coinbase + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + "net/http" +) + +// ServiceOAuthAuthentication Struct implements the Authentication interface +// and takes care of authenticating OAuth RPC requests on behalf of the service +// (i.e GetTokens()) +type serviceOAuthAuthentication struct { + BaseUrl string + Client http.Client +} + +// ServiceOAuth instantiates ServiceOAuthAuthentication with the coinbase certificate file +func serviceOAuth(certFilePath string) (*serviceOAuthAuthentication, error) { + // First we read the cert + certs := x509.NewCertPool() + pemData, err := ioutil.ReadFile(certFilePath) + if err != nil { + return nil, err + } + certs.AppendCertsFromPEM(pemData) + mTLSConfig := &tls.Config{ + RootCAs: certs, //Add the cert as a TLS config + } + a := serviceOAuthAuthentication{ + BaseUrl: "https://coinbase.com/", + Client: http.Client{ + Transport: &http.Transport{ + Dial: dialTimeout, + TLSClientConfig: mTLSConfig, + }, + }, + } + return &a, nil +} + +// Service OAuth authentication requires no additional headers to be sent. The +// Coinbase Public Certificate is set as a TLS config in the http.Client +func (a serviceOAuthAuthentication) authenticate(req *http.Request, endpoint string, params []byte) error { + return nil // No additional headers needed for service OAuth requests +} + +func (a serviceOAuthAuthentication) getBaseUrl() string { + return a.BaseUrl +} + +func (a serviceOAuthAuthentication) getClient() *http.Client { + return &a.Client +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/DELETE_transactions_ID_cancel_request.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/DELETE_transactions_ID_cancel_request.json new file mode 100644 index 0000000..f11b832 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/DELETE_transactions_ID_cancel_request.json @@ -0,0 +1,3 @@ +{ + "success": false +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_account_balance.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_account_balance.json new file mode 100644 index 0000000..9cc74fa --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_account_balance.json @@ -0,0 +1,4 @@ +{ + "amount": "36.62800000", + "currency": "BTC" +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_addresses.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_addresses.json new file mode 100644 index 0000000..2f5f4c5 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_addresses.json @@ -0,0 +1,33 @@ +{ + "addresses": [ + { + "address": { + "address": "moLxGrqWNcnGq4A8Caq8EGP4n9GUGWanj4", + "callback_url": null, + "label": "My Label", + "created_at": "2013-05-09T23:07:08-07:00" + } + }, + { + "address": { + "address": "mwigfecvyG4MZjb6R5jMbmNcs7TkzhUaCj", + "callback_url": null, + "label": null, + "created_at": "2013-05-09T17:50:37-07:00" + } + }, + { + "address": { + "address": "2N139JFn7dwX1ySkdWYDXCV51oyBCuV8zYw", + "callback_url": null, + "label": null, + "created_at": "2013-05-09T17:50:37-07:00", + "type": "p2sh", + "redeem_script": "524104c6e3f151b7d0ca7a63c6090c1eb86fd2cbfce43c367b5b36553ba28ade342b9dd8590f48abd48aa0160babcabfdccc6529609d2f295b3165e724de2f15adca9d410434cca255243e36de58f628b0f462518168b9c97b408f92ea9e01e168c70c003398bbf9b4c5cb9344f00c7cebf40322405f9b063eb4d2da25e710759aa51301eb4104624c024547a858b898bfe0b89c4281d743303da6d9ad5fc2f82228255586a9093011a540acae4bdf77ce427c0cb9b482918093e677238800fc0f6fae14f6712853ae" + } + } + ], + "total_count": 3, + "num_pages": 1, + "current_page": 1 +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_contacts.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_contacts.json new file mode 100644 index 0000000..5b3a520 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_contacts.json @@ -0,0 +1,17 @@ +{ + "contacts": [ + { + "contact": { + "email": "user1@example.com" + } + }, + { + "contact": { + "email": "user2@example.com" + } + } + ], + "total_count": 2, + "num_pages": 1, + "current_page": 1 +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders.json new file mode 100644 index 0000000..024afca --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders.json @@ -0,0 +1,35 @@ +{ + "orders": [ + { + "order": { + "id": "A7C52JQT", + "created_at": "2013-03-11T22:04:37-07:00", + "status": "completed", + "total_btc": { + "cents": 100000000, + "currency_iso": "BTC" + }, + "total_native": { + "cents": 3000, + "currency_iso": "USD" + }, + "custom": "", + "receive_address": "mgrmKftH5CeuFBU3THLWuTNKaZoCGJU5jQ", + "button": { + "type": "buy_now", + "name": "Order #1234", + "description": "order description", + "id": "eec6d08e9e215195a471eae432a49fc7" + }, + "transaction": { + "id": "513eb768f12a9cf27400000b", + "hash": "4cc5eec20cd692f3cdb7fc264a0e1d78b9a7e3d7b862dec1e39cf7e37ababc14", + "confirmations": 0 + } + } + } + ], + "total_count": 1, + "num_pages": 1, + "current_page": 1 +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders_ID.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders_ID.json new file mode 100644 index 0000000..bc31d53 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_orders_ID.json @@ -0,0 +1,28 @@ +{ + "order": { + "id": "A7C52JQT", + "created_at": "2013-03-11T22:04:37-07:00", + "status": "completed", + "total_btc": { + "cents": 10000000, + "currency_iso": "BTC" + }, + "total_native": { + "cents": 10000000, + "currency_iso": "BTC" + }, + "custom": "custom123", + "receive_address": "mgrmKftH5CeuFBU3THLWuTNKaZoCGJU5jQ", + "button": { + "type": "buy_now", + "name": "test", + "description": "", + "id": "eec6d08e9e215195a471eae432a49fc7" + }, + "transaction": { + "id": "513eb768f12a9cf27400000b", + "hash": "4cc5eec20cd692f3cdb7fc264a0e1d78b9a7e3d7b862dec1e39cf7e37ababc14", + "confirmations": 0 + } + } +} diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions.json new file mode 100644 index 0000000..89e99af --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions.json @@ -0,0 +1,61 @@ +{ + "current_user": { + "id": "5011f33df8182b142400000e", + "email": "user2@example.com", + "name": "User Two" + }, + "balance": { + "amount": "50.00000000", + "currency": "BTC" + }, + "native_balance": { + "amount": "500.00", + "currency": "USD" + }, + "total_count": 2, + "num_pages": 1, + "current_page": 1, + "transactions": [ + { + "transaction": { + "id": "5018f833f8182b129c00002f", + "created_at": "2012-08-01T02:34:43-07:00", + "amount": { + "amount": "-1.10000000", + "currency": "BTC" + }, + "request": true, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + } + } + }, + { + "transaction": { + "id": "5018f833f8182b129c00002e", + "created_at": "2012-08-01T02:36:43-07:00", + "hsh": "9d6a7d1112c3db9de5315b421a5153d71413f5f752aff75bf504b77df4e646a3", + "amount": { + "amount": "-1.00000000", + "currency": "BTC" + }, + "request": false, + "status": "complete", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient_address": "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare" + } + } + ] +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions_ID.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions_ID.json new file mode 100644 index 0000000..ee0aac7 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transactions_ID.json @@ -0,0 +1,22 @@ +{ + "transaction": { + "id": "5018f833f8182b129c00002f", + "created_at": "2012-08-01T02:34:43-07:00", + "amount": { + "amount": "-1.10000000", + "currency": "BTC" + }, + "request": true, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transfers.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transfers.json new file mode 100644 index 0000000..83c9e27 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_transfers.json @@ -0,0 +1,40 @@ +{ + "transfers": [ + { + "transfer": { + "type": "Buy", + "code": "QPCUCZHR", + "created_at": "2013-02-27T23:28:18-08:00", + "fees": { + "coinbase": { + "cents": 14, + "currency_iso": "USD" + }, + "bank": { + "cents": 15, + "currency_iso": "USD" + } + }, + "payout_date": "2013-03-05T18:00:00-08:00", + "transaction_id": "5011f33df8182b142400000e", + "status": "Pending", + "btc": { + "amount": "1.00000000", + "currency": "BTC" + }, + "subtotal": { + "amount": "13.55", + "currency": "USD" + }, + "total": { + "amount": "13.84", + "currency": "USD" + }, + "description": "Paid for with $13.84 from Test xxxxx3111." + } + } + ], + "total_count": 1, + "num_pages": 1, + "current_page": 1 +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_users.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_users.json new file mode 100644 index 0000000..a6e9c74 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/GET_users.json @@ -0,0 +1,35 @@ +{ + "users": [ + { + "user": { + "id": "512db383f8182bd24d000001", + "name": "User One", + "email": "user1@example.com", + "time_zone": "Pacific Time (US & Canada)", + "native_currency": "USD", + "balance": { + "amount": "49.76000000", + "currency": "BTC" + }, + "merchant": { + "company_name": "Company Name, Inc.", + "logo": { + "small": "http://smalllogo.example", + "medium": "http://mediumlogo.example", + "url": "http://logo.example" + } + }, + "buy_level": 1, + "sell_level": 1, + "buy_limit": { + "amount": "10.00000000", + "currency": "BTC" + }, + "sell_limit": { + "amount": "100.00000000", + "currency": "BTC" + } + } + } + ] +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_account_generate_receive_address.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_account_generate_receive_address.json new file mode 100644 index 0000000..d7b739b --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_account_generate_receive_address.json @@ -0,0 +1,6 @@ +{ + "success": true, + "address": "muVu2JZo8PbewBHRp6bpqFvVD87qvqEHWA", + "callback_url": null, + "label": null +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons.json new file mode 100644 index 0000000..ff4bb44 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons.json @@ -0,0 +1,18 @@ +{ + "success": true, + "button": { + "code": "93865b9cae83706ae59220c013bc0afd", + "type": "buy_now", + "subscription": false, + "style": "custom_large", + "text": "Pay With Bitcoin", + "name": "test", + "description": "Sample description", + "custom": "Order123", + "callback_url": "http://www.example.com/my_custom_button_callback", + "price": { + "cents": 123, + "currency_iso": "USD" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons_ID_create_order.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons_ID_create_order.json new file mode 100644 index 0000000..ebcd00b --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buttons_ID_create_order.json @@ -0,0 +1,25 @@ +{ + "success": true, + "order": { + "id": "7RTTRDVP", + "created_at": "2013-11-09T22:47:10-08:00", + "status": "new", + "total_btc": { + "cents": 100000000, + "currency_iso": "BTC" + }, + "total_native": { + "cents": 100000000, + "currency_iso": "BTC" + }, + "custom": "Order123", + "receive_address": "mgrmKftH5CeuFBU3THLWuTNKaZoCGJU5jQ", + "button": { + "type": "buy_now", + "name": "test", + "description": "Sample description", + "id": "93865b9cae83706ae59220c013bc0afd" + }, + "transaction": null + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buys.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buys.json new file mode 100644 index 0000000..49718a4 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_buys.json @@ -0,0 +1,32 @@ +{ + "success": true, + "transfer": { + "type": "Buy", + "code": "6H7GYLXZ", + "created_at": "2013-01-28T16:08:58-08:00", + "fees": { + "coinbase": { + "cents": 14, + "currency_iso": "USD" + }, + "bank": { + "cents": 15, + "currency_iso": "USD" + } + }, + "status": "created", + "payout_date": "2013-02-01T18:00:00-08:00", + "btc": { + "amount": "1.00000000", + "currency": "BTC" + }, + "subtotal": { + "amount": "13.55", + "currency": "USD" + }, + "total": { + "amount": "13.84", + "currency": "USD" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_sells.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_sells.json new file mode 100644 index 0000000..a2bf661 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_sells.json @@ -0,0 +1,32 @@ +{ + "success": true, + "transfer": { + "type": "Sell", + "code": "RD2OC8AL", + "created_at": "2013-01-28T16:32:35-08:00", + "fees": { + "coinbase": { + "cents": 14, + "currency_iso": "USD" + }, + "bank": { + "cents": 15, + "currency_iso": "USD" + } + }, + "status": "created", + "payout_date": "2013-02-01T18:00:00-08:00", + "btc": { + "amount": "1.00000000", + "currency": "BTC" + }, + "subtotal": { + "amount": "13.50", + "currency": "USD" + }, + "total": { + "amount": "13.21", + "currency": "USD" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_request_money.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_request_money.json new file mode 100644 index 0000000..5b72fb8 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_request_money.json @@ -0,0 +1,25 @@ +{ + "success": true, + "transaction": { + "id": "501a3554f8182b2754000003", + "created_at": "2012-08-02T01:07:48-07:00", + "hsh": null, + "notes": "Sample request for you!", + "amount": { + "amount": "1.23400000", + "currency": "BTC" + }, + "request": true, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + } + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_send_money.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_send_money.json new file mode 100644 index 0000000..68cd239 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_transactions_send_money.json @@ -0,0 +1,26 @@ +{ + "success": true, + "transaction": { + "id": "501a1791f8182b2071000087", + "created_at": "2012-08-01T23:00:49-07:00", + "hsh": "9d6a7d1112c3db9de5315b421a5153d71413f5f752aff75bf504b77df4e646a3", + "notes": "Sample transaction for you!", + "amount": { + "amount": "-1.23400000", + "currency": "BTC" + }, + "request": false, + "status": "pending", + "sender": { + "id": "5011f33df8182b142400000e", + "name": "User Two", + "email": "user2@example.com" + }, + "recipient": { + "id": "5011f33df8182b142400000a", + "name": "User One", + "email": "user1@example.com" + }, + "recipient_address": "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare" + } + }
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_users.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_users.json new file mode 100644 index 0000000..b8e866f --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/POST_users.json @@ -0,0 +1,9 @@ +{ + "success": true, + "user": { + "id": "501a3d22f8182b2754000011", + "name": "New User", + "email": "newuser@example.com", + "receive_address": "mpJKwdmJKYjiyfNo26eRp4j6qGwuUUnw9x" + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_complete_request.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_complete_request.json new file mode 100644 index 0000000..a8c2f4a --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_complete_request.json @@ -0,0 +1,18 @@ +{ + "success": true, + "errors": [], + "transaction": { + "id": "503c46a3f8182b106500009b", + "created_at": null, + "hsh": null, + "notes": null, + "amount": { + "amount": "0.00000000", + "currency": "BTC" + }, + "request": false, + "status": "pending", + "recipient": null, + "sender": null + } +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_resend_request.json b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_resend_request.json new file mode 100644 index 0000000..28e7be1 --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/test_data/PUT_transactions_ID_resend_request.json @@ -0,0 +1,3 @@ +{ + "success": true +}
\ No newline at end of file diff --git a/vendor/_nuts/github.com/fabioberger/coinbase-go/utils.go b/vendor/_nuts/github.com/fabioberger/coinbase-go/utils.go new file mode 100644 index 0000000..329e59c --- /dev/null +++ b/vendor/_nuts/github.com/fabioberger/coinbase-go/utils.go @@ -0,0 +1,12 @@ +package coinbase + +import ( + "net" + "time" +) + +// dialTimeout is used to enforce a timeout for all http requests. +func dialTimeout(network, addr string) (net.Conn, error) { + var timeout = time.Duration(2 * time.Second) //how long to wait when trying to connect to the coinbase + return net.DialTimeout(network, addr, timeout) +} diff --git a/vendor/_nuts/github.com/go-martini/martini/.gitignore b/vendor/_nuts/github.com/go-martini/martini/.gitignore new file mode 100644 index 0000000..bb78b21 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/.gitignore @@ -0,0 +1,26 @@ +# 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 +*.test + +/.godeps +/.envrc diff --git a/vendor/_nuts/github.com/go-martini/martini/Godeps b/vendor/_nuts/github.com/go-martini/martini/Godeps new file mode 100644 index 0000000..c988ca4 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/Godeps @@ -0,0 +1 @@ +github.com/codegangsta/inject master diff --git a/vendor/_nuts/github.com/go-martini/martini/LICENSE b/vendor/_nuts/github.com/go-martini/martini/LICENSE new file mode 100644 index 0000000..d3fefb8 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015 Jeremy Saenz + +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. diff --git a/vendor/_nuts/github.com/go-martini/martini/README.md b/vendor/_nuts/github.com/go-martini/martini/README.md new file mode 100644 index 0000000..9ce77ff --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/README.md @@ -0,0 +1,394 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini is a powerful package for quickly writing modular web applications/services in Golang. + +Language Translations: +* [繁體中文](translations/README_zh_tw.md) +* [简体中文](translations/README_zh_cn.md) +* [Português Brasileiro (pt_BR)](translations/README_pt_br.md) +* [Español](translations/README_es_ES.md) +* [한국어 번역](translations/README_ko_kr.md) +* [Русский](translations/README_ru_RU.md) +* [日本語](translations/README_ja_JP.md) +* [French](translations/README_fr_FR.md) +* [Turkish](translations/README_tr_TR.md) +* [German](translations/README_de_DE.md) + +## Getting Started + +After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +Then install the Martini package (**go 1.1** or greater is required): +~~~ +go get github.com/go-martini/martini +~~~ + +Then run your server: +~~~ +go run server.go +~~~ + +You will now have a Martini webserver running on `localhost:3000`. + +## Getting Help + +Join the [Mailing list](https://groups.google.com/forum/#!forum/martini-go) + +Watch the [Demo Video](http://martini.codegangsta.io/#demo) + +Ask questions on Stackoverflow using the [martini tag](http://stackoverflow.com/questions/tagged/martini) + +GoDoc [documentation](http://godoc.org/github.com/go-martini/martini) + + +## Features +* Extremely simple to use. +* Non-intrusive design. +* Plays nice with other Golang packages. +* Awesome path matching and routing. +* Modular design - Easy to add functionality, easy to rip stuff out. +* Lots of good handlers/middlewares to use. +* Great 'out of the box' feature set. +* **Fully compatible with the [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) interface.** +* Default document serving (e.g., for serving AngularJS apps in HTML5 mode). + +## More Middleware +For more middleware and functionality, check out the repositories in the [martini-contrib](https://github.com/martini-contrib) organization. + +## Table of Contents +* [Classic Martini](#classic-martini) + * [Handlers](#handlers) + * [Routing](#routing) + * [Services](#services) + * [Serving Static Files](#serving-static-files) +* [Middleware Handlers](#middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +To get up and running quickly, [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) provides some reasonable defaults that work well for most web applications: +~~~ go + m := martini.Classic() + // ... middleware and routing goes here + m.Run() +~~~ + +Below is some of the functionality [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) pulls in automatically: + * Request/Response Logging - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Static File serving - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Routing - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### Handlers +Handlers are the heart and soul of Martini. A handler is basically any kind of callable function: +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Return Values +If a handler returns something, Martini will write the result to the current [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) as a string: +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +You can also optionally return a status code: +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### Service Injection +Handlers are invoked via reflection. Martini makes use of *Dependency Injection* to resolve dependencies in a Handlers argument list. **This makes Martini completely compatible with golang's `http.HandlerFunc` interface.** + +If you add an argument to your Handler, Martini will search its list of services and attempt to resolve the dependency via type assertion: +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +The following services are included with [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * [*log.Logger](http://godoc.org/log#Logger) - Global logger for Martini. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request context. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` of named params found by route matching. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Route helper service. + * [martini.Route](http://godoc.org/github.com/go-martini/martini#Route) - Current active route. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer interface. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### Routing +In Martini, a route is an HTTP method paired with a URL-matching pattern. +Each route can take one or more handler methods: +~~~ go +m.Get("/", func() { + // show something +}) + +m.Patch("/", func() { + // update something +}) + +m.Post("/", func() { + // create something +}) + +m.Put("/", func() { + // replace something +}) + +m.Delete("/", func() { + // destroy something +}) + +m.Options("/", func() { + // http options +}) + +m.NotFound(func() { + // handle 404 +}) +~~~ + +Routes are matched in the order they are defined. The first route that +matches the request is invoked. + +Route patterns may include named parameters, accessible via the [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) service: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Routes can be matched with globs: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +Regular expressions can be used as well: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +Take a look at the [Go documentation](http://golang.org/pkg/regexp/syntax/) for more info about regular expressions syntax . + +Route handlers can be stacked on top of each other, which is useful for things like authentication and authorization: +~~~ go +m.Get("/secret", authorize, func() { + // this will execute as long as authorize doesn't write a response +}) +~~~ + +Route groups can be added too using the Group method. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Just like you can pass middlewares to a handler you can pass middlewares to groups. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Services +Services are objects that are available to be injected into a Handler's argument list. You can map a service on a *Global* or *Request* level. + +#### Global Mapping +A Martini instance implements the inject.Injector interface, so mapping a service is easy: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // the service will be available to all handlers as *MyDatabase +// ... +m.Run() +~~~ + +#### Request-Level Mapping +Mapping on the request level can be done in a handler via [martini.Context](http://godoc.org/github.com/go-martini/martini#Context): +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapped as *MyCustomLogger +} +~~~ + +#### Mapping values to Interfaces +One of the most powerful parts about services is the ability to map a service to an interface. For instance, if you wanted to override the [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) with an object that wrapped it and performed extra operations, you can write the following handler: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter +} +~~~ + +### Serving Static Files +A [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) instance automatically serves static files from the "public" directory in the root of your server. +You can serve from more directories by adding more [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) handlers. +~~~ go +m.Use(martini.Static("assets")) // serve from the "assets" directory as well +~~~ + +#### Serving a Default Document +You can specify the URL of a local file to serve when the requested URL is not +found. You can also specify an exclusion prefix so that certain URLs are ignored. +This is useful for servers that serve both static files and have additional +handlers defined (e.g., REST API). When doing so, it's useful to define the +static handler as a part of the NotFound chain. + +The following example serves the `/index.html` file whenever any URL is +requested that does not match any local file and does not start with `/api/v`: +~~~ go +static := martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/api/v"}) +m.NotFound(static, http.NotFound) +~~~ + +## Middleware Handlers +Middleware Handlers sit between the incoming http request and the router. In essence they are no different than any other Handler in Martini. You can add a middleware handler to the stack like so: +~~~ go +m.Use(func() { + // do some middleware stuff +}) +~~~ + +You can have full control over the middleware stack with the `Handlers` function. This will replace any handlers that have been previously set: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware Handlers work really well for things like logging, authorization, authentication, sessions, gzipping, error pages and any other operations that must happen before or after an http request: +~~~ go +// validate an api key +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) is an optional function that Middleware Handlers can call to yield the until after the other Handlers have been executed. This works really well for any operations that must happen after an http request: +~~~ go +// log before and after a request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("before a request") + + c.Next() + + log.Println("after a request") +}) +~~~ + +## Martini Env + +Some Martini handlers make use of the `martini.Env` global variable to provide special functionality for development environments vs production environments. It is recommended that the `MARTINI_ENV=production` environment variable to be set when deploying a Martini server into a production environment. + +## FAQ + +### Where do I find middleware X? + +Start by looking in the [martini-contrib](https://github.com/martini-contrib) projects. If it is not there feel free to contact a martini-contrib team member about adding a new repo to the organization. + +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler for parsing the `Accept-Language` HTTP header. +* [accessflags](https://github.com/martini-contrib/accessflags) - Handler to enable Access Control. +* [auth](https://github.com/martini-contrib/auth) - Handlers for authentication. +* [binding](https://github.com/martini-contrib/binding) - Handler for mapping/validating a raw request into a structure. +* [cors](https://github.com/martini-contrib/cors) - Handler that enables CORS support. +* [csrf](https://github.com/martini-contrib/csrf) - CSRF protection for applications +* [encoder](https://github.com/martini-contrib/encoder) - Encoder service for rendering data in several formats and content negotiation. +* [gzip](https://github.com/martini-contrib/gzip) - Handler for adding gzip compress to requests +* [gorelic](https://github.com/martini-contrib/gorelic) - NewRelic middleware +* [logstasher](https://github.com/martini-contrib/logstasher) - Middleware that prints logstash-compatiable JSON +* [method](https://github.com/martini-contrib/method) - HTTP method overriding via Header or form fields. +* [oauth2](https://github.com/martini-contrib/oauth2) - Handler that provides OAuth 2.0 login for Martini apps. Google Sign-in, Facebook Connect and Github login is supported. +* [permissions2](https://github.com/xyproto/permissions2) - Handler for keeping track of users, login states and permissions. +* [render](https://github.com/martini-contrib/render) - Handler that provides a service for easily rendering JSON and HTML templates. +* [secure](https://github.com/martini-contrib/secure) - Implements a few quick security wins. +* [sessions](https://github.com/martini-contrib/sessions) - Handler that provides a Session service. +* [sessionauth](https://github.com/martini-contrib/sessionauth) - Handler that provides a simple way to make routes require a login, and to handle user logins in the session +* [strict](https://github.com/martini-contrib/strict) - Strict Mode +* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping. +* [staticbin](https://github.com/martini-contrib/staticbin) - Handler for serving static files from binary data +* [throttle](https://github.com/martini-contrib/throttle) - Request rate throttling middleware. +* [vauth](https://github.com/rafecolton/vauth) - Handlers for vender webhook authentication (currently GitHub and TravisCI) +* [web](https://github.com/martini-contrib/web) - hoisie web.go's Context + +### How do I integrate with existing servers? + +A Martini instance implements `http.Handler`, so it can easily be used to serve subtrees +on existing Go servers. For example this is a working Martini app for Google App Engine: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### How do I change the port/host? + +Martini's `Run` function looks for the PORT and HOST environment variables and uses those. Otherwise Martini will default to localhost:3000. +To have more flexibility over port and host, use the `martini.RunOnAddr` function instead. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Live code reload? + +[gin](https://github.com/codegangsta/gin) and [fresh](https://github.com/pilu/fresh) both live reload martini apps. + +## Contributing +Martini is meant to be kept tiny and clean. Most contributions should end up in a repository in the [martini-contrib](https://github.com/martini-contrib) organization. If you do have a contribution for the core of Martini feel free to put up a Pull Request. + +## About + +Inspired by [express](https://github.com/visionmedia/express) and [sinatra](https://github.com/sinatra/sinatra) + +Martini is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/) diff --git a/vendor/_nuts/github.com/go-martini/martini/env.go b/vendor/_nuts/github.com/go-martini/martini/env.go new file mode 100644 index 0000000..54d5857 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/env.go @@ -0,0 +1,31 @@ +package martini + +import ( + "os" +) + +// Envs +const ( + Dev string = "development" + Prod string = "production" + Test string = "test" +) + +// Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable. +var Env = Dev +var Root string + +func setENV(e string) { + if len(e) > 0 { + Env = e + } +} + +func init() { + setENV(os.Getenv("MARTINI_ENV")) + var err error + Root, err = os.Getwd() + if err != nil { + panic(err) + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/env_test.go b/vendor/_nuts/github.com/go-martini/martini/env_test.go new file mode 100644 index 0000000..d82351e --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/env_test.go @@ -0,0 +1,28 @@ +package martini + +import ( + "testing" +) + +func Test_SetENV(t *testing.T) { + tests := []struct { + in string + out string + }{ + {"", "development"}, + {"not_development", "not_development"}, + } + + for _, test := range tests { + setENV(test.in) + if Env != test.out { + expect(t, Env, test.out) + } + } +} + +func Test_Root(t *testing.T) { + if len(Root) == 0 { + t.Errorf("Expected root path will be set") + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/go_version.go b/vendor/_nuts/github.com/go-martini/martini/go_version.go new file mode 100644 index 0000000..bd271a8 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/go_version.go @@ -0,0 +1,7 @@ +// +build !go1.1 + +package martini + +func MartiniDoesNotSupportGo1Point0() { + "Martini requires Go 1.1 or greater." +} diff --git a/vendor/_nuts/github.com/go-martini/martini/logger.go b/vendor/_nuts/github.com/go-martini/martini/logger.go new file mode 100644 index 0000000..d01107c --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/logger.go @@ -0,0 +1,29 @@ +package martini + +import ( + "log" + "net/http" + "time" +) + +// Logger returns a middleware handler that logs the request as it goes in and the response as it goes out. +func Logger() Handler { + return func(res http.ResponseWriter, req *http.Request, c Context, log *log.Logger) { + start := time.Now() + + addr := req.Header.Get("X-Real-IP") + if addr == "" { + addr = req.Header.Get("X-Forwarded-For") + if addr == "" { + addr = req.RemoteAddr + } + } + + log.Printf("Started %s %s for %s", req.Method, req.URL.Path, addr) + + rw := res.(ResponseWriter) + c.Next() + + log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/logger_test.go b/vendor/_nuts/github.com/go-martini/martini/logger_test.go new file mode 100644 index 0000000..156b149 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/logger_test.go @@ -0,0 +1,31 @@ +package martini + +import ( + "bytes" + "log" + "net/http" + "net/http/httptest" + "testing" +) + +func Test_Logger(t *testing.T) { + buff := bytes.NewBufferString("") + recorder := httptest.NewRecorder() + + m := New() + // replace log for testing + m.Map(log.New(buff, "[martini] ", 0)) + m.Use(Logger()) + m.Use(func(res http.ResponseWriter) { + res.WriteHeader(http.StatusNotFound) + }) + + req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(recorder, req) + expect(t, recorder.Code, http.StatusNotFound) + refute(t, len(buff.String()), 0) +} diff --git a/vendor/_nuts/github.com/go-martini/martini/martini.go b/vendor/_nuts/github.com/go-martini/martini/martini.go new file mode 100644 index 0000000..104d98c --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/martini.go @@ -0,0 +1,183 @@ +// Package martini is a powerful package for quickly writing modular web applications/services in Golang. +// +// For a full guide visit http://github.com/go-martini/martini +// +// package main +// +// import "github.com/go-martini/martini" +// +// func main() { +// m := martini.Classic() +// +// m.Get("/", func() string { +// return "Hello world!" +// }) +// +// m.Run() +// } +package martini + +import ( + "log" + "net/http" + "os" + "reflect" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/codegangsta/inject" +) + +// Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level. +type Martini struct { + inject.Injector + handlers []Handler + action Handler + logger *log.Logger +} + +// New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used. +func New() *Martini { + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + return m +} + +// Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers. +// Will panic if any of the handlers is not a callable function +func (m *Martini) Handlers(handlers ...Handler) { + m.handlers = make([]Handler, 0) + for _, handler := range handlers { + m.Use(handler) + } +} + +// Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic(). +func (m *Martini) Action(handler Handler) { + validateHandler(handler) + m.action = handler +} + +// Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added. +func (m *Martini) Use(handler Handler) { + validateHandler(handler) + + m.handlers = append(m.handlers, handler) +} + +// ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server. +func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) { + m.createContext(res, req).run() +} + +// Run the http server on a given host and port. +func (m *Martini) RunOnAddr(addr string) { + // TODO: Should probably be implemented using a new instance of http.Server in place of + // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. + // This would also allow to improve testing when a custom host and port are passed. + + logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) + logger.Printf("listening on %s (%s)\n", addr, Env) + logger.Fatalln(http.ListenAndServe(addr, m)) +} + +// Run the http server. Listening on os.GetEnv("PORT") or 3000 by default. +func (m *Martini) Run() { + port := os.Getenv("PORT") + if len(port) == 0 { + port = "3000" + } + + host := os.Getenv("HOST") + + m.RunOnAddr(host + ":" + port) +} + +func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context { + c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0} + c.SetParent(m) + c.MapTo(c, (*Context)(nil)) + c.MapTo(c.rw, (*http.ResponseWriter)(nil)) + c.Map(req) + return c +} + +// ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience. +type ClassicMartini struct { + *Martini + Router +} + +// Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery and martini.Static. +// Classic also maps martini.Routes as a service. +func Classic() *ClassicMartini { + r := NewRouter() + m := New() + m.Use(Logger()) + m.Use(Recovery()) + m.Use(Static("public")) + m.MapTo(r, (*Routes)(nil)) + m.Action(r.Handle) + return &ClassicMartini{m, r} +} + +// Handler can be any callable function. Martini attempts to inject services into the handler's argument list. +// Martini will panic if an argument could not be fullfilled via dependency injection. +type Handler interface{} + +func validateHandler(handler Handler) { + if reflect.TypeOf(handler).Kind() != reflect.Func { + panic("martini handler must be a callable func") + } +} + +// Context represents a request context. Services can be mapped on the request level from this interface. +type Context interface { + inject.Injector + // Next is an optional function that Middleware Handlers can call to yield the until after + // the other Handlers have been executed. This works really well for any operations that must + // happen after an http request + Next() + // Written returns whether or not the response for this context has been written. + Written() bool +} + +type context struct { + inject.Injector + handlers []Handler + action Handler + rw ResponseWriter + index int +} + +func (c *context) handler() Handler { + if c.index < len(c.handlers) { + return c.handlers[c.index] + } + if c.index == len(c.handlers) { + return c.action + } + panic("invalid index for context handler") +} + +func (c *context) Next() { + c.index += 1 + c.run() +} + +func (c *context) Written() bool { + return c.rw.Written() +} + +func (c *context) run() { + for c.index <= len(c.handlers) { + _, err := c.Invoke(c.handler()) + if err != nil { + panic(err) + } + c.index += 1 + + if c.Written() { + return + } + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/martini_test.go b/vendor/_nuts/github.com/go-martini/martini/martini_test.go new file mode 100644 index 0000000..f16bf3e --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/martini_test.go @@ -0,0 +1,145 @@ +package martini + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" +) + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if a != b { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func Test_New(t *testing.T) { + m := New() + if m == nil { + t.Error("martini.New() cannot return nil") + } +} + +func Test_Martini_RunOnAddr(t *testing.T) { + // just test that Run doesn't bomb + go New().RunOnAddr("127.0.0.1:8080") +} + +func Test_Martini_Run(t *testing.T) { + go New().Run() +} + +func Test_Martini_ServeHTTP(t *testing.T) { + result := "" + response := httptest.NewRecorder() + + m := New() + m.Use(func(c Context) { + result += "foo" + c.Next() + result += "ban" + }) + m.Use(func(c Context) { + result += "bar" + c.Next() + result += "baz" + }) + m.Action(func(res http.ResponseWriter, req *http.Request) { + result += "bat" + res.WriteHeader(http.StatusBadRequest) + }) + + m.ServeHTTP(response, (*http.Request)(nil)) + + expect(t, result, "foobarbatbazban") + expect(t, response.Code, http.StatusBadRequest) +} + +func Test_Martini_Handlers(t *testing.T) { + result := "" + response := httptest.NewRecorder() + + batman := func(c Context) { + result += "batman!" + } + + m := New() + m.Use(func(c Context) { + result += "foo" + c.Next() + result += "ban" + }) + m.Handlers( + batman, + batman, + batman, + ) + m.Action(func(res http.ResponseWriter, req *http.Request) { + result += "bat" + res.WriteHeader(http.StatusBadRequest) + }) + + m.ServeHTTP(response, (*http.Request)(nil)) + + expect(t, result, "batman!batman!batman!bat") + expect(t, response.Code, http.StatusBadRequest) +} + +func Test_Martini_EarlyWrite(t *testing.T) { + result := "" + response := httptest.NewRecorder() + + m := New() + m.Use(func(res http.ResponseWriter) { + result += "foobar" + res.Write([]byte("Hello world")) + }) + m.Use(func() { + result += "bat" + }) + m.Action(func(res http.ResponseWriter) { + result += "baz" + res.WriteHeader(http.StatusBadRequest) + }) + + m.ServeHTTP(response, (*http.Request)(nil)) + + expect(t, result, "foobar") + expect(t, response.Code, http.StatusOK) +} + +func Test_Martini_Written(t *testing.T) { + response := httptest.NewRecorder() + + m := New() + m.Handlers(func(res http.ResponseWriter) { + res.WriteHeader(http.StatusOK) + }) + + ctx := m.createContext(response, (*http.Request)(nil)) + expect(t, ctx.Written(), false) + + ctx.run() + expect(t, ctx.Written(), true) +} + +func Test_Martini_Basic_NoRace(t *testing.T) { + m := New() + handlers := []Handler{func() {}, func() {}} + // Ensure append will not realloc to trigger the race condition + m.handlers = handlers[:1] + req, _ := http.NewRequest("GET", "/", nil) + for i := 0; i < 2; i++ { + go func() { + response := httptest.NewRecorder() + m.ServeHTTP(response, req) + }() + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/recovery.go b/vendor/_nuts/github.com/go-martini/martini/recovery.go new file mode 100644 index 0000000..e06739f --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/recovery.go @@ -0,0 +1,144 @@ +package martini + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" + "runtime" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/codegangsta/inject" +) + +const ( + panicHtml = `<html> +<head><title>PANIC: %s</title> +<style type="text/css"> +html, body { + font-family: "Roboto", sans-serif; + color: #333333; + background-color: #ea5343; + margin: 0px; +} +h1 { + color: #d04526; + background-color: #ffffff; + padding: 20px; + border-bottom: 1px dashed #2b3848; +} +pre { + margin: 20px; + padding: 20px; + border: 2px solid #2b3848; + background-color: #ffffff; +} +</style> +</head><body> +<h1>PANIC</h1> +<pre style="font-weight: bold;">%s</pre> +<pre>%s</pre> +</body> +</html>` +) + +var ( + dunno = []byte("???") + centerDot = []byte("·") + dot = []byte(".") + slash = []byte("/") +) + +// stack returns a nicely formated stack frame, skipping skip frames +func stack(skip int) []byte { + buf := new(bytes.Buffer) // the returned data + // As we loop, we open files and read them. These variables record the currently + // loaded file. + var lines [][]byte + var lastFile string + for i := skip; ; i++ { // Skip the expected number of frames + pc, file, line, ok := runtime.Caller(i) + if !ok { + break + } + // Print this much at least. If we can't find the source, it won't show. + fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) + if file != lastFile { + data, err := ioutil.ReadFile(file) + if err != nil { + continue + } + lines = bytes.Split(data, []byte{'\n'}) + lastFile = file + } + fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) + } + return buf.Bytes() +} + +// source returns a space-trimmed slice of the n'th line. +func source(lines [][]byte, n int) []byte { + n-- // in stack trace, lines are 1-indexed but our array is 0-indexed + if n < 0 || n >= len(lines) { + return dunno + } + return bytes.TrimSpace(lines[n]) +} + +// function returns, if possible, the name of the function containing the PC. +func function(pc uintptr) []byte { + fn := runtime.FuncForPC(pc) + if fn == nil { + return dunno + } + name := []byte(fn.Name()) + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + // Also the package path might contains dot (e.g. code.google.com/...), + // so first eliminate the path prefix + if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 { + name = name[lastslash+1:] + } + if period := bytes.Index(name, dot); period >= 0 { + name = name[period+1:] + } + name = bytes.Replace(name, centerDot, dot, -1) + return name +} + +// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. +// While Martini is in development mode, Recovery will also output the panic as HTML. +func Recovery() Handler { + return func(c Context, log *log.Logger) { + defer func() { + if err := recover(); err != nil { + stack := stack(3) + log.Printf("PANIC: %s\n%s", err, stack) + + // Lookup the current responsewriter + val := c.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))) + res := val.Interface().(http.ResponseWriter) + + // respond with panic message while in development mode + var body []byte + if Env == Dev { + res.Header().Set("Content-Type", "text/html") + body = []byte(fmt.Sprintf(panicHtml, err, err, stack)) + } else { + body = []byte("500 Internal Server Error") + } + + res.WriteHeader(http.StatusInternalServerError) + if nil != body { + res.Write(body) + } + } + }() + + c.Next() + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/recovery_test.go b/vendor/_nuts/github.com/go-martini/martini/recovery_test.go new file mode 100644 index 0000000..17e2e01 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/recovery_test.go @@ -0,0 +1,49 @@ +package martini + +import ( + "bytes" + "log" + "net/http" + "net/http/httptest" + "testing" +) + +func Test_Recovery(t *testing.T) { + buff := bytes.NewBufferString("") + recorder := httptest.NewRecorder() + + setENV(Dev) + m := New() + // replace log for testing + m.Map(log.New(buff, "[martini] ", 0)) + m.Use(func(res http.ResponseWriter, req *http.Request) { + res.Header().Set("Content-Type", "unpredictable") + }) + m.Use(Recovery()) + m.Use(func(res http.ResponseWriter, req *http.Request) { + panic("here is a panic!") + }) + m.ServeHTTP(recorder, (*http.Request)(nil)) + expect(t, recorder.Code, http.StatusInternalServerError) + expect(t, recorder.HeaderMap.Get("Content-Type"), "text/html") + refute(t, recorder.Body.Len(), 0) + refute(t, len(buff.String()), 0) +} + +func Test_Recovery_ResponseWriter(t *testing.T) { + recorder := httptest.NewRecorder() + recorder2 := httptest.NewRecorder() + + setENV(Dev) + m := New() + m.Use(Recovery()) + m.Use(func(c Context) { + c.MapTo(recorder2, (*http.ResponseWriter)(nil)) + panic("here is a panic!") + }) + m.ServeHTTP(recorder, (*http.Request)(nil)) + + expect(t, recorder2.Code, http.StatusInternalServerError) + expect(t, recorder2.HeaderMap.Get("Content-Type"), "text/html") + refute(t, recorder2.Body.Len(), 0) +} diff --git a/vendor/_nuts/github.com/go-martini/martini/response_writer.go b/vendor/_nuts/github.com/go-martini/martini/response_writer.go new file mode 100644 index 0000000..8bef0bc --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/response_writer.go @@ -0,0 +1,98 @@ +package martini + +import ( + "bufio" + "fmt" + "net" + "net/http" +) + +// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about +// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter +// if the functionality calls for it. +type ResponseWriter interface { + http.ResponseWriter + http.Flusher + http.Hijacker + // Status returns the status code of the response or 0 if the response has not been written. + Status() int + // Written returns whether or not the ResponseWriter has been written. + Written() bool + // Size returns the size of the response body. + Size() int + // Before allows for a function to be called before the ResponseWriter has been written to. This is + // useful for setting headers or any other operations that must happen before a response has been written. + Before(BeforeFunc) +} + +// BeforeFunc is a function that is called before the ResponseWriter has been written to. +type BeforeFunc func(ResponseWriter) + +// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { + return &responseWriter{rw, 0, 0, nil} +} + +type responseWriter struct { + http.ResponseWriter + status int + size int + beforeFuncs []BeforeFunc +} + +func (rw *responseWriter) WriteHeader(s int) { + rw.callBefore() + rw.ResponseWriter.WriteHeader(s) + rw.status = s +} + +func (rw *responseWriter) Write(b []byte) (int, error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + size, err := rw.ResponseWriter.Write(b) + rw.size += size + return size, err +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) Size() int { + return rw.size +} + +func (rw *responseWriter) Written() bool { + return rw.status != 0 +} + +func (rw *responseWriter) Before(before BeforeFunc) { + rw.beforeFuncs = append(rw.beforeFuncs, before) +} + +func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := rw.ResponseWriter.(http.Hijacker) + if !ok { + return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface") + } + return hijacker.Hijack() +} + +func (rw *responseWriter) CloseNotify() <-chan bool { + return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +func (rw *responseWriter) callBefore() { + for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { + rw.beforeFuncs[i](rw) + } +} + +func (rw *responseWriter) Flush() { + flusher, ok := rw.ResponseWriter.(http.Flusher) + if ok { + flusher.Flush() + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/response_writer_test.go b/vendor/_nuts/github.com/go-martini/martini/response_writer_test.go new file mode 100644 index 0000000..6ccb9e0 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/response_writer_test.go @@ -0,0 +1,188 @@ +package martini + +import ( + "bufio" + "io" + "net" + "net/http" + "net/http/httptest" + "testing" + "time" +) + +type closeNotifyingRecorder struct { + *httptest.ResponseRecorder + closed chan bool +} + +func newCloseNotifyingRecorder() *closeNotifyingRecorder { + return &closeNotifyingRecorder{ + httptest.NewRecorder(), + make(chan bool, 1), + } +} + +func (c *closeNotifyingRecorder) close() { + c.closed <- true +} + +func (c *closeNotifyingRecorder) CloseNotify() <-chan bool { + return c.closed +} + +type hijackableResponse struct { + Hijacked bool +} + +func newHijackableResponse() *hijackableResponse { + return &hijackableResponse{} +} + +func (h *hijackableResponse) Header() http.Header { return nil } +func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil } +func (h *hijackableResponse) WriteHeader(code int) {} +func (h *hijackableResponse) Flush() {} +func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) { + h.Hijacked = true + return nil, nil, nil +} + +func Test_ResponseWriter_WritingString(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + rw.Write([]byte("Hello world")) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "Hello world") + expect(t, rw.Status(), http.StatusOK) + expect(t, rw.Size(), 11) + expect(t, rw.Written(), true) +} + +func Test_ResponseWriter_WritingStrings(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + rw.Write([]byte("Hello world")) + rw.Write([]byte("foo bar bat baz")) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "Hello worldfoo bar bat baz") + expect(t, rw.Status(), http.StatusOK) + expect(t, rw.Size(), 26) +} + +func Test_ResponseWriter_WritingHeader(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + rw.WriteHeader(http.StatusNotFound) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "") + expect(t, rw.Status(), http.StatusNotFound) + expect(t, rw.Size(), 0) +} + +func Test_ResponseWriter_Before(t *testing.T) { + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + result := "" + + rw.Before(func(ResponseWriter) { + result += "foo" + }) + rw.Before(func(ResponseWriter) { + result += "bar" + }) + + rw.WriteHeader(http.StatusNotFound) + + expect(t, rec.Code, rw.Status()) + expect(t, rec.Body.String(), "") + expect(t, rw.Status(), http.StatusNotFound) + expect(t, rw.Size(), 0) + expect(t, result, "barfoo") +} + +func Test_ResponseWriter_Hijack(t *testing.T) { + hijackable := newHijackableResponse() + rw := NewResponseWriter(hijackable) + hijacker, ok := rw.(http.Hijacker) + expect(t, ok, true) + _, _, err := hijacker.Hijack() + if err != nil { + t.Error(err) + } + expect(t, hijackable.Hijacked, true) +} + +func Test_ResponseWrite_Hijack_NotOK(t *testing.T) { + hijackable := new(http.ResponseWriter) + rw := NewResponseWriter(*hijackable) + hijacker, ok := rw.(http.Hijacker) + expect(t, ok, true) + _, _, err := hijacker.Hijack() + + refute(t, err, nil) +} + +func Test_ResponseWriter_CloseNotify(t *testing.T) { + rec := newCloseNotifyingRecorder() + rw := NewResponseWriter(rec) + closed := false + notifier := rw.(http.CloseNotifier).CloseNotify() + rec.close() + select { + case <-notifier: + closed = true + case <-time.After(time.Second): + } + expect(t, closed, true) +} + +func Test_ResponseWriter_Flusher(t *testing.T) { + + rec := httptest.NewRecorder() + rw := NewResponseWriter(rec) + + _, ok := rw.(http.Flusher) + expect(t, ok, true) +} + +func Test_ResponseWriter_FlusherHandler(t *testing.T) { + + // New martini instance + m := Classic() + + m.Get("/events", func(w http.ResponseWriter, r *http.Request) { + + f, ok := w.(http.Flusher) + expect(t, ok, true) + + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + + for i := 0; i < 2; i++ { + time.Sleep(10 * time.Millisecond) + io.WriteString(w, "data: Hello\n\n") + f.Flush() + } + + }) + + recorder := httptest.NewRecorder() + r, _ := http.NewRequest("GET", "/events", nil) + m.ServeHTTP(recorder, r) + + if recorder.Code != 200 { + t.Error("Response not 200") + } + + if recorder.Body.String() != "data: Hello\n\ndata: Hello\n\n" { + t.Error("Didn't receive correct body, got:", recorder.Body.String()) + } + +} diff --git a/vendor/_nuts/github.com/go-martini/martini/return_handler.go b/vendor/_nuts/github.com/go-martini/martini/return_handler.go new file mode 100644 index 0000000..511181c --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/return_handler.go @@ -0,0 +1,43 @@ +package martini + +import ( + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/codegangsta/inject" + "net/http" + "reflect" +) + +// ReturnHandler is a service that Martini provides that is called +// when a route handler returns something. The ReturnHandler is +// responsible for writing to the ResponseWriter based on the values +// that are passed into this function. +type ReturnHandler func(Context, []reflect.Value) + +func defaultReturnHandler() ReturnHandler { + return func(ctx Context, vals []reflect.Value) { + rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))) + res := rv.Interface().(http.ResponseWriter) + var responseVal reflect.Value + if len(vals) > 1 && vals[0].Kind() == reflect.Int { + res.WriteHeader(int(vals[0].Int())) + responseVal = vals[1] + } else if len(vals) > 0 { + responseVal = vals[0] + } + if canDeref(responseVal) { + responseVal = responseVal.Elem() + } + if isByteSlice(responseVal) { + res.Write(responseVal.Bytes()) + } else { + res.Write([]byte(responseVal.String())) + } + } +} + +func isByteSlice(val reflect.Value) bool { + return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8 +} + +func canDeref(val reflect.Value) bool { + return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr +} diff --git a/vendor/_nuts/github.com/go-martini/martini/router.go b/vendor/_nuts/github.com/go-martini/martini/router.go new file mode 100644 index 0000000..3abbabb --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/router.go @@ -0,0 +1,425 @@ +package martini + +import ( + "fmt" + "net/http" + "reflect" + "regexp" + "strconv" + "sync" +) + +// Params is a map of name/value pairs for named routes. An instance of martini.Params is available to be injected into any route handler. +type Params map[string]string + +// Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection. +type Router interface { + Routes + + // Group adds a group where related routes can be added. + Group(string, func(Router), ...Handler) + // Get adds a route for a HTTP GET request to the specified matching pattern. + Get(string, ...Handler) Route + // Patch adds a route for a HTTP PATCH request to the specified matching pattern. + Patch(string, ...Handler) Route + // Post adds a route for a HTTP POST request to the specified matching pattern. + Post(string, ...Handler) Route + // Put adds a route for a HTTP PUT request to the specified matching pattern. + Put(string, ...Handler) Route + // Delete adds a route for a HTTP DELETE request to the specified matching pattern. + Delete(string, ...Handler) Route + // Options adds a route for a HTTP OPTIONS request to the specified matching pattern. + Options(string, ...Handler) Route + // Head adds a route for a HTTP HEAD request to the specified matching pattern. + Head(string, ...Handler) Route + // Any adds a route for any HTTP method request to the specified matching pattern. + Any(string, ...Handler) Route + // AddRoute adds a route for a given HTTP method request to the specified matching pattern. + AddRoute(string, string, ...Handler) Route + + // NotFound sets the handlers that are called when a no route matches a request. Throws a basic 404 by default. + NotFound(...Handler) + + // Handle is the entry point for routing. This is used as a martini.Handler + Handle(http.ResponseWriter, *http.Request, Context) +} + +type router struct { + routes []*route + notFounds []Handler + groups []group + routesLock sync.RWMutex +} + +type group struct { + pattern string + handlers []Handler +} + +// NewRouter creates a new Router instance. +// If you aren't using ClassicMartini, then you can add Routes as a +// service with: +// +// m := martini.New() +// r := martini.NewRouter() +// m.MapTo(r, (*martini.Routes)(nil)) +// +// If you are using ClassicMartini, then this is done for you. +func NewRouter() Router { + return &router{notFounds: []Handler{http.NotFound}, groups: make([]group, 0)} +} + +func (r *router) Group(pattern string, fn func(Router), h ...Handler) { + r.groups = append(r.groups, group{pattern, h}) + fn(r) + r.groups = r.groups[:len(r.groups)-1] +} + +func (r *router) Get(pattern string, h ...Handler) Route { + return r.addRoute("GET", pattern, h) +} + +func (r *router) Patch(pattern string, h ...Handler) Route { + return r.addRoute("PATCH", pattern, h) +} + +func (r *router) Post(pattern string, h ...Handler) Route { + return r.addRoute("POST", pattern, h) +} + +func (r *router) Put(pattern string, h ...Handler) Route { + return r.addRoute("PUT", pattern, h) +} + +func (r *router) Delete(pattern string, h ...Handler) Route { + return r.addRoute("DELETE", pattern, h) +} + +func (r *router) Options(pattern string, h ...Handler) Route { + return r.addRoute("OPTIONS", pattern, h) +} + +func (r *router) Head(pattern string, h ...Handler) Route { + return r.addRoute("HEAD", pattern, h) +} + +func (r *router) Any(pattern string, h ...Handler) Route { + return r.addRoute("*", pattern, h) +} + +func (r *router) AddRoute(method, pattern string, h ...Handler) Route { + return r.addRoute(method, pattern, h) +} + +func (r *router) Handle(res http.ResponseWriter, req *http.Request, context Context) { + bestMatch := NoMatch + var bestVals map[string]string + var bestRoute *route + for _, route := range r.getRoutes() { + match, vals := route.Match(req.Method, req.URL.Path) + if match.BetterThan(bestMatch) { + bestMatch = match + bestVals = vals + bestRoute = route + if match == ExactMatch { + break + } + } + } + if bestMatch != NoMatch { + params := Params(bestVals) + context.Map(params) + bestRoute.Handle(context, res) + return + } + + // no routes exist, 404 + c := &routeContext{context, 0, r.notFounds} + context.MapTo(c, (*Context)(nil)) + c.run() +} + +func (r *router) NotFound(handler ...Handler) { + r.notFounds = handler +} + +func (r *router) addRoute(method string, pattern string, handlers []Handler) *route { + if len(r.groups) > 0 { + groupPattern := "" + h := make([]Handler, 0) + for _, g := range r.groups { + groupPattern += g.pattern + h = append(h, g.handlers...) + } + + pattern = groupPattern + pattern + h = append(h, handlers...) + handlers = h + } + + route := newRoute(method, pattern, handlers) + route.Validate() + r.appendRoute(route) + return route +} + +func (r *router) appendRoute(rt *route) { + r.routesLock.Lock() + defer r.routesLock.Unlock() + r.routes = append(r.routes, rt) +} + +func (r *router) getRoutes() []*route { + r.routesLock.RLock() + defer r.routesLock.RUnlock() + return r.routes[:] +} + +func (r *router) findRoute(name string) *route { + for _, route := range r.getRoutes() { + if route.name == name { + return route + } + } + + return nil +} + +// Route is an interface representing a Route in Martini's routing layer. +type Route interface { + // URLWith returns a rendering of the Route's url with the given string params. + URLWith([]string) string + // Name sets a name for the route. + Name(string) + // GetName returns the name of the route. + GetName() string + // Pattern returns the pattern of the route. + Pattern() string + // Method returns the method of the route. + Method() string +} + +type route struct { + method string + regex *regexp.Regexp + handlers []Handler + pattern string + name string +} + +var routeReg1 = regexp.MustCompile(`:[^/#?()\.\\]+`) +var routeReg2 = regexp.MustCompile(`\*\*`) + +func newRoute(method string, pattern string, handlers []Handler) *route { + route := route{method, nil, handlers, pattern, ""} + pattern = routeReg1.ReplaceAllStringFunc(pattern, func(m string) string { + return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:]) + }) + var index int + pattern = routeReg2.ReplaceAllStringFunc(pattern, func(m string) string { + index++ + return fmt.Sprintf(`(?P<_%d>[^#?]*)`, index) + }) + pattern += `\/?` + route.regex = regexp.MustCompile(pattern) + return &route +} + +type RouteMatch int + +const ( + NoMatch RouteMatch = iota + StarMatch + OverloadMatch + ExactMatch +) + +//Higher number = better match +func (r RouteMatch) BetterThan(o RouteMatch) bool { + return r > o +} + +func (r route) MatchMethod(method string) RouteMatch { + switch { + case method == r.method: + return ExactMatch + case method == "HEAD" && r.method == "GET": + return OverloadMatch + case r.method == "*": + return StarMatch + default: + return NoMatch + } +} + +func (r route) Match(method string, path string) (RouteMatch, map[string]string) { + // add Any method matching support + match := r.MatchMethod(method) + if match == NoMatch { + return match, nil + } + + matches := r.regex.FindStringSubmatch(path) + if len(matches) > 0 && matches[0] == path { + params := make(map[string]string) + for i, name := range r.regex.SubexpNames() { + if len(name) > 0 { + params[name] = matches[i] + } + } + return match, params + } + return NoMatch, nil +} + +func (r *route) Validate() { + for _, handler := range r.handlers { + validateHandler(handler) + } +} + +func (r *route) Handle(c Context, res http.ResponseWriter) { + context := &routeContext{c, 0, r.handlers} + c.MapTo(context, (*Context)(nil)) + c.MapTo(r, (*Route)(nil)) + context.run() +} + +var urlReg = regexp.MustCompile(`:[^/#?()\.\\]+|\(\?P<[a-zA-Z0-9]+>.*\)`) + +// URLWith returns the url pattern replacing the parameters for its values +func (r *route) URLWith(args []string) string { + if len(args) > 0 { + argCount := len(args) + i := 0 + url := urlReg.ReplaceAllStringFunc(r.pattern, func(m string) string { + var val interface{} + if i < argCount { + val = args[i] + } else { + val = m + } + i += 1 + return fmt.Sprintf(`%v`, val) + }) + + return url + } + return r.pattern +} + +func (r *route) Name(name string) { + r.name = name +} + +func (r *route) GetName() string { + return r.name +} + +func (r *route) Pattern() string { + return r.pattern +} + +func (r *route) Method() string { + return r.method +} + +// Routes is a helper service for Martini's routing layer. +type Routes interface { + // URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route. + URLFor(name string, params ...interface{}) string + // MethodsFor returns an array of methods available for the path + MethodsFor(path string) []string + // All returns an array with all the routes in the router. + All() []Route +} + +// URLFor returns the url for the given route name. +func (r *router) URLFor(name string, params ...interface{}) string { + route := r.findRoute(name) + + if route == nil { + panic("route not found") + } + + var args []string + for _, param := range params { + switch v := param.(type) { + case int: + args = append(args, strconv.FormatInt(int64(v), 10)) + case string: + args = append(args, v) + default: + if v != nil { + panic("Arguments passed to URLFor must be integers or strings") + } + } + } + + return route.URLWith(args) +} + +func (r *router) All() []Route { + routes := r.getRoutes() + var ri = make([]Route, len(routes)) + + for i, route := range routes { + ri[i] = Route(route) + } + + return ri +} + +func hasMethod(methods []string, method string) bool { + for _, v := range methods { + if v == method { + return true + } + } + return false +} + +// MethodsFor returns all methods available for path +func (r *router) MethodsFor(path string) []string { + methods := []string{} + for _, route := range r.getRoutes() { + matches := route.regex.FindStringSubmatch(path) + if len(matches) > 0 && matches[0] == path && !hasMethod(methods, route.method) { + methods = append(methods, route.method) + } + } + return methods +} + +type routeContext struct { + Context + index int + handlers []Handler +} + +func (r *routeContext) Next() { + r.index += 1 + r.run() +} + +func (r *routeContext) run() { + for r.index < len(r.handlers) { + handler := r.handlers[r.index] + vals, err := r.Invoke(handler) + if err != nil { + panic(err) + } + r.index += 1 + + // if the handler returned something, write it to the http response + if len(vals) > 0 { + ev := r.Get(reflect.TypeOf(ReturnHandler(nil))) + handleReturn := ev.Interface().(ReturnHandler) + handleReturn(r, vals) + } + + if r.Written() { + return + } + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/router_test.go b/vendor/_nuts/github.com/go-martini/martini/router_test.go new file mode 100644 index 0000000..71f2d39 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/router_test.go @@ -0,0 +1,469 @@ +package martini + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func Test_Routing(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + + req2, _ := http.NewRequest("POST", "http://localhost:3000/bar/bat", nil) + context2 := New().createContext(recorder, req2) + + req3, _ := http.NewRequest("DELETE", "http://localhost:3000/baz", nil) + context3 := New().createContext(recorder, req3) + + req4, _ := http.NewRequest("PATCH", "http://localhost:3000/bar/foo", nil) + context4 := New().createContext(recorder, req4) + + req5, _ := http.NewRequest("GET", "http://localhost:3000/fez/this/should/match", nil) + context5 := New().createContext(recorder, req5) + + req6, _ := http.NewRequest("PUT", "http://localhost:3000/pop/blah/blah/blah/bap/foo/", nil) + context6 := New().createContext(recorder, req6) + + req7, _ := http.NewRequest("DELETE", "http://localhost:3000/wap//pow", nil) + context7 := New().createContext(recorder, req7) + + req8, _ := http.NewRequest("HEAD", "http://localhost:3000/wap//pow", nil) + context8 := New().createContext(recorder, req8) + + req9, _ := http.NewRequest("OPTIONS", "http://localhost:3000/opts", nil) + context9 := New().createContext(recorder, req9) + + req10, _ := http.NewRequest("HEAD", "http://localhost:3000/foo", nil) + context10 := New().createContext(recorder, req10) + + req11, _ := http.NewRequest("GET", "http://localhost:3000/bazz/inga", nil) + context11 := New().createContext(recorder, req11) + + req12, _ := http.NewRequest("POST", "http://localhost:3000/bazz/inga", nil) + context12 := New().createContext(recorder, req12) + + req13, _ := http.NewRequest("GET", "http://localhost:3000/bazz/in/ga", nil) + context13 := New().createContext(recorder, req13) + + req14, _ := http.NewRequest("GET", "http://localhost:3000/bzz", nil) + context14 := New().createContext(recorder, req14) + + result := "" + router.Get("/foo", func(req *http.Request) { + result += "foo" + }) + router.Patch("/bar/:id", func(params Params) { + expect(t, params["id"], "foo") + result += "barfoo" + }) + router.Post("/bar/:id", func(params Params) { + expect(t, params["id"], "bat") + result += "barbat" + }) + router.Put("/fizzbuzz", func() { + result += "fizzbuzz" + }) + router.Delete("/bazzer", func(c Context) { + result += "baz" + }) + router.Get("/fez/**", func(params Params) { + expect(t, params["_1"], "this/should/match") + result += "fez" + }) + router.Put("/pop/**/bap/:id/**", func(params Params) { + expect(t, params["id"], "foo") + expect(t, params["_1"], "blah/blah/blah") + expect(t, params["_2"], "") + result += "popbap" + }) + router.Delete("/wap/**/pow", func(params Params) { + expect(t, params["_1"], "") + result += "wappow" + }) + router.Options("/opts", func() { + result += "opts" + }) + router.Head("/wap/**/pow", func(params Params) { + expect(t, params["_1"], "") + result += "wappow" + }) + router.Group("/bazz", func(r Router) { + r.Get("/inga", func() { + result += "get" + }) + + r.Post("/inga", func() { + result += "post" + }) + + r.Group("/in", func(r Router) { + r.Get("/ga", func() { + result += "ception" + }) + }, func() { + result += "group" + }) + }, func() { + result += "bazz" + }, func() { + result += "inga" + }) + router.AddRoute("GET", "/bzz", func(c Context) { + result += "bzz" + }) + + router.Handle(recorder, req, context) + router.Handle(recorder, req2, context2) + router.Handle(recorder, req3, context3) + router.Handle(recorder, req4, context4) + router.Handle(recorder, req5, context5) + router.Handle(recorder, req6, context6) + router.Handle(recorder, req7, context7) + router.Handle(recorder, req8, context8) + router.Handle(recorder, req9, context9) + router.Handle(recorder, req10, context10) + router.Handle(recorder, req11, context11) + router.Handle(recorder, req12, context12) + router.Handle(recorder, req13, context13) + router.Handle(recorder, req14, context14) + expect(t, result, "foobarbatbarfoofezpopbapwappowwappowoptsfoobazzingagetbazzingapostbazzingagroupceptionbzz") + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "404 page not found\n") +} + +func Test_RouterHandlerStatusCode(t *testing.T) { + router := NewRouter() + router.Get("/foo", func() string { + return "foo" + }) + router.Get("/bar", func() (int, string) { + return http.StatusForbidden, "bar" + }) + router.Get("/baz", func() (string, string) { + return "baz", "BAZ!" + }) + router.Get("/bytes", func() []byte { + return []byte("Bytes!") + }) + router.Get("/interface", func() interface{} { + return "Interface!" + }) + + // code should be 200 if none is returned from the handler + recorder := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "foo") + + // if a status code is returned, it should be used + recorder = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "http://localhost:3000/bar", nil) + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusForbidden) + expect(t, recorder.Body.String(), "bar") + + // shouldn't use the first returned value as a status code if not an integer + recorder = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "http://localhost:3000/baz", nil) + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "baz") + + // Should render bytes as a return value as well. + recorder = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "http://localhost:3000/bytes", nil) + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "Bytes!") + + // Should render interface{} values. + recorder = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "http://localhost:3000/interface", nil) + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "Interface!") +} + +func Test_RouterHandlerStacking(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + + result := "" + + f1 := func() { + result += "foo" + } + + f2 := func(c Context) { + result += "bar" + c.Next() + result += "bing" + } + + f3 := func() string { + result += "bat" + return "Hello world" + } + + f4 := func() { + result += "baz" + } + + router.Get("/foo", f1, f2, f3, f4) + + router.Handle(recorder, req, context) + expect(t, result, "foobarbatbing") + expect(t, recorder.Body.String(), "Hello world") +} + +var routeTests = []struct { + // in + method string + path string + + // out + match RouteMatch + params map[string]string +}{ + {"GET", "/foo/123/bat/321", ExactMatch, map[string]string{"bar": "123", "baz": "321"}}, + {"POST", "/foo/123/bat/321", NoMatch, map[string]string{}}, + {"GET", "/foo/hello/bat/world", ExactMatch, map[string]string{"bar": "hello", "baz": "world"}}, + {"GET", "foo/hello/bat/world", NoMatch, map[string]string{}}, + {"GET", "/foo/123/bat/321/", ExactMatch, map[string]string{"bar": "123", "baz": "321"}}, + {"GET", "/foo/123/bat/321//", NoMatch, map[string]string{}}, + {"GET", "/foo/123//bat/321/", NoMatch, map[string]string{}}, + {"HEAD", "/foo/123/bat/321/", OverloadMatch, map[string]string{"bar": "123", "baz": "321"}}, +} + +func Test_RouteMatching(t *testing.T) { + route := newRoute("GET", "/foo/:bar/bat/:baz", nil) + for _, tt := range routeTests { + match, params := route.Match(tt.method, tt.path) + if match != tt.match || params["bar"] != tt.params["bar"] || params["baz"] != tt.params["baz"] { + t.Errorf("expected: (%v, %v) got: (%v, %v)", tt.match, tt.params, match, params) + } + } +} + +func Test_MethodsFor(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("POST", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + context.MapTo(router, (*Routes)(nil)) + router.Post("/foo/bar", func() { + }) + + router.Post("/fo", func() { + }) + + router.Get("/foo", func() { + }) + + router.Put("/foo", func() { + }) + + router.NotFound(func(routes Routes, w http.ResponseWriter, r *http.Request) { + methods := routes.MethodsFor(r.URL.Path) + if len(methods) != 0 { + w.Header().Set("Allow", strings.Join(methods, ",")) + w.WriteHeader(http.StatusMethodNotAllowed) + } + }) + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusMethodNotAllowed) + expect(t, recorder.Header().Get("Allow"), "GET,PUT") +} + +func Test_NotFound(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + + router.NotFound(func(res http.ResponseWriter) { + http.Error(res, "Nope", http.StatusNotFound) + }) + + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "Nope\n") +} + +func Test_NotFoundAsHandler(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + + router.NotFound(func() string { + return "not found" + }) + + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "not found") + + recorder = httptest.NewRecorder() + + context = New().createContext(recorder, req) + + router.NotFound(func() (int, string) { + return 404, "not found" + }) + + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "not found") + + recorder = httptest.NewRecorder() + + context = New().createContext(recorder, req) + + router.NotFound(func() (int, string) { + return 200, "" + }) + + router.Handle(recorder, req, context) + expect(t, recorder.Code, http.StatusOK) + expect(t, recorder.Body.String(), "") +} + +func Test_NotFoundStacking(t *testing.T) { + router := NewRouter() + recorder := httptest.NewRecorder() + + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + + result := "" + + f1 := func() { + result += "foo" + } + + f2 := func(c Context) { + result += "bar" + c.Next() + result += "bing" + } + + f3 := func() string { + result += "bat" + return "Not Found" + } + + f4 := func() { + result += "baz" + } + + router.NotFound(f1, f2, f3, f4) + + router.Handle(recorder, req, context) + expect(t, result, "foobarbatbing") + expect(t, recorder.Body.String(), "Not Found") +} + +func Test_Any(t *testing.T) { + router := NewRouter() + router.Any("/foo", func(res http.ResponseWriter) { + http.Error(res, "Nope", http.StatusNotFound) + }) + + recorder := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + router.Handle(recorder, req, context) + + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "Nope\n") + + recorder = httptest.NewRecorder() + req, _ = http.NewRequest("PUT", "http://localhost:3000/foo", nil) + context = New().createContext(recorder, req) + router.Handle(recorder, req, context) + + expect(t, recorder.Code, http.StatusNotFound) + expect(t, recorder.Body.String(), "Nope\n") +} + +func Test_URLFor(t *testing.T) { + router := NewRouter() + + router.Get("/foo", func() { + // Nothing + }).Name("foo") + + router.Post("/bar/:id", func(params Params) { + // Nothing + }).Name("bar") + + router.Get("/baz/:id/(?P<name>[a-z]*)", func(params Params, routes Routes) { + // Nothing + }).Name("baz_id") + + router.Get("/bar/:id/:name", func(params Params, routes Routes) { + expect(t, routes.URLFor("foo", nil), "/foo") + expect(t, routes.URLFor("bar", 5), "/bar/5") + expect(t, routes.URLFor("baz_id", 5, "john"), "/baz/5/john") + expect(t, routes.URLFor("bar_id", 5, "john"), "/bar/5/john") + }).Name("bar_id") + + // code should be 200 if none is returned from the handler + recorder := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "http://localhost:3000/bar/foo/bar", nil) + context := New().createContext(recorder, req) + context.MapTo(router, (*Routes)(nil)) + router.Handle(recorder, req, context) +} + +func Test_AllRoutes(t *testing.T) { + router := NewRouter() + + patterns := []string{"/foo", "/fee", "/fii"} + methods := []string{"GET", "POST", "DELETE"} + names := []string{"foo", "fee", "fii"} + + router.Get("/foo", func() {}).Name("foo") + router.Post("/fee", func() {}).Name("fee") + router.Delete("/fii", func() {}).Name("fii") + + for i, r := range router.All() { + expect(t, r.Pattern(), patterns[i]) + expect(t, r.Method(), methods[i]) + expect(t, r.GetName(), names[i]) + } +} + +func Test_ActiveRoute(t *testing.T) { + router := NewRouter() + + router.Get("/foo", func(r Route) { + expect(t, r.Pattern(), "/foo") + expect(t, r.GetName(), "foo") + }).Name("foo") + + // code should be 200 if none is returned from the handler + recorder := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil) + context := New().createContext(recorder, req) + context.MapTo(router, (*Routes)(nil)) + router.Handle(recorder, req, context) +} diff --git a/vendor/_nuts/github.com/go-martini/martini/static.go b/vendor/_nuts/github.com/go-martini/martini/static.go new file mode 100644 index 0000000..51af6cf --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/static.go @@ -0,0 +1,135 @@ +package martini + +import ( + "log" + "net/http" + "net/url" + "path" + "path/filepath" + "strings" +) + +// StaticOptions is a struct for specifying configuration options for the martini.Static middleware. +type StaticOptions struct { + // Prefix is the optional prefix used to serve the static directory content + Prefix string + // SkipLogging will disable [Static] log messages when a static file is served. + SkipLogging bool + // IndexFile defines which file to serve as index if it exists. + IndexFile string + // Expires defines which user-defined function to use for producing a HTTP Expires Header + // https://developers.google.com/speed/docs/insights/LeverageBrowserCaching + Expires func() string + // Fallback defines a default URL to serve when the requested resource was + // not found. + Fallback string + // Exclude defines a pattern for URLs this handler should never process. + Exclude string +} + +func prepareStaticOptions(options []StaticOptions) StaticOptions { + var opt StaticOptions + if len(options) > 0 { + opt = options[0] + } + + // Defaults + if len(opt.IndexFile) == 0 { + opt.IndexFile = "index.html" + } + // Normalize the prefix if provided + if opt.Prefix != "" { + // Ensure we have a leading '/' + if opt.Prefix[0] != '/' { + opt.Prefix = "/" + opt.Prefix + } + // Remove any trailing '/' + opt.Prefix = strings.TrimRight(opt.Prefix, "/") + } + return opt +} + +// Static returns a middleware handler that serves static files in the given directory. +func Static(directory string, staticOpt ...StaticOptions) Handler { + if !filepath.IsAbs(directory) { + directory = filepath.Join(Root, directory) + } + dir := http.Dir(directory) + opt := prepareStaticOptions(staticOpt) + + return func(res http.ResponseWriter, req *http.Request, log *log.Logger) { + if req.Method != "GET" && req.Method != "HEAD" { + return + } + if opt.Exclude != "" && strings.HasPrefix(req.URL.Path, opt.Exclude) { + return + } + file := req.URL.Path + // if we have a prefix, filter requests by stripping the prefix + if opt.Prefix != "" { + if !strings.HasPrefix(file, opt.Prefix) { + return + } + file = file[len(opt.Prefix):] + if file != "" && file[0] != '/' { + return + } + } + f, err := dir.Open(file) + if err != nil { + // try any fallback before giving up + if opt.Fallback != "" { + file = opt.Fallback // so that logging stays true + f, err = dir.Open(opt.Fallback) + } + + if err != nil { + // discard the error? + return + } + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return + } + + // try to serve index file + if fi.IsDir() { + // redirect if missing trailing slash + if !strings.HasSuffix(req.URL.Path, "/") { + dest := url.URL{ + Path: req.URL.Path + "/", + RawQuery: req.URL.RawQuery, + Fragment: req.URL.Fragment, + } + http.Redirect(res, req, dest.String(), http.StatusFound) + return + } + + file = path.Join(file, opt.IndexFile) + f, err = dir.Open(file) + if err != nil { + return + } + defer f.Close() + + fi, err = f.Stat() + if err != nil || fi.IsDir() { + return + } + } + + if !opt.SkipLogging { + log.Println("[Static] Serving " + file) + } + + // Add an Expires header to the static content + if opt.Expires != nil { + res.Header().Set("Expires", opt.Expires()) + } + + http.ServeContent(res, req, file, fi.ModTime(), f) + } +} diff --git a/vendor/_nuts/github.com/go-martini/martini/static_test.go b/vendor/_nuts/github.com/go-martini/martini/static_test.go new file mode 100644 index 0000000..e9f592e --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/static_test.go @@ -0,0 +1,254 @@ +package martini + +import ( + "bytes" + "io/ioutil" + "log" + "net/http" + "net/http/httptest" + "os" + "path" + "testing" + + "com.teddywing/new-house-on-the-block/vendor/_nuts/github.com/codegangsta/inject" +) + +var currentRoot, _ = os.Getwd() + +func Test_Static(t *testing.T) { + response := httptest.NewRecorder() + response.Body = new(bytes.Buffer) + + m := New() + r := NewRouter() + + m.Use(Static(currentRoot)) + m.Action(r.Handle) + + req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil) + if err != nil { + t.Error(err) + } + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, response.Header().Get("Expires"), "") + if response.Body.Len() == 0 { + t.Errorf("Got empty body for GET request") + } +} + +func Test_Static_Local_Path(t *testing.T) { + Root = os.TempDir() + response := httptest.NewRecorder() + response.Body = new(bytes.Buffer) + + m := New() + r := NewRouter() + + m.Use(Static(".")) + f, err := ioutil.TempFile(Root, "static_content") + if err != nil { + t.Error(err) + } + f.WriteString("Expected Content") + f.Close() + m.Action(r.Handle) + + req, err := http.NewRequest("GET", "http://localhost:3000/"+path.Base(f.Name()), nil) + if err != nil { + t.Error(err) + } + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, response.Header().Get("Expires"), "") + expect(t, response.Body.String(), "Expected Content") +} + +func Test_Static_Head(t *testing.T) { + response := httptest.NewRecorder() + response.Body = new(bytes.Buffer) + + m := New() + r := NewRouter() + + m.Use(Static(currentRoot)) + m.Action(r.Handle) + + req, err := http.NewRequest("HEAD", "http://localhost:3000/martini.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + if response.Body.Len() != 0 { + t.Errorf("Got non-empty body for HEAD request") + } +} + +func Test_Static_As_Post(t *testing.T) { + response := httptest.NewRecorder() + + m := New() + r := NewRouter() + + m.Use(Static(currentRoot)) + m.Action(r.Handle) + + req, err := http.NewRequest("POST", "http://localhost:3000/martini.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusNotFound) +} + +func Test_Static_BadDir(t *testing.T) { + response := httptest.NewRecorder() + + m := Classic() + + req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + refute(t, response.Code, http.StatusOK) +} + +func Test_Static_Options_Logging(t *testing.T) { + response := httptest.NewRecorder() + + var buffer bytes.Buffer + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + + opt := StaticOptions{} + m.Use(Static(currentRoot, opt)) + + req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n") + + // Now without logging + m.Handlers() + buffer.Reset() + + // This should disable logging + opt.SkipLogging = true + m.Use(Static(currentRoot, opt)) + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, buffer.String(), "") +} + +func Test_Static_Options_ServeIndex(t *testing.T) { + response := httptest.NewRecorder() + + var buffer bytes.Buffer + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + + opt := StaticOptions{IndexFile: "martini.go"} // Define martini.go as index file + m.Use(Static(currentRoot, opt)) + + req, err := http.NewRequest("GET", "http://localhost:3000/", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n") +} + +func Test_Static_Options_Prefix(t *testing.T) { + response := httptest.NewRecorder() + + var buffer bytes.Buffer + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + + // Serve current directory under /public + m.Use(Static(currentRoot, StaticOptions{Prefix: "/public"})) + + // Check file content behaviour + req, err := http.NewRequest("GET", "http://localhost:3000/public/martini.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n") +} + +func Test_Static_Options_Expires(t *testing.T) { + response := httptest.NewRecorder() + + var buffer bytes.Buffer + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + + // Serve current directory under /public + m.Use(Static(currentRoot, StaticOptions{Expires: func() string { return "46" }})) + + // Check file content behaviour + req, err := http.NewRequest("GET", "http://localhost:3000/martini.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Header().Get("Expires"), "46") +} + +func Test_Static_Options_Fallback(t *testing.T) { + response := httptest.NewRecorder() + + var buffer bytes.Buffer + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(&buffer, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + + // Serve current directory under /public + m.Use(Static(currentRoot, StaticOptions{Fallback: "/martini.go"})) + + // Check file content behaviour + req, err := http.NewRequest("GET", "http://localhost:3000/initram.go", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusOK) + expect(t, buffer.String(), "[martini] [Static] Serving /martini.go\n") +} + +func Test_Static_Redirect(t *testing.T) { + response := httptest.NewRecorder() + + m := New() + m.Use(Static(currentRoot, StaticOptions{Prefix: "/public"})) + + req, err := http.NewRequest("GET", "http://localhost:3000/public?param=foo#bar", nil) + if err != nil { + t.Error(err) + } + + m.ServeHTTP(response, req) + expect(t, response.Code, http.StatusFound) + expect(t, response.Header().Get("Location"), "/public/?param=foo#bar") +} diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_de_DE.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_de_DE.md new file mode 100644 index 0000000..7a6e6eb --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_de_DE.md @@ -0,0 +1,369 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini ist eine mächtiges Package zur schnellen Entwicklung von modularen Webanwendungen und -services in Golang. + +## Ein Projekt starten + +Nach der Installation von Go und dem Einrichten des [GOPATH](http://golang.org/doc/code.html#GOPATH), erstelle Deine erste `.go`-Datei. Speichere sie unter `server.go`. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hallo Welt!" + }) + m.Run() +} +~~~ + +Installiere anschließend das Martini Package (**Go 1.1** oder höher wird vorausgesetzt): +~~~ +go get github.com/go-martini/martini +~~~ + +Starte den Server: +~~~ +go run server.go +~~~ + +Der Martini-Webserver ist nun unter `localhost:3000` erreichbar. + +## Hilfe + +Aboniere den [Emailverteiler](https://groups.google.com/forum/#!forum/martini-go) + +Schaue das [Demovideo](http://martini.codegangsta.io/#demo) + +Stelle Fragen auf Stackoverflow mit dem [Martini-Tag](http://stackoverflow.com/questions/tagged/martini) + +GoDoc [Dokumentation](http://godoc.org/github.com/go-martini/martini) + + +## Eigenschaften +* Sehr einfach nutzbar +* Nicht-intrusives Design +* Leicht kombinierbar mit anderen Golang Packages +* Ausgezeichnetes Path Matching und Routing +* Modulares Design - einfaches Hinzufügen und Entfernen von Funktionen +* Eine Vielzahl von guten Handlern/Middlewares nutzbar +* Großer Funktionsumfang mitgeliefert +* **Voll kompatibel mit dem [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) Interface.** +* Standardmäßges ausliefern von Dateien (z.B. von AngularJS-Apps im HTML5-Modus) + +## Mehr Middleware +Mehr Informationen zur Middleware und Funktionalität findest Du in den Repositories der [martini-contrib](https://github.com/martini-contrib) Gruppe. + +## Inhaltsverzeichnis +* [Classic Martini](#classic-martini) + * [Handler](#handler) + * [Routing](#routing) + * [Services](#services) + * [Statische Dateien bereitstellen](#statische-dateien-bereitstellen) +* [Middleware Handler](#middleware-handler) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +Einen schnellen Start in ein Projekt ermöglicht [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic), dessen Voreinstellungen sich für die meisten Webanwendungen eignen: +~~~ go + m := martini.Classic() + // ... Middleware und Routing hier einfügen + m.Run() +~~~ + +Aufgelistet findest Du einige Aspekte, die [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) automatich berücksichtigt: + + * Request/Response Logging - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Static File serving - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Routing - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### Handler +Handler sind das Herz und die Seele von Martini. Ein Handler ist grundsätzlich jede Art von aufrufbaren Funktionen: +~~~ go +m.Get("/", func() { + println("Hallo Welt") +}) +~~~ + +#### Rückgabewerte +Wenn ein Handler Rückgabewerte beinhaltet, übergibt Martini diese an den aktuellen [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) in Form eines String: +~~~ go +m.Get("/", func() string { + return "Hallo Welt" // HTTP 200 : "Hallo Welt" +}) +~~~ + +Die Rückgabe eines Statuscode ist optional: +~~~ go +m.Get("/", func() (int, string) { + return 418, "Ich bin eine Teekanne" // HTTP 418 : "Ich bin eine Teekanne" +}) +~~~ + +#### Service Injection +Handler werden per Reflection aufgerufen. Martini macht Gebrauch von *Dependency Injection*, um Abhängigkeiten in der Argumentliste von Handlern aufzulösen. **Dies macht Martini komplett inkompatibel mit Golangs `http.HandlerFunc` Interface.** + +Fügst Du einem Handler ein Argument hinzu, sucht Martini in seiner Liste von Services und versucht, die Abhängigkeiten via Type Assertion aufzulösen. +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res und req wurden von Martini injiziert + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +Die Folgenden Services sind Bestandteil von [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + + * [*log.Logger](http://godoc.org/log#Logger) - Globaler Logger für Martini. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request context. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` von benannten Parametern, welche durch Route Matching gefunden wurden. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Routen Hilfeservice. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer interface. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### Routing +Eine Route ist in Martini eine HTTP-Methode gepaart mit einem URL-Matching-Pattern. Jede Route kann eine oder mehrere Handler-Methoden übernehmen: +~~~ go +m.Get("/", func() { + // zeige etwas an +}) + +m.Patch("/", func() { + // aktualisiere etwas +}) + +m.Post("/", func() { + // erstelle etwas +}) + +m.Put("/", func() { + // ersetzte etwas +}) + +m.Delete("/", func() { + // lösche etwas +}) + +m.Options("/", func() { + // HTTP Optionen +}) + +m.NotFound(func() { + // bearbeite 404-Fehler +}) +~~~ + +Routen werden in der Reihenfolge, in welcher sie definiert wurden, zugeordnet. Die bei einer Anfrage zuerst zugeordnete Route wird daraufhin aufgerufen. + +Routenmuster enhalten ggf. benannte Parameter, die über den [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) Service abrufbar sind: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hallo " + params["name"] +}) +~~~ + +Routen können mit Globs versehen werden: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hallo " + params["_1"] +}) +~~~ + +Reguläre Ausdrücke sind ebenfalls möglich: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hallo %s", params["name"]) +}) +~~~ +Weitere Informationen zum Syntax regulärer Ausdrücke findest Du in der [Go Dokumentation](http://golang.org/pkg/regexp/syntax/). + +Routen-Handler können auch in einander verschachtelt werden. Dies ist bei der Authentifizierung und Berechtigungen nützlich. +~~~ go +m.Get("/secret", authorize, func() { + // wird ausgeführt, solange authorize nichts zurückgibt +}) +~~~ + +Routengruppen können durch die Group-Methode hinzugefügt werden. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Sowohl Handlern als auch Middlewares können Gruppen übergeben werden. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Services +Services sind Okjekte, welche der Argumentliste von Handlern beigefügt werden können. +Du kannst einem Service der *Global* oder *Request* Ebene zuordnen. + +#### Global Mapping +Eine Martini-Instanz implementiert das inject.Injector Interface, sodass ein Service leicht zugeordnet werden kann: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // der Service ist allen Handlern unter *MyDatabase verfügbar +// ... +m.Run() +~~~ + +#### Request-Level Mapping +Das Zuordnen auf der Request-Ebene kann in einem Handler via [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) realisiert werden: +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // zugeordnet als *MyCustomLogger +} +~~~ + +#### Werten einem Interface zuordnen +Einer der mächtigsten Aspekte von Services ist dessen Fähigkeit, einen Service einem Interface zuzuordnen. Möchtest Du den [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) mit einem Decorator (Objekt) und dessen Zusatzfunktionen überschreiben, definiere den Handler wie folgt: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // überschribe ResponseWriter mit dem ResponseWriter Decorator +} +~~~ + +### Statische Dateien bereitstellen +Eine [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) Instanz übertragt automatisch statische Dateien aus dem "public"-Ordner im Stammverzeichnis Deines Servers. Dieses Verhalten lässt sich durch weitere [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) Handler auf andere Verzeichnisse übertragen. +~~~ go +m.Use(martini.Static("assets")) // überträgt auch vom "assets"-Verzeichnis +~~~ + +#### Eine voreingestelle Datei übertragen +Du kannst die URL zu einer lokalen Datei angeben, sollte die URL einer Anfrage nicht gefunden werden. Durch einen Präfix können bestimmte URLs ignoriert werden. +Dies ist für Server nützlich, welche statische Dateien übertragen und ggf. zusätzliche Handler defineren (z.B. eine REST-API). Ist dies der Fall, so ist das Anlegen eines Handlers in der NotFound-Reihe nützlich. + +Das gezeigte Beispiel zeigt die `/index.html` immer an, wenn die angefrage URL keiner lokalen Datei zugeordnet werden kann bzw. wenn sie nicht mit `/api/v` beginnt: +~~~ go +static := martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/api/v"}) +m.NotFound(static, http.NotFound) +~~~ + +## Middleware Handler +Middleware-Handler befinden sich logisch zwischen einer Anfrage via HTTP und dem Router. Im wesentlichen unterscheiden sie sich nicht von anderen Handlern in Martini. +Du kannst einen Middleware-Handler dem Stack folgendermaßen anfügen: +~~~ go +m.Use(func() { + // durchlaufe die Middleware +}) +~~~ + +Volle Kontrolle über den Middleware Stack erlangst Du mit der `Handlers`-Funktion. +Sie ersetzt jeden zuvor definierten Handler: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware Handler arbeiten gut mit Aspekten wie Logging, Berechtigungen, Authentifizierung, Sessions, Komprimierung durch gzip, Fehlerseiten und anderen Operationen zusammen, die vor oder nach einer Anfrage passieren. +~~~ go +// überprüfe einen API-Schlüssel +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) ist eine optionale Funktion, die Middleware-Handler aufrufen können, um sie nach dem Beenden der anderen Handler auszuführen. Dies funktioniert besonders gut, wenn Operationen nach einer HTTP-Anfrage ausgeführt werden müssen. +~~~ go +// protokolliere vor und nach einer Anfrage +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("vor einer Anfrage") + + c.Next() + + log.Println("nach einer Anfrage") +}) +~~~ + +## Martini Env + +Einige Martini-Handler machen von der globalen `martini.Env` Variable gebrauch, die der Entwicklungsumgebung erweiterte Funktionen bietet, welche die Produktivumgebung nicht enthält. Es wird empfohlen, die `MARTINI_ENV=production` Umgebungsvariable zu setzen, sobald der Martini-Server in den Live-Betrieb übergeht. + +## FAQ + +### Wo finde ich eine bestimmte Middleware? + +Starte die Suche mit einem Blick in die Projekte von [martini-contrib](https://github.com/martini-contrib). Solltest Du nicht fündig werden, kontaktiere ein Mitglied des martini-contrib Teams, um eine neue Repository anzulegen. + +* [auth](https://github.com/martini-contrib/auth) - Handler zur Authentifizierung. +* [binding](https://github.com/martini-contrib/binding) - Handler zum Zuordnen/Validieren einer Anfrage zu einem Struct. +* [gzip](https://github.com/martini-contrib/gzip) - Handler zum Ermöglichen von gzip-Kompression bei Anfragen. +* [render](https://github.com/martini-contrib/render) - Handler der einen einfachen Service zum Rendern von JSON und HTML Templates bereitstellt. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler zum Parsen des `Accept-Language` HTTP-Header. +* [sessions](https://github.com/martini-contrib/sessions) - Handler mit einem Session service. +* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping. +* [method](https://github.com/martini-contrib/method) - Überschreibe eine HTTP-Method via Header oder Formularfelder. +* [secure](https://github.com/martini-contrib/secure) - Implementation von Sicherheitsfunktionen +* [encoder](https://github.com/martini-contrib/encoder) - Encoderservice zum Datenrendering in den verschiedensten Formaten. +* [cors](https://github.com/martini-contrib/cors) - Handler der CORS ermöglicht. +* [oauth2](https://github.com/martini-contrib/oauth2) - Handler der den Login mit OAuth 2.0 in Martinianwendungen ermöglicht. Google Sign-in, Facebook Connect und Github werden ebenfalls unterstützt. +* [vauth](https://github.com/rafecolton/vauth) - Handlers zur Webhook Authentifizierung (momentan nur GitHub und TravisCI) + +### Wie integriere ich in bestehende Systeme? + +Eine Martiniinstanz implementiert `http.Handler`, sodass Subrouten in bestehenden Servern einfach genutzt werden können. Hier ist eine funktionierende Martinianwendungen für die Google App Engine: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hallo Welt!" + }) + http.Handle("/", m) +} +~~~ + +### Wie ändere ich den Port/Host? + +Martinis `Run` Funktion sucht automatisch nach den PORT und HOST Umgebungsvariablen, um diese zu nutzen. Andernfalls ist localhost:3000 voreingestellt. +Für mehr Flexibilität über den Port und den Host nutze stattdessen die `martini.RunOnAddr` Funktion. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Automatisches Aktualisieren? + +[Gin](https://github.com/codegangsta/gin) und [Fresh](https://github.com/pilu/fresh) aktualisieren Martini-Apps live. + +## Bei Martini mitwirken + +Martinis Maxime ist Minimalismus und sauberer Code. Die meisten Beiträge sollten sich in den Repositories der [martini-contrib](https://github.com/martini-contrib) Gruppe wiederfinden. Beinhaltet Dein Beitrag Veränderungen am Kern von Martini, zögere nicht, einen Pull Request zu machen. + +## Über das Projekt + +Inspiriert von [Express](https://github.com/visionmedia/express) und [Sinatra](https://github.com/sinatra/sinatra) + +Martini wird leidenschaftlich von Niemand gerigeren als dem [Code Gangsta](http://codegangsta.io/) entwickelt diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_es_ES.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_es_ES.md new file mode 100644 index 0000000..3a76a66 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_es_ES.md @@ -0,0 +1,353 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini es un poderoso paquete para escribir rápidamente aplicaciones/servicios web modulares en Golang. + + +## Vamos a iniciar + +Antes de instalar Go y de configurar su [GOPATH](http://golang.org/doc/code.html#GOPATH), cree su primer archivo `.go`. Vamos a llamar a este `server.go`. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hola Mundo!" + }) + m.Run() +} +~~~ + +Luego instale el paquete Martini (Es necesario **go 1.1** o superior): +~~~ +go get github.com/go-martini/martini +~~~ + +Después corra su servidor: +~~~ +go run server.go +~~~ + +Ahora tendrá un webserver Martini corriendo en el puerto `localhost:3000`. + +## Obtenga ayuda + +Suscribase a la [Lista de email](https://groups.google.com/forum/#!forum/martini-go) + +Observe el [Video demostrativo](http://martini.codegangsta.io/#demo) + +Use la etiqueta [martini](http://stackoverflow.com/questions/tagged/martini) para preguntas en Stackoverflow + +GoDoc [documentation](http://godoc.org/github.com/go-martini/martini) + + +## Caracteríticas +* Extremadamente simple de usar. +* Diseño no intrusivo. +* Buena integración con otros paquetes Golang. +* Enrutamiento impresionante. +* Diseño modular - Fácil de añadir y remover funcionalidades. +* Muy buen uso de handlers/middlewares. +* Grandes características innovadoras. +* **Compatibilidad total con la interface [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc).** + +## Más Middlewares +Para más middlewares y funcionalidades, revisar los repositorios en [martini-contrib](https://github.com/martini-contrib). + +## Lista de contenidos +* [Classic Martini](#classic-martini) + * [Handlers](#handlers) + * [Routing](#routing) + * [Services](#services) + * [Serving Static Files](#serving-static-files) +* [Middleware Handlers](#middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +Para iniciar rápidamente, [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) prevee algunas herramientas que funcionan bien para la mayoría de aplicaciones web: +~~~ go + m := martini.Classic() + // middlewares y rutas aquí + m.Run() +~~~ + +Algunas funcionalidades que [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) ofrece automáticamente son: + * Request/Response Logging - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Static File serving - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Routing - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### Handlers +Handlers son el corazón y el alma de Martini. Un handler es básicamente cualquier tipo de función que puede ser llamada. +~~~ go +m.Get("/", func() { + println("hola mundo") +}) +~~~ + +#### Retorno de Valores +Si un handler retorna cualquier cosa, Martini escribirá el valor retornado como una cadena [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter): +~~~ go +m.Get("/", func() string { + return "hola mundo" // HTTP 200 : "hola mundo" +}) +~~~ + +Usted también puede retornar un código de estado: +~~~ go +m.Get("/", func() (int, string) { + return 418, "soy una tetera" // HTTP 418 : "soy una tetera" +}) +~~~ + +#### Inyección de Servicios +Handlers son invocados vía reflexión. Martini utiliza *Inyección de Dependencia* para resolver dependencias en la lista de argumentos Handlers. **Esto hace que Martini sea completamente compatible con la interface `http.HandlerFunc` de golang.** + +Si agrega un argumento a su Handler, Martini buscará en su lista de servicios e intentará resolver su dependencia vía su tipo de aserción: +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res e req son inyectados por Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +Los siguientes servicios son incluidos con [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * [*log.Logger](http://godoc.org/log#Logger) - Log Global para Martini. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request context. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` de nombres de los parámetros buscados por la ruta. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Servicio de ayuda para las Rutas. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response escribe la interfaz. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### Rutas +En Martini, una ruta es un método HTTP emparejado con un patrón URL. Cada ruta puede tener uno o más métodos handler: +~~~ go +m.Get("/", func() { + // mostrar algo +}) + +m.Patch("/", func() { + // actualizar algo +}) + +m.Post("/", func() { + // crear algo +}) + +m.Put("/", func() { + // reemplazar algo +}) + +m.Delete("/", func() { + // destruir algo +}) + +m.Options("/", func() { + // opciones HTTP +}) + +m.NotFound(func() { + // manipula 404 +}) +~~~ + +Las rutas son emparejadas en el orden en que son definidas. La primera ruta que coincide con la solicitud es invocada. + +Los patrones de rutas puede incluir nombres como parámetros accesibles vía el servicio [martini.Params](http://godoc.org/github.com/go-martini/martini#Params): +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Las rutas se pueden combinar con globs: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +Las expresiones regulares puede ser usadas también: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +Observe la [documentación](http://golang.org/pkg/regexp/syntax/) para mayor información sobre la sintaxis de expresiones regulares. + + +Handlers de ruta pueden ser empilados en la cima de otros, la cual es útil para cosas como autenticación y autorización: +~~~ go +m.Get("/secret", authorize, func() { + // será ejecutado cuando autorice escribir una respuesta +}) +~~~ + +Grupos de rutas puede ser añadidas usando el método Group. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Igualmente como puede pasar middlewares para un handler, usted puede pasar middlewares para grupos. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Servicios +Servicios son objetos que están disponibles para ser inyectados en una lista de argumentos Handler. Usted puede mapear un servicios a nivel *Global* o *Request*. + +#### Mapeamento Global +Una instancia de Martini implementa la interface inject.Injector, entonces un mapeamiento de un servicio es fácil: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // el servicio estará disponible para todos los handlers como *MyDatabase. +// ... +m.Run() +~~~ + +#### Mapeamiento por Request +Mapeamiento a nivel de request se puede realizar un handler vía [martini.Context](http://godoc.org/github.com/go-martini/martini#Context): +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapeado como *MyCustomLogger +} +~~~ + +#### Valores de Mapeamiento para Interfaces +Una de las partes mas poderosas sobre servicios es la capadidad de mapear un servicio para una interface. Por ejemplo, si desea sobreescribir [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) con un objeto que envuelva y realice operaciones extra, puede escribir el siguiente handler: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // sobreescribir ResponseWriter con nuestro ResponseWriter +} +~~~ + +### Sirviendo Archivos Estáticos +Una instancia de [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) sirve automáticamente archivos estáticos del directorio "public" en la raíz de su servidor. +Usted puede servir más directorios, añadiendo más [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) handlers. +~~~ go +m.Use(martini.Static("assets")) // sirviendo los archivos del directorio "assets" +~~~ + +## Middleware Handlers +Middleware Handlers se sitúan entre una solicitud HTTP y un router. En esencia, ellos no son diferentes de cualquier otro Handler en Martini. Usted puede añadir un handler de middleware para la pila de la siguiente forma: +~~~ go +m.Use(func() { + // Hacer algo con middleware +}) +~~~ + +Puede tener el control total sobre la pila de middleware con la función `Handlers`. Esto reemplazará a cualquier handler que se ha establecido previamente: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware Handlers trabaja realmente bien como logging, autorización, autenticación, sessión, gzipping, páginas de errores y una serie de otras operaciones que deben suceder antes de una solicitud http: +~~~ go +// Valida una llave de api +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) es una función opcional que Middleware Handlers puede llamar para aguardar una ejecución de otros Handlers. Esto trabaja muy bien para calquier operación que debe suceder antes de una solicitud http: +~~~ go +// log antes y después de una solicitud +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("antes de una solicitud") + + c.Next() + + log.Println("luego de una solicitud") +}) +~~~ + +## Martini Env + +Martini handlers hace uso de `martini.Env`, una variable global para proveer funcionalidad especial en ambientes de desarrollo y ambientes de producción. Es recomendado que una variable `MARTINI_ENV=production` sea definida cuando se despliegue en un ambiente de producción. + +## FAQ + +### ¿Dónde puedo encontrar una middleware X? + +Inicie su búsqueda en los proyectos [martini-contrib](https://github.com/martini-contrib). Si no esta allí, no dude en contactar a algún miembro del equipo martini-contrib para adicionar un nuevo repositorio para la organización. + +* [auth](https://github.com/martini-contrib/auth) - Handlers para autenticación. +* [binding](https://github.com/martini-contrib/binding) - Handler para mapeamiento/validación de un request en una estrutura. +* [gzip](https://github.com/martini-contrib/gzip) - Handler para agregar gzip comprimidos para requests +* [render](https://github.com/martini-contrib/render) - Handler que provee un servicio de fácil renderizado JSON y plantillas HTML. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler para analizar `Accept-Language` header HTTP. +* [sessions](https://github.com/martini-contrib/sessions) - Handler que provee un servicio de sesión. +* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping. +* [method](https://github.com/martini-contrib/method) - HTTP método de sobreescritura vía header o campos de formulario. +* [secure](https://github.com/martini-contrib/secure) - Implementa rápidamente items de seguridad. +* [encoder](https://github.com/martini-contrib/encoder) - Servicio de encoder para renderización de datos en varios formatos y negocios de contenidos. +* [cors](https://github.com/martini-contrib/cors) - Handler que habilita suporte a CORS. +* [oauth2](https://github.com/martini-contrib/oauth2) - Handler que provee sistema de login OAuth 2.0 para aplicaciones Martini. Google Sign-in, Facebook Connect y Github login son soportados. + +### ¿Cómo se integra con los servidores existentes? + +Una instancia de Martini implementa `http.Handler`, de modo que puede ser fácilmente utilizado para servir sub-rutas y directorios en servidores Go existentes. Por ejemplo, este es un aplicativo Martini trabajando para Google App Engine: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hola Mundo!" + }) + http.Handle("/", m) +} +~~~ + +### ¿Cómo cambiar el puerto/host? + +La función `Run` de Martini observa las variables PORT e HOST para utilizarlas. Caso contrário, Martini asume por defecto localhost:3000. Para tener maayor flexibilidad sobre el puerto y host, use la función `martini.RunOnAddr`. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### ¿Servidor con autoreload? + +[gin](https://github.com/codegangsta/gin) y [fresh](https://github.com/pilu/fresh) son aplicaciones para autorecarga de Martini. + +## Contribuyendo +Martini se desea mantener pequeño y limpio. La mayoría de contribuciones deben realizarse en el repositorio [martini-contrib](https://github.com/martini-contrib). Si desea hacer una contribución al core de Martini es libre de realizar un Pull Request. + +## Sobre + +Inspirado por [express](https://github.com/visionmedia/express) y [sinatra](https://github.com/sinatra/sinatra) + +Martini está diseñoado obsesivamente por nada menos que [Code Gangsta](http://codegangsta.io/) diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_fr_FR.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_fr_FR.md new file mode 100644 index 0000000..8381bf2 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_fr_FR.md @@ -0,0 +1,344 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini est une puissante bibliothèque pour développer rapidement des applications et services web en Golang. + + +## Pour commencer + +Après avoir installé Go et configuré le chemin d'accès pour [GOPATH](http://golang.org/doc/code.html#GOPATH), créez votre premier fichier '.go'. Nous l'appellerons 'server.go'. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +Installez ensuite le paquet Martini (**go 1.1** ou supérieur est requis) : + +~~~ +go get github.com/go-martini/martini +~~~ + +La commande suivante vous permettra de lancer votre serveur : +~~~ +go run server.go +~~~ + +Vous avez à présent un serveur web Martini à l'écoute sur l'adresse et le port suivants : `localhost:3000`. + +## Besoin d'aide +- Souscrivez à la [Liste d'emails](https://groups.google.com/forum/#!forum/martini-go) +- Regardez les vidéos [Demo en vidéo](http://martini.codegangsta.io/#demo) +- Posez vos questions sur StackOverflow.com en utilisant le tag [martini](http://stackoverflow.com/questions/tagged/martini) +- La documentation GoDoc [documentation](http://godoc.org/github.com/go-martini/martini) + + +## Caractéristiques +* Simple d'utilisation +* Design non-intrusif +* Compatible avec les autres paquets Golang +* Gestionnaire d'URL et routeur disponibles +* Modulable, permettant l'ajout et le retrait de fonctionnalités +* Un grand nombre de handlers/middlewares disponibles +* Prêt pour une utilisation immédiate +* **Entièrement compatible avec l'interface [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc).** + +## Plus de Middleware +Pour plus de middlewares et de fonctionnalités, consultez le dépôt [martini-contrib](https://github.com/martini-contrib). + +## Table des matières +* [Classic Martini](#classic-martini) + * [Handlers](#handlers) + * [Routage](#routing) + * [Services](#services) + * [Serveur de fichiers statiques](#serving-static-files) +* [Middleware Handlers](#middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +Pour vous faire gagner un temps précieux, [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) est configuré avec des paramètres qui devraient couvrir les besoins de la plupart des applications web : + +~~~ go + m := martini.Classic() + // ... les middlewares and le routage sont insérés ici... + m.Run() +~~~ + +Voici quelques handlers/middlewares que [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) intègre par défault : + * Logging des requêtes/réponses - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Récupération sur erreur - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Serveur de fichiers statiques - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Routage - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### Handlers +Les Handlers sont le coeur et l'âme de Martini. N'importe quelle fonction peut être utilisée comme un handler. +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Valeurs retournées +Si un handler retourne une valeur, Martini écrira le résultat dans l'instance [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) courante sous forme de ```string```: +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ +Vous pouvez aussi optionnellement renvoyer un code de statut HTTP : +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### Injection de services +Les handlers sont appelés via réflexion. Martini utilise "l'injection par dépendance" pour résoudre les dépendances des handlers dans la liste d'arguments. **Cela permet à Martini d'être parfaitement compatible avec l'interface golang ```http.HandlerFunc```.** + +Si vous ajoutez un argument à votre Handler, Martini parcourera la liste des services et essayera de déterminer ses dépendances selon son type : +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ +Les services suivants sont inclus avec [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * [log.Logger](http://godoc.org/log#Logger) - Global logger for Martini. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - Contexte d'une requête HTTP. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` contenant les paramètres retrouvés par correspondance des routes. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Service d'aide au routage. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - Interface d'écriture de réponses HTTP. + * [*http.Request](http://godoc.org/net/http/#Request) - Requête HTTP. + +### Routeur +Dans Martini, un chemin est une méthode HTTP liée à un modèle d'adresse URL. +Chaque chemin peut avoir un seul ou plusieurs méthodes *handler* : +~~~ go +m.Get("/", func() { + // show something +}) + +m.Patch("/", func() { + // update something +}) + +m.Post("/", func() { + // create something +}) + +m.Put("/", func() { + // replace something +}) + +m.Delete("/", func() { + // destroy something +}) + +m.Options("/", func() { + // http options +}) + +m.NotFound(func() { + // handle 404 +}) +~~~ +Les chemins seront traités dans l'ordre dans lequel ils auront été définis. Le *handler* du premier chemin trouvé qui correspondra à la requête sera invoqué. + + +Les chemins peuvent inclure des paramètres nommés, accessibles avec le service [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) : +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Les chemins peuvent correspondre à des globs : +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ +Les expressions régulières peuvent aussi être utilisées : +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +Jetez un oeil à la documentation [Go documentation](http://golang.org/pkg/regexp/syntax/) pour plus d'informations sur la syntaxe des expressions régulières. + +Les handlers d'un chemins peuvent être superposés, ce qui s'avère particulièrement pratique pour des tâches comme la gestion de l'authentification et des autorisations : +~~~ go +m.Get("/secret", authorize, func() { + // this will execute as long as authorize doesn't write a response +}) +~~~ + +Un groupe de chemins peut aussi être ajouté en utilisant la méthode ```Group``` : +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Comme vous pouvez passer des middlewares à un handler, vous pouvez également passer des middlewares à des groupes : +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Services +Les services sont des objets injectés dans la liste d'arguments d'un handler. Un service peut être défini pour une *requête*, ou de manière *globale*. + + +#### Global Mapping +Les instances Martini implémentent l'interace inject.Injector, ce qui facilite grandement le mapping de services : +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // the service will be available to all handlers as *MyDatabase +// ... +m.Run() +~~~ + +#### Requête-Level Mapping +Pour une déclaration au niveau d'une requête, il suffit d'utiliser un handler via [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) : +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapped as *MyCustomLogger +} +~~~ + +#### Mapping de valeurs à des interfaces +L'un des aspects les plus intéressants des services réside dans le fait qu'ils peuvent être liés à des interfaces. Par exemple, pour surcharger [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) avec un objet qui l'enveloppe et étend ses fonctionnalités, vous pouvez utiliser le handler suivant : +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter +} +~~~ + +### Serveur de fichiers statiques +Une instance [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) est déjà capable de servir les fichiers statiques qu'elle trouvera dans le dossier *public* à la racine de votre serveur. +Vous pouvez indiquer d'autres dossiers sources à l'aide du handler [martini.Static](http://godoc.org/github.com/go-martini/martini#Static). +~~~ go +m.Use(martini.Static("assets")) // serve from the "assets" directory as well +~~~ + +## Les middleware Handlers +Les *middleware handlers* sont placés entre la requête HTTP entrante et le routeur. Ils ne sont aucunement différents des autres handlers présents dans Martini. Vous pouvez ajouter un middleware handler comme ceci : +~~~ go +m.Use(func() { + // do some middleware stuff +}) +~~~ +Vous avez un contrôle total sur la structure middleware avec la fonction ```Handlers```. Son exécution écrasera tous les handlers configurés précédemment : +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ +Middleware Handlers est très pratique pour automatiser des fonctions comme le logging, l'autorisation, l'authentification, sessions, gzipping, pages d'erreur, et toutes les opérations qui se font avant ou après chaque requête HTTP : +~~~ go +// validate an api key +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() (Suivant) +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) est une fonction optionnelle que les Middleware Handlers peuvent appeler pour patienter jusqu'à ce que tous les autres handlers aient été exécutés. Cela fonctionne très bien pour toutes opérations qui interviennent après une requête HTTP : +~~~ go +// log before and after a request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("avant la requête") + + c.Next() + + log.Println("après la requête") +}) +~~~ + +## Martini Env +Plusieurs Martini handlers utilisent 'martini.Env' comme variable globale pour fournir des fonctionnalités particulières qui diffèrent entre l'environnement de développement et l'environnement de production. Il est recommandé que la variable 'MARTINI_ENV=production' soit définie pour déployer un serveur Martini en environnement de production. + +## FAQ (Foire aux questions) + +### Où puis-je trouver des middleware ? +Commencer par regarder dans le [martini-contrib](https://github.com/martini-contrib) projet. S'il n'y est pas, n'hésitez pas à contacter un membre de l'équipe martini-contrib pour ajouter un nouveau dépôt à l'organisation. + +* [auth](https://github.com/martini-contrib/auth) - Handlers for authentication. +* [binding](https://github.com/martini-contrib/binding) - Handler for mapping/validating a raw request into a structure. +* [gzip](https://github.com/martini-contrib/gzip) - Handler for adding gzip compress to requests +* [render](https://github.com/martini-contrib/render) - Handler that provides a service for easily rendering JSON and HTML templates. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler for parsing the `Accept-Language` HTTP header. +* [sessions](https://github.com/martini-contrib/sessions) - Handler that provides a Session service. +* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping. +* [method](https://github.com/martini-contrib/method) - HTTP method overriding via Header or form fields. +* [secure](https://github.com/martini-contrib/secure) - Implements a few quick security wins. +* [encoder](https://github.com/martini-contrib/encoder) - Encoder service for rendering data in several formats and content negotiation. +* [cors](https://github.com/martini-contrib/cors) - Handler that enables CORS support. +* [oauth2](https://github.com/martini-contrib/oauth2) - Handler that provides OAuth 2.0 login for Martini apps. Google Sign-in, Facebook Connect and Github login is supported. +* [vauth](https://github.com/rafecolton/vauth) - Handlers for vender webhook authentication (currently GitHub and TravisCI) + +### Comment puis-je m'intègrer avec des serveurs existants ? +Une instance Martini implémente ```http.Handler```. Elle peut donc utilisée pour alimenter des sous-arbres sur des serveurs Go existants. Voici l'exemple d'une application Martini pour Google App Engine : + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### Comment changer le port/adresse ? + +La fonction ```Run``` de Martini utilise le port et l'adresse spécifiés dans les variables d'environnement. Si elles ne peuvent y être trouvées, Martini utilisera *localhost:3000* par default. +Pour avoir plus de flexibilité sur le port et l'adresse, utilisez la fonction `martini.RunOnAddr` à la place. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Rechargement du code en direct ? + +[gin](https://github.com/codegangsta/gin) et [fresh](https://github.com/pilu/fresh) sont tous les capables de recharger le code des applications martini chaque fois qu'il est modifié. + +## Contribuer +Martini est destiné à rester restreint et épuré. Toutes les contributions doivent finir dans un dépot dans l'organisation [martini-contrib](https://github.com/martini-contrib). Si vous avez une contribution pour le noyau de Martini, n'hésitez pas à envoyer une Pull Request. + +## A propos de Martini + +Inspiré par [express](https://github.com/visionmedia/express) et [Sinatra](https://github.com/sinatra/sinatra), Martini est l'oeuvre de nul d'autre que [Code Gangsta](http://codegangsta.io/), votre serviteur. diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_ja_JP.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_ja_JP.md new file mode 100644 index 0000000..e5fdd90 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_ja_JP.md @@ -0,0 +1,356 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +MartiniはGolangによる、モジュール形式のウェブアプリケーション/サービスを作成するパワフルなパッケージです。 + +## はじめに + +Goをインストールし、[GOPATH](http://golang.org/doc/code.html#GOPATH)を設定した後、Martiniを始める最初の`.go`ファイルを作りましょう。これを`server.go`とします。 + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +そのあとで、Martini パッケージをインストールします。(**go 1.1**か、それ以上のバーションが必要です。) + +~~~ +go get github.com/go-martini/martini +~~~ + +インストールが完了したら、サーバを起動しましょう。 +~~~ +go run server.go +~~~ + +そうすれば`localhost:3000`でMartiniのサーバが起動します。 + +## 分からないことがあったら? + +[メーリングリスト](https://groups.google.com/forum/#!forum/martini-go)に入る + +[デモビデオ](http://martini.codegangsta.io/#demo)をみる + +Stackoverflowで[martini tag](http://stackoverflow.com/questions/tagged/martini)を使い質問する + +GoDoc [documentation](http://godoc.org/github.com/go-martini/martini) + + +## 特徴 +* 非常にシンプルに使用できる +* 押し付けがましくないデザイン +* 他のGolangパッケージとの協調性 +* 素晴らしいパスマッチングとルーティング +* モジュラーデザイン - 機能性の付け外しが簡単 +* たくさんの良いハンドラ/ミドルウェア +* 優れた 'すぐに使える' 機能たち +* **[http.HandlerFunc](http://godoc.org/net/http#HandlerFunc)との完全な互換性** + +## もっとミドルウェアについて知るには? +さらに多くのミドルウェアとその機能について知りたいときは、[martini-contrib](https://github.com/martini-contrib) オーガナイゼーションにあるリポジトリを確認してください。 + +## 目次(Table of Contents) +* [Classic Martini](#classic-martini) + * [ハンドラ](#handlers) + * [ルーティング](#routing) + * [サービス](#services) + * [静的ファイル配信](#serving-static-files) +* [ミドルウェアハンドラ](#middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +立ち上げ、すぐ実行できるように、[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) はほとんどのウェブアプリケーションで機能する、標準的な機能を提供します。 +~~~ go + m := martini.Classic() + // ... middleware and routing goes here + m.Run() +~~~ + +下記が[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic)が自動的に読み込む機能の一覧です。 + * Request/Response Logging - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Static File serving - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Routing - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### ハンドラ +ハンドラはMartiniのコアであり、存在意義でもあります。ハンドラには基本的に、呼び出し可能な全ての関数が適応できます。 +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Return Values +もしハンドラが何かを返す場合、Martiniはその結果を現在の[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)にstringとして書き込みます。 +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +任意でステータスコードを返すこともできます。 +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### Service Injection +ハンドラはリフレクションによって実行されます。Martiniはハンドラの引数内の依存関係を**依存性の注入(Dependency Injection)**を使って解決しています。**これによって、Martiniはgolangの`http.HandlerFunc`と完全な互換性を備えています。** + +ハンドラに引数を追加すると、Martiniは内部のサービスを検索し、依存性をtype assertionによって解決しようと試みます。 +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic)にはこれらのサービスが内包されています: + * [*log.Logger](http://godoc.org/log#Logger) - Martiniのためのグローバルなlogger. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request context. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string`型の、ルートマッチングによって検出されたパラメータ + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Route helper service. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer interface. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### ルーティング +Martiniでは、ルーティングはHTTPメソッドとURL-matching patternによって対になっており、それぞれが一つ以上のハンドラメソッドを持つことができます。 +~~~ go +m.Get("/", func() { + // show something +}) + +m.Patch("/", func() { + // update something +}) + +m.Post("/", func() { + // create something +}) + +m.Put("/", func() { + // replace something +}) + +m.Delete("/", func() { + // destroy something +}) + +m.Options("/", func() { + // http options +}) + +m.NotFound(func() { + // handle 404 +}) +~~~ + +ルーティングはそれらの定義された順番に検索され、最初にマッチしたルーティングが呼ばれます。 + +名前付きパラメータを定義することもできます。これらのパラメータは[martini.Params](http://godoc.org/github.com/go-martini/martini#Params)サービスを通じてアクセスすることができます: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +ワイルドカードを使用することができます: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +正規表現も、このように使うことができます: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ + +もっと正規表現の構文をしりたい場合は、[Go documentation](http://golang.org/pkg/regexp/syntax/) を見てください。 + + +ハンドラは互いの上に積み重ねてることができます。これは、認証や承認処理の際に便利です: +~~~ go +m.Get("/secret", authorize, func() { + // this will execute as long as authorize doesn't write a response +}) +~~~ + +ルーティンググループも、Groupメソッドを使用することで追加できます。 +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +ハンドラにミドルウェアを渡せるのと同じように、グループにもミドルウェアを渡すことができます: +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### サービス +サービスはハンドラの引数として注入されることで利用可能になるオブジェクトです。これらは*グローバル*、または*リクエスト*のレベルでマッピングすることができます。 + +#### Global Mapping +Martiniのインスタンスはinject.Injectorのインターフェースを実装しています。なので、サービスをマッピングすることは簡単です: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // the service will be available to all handlers as *MyDatabase +// ... +m.Run() +~~~ + +#### Request-Level Mapping +リクエストレベルでのマッピングは[martini.Context](http://godoc.org/github.com/go-martini/martini#Context)を使い、ハンドラ内で行うことができます: +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapped as *MyCustomLogger +} +~~~ + +#### Mapping values to Interfaces +サービスの最も強力なことの一つは、インターフェースにサービスをマッピングできる機能です。例えば、[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)を機能を追加して上書きしたい場合、このようにハンドラを書くことができます: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter +} +~~~ + +### 静的ファイル配信 + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) インスタンスは、自動的にルート直下の "public" ディレクトリ以下の静的ファイルを配信します。[martini.Static](http://godoc.org/github.com/go-martini/martini#Static)を追加することで、もっと多くのディレクトリを配信することもできます: +~~~ go +m.Use(martini.Static("assets")) // serve from the "assets" directory as well +~~~ + +## ミドルウェア ハンドラ +ミドルウェア ハンドラは次に来るhttpリクエストとルーターの間に位置します。本質的には、その他のハンドラとの違いはありません。ミドルウェア ハンドラの追加はこのように行います: +~~~ go +m.Use(func() { + // do some middleware stuff +}) +~~~ + +`Handlers`関数を使えば、ミドルウェアスタックを完全に制御できます。これは以前に設定されている全てのハンドラを置き換えます: + +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +ミドルウェア ハンドラはロギング、認証、承認プロセス、セッション、gzipping、エラーページの表示、その他httpリクエストの前後で怒らなければならないような場合に素晴らしく効果を発揮します。 +~~~ go +// validate an api key +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() + +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) は他のハンドラが実行されたことを取得するために使用する機能です。これはhttpリクエストのあとに実行したい任意の関数があるときに素晴らしく機能します: +~~~ go +// log before and after a request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("before a request") + + c.Next() + + log.Println("after a request") +}) +~~~ + +## Martini Env + +いくつかのMartiniのハンドラはdevelopment環境とproduction環境で別々の動作を提供するために`martini.Env`グローバル変数を使用しています。Martiniサーバを本番環境にデプロイする際には、`MARTINI_ENV=production`環境変数をセットすることをおすすめします。 + +## FAQ + +### Middlewareを見つけるには? + +[martini-contrib](https://github.com/martini-contrib)プロジェクトをみることから始めてください。もし望みのものがなければ、新しいリポジトリをオーガナイゼーションに追加するために、martini-contribチームのメンバーにコンタクトを取ってみてください。 + +* [auth](https://github.com/martini-contrib/auth) - Handlers for authentication. +* [binding](https://github.com/martini-contrib/binding) - Handler for mapping/validating a raw request into a structure. +* [gzip](https://github.com/martini-contrib/gzip) - Handler for adding gzip compress to requests +* [render](https://github.com/martini-contrib/render) - Handler that provides a service for easily rendering JSON and HTML templates. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler for parsing the `Accept-Language` HTTP header. +* [sessions](https://github.com/martini-contrib/sessions) - Handler that provides a Session service. +* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping. +* [method](https://github.com/martini-contrib/method) - HTTP method overriding via Header or form fields. +* [secure](https://github.com/martini-contrib/secure) - Implements a few quick security wins. +* [encoder](https://github.com/martini-contrib/encoder) - Encoder service for rendering data in several formats and content negotiation. +* [cors](https://github.com/martini-contrib/cors) - Handler that enables CORS support. +* [oauth2](https://github.com/martini-contrib/oauth2) - Handler that provides OAuth 2.0 login for Martini apps. Google Sign-in, Facebook Connect and Github login is supported. + +### 既存のサーバに組み込むには? + +Martiniのインスタンスは`http.Handler`を実装しているので、既存のGoサーバ上でサブツリーを提供するのは簡単です。例えばこれは、Google App Engine上で動くMartiniアプリです: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### どうやってポート/ホストをかえるの? + +Martiniの`Run`関数はPORTとHOSTという環境変数を探し、その値を使用します。見つからない場合はlocalhost:3000がデフォルトで使用されます。もっと柔軟性をもとめるなら、`martini.RunOnAddr`関数が役に立ちます: + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Live code reload? + +[gin](https://github.com/codegangsta/gin) と [fresh](https://github.com/pilu/fresh) 両方がMartiniアプリケーションを自動リロードできます。 + +## Contributing +Martini本体は小さく、クリーンであるべきであり、ほとんどのコントリビューションは[martini-contrib](https://github.com/martini-contrib) オーガナイゼーション内で完結すべきですが、もしMartiniのコアにコントリビュートすることがあるなら、自由に行ってください。 + +## About + +Inspired by [express](https://github.com/visionmedia/express) and [sinatra](https://github.com/sinatra/sinatra) + +Martini is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/) diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_ko_kr.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_ko_kr.md new file mode 100644 index 0000000..1df81bf --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_ko_kr.md @@ -0,0 +1,358 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +마티니(Martini)는 강력하고 손쉬운 웹애플리케이션 / 웹서비스개발을 위한 Golang 패키지입니다. + +## 시작하기 + +Go 인스톨 및 [GOPATH](http://golang.org/doc/code.html#GOPATH) 환경변수 설정 이후에, `.go` 파일 하나를 만들어 보죠..흠... 일단 `server.go`라고 부르겠습니다. +~~~go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello, 세계!" + }) + m.Run() +} +~~~ + +마티니 패키지를 인스톨 합니다. (**go 1.1** 혹은 그 이상 버젼 필요): +~~~ +go get github.com/go-martini/martini +~~~ + +이제 서버를 돌려 봅시다: +~~~ +go run server.go +~~~ + +마티니 웹서버가 `localhost:3000`에서 돌아가고 있는 것을 확인하실 수 있을 겁니다. + +## 도움이 필요하다면? + +[메일링 리스트](https://groups.google.com/forum/#!forum/martini-go)에 가입해 주세요 + +[데모 비디오](http://martini.codegangsta.io/#demo)도 있어요. + +혹은 Stackoverflow에 [마티니 태크](http://stackoverflow.com/questions/tagged/martini)를 이용해서 물어봐 주세요 + +GoDoc [문서(documentation)](http://godoc.org/github.com/go-martini/martini) + +문제는 전부다 영어로 되어 있다는 건데요 -_-;;; +나는 한글 아니면 보기 싫다! 하는 분들은 아래 링크를 참조하세요 +- [golang-korea](https://code.google.com/p/golang-korea/) +- 혹은 ([RexK](http://github.com/RexK))의 이메일로 연락주세요. + +## 주요기능 +* 사용하기 엄청 쉽습니다. +* 비간섭(Non-intrusive) 디자인 +* 다른 Golang 패키지들과 잘 어울립니다. +* 끝내주는 경로 매칭과 라우팅. +* 모듈형 디자인 - 기능추가가 쉽고, 코드 꺼내오기도 쉬움. +* 유용한 핸들러와 미들웨어가 많음. +* 훌륭한 패키지화(out of the box) 기능들 +* **[http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) 인터페이스와 호환율 100%** + +## 미들웨어(Middleware) +미들웨어들과 추가기능들은 [martini-contrib](https://github.com/martini-contrib)에서 확인해 주세요. + +## 목차 +* [Classic Martini](#classic-martini) + * [핸들러](#핸들러handlers) + * [라우팅](#라우팅routing) + * [서비스](#서비스services) + * [정적파일 서빙](#정적파일-서빙serving-static-files) +* [미들웨어 핸들러](#미들웨어-핸들러middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +마티니를 쉽고 빠르게 이용하시려면, [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic)를 이용해 보세요. 보통 웹애플리케이션에서 사용하는 설정들이 이미 포함되어 있습니다. +~~~ go + m := martini.Classic() + // ... 미들웨어와 라우팅 설정은 이곳에 오면 작성하면 됩니다. + m.Run() +~~~ + +아래는 [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic)에 자동으로 제공되는 기본 기능들 입니다. + + * Request/Response 로그 기능 - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * 패닉 리커버리 (Panic Recovery) - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * 정적 파일 서빙 - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * 라우팅(Routing) - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### 핸들러(Handlers) + +핸들러(Handlers)는 마티니의 핵심입니다. 핸들러는 기본적으로 실행 가능한 모든 형태의 함수들입니다. +~~~ go +m.Get("/", func() { + println("hello 세계") +}) +~~~ + +#### 반환 값 (Return Values) +핸들러가 반환을 하는 함수라면, 마티니는 반환 값을 [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)에 스트링으로 입력 할 것입니다. +~~~ go +m.Get("/", func() string { + return "hello 세계" // HTTP 200 : "hello 세계" +}) +~~~ + +원하신다면, 선택적으로 상태코드도 함께 반환 할 수 있습니다. +~~~ go +m.Get("/", func() (int, string) { + return 418, "난 주전자야!" // HTTP 418 : "난 주전자야!" +}) +~~~ + +#### 서비스 주입(Service Injection) +핸들러들은 리플렉션을 통해 호출됩니다. 마티니는 *의존성 주입*을 이용해서 핸들러의 인수들을 주입합니다. **이것이 마티니를 `http.HandlerFunc` 인터페이스와 100% 호환할 수 있게 해줍니다.** + +핸들러의 인수를 입력했다면, 마티니가 서비스 목록들을 살펴본 후 타입확인(type assertion)을 통해 의존성문제 해결을 시도 할 것입니다. +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res와 req는 마티니에 의해 주입되었다. + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +아래 서비스들은 [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic):에 포함되어 있습니다. + * [*log.Logger](http://godoc.org/log#Logger) - 마티니의 글로벌(전역) 로그. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http 요청 컨텍스트. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - 루트 매칭으로 찾은 인자를 `map[string]string`으로 변형. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - 루트 도우미 서비스. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer 인터페이스. + * [*http.Request](http://godoc.org/net/http/#Request) - http 리퀘스트. + +### 라우팅(Routing) +마티니에서 루트는 HTTP 메소드와 URL매칭 패턴의 페어입니다. +각 루트는 하나 혹은 그 이상의 핸들러 메소드를 가질 수 있습니다. +~~~ go +m.Get("/", func() { + // 보여줘 봐 +}) + +m.Patch("/", func() { + // 업데이트 좀 해 +}) + +m.Post("/", func() { + // 만들어봐 +}) + +m.Put("/", func() { + // 변경해봐 +}) + +m.Delete("/", func() { + // 없애버려! +}) + +m.Options("/", func() { + // http 옵션 메소드 +}) + +m.NotFound(func() { + // 404 해결하기 +}) +~~~ + +루트들은 정의된 순서대로 매칭된다. 들어온 요구에 처음으로 매칭된 루트가 호출된다. + +루트 패턴은 [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) service로 액세스 가능한 인자들을 포함하기도 한다: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] // :name을 Params인자에서 추출 +}) +~~~ + +루트는 별표식(\*)으로 매칭 될 수도 있습니다: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +정규식도 사용가능합니다: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +정규식에 관하여 더 자세히 알고 싶다면 [Go documentation](http://golang.org/pkg/regexp/syntax/)을 참조해 주세요. + +루트 핸들러는 스택을 쌓아 올릴 수 있습니다. 특히 유저 인증작업이나, 허가작업에 유용히 쓰일 수 있죠. +~~~ go +m.Get("/secret", authorize, func() { + // 이 함수는 authorize 함수가 resopnse에 결과를 쓰지 않는이상 실행 될 거에요. +}) +~~~ + +```RootGroup```은 루트들을 한 곳에 모아 정리하는데 유용합니다. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +핸들러에 미들웨어를 집어넣을 수 있는것과 같이, 그룹에도 미들웨어를 집어넣는 것이 가능합니다. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### 서비스(Services) +서비스는 핸들러의 인수목록에 주입 될 수 있는 오브젝트들을 말합니다. 서비스는 *글로벌* 혹은 *리퀘스트* 레벨단위로 주입이 가능합니다. + +#### 글로벌 맵핑(Global Mapping) +마타니 인스턴스는 서비스 맵핑을 쉽게 하기 위해서 inject.Injector 인터페이스를 반형합니다: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // 서비스가 모든 핸들러에서 *MyDatabase로서 사용될 수 있습니다. +// ... +m.Run() +~~~ + +#### 리퀘스트 레벨 맵핑(Request-Level Mapping) +리퀘스트 레벨 맵핑은 핸들러안에서 [martini.Context](http://godoc.org/github.com/go-martini/martini#Context)를 사용하면 됩니다: +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // *MyCustomLogger로서 맵핑 됨 +} +~~~ + +#### 인터페이스로 값들 맵핑(Mapping values to Interfaces) +서비스의 강력한 기능중 하나는 서비스를 인터페이스로 맵핑이 가능하다는 것입니다. 예를들어, [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)를 재정의(override)해서 부가 기능들을 수행하게 하고 싶으시다면, 아래와 같이 핸들러를 작성 하시면 됩니다. + +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // ResponseWriter를 NewResponseWriter로 치환(override) +} +~~~ + +### 정적파일 서빙(Serving Static Files) +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) 인스턴스는 "public" 폴더안에 있는 파일들을 정적파일로써 자동으로 서빙합니다. 더 많은 폴더들은 정적파일 폴더에 포함시키시려면 [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) 핸들러를 이용하시면 됩니다. + +~~~ go +m.Use(martini.Static("assets")) // "assets" 폴더에서도 정적파일 서빙. +~~~ + +## 미들웨어 핸들러(Middleware Handlers) +미들웨어 핸들러는 http request와 라우팅 사이에서 작동합니다. 미들웨어 핸들러는 근본적으로 다른 핸들러들과는 다릅니다. 사용방법은 아래와 같습니다: +~~~ go +m.Use(func() { + // 미들웨어 임무 수행! +}) +~~~ + +`Handlers`를 이용하여 미들웨어 스택들의 완전 컨트롤이 가능합니다. 다만, 이렇게 설정하시면 이전에 `Handlers`를 이용하여 설정한 핸들러들은 사라집니다: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +미들웨어 핸들러는 로깅(logging), 허가(authorization), 인가(authentication), 세션, 압축(gzipping), 에러 페이지 등 등, http request의 전후로 실행되어야 할 일들을 처리하기 아주 좋습니다: +~~~ go +// API 키 확인작업 +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "비밀암호!!!" { + res.WriteHeader(http.StatusUnauthorized) // HTTP 401 + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context)는 선택적 함수입니다. 이 함수는 http request가 다 작동 될때까지 기다립니다.따라서 http request 이후에 실행 되어야 할 업무들을 수행하기 좋은 함수입니다. +~~~ go +// log before and after a request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("request전입니다.") + + c.Next() + + log.Println("request후 입니다.") +}) +~~~ + +## Martini Env +마티니 핸들러들은 `martini.Env` 글로벌 변수를 사용하여 개발환경에서는 프로덕션 환경과는 다르게 작동하기도 합니다. 따라서, 프로덕션 서버로 마티니 서버를 배포하시게 된다면 꼭 환경변수 `MARTINI_ENV=production`를 세팅해주시기 바랍니다. + +## FAQ + +### 미들웨어들을 어디서 찾아야 하나요? + +깃헙에서 [martini-contrib](https://github.com/martini-contrib) 프로젝트들을 찾아보세요. 만약에 못 찾으시겠으면, martini-contrib 팀원들에게 연락해서 하나 만들어 달라고 해보세요. +* [auth](https://github.com/martini-contrib/auth) - 인증작업을 도와주는 핸들러. +* [binding](https://github.com/martini-contrib/binding) - request를 맵핑하고 검사하는 핸들러. +* [gzip](https://github.com/martini-contrib/gzip) - gzip 핸들러. +* [render](https://github.com/martini-contrib/render) - HTML 템플레이트들과 JSON를 사용하기 편하게 해주는 핸들러. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - `Accept-Language` HTTP 해더를 파싱 할 때 유용한 핸들러. +* [sessions](https://github.com/martini-contrib/sessions) - 세션 서비스를 제공하는 핸들러. +* [strip](https://github.com/martini-contrib/strip) - URL 프리틱스를 없애주는 핸들러. +* [method](https://github.com/martini-contrib/method) - 해더나 폼필드를 이용한 HTTP 메소드 치환. +* [secure](https://github.com/martini-contrib/secure) - 몇몇 보안설정을 위한 핸들러. +* [encoder](https://github.com/martini-contrib/encoder) - 데이터 렌더링과 컨텐트 타입을위한 인코딩 서비스. +* [cors](https://github.com/martini-contrib/cors) - CORS 서포트를 위한 핸들러. +* [oauth2](https://github.com/martini-contrib/oauth2) - OAuth2.0 로그인 핸들러. 페이스북, 구글, 깃헙 지원. + +### 현재 작동중인 서버에 마티니를 적용하려면? + +마티니 인스턴스는 `http.Handler` 인터페이스를 차용합니다. 따라서 Go 서버 서브트리로 쉽게 사용될 수 있습니다. 아래 코드는 구글 앱 엔진에서 작동하는 마티니 앱입니다: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello 세계!" + }) + http.Handle("/", m) +} +~~~ + +### 포트와 호스트는 어떻게 바꾸나요? + +마티니의 `Run` 함수는 PORT와 HOST 환경변수를 이용하는데, 설정이 안되어 있다면 localhost:3000으로 설정 되어 집니다. +좀더 유연하게 설정을 하고 싶다면, `martini.RunOnAddr`를 활용해 주세요. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### 라이브 코드 리로드? + +[gin](https://github.com/codegangsta/gin) 과 [fresh](https://github.com/pilu/fresh) 가 마티니 앱의 라이브 리로드를 도와줍니다. + +## 공헌하기(Contributing) + +마티니는 간단하고 가벼운 패키지로 남을 것입니다. 따라서 보통 대부분의 공헌들은 [martini-contrib](https://github.com/martini-contrib) 그룹의 저장소로 가게 됩니다. 만약 마티니 코어에 기여하고 싶으시다면 주저없이 Pull Request를 해주세요. + +## About + +[express](https://github.com/visionmedia/express) 와 [sinatra](https://github.com/sinatra/sinatra)의 영향을 받았습니다. + +마티니는 [Code Gangsta](http://codegangsta.io/)가 디자인 했습니다. diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_pt_br.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_pt_br.md new file mode 100644 index 0000000..2c0da51 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_pt_br.md @@ -0,0 +1,355 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini é um poderoso pacote para escrever aplicações/serviços modulares em Golang.. + + +## Vamos começar + +Após a instalação do Go e de configurar o [GOPATH](http://golang.org/doc/code.html#GOPATH), crie seu primeiro arquivo `.go`. Vamos chamá-lo de `server.go`. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +Então instale o pacote do Martini (É necessário **go 1.1** ou superior): +~~~ +go get github.com/go-martini/martini +~~~ + +Então rode o servidor: +~~~ +go run server.go +~~~ + +Agora você tem um webserver Martini rodando na porta `localhost:3000`. + +## Obtenha ajuda + +Assine a [Lista de email](https://groups.google.com/forum/#!forum/martini-go) + +Veja o [Vídeo demonstrativo](http://martini.codegangsta.io/#demo) + +Use a tag [martini](http://stackoverflow.com/questions/tagged/martini) para perguntas no Stackoverflow + + + +## Caracteríticas +* Extrema simplicidade de uso. +* Design não intrusivo. +* Boa integração com outros pacotes Golang. +* Router impressionante. +* Design modular - Fácil para adicionar e remover funcionalidades. +* Muito bom no uso handlers/middlewares. +* Grandes caracteríticas inovadoras. +* **Completa compatibilidade com a interface [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc).** + +## Mais Middleware +Para mais middleware e funcionalidades, veja os repositórios em [martini-contrib](https://github.com/martini-contrib). + +## Tabela de Conteudos +* [Classic Martini](#classic-martini) + * [Handlers](#handlers) + * [Routing](#routing) + * [Services](#services) + * [Serving Static Files](#serving-static-files) +* [Middleware Handlers](#middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +Para iniciar rapidamente, [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) provê algumas ferramentas razoáveis para maioria das aplicações web: +~~~ go + m := martini.Classic() + // ... middleware e rota aqui + m.Run() +~~~ + +Algumas das funcionalidade que o [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) oferece automaticamente são: + * Request/Response Logging - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Servidor de arquivos státicos - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Rotas - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### Handlers +Handlers são o coração e a alma do Martini. Um handler é basicamente qualquer função que pode ser chamada: +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Retorno de Valores +Se um handler retornar alguma coisa, Martini irá escrever o valor retornado como uma string ao [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter): +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +Você também pode retornar o código de status: +~~~ go +m.Get("/", func() (int, string) { + return 418, "Eu sou um bule" // HTTP 418 : "Eu sou um bule" +}) +~~~ + +#### Injeção de Serviços +Handlers são chamados via reflexão. Martini utiliza *Injeção de Dependencia* para resolver as dependencias nas listas de argumentos dos Handlers . **Isso faz Martini ser completamente compatível com a interface `http.HandlerFunc` do golang.** + +Se você adicionar um argumento ao seu Handler, Martini ira procurar na sua lista de serviços e tentar resolver sua dependencia pelo seu tipo: +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res e req são injetados pelo Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +Os seguintes serviços são incluídos com [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * [*log.Logger](http://godoc.org/log#Logger) - Log Global para Martini. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request context. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` de nomes dos parâmetros buscados pela rota. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Serviço de auxílio as rotas. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response escreve a interface. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### Rotas +No Martini, uma rota é um método HTTP emparelhado com um padrão de URL de correspondência. +Cada rota pode ter um ou mais métodos handler: +~~~ go +m.Get("/", func() { + // mostra alguma coisa +}) + +m.Patch("/", func() { + // altera alguma coisa +}) + +m.Post("/", func() { + // cria alguma coisa +}) + +m.Put("/", func() { + // sobrescreve alguma coisa +}) + +m.Delete("/", func() { + // destrói alguma coisa +}) + +m.Options("/", func() { + // opções do HTTP +}) + +m.NotFound(func() { + // manipula 404 +}) +~~~ + +As rotas são combinadas na ordem em que são definidas. A primeira rota que corresponde a solicitação é chamada. + +O padrão de rotas pode incluir parâmetros que podem ser acessados via [martini.Params](http://godoc.org/github.com/go-martini/martini#Params): +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +As rotas podem ser combinados com expressões regulares e globs: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +Expressões regulares podem ser bem usadas: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +Dê uma olhada na [documentação](http://golang.org/pkg/regexp/syntax/) para mais informações sobre expressões regulares. + + +Handlers de rota podem ser empilhados em cima uns dos outros, o que é útil para coisas como autenticação e autorização: +~~~ go +m.Get("/secret", authorize, func() { + // Será executado quando authorize não escrever uma resposta +}) +~~~ + +Grupos de rota podem ser adicionados usando o método Group. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Assim como você pode passar middlewares para um manipulador você pode passar middlewares para grupos. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Serviços +Serviços são objetos que estão disponíveis para ser injetado em uma lista de argumentos de Handler. Você pode mapear um serviço num nível *Global* ou *Request*. + +#### Mapeamento Global +Um exemplo onde o Martini implementa a interface inject.Injector, então o mapeamento de um serviço é fácil: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // o serviço estará disponível para todos os handlers *MyDatabase. +// ... +m.Run() +~~~ + +#### Mapeamento por requisição +Mapeamento do nível de request pode ser feito via handler através [martini.Context](http://godoc.org/github.com/go-martini/martini#Context): +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapeamento é *MyCustomLogger +} +~~~ + +#### Valores de Mapeamento para Interfaces +Uma das partes mais poderosas sobre os serviços é a capacidade para mapear um serviço de uma interface. Por exemplo, se você quiser substituir o [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) com um objeto que envolveu-o e realizou operações extras, você pode escrever o seguinte handler: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // substituir ResponseWriter com nosso ResponseWriter invólucro +} +~~~ + +### Servindo Arquivos Estáticos +Uma instância de [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) serve automaticamente arquivos estáticos do diretório "public" na raiz do seu servidor. +Você pode servir de mais diretórios, adicionando mais [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) handlers. +~~~ go +m.Use(martini.Static("assets")) // servindo os arquivos do diretório "assets" +~~~ + +## Middleware Handlers +Middleware Handlers ficam entre a solicitação HTTP e o roteador. Em essência, eles não são diferentes de qualquer outro Handler no Martini. Você pode adicionar um handler de middleware para a pilha assim: +~~~ go +m.Use(func() { + // faz algo com middleware +}) +~~~ + +Você pode ter o controle total sobre a pilha de middleware com a função `Handlers`. Isso irá substituir quaisquer manipuladores que foram previamente definidos: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware Handlers trabalham muito bem com princípios com logging, autorização, autenticação, sessão, gzipping, páginas de erros e uma série de outras operações que devem acontecer antes ou depois de uma solicitação HTTP: +~~~ go +// Valida uma chave de API +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) é uma função opcional que Middleware Handlers podem chamar para aguardar a execução de outros Handlers. Isso funciona muito bem para operações que devem acontecer após uma requisição: +~~~ go +// log antes e depois do request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("antes do request") + + c.Next() + + log.Println("depois do request") +}) +~~~ + +## Martini Env + +Martini handlers fazem uso do `martini.Env`, uma variável global para fornecer funcionalidade especial para ambientes de desenvolvimento e ambientes de produção. É recomendado que a variável `MARTINI_ENV=production` seja definida quando a implementação estiver em um ambiente de produção. + +## FAQ + +### Onde posso encontrar o middleware X? + +Inicie sua busca nos projetos [martini-contrib](https://github.com/martini-contrib). Se ele não estiver lá não hesite em contactar um membro da equipe martini-contrib sobre como adicionar um novo repo para a organização. + +* [auth](https://github.com/martini-contrib/auth) - Handlers para autenticação. +* [binding](https://github.com/martini-contrib/binding) - Handler para mapeamento/validação de um request a estrutura. +* [gzip](https://github.com/martini-contrib/gzip) - Handler para adicionar compreção gzip para o requests +* [render](https://github.com/martini-contrib/render) - Handler que providencia uma rederização simples para JSON e templates HTML. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Handler para parsing do `Accept-Language` no header HTTP. +* [sessions](https://github.com/martini-contrib/sessions) - Handler que prove o serviço de sessão. +* [strip](https://github.com/martini-contrib/strip) - URL Prefix stripping. +* [method](https://github.com/martini-contrib/method) - HTTP método de substituição via cabeçalho ou campos do formulário. +* [secure](https://github.com/martini-contrib/secure) - Implementa rapidamente itens de segurança. +* [encoder](https://github.com/martini-contrib/encoder) - Serviço Encoder para renderização de dados em vários formatos e negociação de conteúdo. +* [cors](https://github.com/martini-contrib/cors) - Handler que habilita suporte a CORS. +* [oauth2](https://github.com/martini-contrib/oauth2) - Handler que prove sistema de login OAuth 2.0 para aplicações Martini. Google Sign-in, Facebook Connect e Github login são suportados. + +### Como faço para integrar com os servidores existentes? + +Uma instância do Martini implementa `http.Handler`, de modo que pode ser facilmente utilizado para servir sub-rotas e diretórios +em servidores Go existentes. Por exemplo, este é um aplicativo Martini trabalhando para Google App Engine: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### Como faço para alterar a porta/host? + +A função `Run` do Martini olha para as variáveis PORT e HOST para utilizá-las. Caso contrário o Martini assume como padrão localhost:3000. +Para ter mais flexibilidade sobre a porta e host use a função `martini.RunOnAddr`. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Servidor com autoreload? + +[gin](https://github.com/codegangsta/gin) e [fresh](https://github.com/pilu/fresh) são aplicativos para autoreload do Martini. + +## Contribuindo +Martini é feito para ser mantido pequeno e limpo. A maioria das contribuições devem ser feitas no repositório [martini-contrib](https://github.com/martini-contrib). Se quiser contribuir com o core do Martini fique livre para fazer um Pull Request. + +## Sobre + +Inspirado por [express](https://github.com/visionmedia/express) e [sinatra](https://github.com/sinatra/sinatra) + +Martini is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/) diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_ru_RU.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_ru_RU.md new file mode 100644 index 0000000..2cf00ea --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_ru_RU.md @@ -0,0 +1,354 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini - мощный пакет для быстрой разработки веб приложений и сервисов на Golang. + +## Начало работы + +После установки Golang и настройки вашего [GOPATH](http://golang.org/doc/code.html#GOPATH), создайте ваш первый `.go` файл. Назовем его `server.go`. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +Потом установите пакет Martini (требуется **go 1.1** или выше): +~~~ +go get github.com/go-martini/martini +~~~ + +Потом запустите ваш сервер: +~~~ +go run server.go +~~~ + +И вы получите запущенный Martini сервер на `localhost:3000`. + +## Помощь + +Присоединяйтесь к [рассылке](https://groups.google.com/forum/#!forum/martini-go) + +Смотрите [демо видео](http://martini.codegangsta.io/#demo) + +Задавайте вопросы на Stackoverflow используя [тэг martini](http://stackoverflow.com/questions/tagged/martini) + +GoDoc [документация](http://godoc.org/github.com/go-martini/martini) + + +## Возможности +* Очень прост в использовании. +* Ненавязчивый дизайн. +* Хорошо сочетается с другими пакетами. +* Потрясающий роутинг и маршрутизация. +* Модульный дизайн - легко добавлять и исключать функциональность. +* Большое количество хороших обработчиков/middlewares, готовых к использованию. +* Отличный набор 'из коробки'. +* **Полностью совместим с интерфейсом [http.HandlerFunc](http://godoc.org/net/http#HandlerFunc).** + +## Больше Middleware +Смотрите репозитории организации [martini-contrib](https://github.com/martini-contrib), для большей информации о функциональности и middleware. + +## Содержание +* [Classic Martini](#classic-martini) + * [Обработчики](#%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B8) + * [Роутинг](#%D0%A0%D0%BE%D1%83%D1%82%D0%B8%D0%BD%D0%B3) + * [Сервисы](#%D0%A1%D0%B5%D1%80%D0%B2%D0%B8%D1%81%D1%8B) + * [Отдача статических файлов](#%D0%9E%D1%82%D0%B4%D0%B0%D1%87%D0%B0-%D1%81%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85-%D1%84%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2) +* [Middleware обработчики](#middleware-%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B8) + * [Next()](#next) +* [Окружение](#%D0%9E%D0%BA%D1%80%D1%83%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5) +* [FAQ](#faq) + +## Classic Martini +Для быстрого старта [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) предлагает несколько предустановок, это используется для большинства веб приложений: +~~~ go + m := martini.Classic() + // ... middleware и роутинг здесь + m.Run() +~~~ + +Ниже представлена уже подключенная [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) функциональность: + + * Request/Response логгирование - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Отдача статики - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Роутинг - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### Обработчики +Обработчики - это сердце и душа Martini. Обработчик - любая функция, которая может быть вызвана: +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Возвращаемые значения +Если обработчик возвращает что либо, Martini запишет это как результат в текущий [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter), в виде строки: +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +Так же вы можете возвращать код статуса, опционально: +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### Внедрение сервисов +Обработчики вызываются посредством рефлексии. Martini использует **Внедрение зависимости** для разрешения зависимостей в списке аргумента обработчика. **Это делает Martini полностью совместимым с интерфейсом `http.HandlerFunc`.** + +Если вы добавите аргументы в ваш обработчик, Martini будет пытаться найти этот список сервисов за счет проверки типов(type assertion): +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res и req будут внедрены Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +Следующие сервисы включены в [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + + * [*log.Logger](http://godoc.org/log#Logger) - Глобальный логгер для Martini. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request контекст. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` именованых аргументов из роутера. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Хэлпер роутеров. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer интерфейс. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. + +### Роутинг +В Martini, роут - это объединенные паттерн и HTTP метод. +Каждый роут может принимать один или несколько обработчиков: +~~~ go +m.Get("/", func() { + // показать что-то +}) + +m.Patch("/", func() { + // обновить что-то +}) + +m.Post("/", func() { + // создать что-то +}) + +m.Put("/", func() { + // изменить что-то +}) + +m.Delete("/", func() { + // удалить что-то +}) + +m.Options("/", func() { + // http опции +}) + +m.NotFound(func() { + // обработчик 404 +}) +~~~ + +Роуты могут сопоставляться с http запросами только в порядке объявления. Вызывается первый роут, который соответствует запросу. + +Паттерны роутов могут включать именованные параметры, доступные через [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) сервис: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Роуты можно объявлять как glob'ы: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +Так же могут использоваться регулярные выражения: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +Синтаксис регулярных выражений смотрите [Go documentation](http://golang.org/pkg/regexp/syntax/). + +Обработчики роутов так же могут быть выстроены в стек, друг перед другом. Это очень удобно для таких задач как авторизация и аутентификация: +~~~ go +m.Get("/secret", authorize, func() { + // будет вызываться, в случае если authorize ничего не записал в ответ +}) +~~~ + +Роуты так же могут быть объединены в группы, посредством метода Group: +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Так же как вы можете добавить middleware для обычного обработчика, вы можете добавить middleware и для группы. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Сервисы +Сервисы - это объекты, которые доступны для внедрения в аргументы обработчиков. Вы можете замапить сервисы на уровне всего приложения либо на уровне запроса. + +#### Глобальный маппинг +Экземпляр Martini реализует интерфейс inject.Injector, поэтому замаппить сервис легко: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // сервис будет доступен для всех обработчиков как *MyDatabase +// ... +m.Run() +~~~ + +#### Маппинг уровня запроса +Маппинг на уровне запроса можно сделать при помощи [martini.Context](http://godoc.org/github.com/go-martini/martini#Context): +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // как *MyCustomLogger +} +~~~ + +#### Маппинг на определенный интерфейс +Одна из мощных частей, того что касается сервисов - маппинг сервиса на определенный интерфейс. Например, если вы хотите переопределить [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) объектом, который оборачивает и добавляет новые операции, вы можете написать следующее: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // переопределить ResponseWriter нашей оберткой +} +~~~ + +### Отдача статических файлов +Экземпляр [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) автоматически отдает статические файлы из директории "public" в корне, рядом с вашим файлом `server.go`. +Вы можете добавить еще директорий, добавляя [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) обработчики. +~~~ go +m.Use(martini.Static("assets")) // отдача файлов из "assets" директории +~~~ + +## Middleware Обработчики +Middleware обработчики находятся между входящим http запросом и роутом. По сути, они ничем не отличаются от любого другого обработчика Martini. Вы можете добавить middleware обработчик в стек следующим образом: +~~~ go +m.Use(func() { + // делать какую то middleware работу +}) +~~~ + +Для полного контроля над стеком middleware существует метод `Handlers`. В этом примере будут заменены все обработчики, которые были до этого: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware обработчики очень хорошо работают для таких вещей как логгирование, авторизация, аутентификация, сессии, сжатие, страницы ошибок и любые другие операции, которые должны быть выполнены до или после http запроса: +~~~ go +// валидация api ключа +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) опциональная функция, которая может быть вызвана в Middleware обработчике, для выхода из контекста, и возврата в него, после вызова всего стека обработчиков. Это можно использовать для операций, которые должны быть выполнены после http запроса: +~~~ go +// логгирование до и после http запроса +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("до запроса") + + c.Next() + + log.Println("после запроса") +}) +~~~ + +## Окружение +Некоторые Martini обработчики используют глобальную переменную `martini.Env` для того, чтоб предоставить специальную функциональность для девелопмент и продакшн окружения. Рекомендуется устанавливать `MARTINI_ENV=production`, когда вы деплоите приложение на продакшн. + +## FAQ + +### Где найти готовые middleware? + +Начните поиск с [martini-contrib](https://github.com/martini-contrib) проектов. Если нет ничего подходящего, без колебаний пишите члену команды martini-contrib о добавлении нового репозитория в организацию. + +* [auth](https://github.com/martini-contrib/auth) - Обработчики для аутентификации. +* [binding](https://github.com/martini-contrib/binding) - Обработчик для маппинга/валидации сырого запроса в определенную структуру(struct). +* [gzip](https://github.com/martini-contrib/gzip) - Обработчик, добавляющий gzip сжатие для запросов. +* [render](https://github.com/martini-contrib/render) - Обработчик, которые предоставляет сервис для легкого рендеринга JSON и HTML шаблонов. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - Обработчик для парсинга `Accept-Language` HTTP заголовка. +* [sessions](https://github.com/martini-contrib/sessions) - Сервис сессий. +* [strip](https://github.com/martini-contrib/strip) - Удаление префиксов из URL. +* [method](https://github.com/martini-contrib/method) - Подмена HTTP метода через заголовок. +* [secure](https://github.com/martini-contrib/secure) - Набор для безопасности. +* [encoder](https://github.com/martini-contrib/encoder) - Сервис для представления данных в нескольких форматах и взаимодействия с контентом. +* [cors](https://github.com/martini-contrib/cors) - Поддержка CORS. +* [oauth2](https://github.com/martini-contrib/oauth2) - Обработчик, предоставляющий OAuth 2.0 логин для Martini приложений. Вход через Google, Facebook и через Github поддерживаются. + +### Как интегрироваться с существуюшими серверами? + +Экземпляр Martini реализует интерфейс `http.Handler`, потому - это очень просто использовать вместе с существующим Go проектом. Например, это работает для платформы Google App Engine: +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### Как изменить порт и/или хост? +Функция `Run` смотрит переменные окружиения PORT и HOST, и использует их. +В противном случае Martini по умолчанию будет использовать `localhost:3000`. +Для большей гибкости используйте вместо этого функцию `martini.RunOnAddr`. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Живая перезагрузка кода? + +[gin](https://github.com/codegangsta/gin) и [fresh](https://github.com/pilu/fresh) могут работать вместе с Martini. + +## Вклад в обшее дело + +Подразумевается что Martini чистый и маленький. Большинство улучшений должны быть в организации [martini-contrib](https://github.com/martini-contrib). Но если вы хотите улучшить ядро Martini, отправляйте пулл реквесты. + +## О проекте + +Вдохновлен [express](https://github.com/visionmedia/express) и [sinatra](https://github.com/sinatra/sinatra) + +Martini создан [Code Gangsta](http://codegangsta.io/) diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_tr_TR.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_tr_TR.md new file mode 100644 index 0000000..9221b34 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_tr_TR.md @@ -0,0 +1,387 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini Go dilinde hızlı ve modüler web uygulamaları ve servisleri için güçlü bir pakettir. + + +## Başlangıç + +Go kurulumu ve [GOPATH](http://golang.org/doc/code.html#GOPATH) ayarını yaptıktan sonra, ilk `.go` uzantılı dosyamızı oluşturuyoruz. Bu oluşturduğumuz dosyayı `server.go` olarak adlandıracağız. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +Martini paketini kurduktan sonra (**go 1.1** ve daha üst go sürümü gerekmektedir.): + +~~~ +go get github.com/go-martini/martini +~~~ + +Daha sonra server'ımızı çalıştırıyoruz: + +~~~ +go run server.go +~~~ + +Şimdi elimizde çalışan bir adet Martini webserver `localhost:3000` adresinde bulunmaktadır. + + +## Yardım Almak İçin + +[Mail Listesi](https://groups.google.com/forum/#!forum/martini-go) + +[Örnek Video](http://martini.codegangsta.io/#demo) + +Stackoverflow üzerinde [martini etiketine](http://stackoverflow.com/questions/tagged/martini) sahip sorular + +[GO Diline ait Dökümantasyonlar](http://godoc.org/github.com/go-martini/martini) + + +## Özellikler +* Oldukça basit bir kullanıma sahip. +* Kısıtlama yok. +* Golang paketleri ile rahat bir şekilde kullanılıyor. +* Müthiş bir şekilde path eşleştirme ve yönlendirme. +* Modüler dizayn - Kolay eklenen fonksiyonellik. +* handlers/middlewares kullanımı çok iyi. +* Büyük 'kutu dışarı' özellik seti. +* **[http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) arayüzü ile tam uyumludur.** +* Varsayılan belgelendirme işlemleri (örnek olarak, AngularJS uygulamalarının HTML5 modunda servis edilmesi). + +## Daha Fazla Middleware(Ara Katman) + +Daha fazla ara katman ve fonksiyonellik için, şu repoları inceleyin [martini-contrib](https://github.com/martini-contrib). + +## Tablo İçerikleri +* [Classic Martini](#classic-martini) + * [İşleyiciler / Handlers](#handlers) + * [Yönlendirmeler / Routing](#routing) + * [Servisler](#services) + * [Statik Dosyaların Sunumu](#serving-static-files) +* [Katman İşleyiciler / Middleware Handlers](#middleware-handlers) + * [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ](#faq) + +## Classic Martini +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) hızlıca projeyi çalıştırır ve çoğu web uygulaması için iyi çalışan bazı makul varsayılanlar sağlar: + +~~~ go + m := martini.Classic() + // ... middleware and routing goes here + m.Run() +~~~ + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) aşağıdaki bazı fonsiyonelleri otomatik olarak çeker: + + * İstek/Yanıt Kayıtları (Request/Response Logging) - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Hataların Düzeltilmesi (Panic Recovery) - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Statik Dosyaların Sunumu (Static File serving) - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Yönlendirmeler (Routing) - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### İşleyiciler (Handlers) +İşleyiciler Martini'nin ruhu ve kalbidir. Bir işleyici temel olarak her türlü fonksiyonu çağırabilir: + +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### Geriye Dönen Değerler + +Eğer bir işleyici geriye bir şey dönderiyorsa, Martini string olarak sonucu [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) ile yazacaktır: + +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +Ayrıca isteğe bağlı bir durum kodu dönderebilir: +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### Service Injection +İşlemciler yansıma yoluyla çağrılır. Martini *Dependency Injection* kullanarak arguman listesindeki bağımlıkları giderir.**Bu sayede Martini go programlama dilinin `http.HandlerFunc` arayüzü ile tamamen uyumlu hale getirilir.** + +Eğer işleyiciye bir arguman eklersek, Martini "type assertion" ile servis listesinde arayacak ve bağımlılıkları çözmek için girişimde bulunacaktır: + +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +Aşağıdaki servislerin içerikleri + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * [*log.Logger](http://godoc.org/log#Logger) - Martini için Global loglayıcı. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request içereği. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` ile yol eşleme tarafından params olarak isimlendirilen yapılar bulundu. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Yönledirilme için yardımcı olan yapıdır. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http yanıtlarını yazacak olan yapıdır. + * [*http.Request](http://godoc.org/net/http/#Request) - http Request(http isteği yapar). + +### Yönlendirme - Routing +Martini'de bir yol HTTP metodu URL-matching pattern'i ile eşleştirilir. +Her bir yol bir veya daha fazla işleyici metod alabilir: +~~~ go +m.Get("/", func() { + // show something +}) + +m.Patch("/", func() { + // update something +}) + +m.Post("/", func() { + // create something +}) + +m.Put("/", func() { + // replace something +}) + +m.Delete("/", func() { + // destroy something +}) + +m.Options("/", func() { + // http options +}) + +m.NotFound(func() { + // handle 404 +}) +~~~ + +Yollar sırayla tanımlandıkları şekilde eşleştirilir.Request ile eşleşen ilk rota çağrılır. + +Yol patternleri [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) servisi tarafından adlandırılan parametreleri içerebilir: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Yollar globaller ile eşleşebilir: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +Düzenli ifadeler kullanılabilir: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +Düzenli ifadeler hakkında daha fazla bilgiyi [Go dökümanlarından](http://golang.org/pkg/regexp/syntax/) elde edebilirsiniz. + +Yol işleyicileri birbirlerinin üstüne istiflenebilir. Bu durum doğrulama ve yetkilendirme(authentication and authorization) işlemleri için iyi bir yöntemdir: +~~~ go +m.Get("/secret", authorize, func() { + // this will execute as long as authorize doesn't write a response +}) +~~~ + +Yol grupları Grup metodlar kullanılarak eklenebilir. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +Tıpkı ara katmanların işleyiciler için bazı ara katman işlemlerini atlayabileceği gibi gruplar içinde atlayabilir. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Servisler + +Servisler işleyicilerin arguman listesine enjekte edilecek kullanılabilir nesnelerdir. İstenildiği taktirde bir servis *Global* ve *Request* seviyesinde eşlenebilir. + +#### Global Eşleme - Global Mapping + +Bir martini örneği(instance) projeye enjekte edilir. +A Martini instance implements the inject.Enjekte arayüzü, çok kolay bir şekilde servis eşlemesi yapar: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // the service will be available to all handlers as *MyDatabase +// ... +m.Run() +~~~ + +#### Request-Level Mapping +Request düzeyinde eşleme yapmak üzere işleyici [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) ile oluşturulabilir: +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // mapped as *MyCustomLogger +} +~~~ + +#### Arayüz Eşleme Değerleri +Servisler hakkındaki en güçlü şeylerden birisi bir arabirim ile bir servis eşleşmektedir. Örneğin, istenirse [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter) yapısı paketlenmiş ve ekstra işlemleri gerçekleştirilen bir nesne ile override edilebilir. Şu işleyici yazılabilir: + +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // override ResponseWriter with our wrapper ResponseWriter +} +~~~ + +### Statik Dosyaların Sunumu + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) örneği otomatik olarak statik dosyaları serverda root içinde yer alan "public" dizininden servis edilir. + +Eğer istenirse daha fazla [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) işleyicisi eklenerek daha fazla dizin servis edilebilir. +~~~ go +m.Use(martini.Static("assets")) // serve from the "assets" directory as well +~~~ + +#### Standart Dökümanların Sunulması - Serving a Default Document + +Eğer istenilen URL bulunamaz ise özel bir URL dönderilebilir. Ayrıca bir dışlama(exclusion) ön eki ile bazı URL'ler göz ardı edilir. Bu durum statik dosyaların ve ilave işleyiciler için kullanışlıdır(Örneğin, REST API). Bunu yaparken, bu işlem ile NotFound zincirinin bir parçası olan statik işleyiciyi tanımlamak kolaydır. + +Herhangi bir URL isteği bir local dosya ile eşleşmediği ve `/api/v` ile başlamadığı zaman aşağıdaki örnek `/index.html` dosyasını sonuç olarak geriye döndürecektir. +~~~ go +static := martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/api/v"}) +m.NotFound(static, http.NotFound) +~~~ + +## Ara Katman İşleyicileri +Ara katmana ait işleyiciler http isteği ve yönlendirici arasında bulunmaktadır. Özünde onlar diğer Martini işleyicilerinden farklı değildirler. İstenildiği taktirde bir yığına ara katman işleyicisi şu şekilde eklenebilir: +~~~ go +m.Use(func() { + // do some middleware stuff +}) +~~~ + +`Handlers` fonksiyonu ile ara katman yığını üzerinde tüm kontrole sahip olunabilir. Bu daha önceden ayarlanmış herhangi bir işleyicinin yerini alacaktır: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Orta katman işleyicileri loglama, giriş , yetkilendirme , sessionlar, sıkıştırma(gzipping) , hata sayfaları ve HTTP isteklerinden önce ve sonra herhangi bir olay sonucu oluşan durumlar için gerçekten iyi bir yapıya sahiptir: + +~~~ go +// validate an api key +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) orta katman işleyicilerinin diğer işleyiciler yok edilmeden çağrılmasını sağlayan opsiyonel bir fonksiyondur.Bu iş http işlemlerinden sonra gerçekleşecek işlemler için gerçekten iyidir: +~~~ go +// log before and after a request +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("before a request") + + c.Next() + + log.Println("after a request") +}) +~~~ + +## Martini Env + +Bazı Martini işleyicileri `martini.Env` yapısının özel fonksiyonlarını kullanmak için geliştirici ortamları, üretici ortamları vs. kullanır.Bu üretim ortamına Martini sunucu kurulurken `MARTINI_ENV=production` şeklinde ortam değişkeninin ayarlanması gerekir. + +## FAQ + +### Ara Katmanda X'i Nerede Bulurum? + +[martini-contrib](https://github.com/martini-contrib) projelerine bakarak başlayın. Eğer aradığınız şey orada mevcut değil ise yeni bir repo eklemek için martini-contrib takım üyeleri ile iletişime geçin. + +* [auth](https://github.com/martini-contrib/auth) - Kimlik doğrulama için işleyiciler. +* [binding](https://github.com/martini-contrib/binding) - Mapping/Validating yapısı içinde ham request'i doğrulamak için kullanılan işleyici(handler) +* [gzip](https://github.com/martini-contrib/gzip) - İstekleri gzip sıkışıtırıp eklemek için kullanılan işleyici +* [render](https://github.com/martini-contrib/render) - Kolay bir şekilde JSON ve HTML şablonları oluşturmak için kullanılan işleyici. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - `Kabul edilen dile` göre HTTP başlığını oluşturmak için kullanılan işleyici. +* [sessions](https://github.com/martini-contrib/sessions) - Oturum hizmeti vermek için kullanılır. +* [strip](https://github.com/martini-contrib/strip) - İşleyicilere gitmeden önce URL'ye ait ön şeriti değiştirme işlemini yapar. +* [method](https://github.com/martini-contrib/method) - Formlar ve başlık için http metodunu override eder. +* [secure](https://github.com/martini-contrib/secure) - Birkaç hızlı güvenlik uygulaması ile kazanımda bulundurur. +* [encoder](https://github.com/martini-contrib/encoder) - Encoder servis veri işlemleri için çeşitli format ve içerik sağlar. +* [cors](https://github.com/martini-contrib/cors) - İşleyicilerin CORS desteği bulunur. +* [oauth2](https://github.com/martini-contrib/oauth2) - İşleyiciler OAuth 2.0 için Martini uygulamalarına giriş sağlar. Google , Facebook ve Github için desteği mevcuttur. +* [vauth](https://github.com/rafecolton/vauth) - Webhook için giriş izni sağlar. (şimdilik sadece GitHub ve TravisCI ile) + +### Mevcut Sunucular ile Nasıl Entegre Edilir? + +Bir martini örneği `http.Handler`'ı projeye dahil eder, bu sayde kolay bir şekilde mevcut olan Go sunucularında bulunan alt ağaçlarda kullanabilir. Örnek olarak, bu olay Google App Engine için hazırlanmış Martini uygulamalarında kullanılmaktadır: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### port/hostu nasıl değiştiririm? + +Martini'ye ait `Run` fonksiyounu PORT ve HOST'a ait ortam değişkenlerini arar ve bunları kullanır. Aksi taktirde standart olarak localhost:3000 adresini port ve host olarak kullanacaktır. + +Port ve host için daha fazla esneklik isteniyorsa `martini.RunOnAddr` fonksiyonunu kullanın. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### Anlık Kod Yüklemesi? + +[gin](https://github.com/codegangsta/gin) ve [fresh](https://github.com/pilu/fresh) anlık kod yüklemeleri yapan martini uygulamalarıdır. + +## Katkıda Bulunmak +Martini'nin temiz ve düzenli olaması gerekiyordu. +Martini is meant to be kept tiny and clean. Tüm kullanıcılar katkı yapmak için [martini-contrib](https://github.com/martini-contrib) organizasyonunda yer alan repoları bitirmelidirler. Eğer martini core için katkıda bulunacaksanız fork işlemini yaparak başlayabilirsiniz. + +## Hakkında + +[express](https://github.com/visionmedia/express) ve [sinatra](https://github.com/sinatra/sinatra) projelerinden esinlenmiştir. + +Martini [Code Gangsta](http://codegangsta.io/) tarafından tasarlanılmıştır. diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_zh_cn.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_zh_cn.md new file mode 100644 index 0000000..dc208f8 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_zh_cn.md @@ -0,0 +1,328 @@ +# Martini [](https://app.wercker.com/project/bykey/174bef7e3c999e103cacfe2770102266) [](http://godoc.org/github.com/go-martini/martini) + +Martini是一个强大为了编写模块化Web应用而生的GO语言框架. + +## 第一个应用 + +在你安装了GO语言和设置了你的[GOPATH](http://golang.org/doc/code.html#GOPATH)之后, 创建你的自己的`.go`文件, 这里我们假设它的名字叫做 `server.go`. + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +~~~ + +然后安装Martini的包. (注意Martini需要Go语言1.1或者以上的版本支持): +~~~ +go get github.com/go-martini/martini +~~~ + +最后运行你的服务: +~~~ +go run server.go +~~~ + +这时你将会有一个Martini的服务监听了, 地址是: `localhost:3000`. + +## 获得帮助 + +请加入: [邮件列表](https://groups.google.com/forum/#!forum/martini-go) + +或者可以查看在线演示地址: [演示视频](http://martini.codegangsta.io/#demo) + +## 功能列表 +* 使用极其简单. +* 无侵入式的设计. +* 很好的与其他的Go语言包协同使用. +* 超赞的路径匹配和路由. +* 模块化的设计 - 容易插入功能件,也容易将其拔出来. +* 已有很多的中间件可以直接使用. +* 框架内已拥有很好的开箱即用的功能支持. +* **完全兼容[http.HandlerFunc](http://godoc.org/net/http#HandlerFunc)接口.** + +## 更多中间件 +更多的中间件和功能组件, 请查看代码仓库: [martini-contrib](https://github.com/martini-contrib). + +## 目录 +* [核心 Martini](#classic-martini) + * [处理器](#handlers) + * [路由](#routing) + * [服务](#services) + * [服务静态文件](#serving-static-files) +* [中间件处理器](#middleware-handlers) + * [Next()](#next) +* [常见问答](#faq) + +## 核心 Martini +为了更快速的启用Martini, [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) 提供了一些默认的方便Web开发的工具: +~~~ go + m := martini.Classic() + // ... middleware and routing goes here + m.Run() +~~~ + +下面是Martini核心已经包含的功能 [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * Request/Response Logging (请求/响应日志) - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) + * Panic Recovery (容错) - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) + * Static File serving (静态文件服务) - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) + * Routing (路由) - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + +### 处理器 +处理器是Martini的灵魂和核心所在. 一个处理器基本上可以是任何的函数: +~~~ go +m.Get("/", func() { + println("hello world") +}) +~~~ + +#### 返回值 +当一个处理器返回结果的时候, Martini将会把返回值作为字符串写入到当前的[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)里面: +~~~ go +m.Get("/", func() string { + return "hello world" // HTTP 200 : "hello world" +}) +~~~ + +另外你也可以选择性的返回多一个状态码: +~~~ go +m.Get("/", func() (int, string) { + return 418, "i'm a teapot" // HTTP 418 : "i'm a teapot" +}) +~~~ + +#### 服务的注入 +处理器是通过反射来调用的. Martini 通过*Dependency Injection* *(依赖注入)* 来为处理器注入参数列表. **这样使得Martini与Go语言的`http.HandlerFunc`接口完全兼容.** + +如果你加入一个参数到你的处理器, Martini将会搜索它参数列表中的服务,并且通过类型判断来解决依赖关系: +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res 和 req 是通过Martini注入的 + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +下面的这些服务已经被包含在核心Martini中: [martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic): + * [*log.Logger](http://godoc.org/log#Logger) - Martini的全局日志. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request context (请求上下文). + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` of named params found by route matching. (名字和参数键值对的参数列表) + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Route helper service. (路由协助处理) + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http Response writer interface. (响应结果的流接口) + * [*http.Request](http://godoc.org/net/http/#Request) - http Request. (http请求) + +### 路由 +在Martini中, 路由是一个HTTP方法配对一个URL匹配模型. 每一个路由可以对应一个或多个处理器方法: +~~~ go +m.Get("/", func() { + // 显示 +}) + +m.Patch("/", func() { + // 更新 +}) + +m.Post("/", func() { + // 创建 +}) + +m.Put("/", func() { + // 替换 +}) + +m.Delete("/", func() { + // 删除 +}) + +m.Options("/", func() { + // http 选项 +}) + +m.NotFound(func() { + // 处理 404 +}) +~~~ + +路由匹配的顺序是按照他们被定义的顺序执行的. 最先被定义的路由将会首先被用户请求匹配并调用. + +路由模型可能包含参数列表, 可以通过[martini.Params](http://godoc.org/github.com/go-martini/martini#Params)服务来获取: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +路由匹配可以通过正则表达式或者glob的形式: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +路由处理器可以被相互叠加使用, 例如很有用的地方可以是在验证和授权的时候: +~~~ go +m.Get("/secret", authorize, func() { + // 该方法将会在authorize方法没有输出结果的时候执行. +}) +~~~ + +### 服务 +服务即是被注入到处理器中的参数. 你可以映射一个服务到 *全局* 或者 *请求* 的级别. + + +#### 全局映射 +如果一个Martini实现了inject.Injector的接口, 那么映射成为一个服务就非常简单: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // *MyDatabase 这个服务将可以在所有的处理器中被使用到. +// ... +m.Run() +~~~ + +#### 请求级别的映射 +映射在请求级别的服务可以用[martini.Context](http://godoc.org/github.com/go-martini/martini#Context)来完成: +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // 映射成为了 *MyCustomLogger +} +~~~ + +#### 映射值到接口 +关于服务最强悍的地方之一就是它能够映射服务到接口. 例如说, 假设你想要覆盖[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter)成为一个对象, 那么你可以封装它并包含你自己的额外操作, 你可以如下这样来编写你的处理器: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // 覆盖 ResponseWriter 成为我们封装过的 ResponseWriter +} +~~~ + +### 服务静态文件 +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) 默认会服务位于你服务器环境根目录下的"public"文件夹. +你可以通过加入[martini.Static](http://godoc.org/github.com/go-martini/martini#Static)的处理器来加入更多的静态文件服务的文件夹. +~~~ go +m.Use(martini.Static("assets")) // 也会服务静态文件于"assets"的文件夹 +~~~ + +## 中间件处理器 +中间件处理器是工作于请求和路由之间的. 本质上来说和Martini其他的处理器没有分别. 你可以像如下这样添加一个中间件处理器到它的堆中: +~~~ go +m.Use(func() { + // 做一些中间件该做的事情 +}) +~~~ + +你可以通过`Handlers`函数对中间件堆有完全的控制. 它将会替换掉之前的任何设置过的处理器: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +中间件处理器可以非常好处理一些功能,像logging(日志), authorization(授权), authentication(认证), sessions(会话), error pages(错误页面), 以及任何其他的操作需要在http请求发生之前或者之后的: + +~~~ go +// 验证api密匙 +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context)是一个可选的函数用于中间件处理器暂时放弃执行直到其他的处理器都执行完毕. 这样就可以很好的处理在http请求完成后需要做的操作. +~~~ go +// log 记录请求完成前后 (*译者注: 很巧妙,掌声鼓励.) +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("before a request") + + c.Next() + + log.Println("after a request") +}) +~~~ + +## Martini Env +一些handler使用环境变量 `martini.Env` 对开发环境和生产环境提供特殊功能. 推荐在生产环境设置环境变量 `MARTINI_ENV=production`. + + +## 常见问答 + +### 我在哪里可以找到中间件资源? + +可以查看 [martini-contrib](https://github.com/martini-contrib) 项目. 如果看了觉得没有什么好货色, 可以联系martini-contrib的团队成员为你创建一个新的代码资源库. + +* [acceptlang](https://github.com/martini-contrib/acceptlang) - 解析`Accept-Language` HTTP报头的处理器。 +* [accessflags](https://github.com/martini-contrib/accessflags) - 启用访问控制处理器. +* [auth](https://github.com/martini-contrib/auth) - 认证处理器。 +* [binding](https://github.com/martini-contrib/binding) - 映射/验证raw请求到结构体(structure)里的处理器。 +* [cors](https://github.com/martini-contrib/cors) - 提供支持 CORS 的处理器。 +* [csrf](https://github.com/martini-contrib/csrf) - 为应用提供CSRF防护。 +* [encoder](https://github.com/martini-contrib/encoder) - 提供用于多种格式的数据渲染或内容协商的编码服务。 +* [gzip](https://github.com/martini-contrib/gzip) - 通过giz方式压缩请求信息的处理器。 +* [gorelic](https://github.com/martini-contrib/gorelic) - NewRelic 中间件 +* [logstasher](https://github.com/martini-contrib/logstasher) - logstash日志兼容JSON中间件 +* [method](https://github.com/martini-contrib/method) - 通过请求头或表单域覆盖HTTP方法。 +* [oauth2](https://github.com/martini-contrib/oauth2) - 基于 OAuth 2.0 的应用登录处理器。支持谷歌、Facebook和Github的登录。 +* [permissions2](https://github.com/xyproto/permissions2) - 跟踪用户,登录状态和权限控制器 +* [render](https://github.com/martini-contrib/render) - 渲染JSON和HTML模板的处理器。 +* [secure](https://github.com/martini-contrib/secure) - 提供一些安全方面的速效方案。 +* [sessions](https://github.com/martini-contrib/sessions) - 提供`Session`服务支持的处理器。 +* [sessionauth](https://github.com/martini-contrib/sessionauth) - 提供简单的方式使得路由需要登录, 并在Session中处理用户登录 +* [strip](https://github.com/martini-contrib/strip) - 用于过滤指定的URL前缀。 +* [strip](https://github.com/martini-contrib/strip) - URL前缀剥离。 +* [staticbin](https://github.com/martini-contrib/staticbin) - 从二进制数据中提供静态文件服务的处理器。 +* [throttle](https://github.com/martini-contrib/throttle) - 请求速率调节中间件. +* [vauth](https://github.com/rafecolton/vauth) - 负责webhook认证的处理器(目前支持GitHub和TravisCI)。 +* [web](https://github.com/martini-contrib/web) - hoisie web.go's Context + +### 我如何整合到我现有的服务器中? + +由于Martini实现了 `http.Handler`, 所以它可以很简单的应用到现有Go服务器的子集中. 例如说这是一段在Google App Engine中的示例: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### 我如何修改port/host? + +Martini的`Run`函数会检查PORT和HOST的环境变量并使用它们. 否则Martini将会默认使用localhost:3000 +如果想要自定义PORT和HOST, 使用`martini.RunOnAddr`函数来代替. + +~~~ go + m := martini.Classic() + // ... + m.RunOnAddr(":8080") +~~~ + +## 贡献 +Martini项目想要保持简单且干净的代码. 大部分的代码应该贡献到[martini-contrib](https://github.com/martini-contrib)组织中作为一个项目. 如果你想要贡献Martini的核心代码也可以发起一个Pull Request. + +## 关于 + +灵感来自于 [express](https://github.com/visionmedia/express) 和 [sinatra](https://github.com/sinatra/sinatra) + +Martini作者 [Code Gangsta](http://codegangsta.io/) +译者: [Leon](http://github.com/leonli) diff --git a/vendor/_nuts/github.com/go-martini/martini/translations/README_zh_tw.md b/vendor/_nuts/github.com/go-martini/martini/translations/README_zh_tw.md new file mode 100644 index 0000000..8d19dbe --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/translations/README_zh_tw.md @@ -0,0 +1,381 @@ +# Martini [](https://app.wercker.com/project/bykey/9b7dbc6e2654b604cd694d191c3d5487)[](http://godoc.org/github.com/go-martini/martini) + +Martini 是一個使用 Go 語言來快速開發模組化 Web 應用程式或服務的強大套件 + +## 開始 + +在您安裝Go語言以及設定好 +[GOPATH](http://golang.org/doc/code.html#GOPATH)環境變數後, +開始寫您第一支`.go`檔, 我們將稱它為`server.go` + +~~~ go +package main + +import "github.com/go-martini/martini" + +func main() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello 世界!" + }) + m.Run() +} +~~~ + +然後安裝Martini套件 (**go 1.1**以上的版本是必要的) +~~~ +go get github.com/go-martini/martini +~~~ + +然後利用以下指令執行你的程式: +~~~ +go run server.go +~~~ + +此時, 您將會看到一個 Martini Web 伺服器在`localhost:3000`上執行 + +## 尋求幫助 + +可以加入 [Mailing list](https://groups.google.com/forum/#!forum/martini-go) + +觀看 [Demo Video](http://martini.codegangsta.io/#demo) + +## 功能 + +* 超容易使用 +* 非侵入式設計 +* 很容易跟其他Go套件同時使用 +* 很棒的路徑matching和routing方式 +* 模組化設計 - 容易增加或移除功能 +* 有很多handlers或middlewares可以直接使用 +* 已經提供很多內建功能 +* **跟[http.HandlerFunc](http://godoc.org/net/http#HandlerFunc) 介面**完全相容 +* 預設document服務 (例如, 提供AngularJS在HTML5模式的服務) + +## 其他Middleware +尋找更多的middleware或功能, 請到 [martini-contrib](https://github.com/martini-contrib)程式集搜尋 + +## 目錄 +* [Classic Martini](#classic-martini) +* [Handlers](#handlers) +* [Routing](#routing) +* [Services (服務)](#services) +* [Serving Static Files (伺服靜態檔案)](#serving-static-files) +* [Middleware Handlers](#middleware-handlers) +* [Next()](#next) +* [Martini Env](#martini-env) +* [FAQ (常見問題與答案)](#faq) + +## Classic Martini + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) +提供大部份web應用程式所需要的基本預設功能: + +~~~ go + m := martini.Classic() + // ... middleware 或 routing 寫在這裡 + m.Run() +~~~ +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) + 會自動提供以下功能 +* Request/Response Logging - [martini.Logger](http://godoc.org/github.com/go-martini/martini#Logger) +* Panic Recovery - [martini.Recovery](http://godoc.org/github.com/go-martini/martini#Recovery) +* Static File serving - [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) +* Routing - [martini.Router](http://godoc.org/github.com/go-martini/martini#Router) + + +### Handlers +Handlers 是 Martini 的核心, 每個 handler 就是一個基本的呼叫函式, 例如: +~~~ go +m.Get("/", func() { + println("hello 世界") +}) +~~~ + +#### 回傳值 +如果一個 handler 有回傳值, Martini就會用字串的方式將結果寫回現在的 +[http.ResponseWriter](http://godoc.org/net/http#ResponseWriter), 例如: +~~~ go +m.Get("/", func() string { + return "hello 世界" // HTTP 200 : "hello 世界" +}) +~~~ + +你也可以選擇回傳狀態碼, 例如: +~~~ go +m.Get("/", func() (int, string) { + return 418, "我是一個茶壺" // HTTP 418 : "我是一個茶壺" +}) +~~~ + +#### 注入服務 (Service Injection) +Handlers 是透過 reflection 方式被喚起, Martini 使用 *Dependency Injection* 的方法 +載入 Handler 變數所需要的相關物件 **這也是 Martini 跟 Go 語言`http.HandlerFunc`介面 +完全相容的原因** + +如果你在 Handler 裡加入一個變數, Martini 會嘗試著從它的服務清單裡透過 type assertion +方式將相關物件載入 +~~~ go +m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res 和 req 是由 Martini 注入 + res.WriteHeader(200) // HTTP 200 +}) +~~~ + +[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) 包含以下物件: + * [*log.Logger](http://godoc.org/log#Logger) - Martini 的全區域 Logger. + * [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) - http request 內文. + * [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) - `map[string]string` of named params found by route matching. + * [martini.Routes](http://godoc.org/github.com/go-martini/martini#Routes) - Route helper 服務. + * [http.ResponseWriter](http://godoc.org/net/http/#ResponseWriter) - http 回應 writer 介面. + * [*http.Request](http://godoc.org/net/http/#Request) - http 請求. + +### Routing +在 Martini 裡, 一個 route 就是一個 HTTP 方法與其 URL 的比對模式. +每個 route 可以有ㄧ或多個 handler 方法: +~~~ go +m.Get("/", func() { + // 顯示(值) +}) + +m.Patch("/", func() { + // 更新 +}) + +m.Post("/", func() { + // 產生 +}) + +m.Put("/", func() { + // 取代 +}) + +m.Delete("/", func() { + // 刪除 +}) + +m.Options("/", func() { + // http 選項 +}) + +m.NotFound(func() { + // handle 404 +}) +~~~ + +Routes 依照它們被定義時的順序做比對. 第一個跟請求 (request) 相同的 route 就被執行. + +Route 比對模式可以包含變數部分, 可以透過 [martini.Params](http://godoc.org/github.com/go-martini/martini#Params) 物件來取值: +~~~ go +m.Get("/hello/:name", func(params martini.Params) string { + return "Hello " + params["name"] +}) +~~~ + +Routes 也可以用 "**" 來配對, 例如: +~~~ go +m.Get("/hello/**", func(params martini.Params) string { + return "Hello " + params["_1"] +}) +~~~ + +也可以用正規表示法 (regular expressions) 來做比對, 例如: +~~~go +m.Get("/hello/(?P<name>[a-zA-Z]+)", func(params martini.Params) string { + return fmt.Sprintf ("Hello %s", params["name"]) +}) +~~~ +更多有關正規表示法文法的資訊, 請參考 [Go 文件](http://golang.org/pkg/regexp/syntax/). + +Route handlers 也可以相互堆疊, 尤其是認證與授權相當好用: +~~~ go +m.Get("/secret", authorize, func() { + // 這裏開始處理授權問題, 而非寫出回應 +}) +~~~ + +也可以用 Group 方法, 將 route 編成一組. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}) +~~~ + +跟對 handler 增加 middleware 方法一樣, 你也可以為一組 routes 增加 middleware. +~~~ go +m.Group("/books", func(r martini.Router) { + r.Get("/:id", GetBooks) + r.Post("/new", NewBook) + r.Put("/update/:id", UpdateBook) + r.Delete("/delete/:id", DeleteBook) +}, MyMiddleware1, MyMiddleware2) +~~~ + +### Services +服務是一些物件可以被注入 Handler 變數裡的東西, 可以分對應到 *Global* 或 *Request* 兩種等級. + +#### Global Mapping (全域級對應) +一個 Martini 實體 (instance) 實現了 inject.Injector 介面, 所以非常容易對應到所需要的服務, 例如: +~~~ go +db := &MyDatabase{} +m := martini.Classic() +m.Map(db) // 所以 *MyDatabase 就可以被所有的 handlers 使用 +// ... +m.Run() +~~~ + +#### Request-Level Mapping (請求級對應) +如果只在一個 handler 裡定義, 透由 [martini.Context](http://godoc.org/github.com/go-martini/martini#Context) 獲得一個請求 (request) 級的對應: +~~~ go +func MyCustomLoggerHandler(c martini.Context, req *http.Request) { + logger := &MyCustomLogger{req} + c.Map(logger) // 對應到 *MyCustomLogger +} +~~~ + +#### 透由介面對應 +有關服務, 最強的部分是它還能對應到一個介面 (interface), 例如, +如果你想要包裹並增加一個變數而改寫 (override) 原有的 [http.ResponseWriter](http://godoc.org/net/http#ResponseWriter), 你的 handler 可以寫成: +~~~ go +func WrapResponseWriter(res http.ResponseWriter, c martini.Context) { + rw := NewSpecialResponseWriter(res) + c.MapTo(rw, (*http.ResponseWriter)(nil)) // 我們包裹的 ResponseWriter 蓋掉原始的 ResponseWrite +} +~~~ + +### Serving Static Files +一個[martini.Classic()](http://godoc.org/github.com/go-martini/martini#Classic) 實體會將伺服器根目錄下 public 子目錄裡的檔案自動當成靜態檔案處理. 你也可以手動用 [martini.Static](http://godoc.org/github.com/go-martini/martini#Static) 增加其他目錄, 例如. +~~~ go +m.Use(martini.Static("assets")) // "assets" 子目錄裡, 也視為靜態檔案 +~~~ + +#### Serving a Default Document +當某些 URL 找不到時, 你也可以指定本地檔案的 URL 來顯示. +你也可以用開頭除外 (exclusion prefix) 的方式, 來忽略某些 URLs, +它尤其在某些伺服器同時伺服靜態檔案, 而且還有額外 handlers 處理 (例如 REST API) 時, 特別好用. +比如說, 在比對找不到之後, 想要用靜態檔來處理特別好用. + +以下範例, 就是在 URL 開頭不是`/api/v`而且也不是本地檔案的情況下, 顯示`/index.html`檔: +~~~ go +static := martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/api/v"}) +m.NotFound(static, http.NotFound) +~~~ + +## Middleware Handlers +Middleware Handlers 位於進來的 http 請求與 router 之間, 在 Martini 裡, 本質上它跟其他 + Handler 沒有什麼不同, 例如, 你可加入一個 middleware 方法如下 +~~~ go +m.Use(func() { + // 做 middleware 的事 +}) +~~~ + +你也可以用`Handlers`完全控制 middelware 層, 把先前設定的 handlers 都替換掉, 例如: +~~~ go +m.Handlers( + Middleware1, + Middleware2, + Middleware3, +) +~~~ + +Middleware Handlers 成被拿來處理 http 請求之前和之後的事, 尤其是用來紀錄logs, 授權, 認證, +sessions, 壓縮 (gzipping), 顯示錯誤頁面等等, 都非常好用, 例如: +~~~ go +// validate an api key +m.Use(func(res http.ResponseWriter, req *http.Request) { + if req.Header.Get("X-API-KEY") != "secret123" { + res.WriteHeader(http.StatusUnauthorized) + } +}) +~~~ + +### Next() +[Context.Next()](http://godoc.org/github.com/go-martini/martini#Context) 是 Middleware Handlers 可以呼叫的選項功能, 用來等到其他 handlers 處理完再開始執行. +它常常被用來處理那些必須在 http 請求之後才能發生的事件, 例如: +~~~ go +// 在請求前後加 logs +m.Use(func(c martini.Context, log *log.Logger){ + log.Println("before a request") + + c.Next() + + log.Println("after a request") +}) +~~~ + +## Martini Env + +有些 Martini handlers 使用 `martini.Env` 全區域變數, 來當成開發環境或是上架 (production) +環境的設定判斷. 建議用 `MARTINI_ENV=production` 環境變數來設定 Martini 伺服器是上架與否. + +## FAQ + +### 我去哪可以找到 middleware X? + +可以從 [martini-contrib](https://github.com/martini-contrib) 裡的專案找起. +如果那裡沒有, 請與 martini-contrib 團隊聯絡, 將它加入. + +* [auth](https://github.com/martini-contrib/auth) - 處理認證的 Handler. +* [binding](https://github.com/martini-contrib/binding) - +處理一個單純的請求對應到一個結構體與確認內容正確與否的 Handler. +* [gzip](https://github.com/martini-contrib/gzip) - 對請求加 gzip 壓縮的 Handler. +* [render](https://github.com/martini-contrib/render) - 提供簡單處理 JSON 和 +HTML 樣板成形 (rendering) 的 Handler. +* [acceptlang](https://github.com/martini-contrib/acceptlang) - 解析 `Accept-Language` HTTP 檔頭的 Handler. +* [sessions](https://github.com/martini-contrib/sessions) - 提供 Session 服務的 Handler. +* [strip](https://github.com/martini-contrib/strip) - URL 字頭處理 (Prefix stripping). +* [method](https://github.com/martini-contrib/method) - 透過 Header 或表格 (form) 欄位蓋過 HTTP 方法 (method). +* [secure](https://github.com/martini-contrib/secure) - 提供一些簡單的安全機制. +* [encoder](https://github.com/martini-contrib/encoder) - 轉換資料格式之 Encoder 服務. +* [cors](https://github.com/martini-contrib/cors) - 啟動支援 CORS 之 Handler. +* [oauth2](https://github.com/martini-contrib/oauth2) - 讓 Martini 應用程式能提供 OAuth 2.0 登入的 Handler. 其中支援 Google 登錄, Facebook Connect 與 Github 的登入等. +* [vauth](https://github.com/rafecolton/vauth) - 處理 vender webhook 認證的 Handler (目前支援 GitHub 以及 TravisCI) + +### 我如何整合到現有的伺服器? + +Martini 實作 `http.Handler`,所以可以非常容易整合到現有的 Go 伺服器裡. +以下寫法, 是一個能在 Google App Engine 上運行的 Martini 應用程式: + +~~~ go +package hello + +import ( + "net/http" + "github.com/go-martini/martini" +) + +func init() { + m := martini.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + http.Handle("/", m) +} +~~~ + +### 我要如何改變 port/host? + +Martini 的 `Run` 功能會看 PORT 及 HOST 當時的環境變數, 否則 Martini 會用 localhost:3000 +當預設值. 讓 port 及 host 更有彈性, 可以用 `martini.RunOnAddr` 取代. + +~~~ go + m := martini.Classic() + // ... + log.Fatal(m.RunOnAddr(":8080")) +~~~ + +### 可以線上更新 (live reload) 嗎? + +[gin](https://github.com/codegangsta/gin) 和 [fresh](https://github.com/pilu/fresh) 可以幫 Martini 程式做到線上更新. + +## 貢獻 +Martini 盡量保持小而美的精神, 大多數的程式貢獻者可以在 [martini-contrib](https://github.com/martini-contrib) 組織提供代碼. 如果你想要對 Martini 核心提出貢獻, 請丟出 Pull Request. + +## 關於 + +靈感來自與 [express](https://github.com/visionmedia/express) 以及 [sinatra](https://github.com/sinatra/sinatra) + +Martini 由 [Code Gangsta](http://codegangsta.io/) 公司設計出品 (著魔地) diff --git a/vendor/_nuts/github.com/go-martini/martini/wercker.yml b/vendor/_nuts/github.com/go-martini/martini/wercker.yml new file mode 100644 index 0000000..f8bf918 --- /dev/null +++ b/vendor/_nuts/github.com/go-martini/martini/wercker.yml @@ -0,0 +1 @@ +box: wercker/golang@1.1.1
\ No newline at end of file diff --git a/vendor/_nuts/github.com/stretchr/testify/.gitignore b/vendor/_nuts/github.com/stretchr/testify/.gitignore new file mode 100644 index 0000000..5aacdb7 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/.gitignore @@ -0,0 +1,24 @@ +# 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 + +.DS_Store diff --git a/vendor/_nuts/github.com/stretchr/testify/.travis.yml b/vendor/_nuts/github.com/stretchr/testify/.travis.yml new file mode 100644 index 0000000..0595ddb --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.1 + - 1.2 + - 1.3 + - tip + +script: + - go test -v ./... + diff --git a/vendor/_nuts/github.com/stretchr/testify/LICENCE.txt b/vendor/_nuts/github.com/stretchr/testify/LICENCE.txt new file mode 100644 index 0000000..a009ba4 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/LICENCE.txt @@ -0,0 +1,9 @@ +Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell + +Please consider promoting this project if you find it useful. + +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.
\ No newline at end of file diff --git a/vendor/_nuts/github.com/stretchr/testify/README.md b/vendor/_nuts/github.com/stretchr/testify/README.md new file mode 100644 index 0000000..e27b6b5 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/README.md @@ -0,0 +1,332 @@ +Testify - Thou Shalt Write Tests +================================ + +[](https://travis-ci.org/stretchr/testify) + +Go code (golang) set of packages that provide many tools for testifying that your code will behave as you intend. + +Features include: + + * [Easy assertions](#assert-package) + * [Mocking](#mock-package) + * [HTTP response trapping](#http-package) + * [Testing suite interfaces and functions](#suite-package) + +Get started: + + * Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date) + * For an introduction to writing test code in Go, see our [blog post article](http://blog.stretchr.com/2014/03/05/test-driven-development-specifically-in-golang/) or check out http://golang.org/doc/code.html#Testing + * Check out the API Documentation http://godoc.org/github.com/stretchr/testify + * To make your testing life easier, check out our other project, [gorc](http://github.com/stretchr/gorc) + * A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development) + + + +[`assert`](http://godoc.org/github.com/stretchr/testify/assert "API documentation") package +------------------------------------------------------------------------------------------- + +The `assert` package provides some helpful methods that allow you to write better test code in Go. + + * Prints friendly, easy to read failure descriptions + * Allows for very readable code + * Optionally annotate each assertion with a message + +See it in action: + +```go +package yours + +import ( + "testing" + "github.com/stretchr/testify/assert" +) + +func TestSomething(t *testing.T) { + + // assert equality + assert.Equal(t, 123, 123, "they should be equal") + + // assert inequality + assert.NotEqual(t, 123, 456, "they should not be equal") + + // assert for nil (good for errors) + assert.Nil(t, object) + + // assert for not nil (good when you expect something) + if assert.NotNil(t, object) { + + // now we know that object isn't nil, we are safe to make + // further assertions without causing any errors + assert.Equal(t, "Something", object.Value) + + } + +} +``` + + * Every assert func takes the `testing.T` object as the first argument. This is how it writes the errors out through the normal `go test` capabilities. + * Every assert func returns a bool indicating whether the assertion was successful or not, this is useful for if you want to go on making further assertions under certain conditions. + +if you assert many times, use the below: + +```go +package yours + +import ( + "testing" + "github.com/stretchr/testify/assert" +) + +func TestSomething(t *testing.T) { + assert := assert.New(t) + + // assert equality + assert.Equal(123, 123, "they should be equal") + + // assert inequality + assert.NotEqual(123, 456, "they should not be equal") + + // assert for nil (good for errors) + assert.Nil(object) + + // assert for not nil (good when you expect something) + if assert.NotNil(object) { + + // now we know that object isn't nil, we are safe to make + // further assertions without causing any errors + assert.Equal("Something", object.Value) + } +} +``` + +`require` package +------------------------------------------------------------------------------------------- + +The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test. + +See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details. + + +[`http`](http://godoc.org/github.com/stretchr/testify/http "API documentation") package +--------------------------------------------------------------------------------------- + +The `http` package contains test objects useful for testing code that relies on the `net/http` package. Check out the [(deprecated) API documentation for the `http` package](http://godoc.org/github.com/stretchr/testify/http). + +We recommend you use [httptest](http://golang.org/pkg/net/http/httptest) instead. + +[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package +---------------------------------------------------------------------------------------- + +The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code. + +An example test function that tests a piece of code that relies on an external object `testObj`, can setup expectations (testify) and assert that they indeed happened: + +```go +package yours + +import ( + "testing" + "github.com/stretchr/testify/mock" +) + +/* + Test objects +*/ + +// MyMockedObject is a mocked object that implements an interface +// that describes an object that the code I am testing relies on. +type MyMockedObject struct{ + mock.Mock +} + +// DoSomething is a method on MyMockedObject that implements some interface +// and just records the activity, and returns what the Mock object tells it to. +// +// In the real object, this method would do something useful, but since this +// is a mocked object - we're just going to stub it out. +// +// NOTE: This method is not being tested here, code that uses this object is. +func (m *MyMockedObject) DoSomething(number int) (bool, error) { + + args := m.Called(number) + return args.Bool(0), args.Error(1) + +} + +/* + Actual test functions +*/ + +// TestSomething is an example of how to use our test object to +// make assertions about some target code we are testing. +func TestSomething(t *testing.T) { + + // create an instance of our test object + testObj := new(MyMockedObject) + + // setup expectations + testObj.On("DoSomething", 123).Return(true, nil) + + // call the code we are testing + targetFuncThatDoesSomethingWithObj(testObj) + + // assert that the expectations were met + testObj.AssertExpectations(t) + +} +``` + +For more information on how to write mock code, check out the [API documentation for the `mock` package](http://godoc.org/github.com/stretchr/testify/mock). + +You can use the [mockery tool](http://github.com/vektra/mockery) to autogenerate the mock code against an interface as well, making using mocks much quicker. + +[`suite`](http://godoc.org/github.com/stretchr/testify/suite "API documentation") package +----------------------------------------------------------------------------------------- + +The `suite` package provides functionality that you might be used to from more common object oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal. + +An example suite is shown below: + +```go +// Basic imports +import ( + "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including a T() method which +// returns the current testing context +type ExampleTestSuite struct { + suite.Suite + VariableThatShouldStartAtFive int +} + +// Make sure that VariableThatShouldStartAtFive is set to five +// before each test +func (suite *ExampleTestSuite) SetupTest() { + suite.VariableThatShouldStartAtFive = 5 +} + +// All methods that begin with "Test" are run as tests within a +// suite. +func (suite *ExampleTestSuite) TestExample() { + assert.Equal(suite.T(), suite.VariableThatShouldStartAtFive, 5) +} + +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestExampleTestSuite(t *testing.T) { + suite.Run(t, new(ExampleTestSuite)) +} +``` + +For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go) + +For more information on writing suites, check out the [API documentation for the `suite` package](http://godoc.org/github.com/stretchr/testify/suite). + +`Suite` object has assertion methods: + +```go +// Basic imports +import ( + "testing" + "github.com/stretchr/testify/suite" +) + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including assertion methods. +type ExampleTestSuite struct { + suite.Suite + VariableThatShouldStartAtFive int +} + +// Make sure that VariableThatShouldStartAtFive is set to five +// before each test +func (suite *ExampleTestSuite) SetupTest() { + suite.VariableThatShouldStartAtFive = 5 +} + +// All methods that begin with "Test" are run as tests within a +// suite. +func (suite *ExampleTestSuite) TestExample() { + suite.Equal(suite.VariableThatShouldStartAtFive, 5) +} + +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestExampleTestSuite(t *testing.T) { + suite.Run(t, new(ExampleTestSuite)) +} +``` + +------ + +Installation +============ + +To install Testify, use `go get`: + + * Latest version: go get github.com/stretchr/testify + * Specific version: go get gopkg.in/stretchr/testify.v1 + +This will then make the following packages available to you: + + github.com/stretchr/testify/assert + github.com/stretchr/testify/mock + github.com/stretchr/testify/http + +Import the `testify/assert` package into your code using this template: + +```go +package yours + +import ( + "testing" + "github.com/stretchr/testify/assert" +) + +func TestSomething(t *testing.T) { + + assert.True(t, true, "True is true!") + +} +``` + +------ + +Staying up to date +================== + +To update Testify to the latest version, use `go get -u github.com/stretchr/testify`. + +------ + +Version History +=============== + + * 1.0 - New package versioning strategy adopted. + +------ + +Contributing +============ + +Please feel free to submit issues, fork the repository and send pull requests! + +When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it. + +------ + +Licence +======= +Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell + +Please consider promoting this project if you find it useful. + +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. diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/assertions.go b/vendor/_nuts/github.com/stretchr/testify/assert/assertions.go new file mode 100644 index 0000000..7b5ce72 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/assertions.go @@ -0,0 +1,890 @@ +package assert + +import ( + "bufio" + "bytes" + "fmt" + "math" + "reflect" + "regexp" + "runtime" + "strings" + "time" + "unicode" + "unicode/utf8" +) + +// 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 + } + + return false + +} + +// ObjectsAreEqualValues gets whether two objects are equal, or if their +// values are equal. +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 an array of strings containing the file and line number +// of each stack frame leading from the current test to the assert call that +// failed. +func CallerInfo() []string { + + pc := uintptr(0) + file := "" + line := 0 + ok := false + name := "" + + callers := []string{} + for i := 0; ; i++ { + pc, file, line, ok = runtime.Caller(i) + if !ok { + return nil + } + + 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" { + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) + } + + f := runtime.FuncForPC(pc) + if f == nil { + break + } + name = f.Name() + // Drop the package + segments := strings.Split(name, ".") + name = segments[len(segments)-1] + if isTest(name, "Test") || + isTest(name, "Benchmark") || + isTest(name, "Example") { + break + } + } + + return callers +} + +// Stolen from the `go test` tool. +// isTest tells whether name looks like a test (or benchmark, according to prefix). +// It is a Test (say) if there is a character after Test that is not a lower-case letter. +// We don't want TesticularCancer. +func isTest(name, prefix string) bool { + if !strings.HasPrefix(name, prefix) { + return false + } + if len(name) == len(prefix) { // "Test" is ok + return true + } + rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(rune) +} + +// 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...) + + errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t") + if len(message) > 0 { + t.Errorf("\r%s\r\tError Trace:\t%s\n"+ + "\r\tError:%s\n"+ + "\r\tMessages:\t%s\n\r", + getWhitespaceString(), + errorTrace, + indentMessageLines(failureMessage, 2), + message) + } else { + t.Errorf("\r%s\r\tError Trace:\t%s\n"+ + "\r\tError:%s\n\r", + getWhitespaceString(), + errorTrace, + 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...) + } + + if math.IsNaN(af) { + return Fail(t, fmt.Sprintf("Actual must not be NaN"), msgAndArgs...) + } + + if math.IsNaN(bf) { + return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), 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 +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { + return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + } + + actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) + + for i := 0; i < actualSlice.Len(); i++ { + result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta) + if !result { + return result + } + } + + 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...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares two slices. +func InEpsilonSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { + return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + } + + actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) + + for i := 0; i < actualSlice.Len(); i++ { + result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta) + if !result { + return result + } + } + + return true +} + +/* + 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 + +} diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/assertions_test.go b/vendor/_nuts/github.com/stretchr/testify/assert/assertions_test.go new file mode 100644 index 0000000..d859c77 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/assertions_test.go @@ -0,0 +1,791 @@ +package assert + +import ( + "errors" + "math" + "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") + } + +} + +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 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") + False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail") + False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected 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 TestInDeltaSlice(t *testing.T) { + mockT := new(testing.T) + + True(t, InDeltaSlice(mockT, + []float64{1.001, 0.999}, + []float64{1, 1}, + 0.1), "{1.001, 0.009} is element-wise close to {1, 1} in delta=0.1") + + True(t, InDeltaSlice(mockT, + []float64{1, 2}, + []float64{0, 3}, + 1), "{1, 2} is element-wise close to {0, 3} in delta=1") + + False(t, InDeltaSlice(mockT, + []float64{1, 2}, + []float64{0, 3}, + 0.1), "{1, 2} is not element-wise close to {0, 3} in delta=0.1") + + False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") +} + +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 TestInEpsilonSlice(t *testing.T) { + mockT := new(testing.T) + + True(t, InEpsilonSlice(mockT, + []float64{2.2, 2.0}, + []float64{2.1, 2.1}, + 0.06), "{2.2, 2.0} is element-wise close to {2.1, 2.1} in espilon=0.06") + + False(t, InEpsilonSlice(mockT, + []float64{2.2, 2.0}, + []float64{2.1, 2.1}, + 0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04") + + False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") +} + +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)) + } +} diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/doc.go b/vendor/_nuts/github.com/stretchr/testify/assert/doc.go new file mode 100644 index 0000000..f678106 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/doc.go @@ -0,0 +1,154 @@ +// Package assert provides 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.EqualValues(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.EqualValues(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 diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/errors.go b/vendor/_nuts/github.com/stretchr/testify/assert/errors.go new file mode 100644 index 0000000..ac9dc9d --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/errors.go @@ -0,0 +1,10 @@ +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") diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/_nuts/github.com/stretchr/testify/assert/forward_assertions.go new file mode 100644 index 0000000..d8d3f53 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/forward_assertions.go @@ -0,0 +1,265 @@ +package assert + +import "time" + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified 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...) +} + +// NotEmpty 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...) +} + +// Condition 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...) +} diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/forward_assertions_test.go b/vendor/_nuts/github.com/stretchr/testify/assert/forward_assertions_test.go new file mode 100644 index 0000000..3df3f39 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/forward_assertions_test.go @@ -0,0 +1,511 @@ +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 TestNoErrorWrapper(t *testing.T) { + assert := New(t) + mockAssert := New(new(testing.T)) + + // start with a nil error + var err error + + 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 + + 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)) + } +} diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/http_assertions.go b/vendor/_nuts/github.com/stretchr/testify/assert/http_assertions.go new file mode 100644 index 0000000..1246e58 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/http_assertions.go @@ -0,0 +1,157 @@ +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) +} diff --git a/vendor/_nuts/github.com/stretchr/testify/assert/http_assertions_test.go b/vendor/_nuts/github.com/stretchr/testify/assert/http_assertions_test.go new file mode 100644 index 0000000..684c2d5 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/assert/http_assertions_test.go @@ -0,0 +1,86 @@ +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")) + +} diff --git a/vendor/_nuts/github.com/stretchr/testify/doc.go b/vendor/_nuts/github.com/stretchr/testify/doc.go new file mode 100644 index 0000000..377d5cc --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/doc.go @@ -0,0 +1,22 @@ +// Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend. +// +// testify contains the following packages: +// +// The assert package provides a comprehensive set of assertion functions that tie in to the Go testing system. +// +// The http package contains tools to make it easier to test http activity using the Go testing system. +// +// The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected. +// +// The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces. +package testify + +// blank imports help docs. +import ( + // assert package + _ "github.com/stretchr/testify/assert" + // http package + _ "github.com/stretchr/testify/http" + // mock package + _ "github.com/stretchr/testify/mock" +) diff --git a/vendor/_nuts/github.com/stretchr/testify/http/doc.go b/vendor/_nuts/github.com/stretchr/testify/http/doc.go new file mode 100644 index 0000000..c784014 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/http/doc.go @@ -0,0 +1,2 @@ +// A set of tools to make testing http activity using the Go testing system easier. +package http diff --git a/vendor/_nuts/github.com/stretchr/testify/http/test_response_writer.go b/vendor/_nuts/github.com/stretchr/testify/http/test_response_writer.go new file mode 100644 index 0000000..efd4d66 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/http/test_response_writer.go @@ -0,0 +1,52 @@ +package http + +import ( + "net/http" +) + +// TestResponseWriter is a http.ResponseWriter object that keeps track of all activity +// allowing you to make assertions about how it was used. +// +// DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. +type TestResponseWriter struct { + + // StatusCode is the last int written by the call to WriteHeader(int) + StatusCode int + + // Output is a string containing the written bytes using the Write([]byte) func. + Output string + + // header is the internal storage of the http.Header object + header http.Header +} + +// Header gets the http.Header describing the headers that were set in this response. +func (rw *TestResponseWriter) Header() http.Header { + + if rw.header == nil { + rw.header = make(http.Header) + } + + return rw.header +} + +// Write writes the specified bytes to Output. +func (rw *TestResponseWriter) Write(bytes []byte) (int, error) { + + // assume 200 success if no header has been set + if rw.StatusCode == 0 { + rw.WriteHeader(200) + } + + // add these bytes to the output string + rw.Output = rw.Output + string(bytes) + + // return normal values + return 0, nil + +} + +// WriteHeader stores the HTTP status code in the StatusCode. +func (rw *TestResponseWriter) WriteHeader(i int) { + rw.StatusCode = i +} diff --git a/vendor/_nuts/github.com/stretchr/testify/http/test_round_tripper.go b/vendor/_nuts/github.com/stretchr/testify/http/test_round_tripper.go new file mode 100644 index 0000000..b0ad545 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/http/test_round_tripper.go @@ -0,0 +1,15 @@ +package http + +import ( + "github.com/stretchr/testify/mock" + "net/http" +) + +type TestRoundTripper struct { + mock.Mock +} + +func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + args := t.Called(req) + return args.Get(0).(*http.Response), args.Error(1) +} diff --git a/vendor/_nuts/github.com/stretchr/testify/mock/doc.go b/vendor/_nuts/github.com/stretchr/testify/mock/doc.go new file mode 100644 index 0000000..dd38507 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/mock/doc.go @@ -0,0 +1,43 @@ +// 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 diff --git a/vendor/_nuts/github.com/stretchr/testify/mock/mock.go b/vendor/_nuts/github.com/stretchr/testify/mock/mock.go new file mode 100644 index 0000000..007643f --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/mock/mock.go @@ -0,0 +1,594 @@ +package mock + +import ( + "fmt" + "reflect" + "runtime" + "strings" + "sync" + "time" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +// 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 + + // Holds a channel that will be used to block the Return until it either + // recieves a message or is closed. nil means it returns immediately. + WaitFor <-chan time.Time + + // Holds a handler used to manipulate arguments content that are passed by + // reference. It's useful when mocking methods such as unmarshalers or + // decoders. + Run func(Arguments) +} + +// 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 + + for _, arg := range arguments { + if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { + panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) + } + } + + 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.mutex.Lock() + defer m.mutex.Unlock() + + m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil}) + 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.mutex.Lock() + m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1 + m.mutex.Unlock() +} + +// 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.mutex.Lock() + m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2 + m.mutex.Unlock() +} + +// 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.mutex.Lock() + m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i + m.mutex.Unlock() +} + +// WaitUntil sets the channel that will block the mock's return until its closed +// or a message is received. +// +// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) +func (m *Mock) WaitUntil(w <-chan time.Time) *Mock { + m.mutex.Lock() + m.ExpectedCalls[len(m.ExpectedCalls)-1].WaitFor = w + m.mutex.Unlock() + return m +} + +// After sets how long to block until the call returns +// +// Mock.On("MyMethod", arg1, arg2).After(time.Second) +func (m *Mock) After(d time.Duration) *Mock { + return m.WaitUntil(time.After(d)) +} + +// Run sets a handler to be called before returning. It can be used when +// mocking a method such as unmarshalers that takes a pointer to a struct and +// sets properties in such struct +// +// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(function(args Arguments) { +// arg := args.Get(0).(*map[string]interface{}) +// arg["foo"] = "bar" +// }) +func (m *Mock) Run(fn func(Arguments)) *Mock { + m.mutex.Lock() + m.ExpectedCalls[len(m.ExpectedCalls)-1].Run = fn + m.mutex.Unlock() + return m +} + +/* + 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) +// If Call.WaitFor is set, blocks until the channel is closed or receives a message. +func (m *Mock) Called(arguments ...interface{}) Arguments { + // 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...) + + if 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())) + } + } else { + m.mutex.Lock() + switch { + case call.Repeatability == 1: + call.Repeatability = -1 + m.ExpectedCalls[found] = *call + case call.Repeatability > 1: + call.Repeatability -= 1 + m.ExpectedCalls[found] = *call + } + m.mutex.Unlock() + } + + // add the call + m.mutex.Lock() + m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil}) + m.mutex.Unlock() + + // block if specified + if call.WaitFor != nil { + <-call.WaitFor + } + + if call.Run != nil { + call.Run(arguments) + } + + 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 + expectedCalls := m.expectedCalls() + for _, expectedCall := range 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(expectedCalls)-failedExpectations, len(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("%v", 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("%v", 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 +} + +func (m *Mock) expectedCalls() []Call { + m.mutex.Lock() + defer m.mutex.Unlock() + return append([]Call{}, m.ExpectedCalls...) +} + +func (m *Mock) calls() []Call { + m.mutex.Lock() + defer m.mutex.Unlock() + return append([]Call{}, m.Calls...) +} + +/* + 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 +} diff --git a/vendor/_nuts/github.com/stretchr/testify/mock/mock_test.go b/vendor/_nuts/github.com/stretchr/testify/mock/mock_test.go new file mode 100644 index 0000000..b1ee954 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/mock/mock_test.go @@ -0,0 +1,908 @@ +package mock + +import ( + "errors" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +/* + 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 { + ran bool +} + +func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error { + args := i.Called(et) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error { + args := i.Called(fn) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodVariadic(a ...int) error { + args := i.Called(a) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...interface{}) error { + args := i.Called(a) + return args.Error(0) +} + +type ExampleFuncType func(string) error + +func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { + args := i.Called(fn) + 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_On_WithFuncArg(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Equal(t, mockedService.On("TheExampleMethodFunc", AnythingOfType("func(string) error")).Return(nil), &mockedService.Mock) + assert.Equal(t, "TheExampleMethodFunc", mockedService.onMethodName) + assert.Equal(t, AnythingOfType("func(string) error"), mockedService.onMethodArguments[0]) + + fn := func(string) error { return nil } + mockedService.TheExampleMethodFunc(fn) + +} + +func Test_Mock_On_WithVariadicFunc(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Equal(t, mockedService.On("TheExampleMethodVariadic", []int{1, 2, 3}).Return(nil), &mockedService.Mock) + assert.Equal(t, "TheExampleMethodVariadic", mockedService.onMethodName) + assert.Equal(t, []int{1, 2, 3}, mockedService.onMethodArguments[0]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodVariadic(1, 2, 3) + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodVariadic(1, 2) + }) + +} + +func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Equal(t, mockedService.On("TheExampleMethodVariadicInterface", []interface{}{1, 2, 3}).Return(nil), &mockedService.Mock) + assert.Equal(t, "TheExampleMethodVariadicInterface", mockedService.onMethodName) + assert.Equal(t, []interface{}{1, 2, 3}, mockedService.onMethodArguments[0]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodVariadicInterface(1, 2, 3) + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodVariadicInterface(1, 2) + }) + +} + +func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + var expected []interface{} + assert.Equal(t, mockedService.On("TheExampleMethodVariadicInterface", expected).Return(nil), &mockedService.Mock) + assert.Equal(t, "TheExampleMethodVariadicInterface", mockedService.onMethodName) + assert.Equal(t, expected, mockedService.onMethodArguments[0]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodVariadicInterface() + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodVariadicInterface(1, 2) + }) + +} + +func Test_Mock_On_WithFuncPanics(t *testing.T) { + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Panics(t, func() { + mockedService.On("TheExampleMethodFunc", func(string) error { return nil }) + }) +} + +func Test_Mock_On_WithFuncTypeArg(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Equal(t, mockedService.On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).Return(nil), &mockedService.Mock) + assert.Equal(t, "TheExampleMethodFuncType", mockedService.onMethodName) + assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), mockedService.onMethodArguments[0]) + + fn := func(string) error { return nil } + mockedService.TheExampleMethodFuncType(fn) + +} + +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) + assert.Nil(t, call.WaitFor) + + } + +} + +func Test_Mock_Return_WaitUntil(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + ch := time.After(time.Second) + + assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).WaitUntil(ch), &mockedService.Mock) + + // ensure the call was created + if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) { + call := mockedService.Mock.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) + assert.Equal(t, ch, call.WaitFor) + + } + +} + +func Test_Mock_Return_After(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Equal(t, mockedService.Mock.On("TheExampleMethod", "A", "B", true).Return(1, "two", true).After(time.Second), &mockedService.Mock) + + // ensure the call was created + if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) { + call := mockedService.Mock.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) + assert.NotEqual(t, nil, call.WaitFor) + + } + +} + +func Test_Mock_Return_Run(t *testing.T) { + + // make a test impl object + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + assert.Equal(t, mockedService.Mock.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Run(func(args Arguments) { + arg := args.Get(0).(*ExampleType) + arg.ran = true + }), &mockedService.Mock) + + // ensure the call was created + if assert.Equal(t, 1, len(mockedService.Mock.ExpectedCalls)) { + call := mockedService.Mock.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod3", call.Method) + assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0]) + assert.Equal(t, nil, call.ReturnArguments[0]) + assert.Equal(t, 0, call.Repeatability) + assert.NotEqual(t, nil, call.WaitFor) + assert.NotNil(t, call.Run) + + } + + et := ExampleType{} + assert.Equal(t, false, et.ran) + mockedService.TheExampleMethod3(&et) + assert.Equal(t, true, et.ran) + +} + +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) + assert.Nil(t, call.WaitFor) + + } + +} + +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) + assert.Nil(t, call.WaitFor) + + } + +} + +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) + assert.Nil(t, call.WaitFor) + + } + +} + +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 asyncCall(m *Mock, ch chan Arguments) { + ch <- m.Called(1, 2, 3) +} + +func Test_Mock_Called_blocks(t *testing.T) { + + var mockedService *TestExampleImplementation = new(TestExampleImplementation) + + mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond) + + ch := make(chan Arguments) + + go asyncCall(&mockedService.Mock, ch) + + select { + case <-ch: + t.Fatal("should have waited") + case <-time.After(1 * time.Millisecond): + } + + returnArguments := <-ch + + if assert.Equal(t, 1, len(mockedService.Mock.Calls)) { + assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method) + assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0]) + assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1]) + assert.Equal(t, 3, mockedService.Mock.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)) + +} diff --git a/vendor/_nuts/github.com/stretchr/testify/package_test.go b/vendor/_nuts/github.com/stretchr/testify/package_test.go new file mode 100644 index 0000000..7ac5d6d --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/package_test.go @@ -0,0 +1,12 @@ +package testify + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestImports(t *testing.T) { + if assert.Equal(t, 1, 1) != true { + t.Error("Something is wrong.") + } +} diff --git a/vendor/_nuts/github.com/stretchr/testify/require/doc.go b/vendor/_nuts/github.com/stretchr/testify/require/doc.go new file mode 100644 index 0000000..7b38438 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/require/doc.go @@ -0,0 +1,77 @@ +// Alternative testing tools which stop test execution if test failed. +// +// Example Usage +// +// The following is a complete example using require in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// require.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// Assertions +// +// The `require` package have same global functions as in the `assert` package, +// but instead of returning a boolean result they call `t.FailNow()`. +// +// 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: +// +// require.Equal(t, expected, actual [, message [, format-args]) +// +// require.NotEqual(t, notExpected, actual [, message [, format-args]]) +// +// require.True(t, actualBool [, message [, format-args]]) +// +// require.False(t, actualBool [, message [, format-args]]) +// +// require.Nil(t, actualObject [, message [, format-args]]) +// +// require.NotNil(t, actualObject [, message [, format-args]]) +// +// require.Empty(t, actualObject [, message [, format-args]]) +// +// require.NotEmpty(t, actualObject [, message [, format-args]]) +// +// require.Error(t, errorObject [, message [, format-args]]) +// +// require.NoError(t, errorObject [, message [, format-args]]) +// +// require.EqualError(t, theError, errString [, message [, format-args]]) +// +// require.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]]) +// +// require.IsType(t, expectedObject, actualObject [, message [, format-args]]) +// +// require.Contains(t, string, substring [, message [, format-args]]) +// +// require.NotContains(t, string, substring [, message [, format-args]]) +// +// require.Panics(t, func(){ +// +// // call code that should panic +// +// } [, message [, format-args]]) +// +// require.NotPanics(t, func(){ +// +// // call code that should not panic +// +// } [, message [, format-args]]) +// +// require.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]]) +// +// require.InDelta(t, numA, numB, delta, [, message [, format-args]]) +// +// require.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]]) +package require diff --git a/vendor/_nuts/github.com/stretchr/testify/require/forward_requirements.go b/vendor/_nuts/github.com/stretchr/testify/require/forward_requirements.go new file mode 100644 index 0000000..069d419 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/require/forward_requirements.go @@ -0,0 +1,211 @@ +package require + +import ( + "time" + + "github.com/stretchr/testify/assert" +) + +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{}) { + FailNow(a.t, failureMessage, msgAndArgs...) +} + +// Implements asserts that an object is implemented by the specified interface. + +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + 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{}) { + IsType(a.t, expectedType, object, msgAndArgs...) +} + +// Equal asserts that two objects are equal. +// +// require.Equal(123, 123, "123 and 123 should be equal") +func (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) { + Equal(a.t, expected, actual, msgAndArgs...) +} + +// Exactly asserts that two objects are equal is value and type. +// +// require.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal") +func (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) { + Exactly(a.t, expected, actual, msgAndArgs...) +} + +// NotNil asserts that the specified object is not nil. +// +// require.NotNil(err, "err should be something") +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { + NotNil(a.t, object, msgAndArgs...) +} + +// Nil asserts that the specified object is nil. +// +// require.Nil(err, "err should be nothing") +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { + Nil(a.t, object, msgAndArgs...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or a +// slice with len == 0. +// +// require.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { + 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 require.NotEmpty(obj) { +// require.Equal("two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { + 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. +// +// require.Len(mySlice, 3, "The size of slice is not 3") +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { + Len(a.t, object, length, msgAndArgs...) +} + +// True asserts that the specified value is true. +// +// require.True(myBool, "myBool should be true") +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { + True(a.t, value, msgAndArgs...) +} + +// False asserts that the specified value is true. +// +// require.False(myBool, "myBool should be false") +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { + False(a.t, value, msgAndArgs...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// require.NotEqual(obj1, obj2, "two objects shouldn't be equal") +func (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) { + NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// Contains asserts that the specified string contains the specified substring. +// +// require.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") +func (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) { + Contains(a.t, s, contains, msgAndArgs...) +} + +// NotContains asserts that the specified string does NOT contain the specified substring. +// +// require.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") +func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) { + NotContains(a.t, s, contains, msgAndArgs...) +} + +// Uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { + Condition(a.t, comp, msgAndArgs...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// require.Panics(func(){ +// GoCrazy() +// }, "Calling GoCrazy() should panic") +func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + Panics(a.t, f, msgAndArgs...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// require.NotPanics(func(){ +// RemainCalm() +// }, "Calling RemainCalm() should NOT panic") +func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + NotPanics(a.t, f, msgAndArgs...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// require.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") +func (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// require.InDelta(t, math.Pi, (22 / 7.0), 0.01) +func (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) { + InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if require.NoError(err) { +// require.Equal(actualObj, expectedObj) +// } +func (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) { + NoError(a.t, theError, msgAndArgs...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if require.Error(err, "An error was expected") { +// require.Equal(err, expectedError) +// } +func (a *Assertions) Error(theError error, msgAndArgs ...interface{}) { + 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 require.Error(err, "An error was expected") { +// require.Equal(err, expectedError) +// } +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { + EqualError(a.t, theError, errString, msgAndArgs...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// require.Regexp(t, regexp.MustCompile("start"), "it's starting") +// require.Regexp(t, "start...$", "it's not starting") +func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + Regexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// require.NotRegexp(t, "^start", "it's not starting") +func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + NotRegexp(a.t, rx, str, msgAndArgs...) +} diff --git a/vendor/_nuts/github.com/stretchr/testify/require/forward_requirements_test.go b/vendor/_nuts/github.com/stretchr/testify/require/forward_requirements_test.go new file mode 100644 index 0000000..02be291 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/require/forward_requirements_test.go @@ -0,0 +1,260 @@ +package require + +import ( + "errors" + "testing" + "time" +) + +func TestImplementsWrapper(t *testing.T) { + require := New(t) + + require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestIsTypeWrapper(t *testing.T) { + require := New(t) + require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestEqualWrapper(t *testing.T) { + require := New(t) + require.Equal(1, 1) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Equal(1, 2) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotEqualWrapper(t *testing.T) { + require := New(t) + require.NotEqual(1, 2) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.NotEqual(2, 2) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestExactlyWrapper(t *testing.T) { + require := New(t) + + a := float32(1) + b := float32(1) + c := float64(1) + + require.Exactly(a, b) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Exactly(a, c) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotNilWrapper(t *testing.T) { + require := New(t) + require.NotNil(t, new(AssertionTesterConformingObject)) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.NotNil(nil) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNilWrapper(t *testing.T) { + require := New(t) + require.Nil(nil) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Nil(new(AssertionTesterConformingObject)) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestTrueWrapper(t *testing.T) { + require := New(t) + require.True(true) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.True(false) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestFalseWrapper(t *testing.T) { + require := New(t) + require.False(false) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.False(true) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestContainsWrapper(t *testing.T) { + require := New(t) + require.Contains("Hello World", "Hello") + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Contains("Hello World", "Salut") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotContainsWrapper(t *testing.T) { + require := New(t) + require.NotContains("Hello World", "Hello!") + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.NotContains("Hello World", "Hello") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestPanicsWrapper(t *testing.T) { + require := New(t) + require.Panics(func() { + panic("Panic!") + }) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Panics(func() {}) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotPanicsWrapper(t *testing.T) { + require := New(t) + require.NotPanics(func() {}) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.NotPanics(func() { + panic("Panic!") + }) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNoErrorWrapper(t *testing.T) { + require := New(t) + require.NoError(nil) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.NoError(errors.New("some error")) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestErrorWrapper(t *testing.T) { + require := New(t) + require.Error(errors.New("some error")) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Error(nil) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestEqualErrorWrapper(t *testing.T) { + require := New(t) + require.EqualError(errors.New("some error"), "some error") + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.EqualError(errors.New("some error"), "Not some error") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestEmptyWrapper(t *testing.T) { + require := New(t) + require.Empty("") + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.Empty("x") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotEmptyWrapper(t *testing.T) { + require := New(t) + require.NotEmpty("x") + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.NotEmpty("") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestWithinDurationWrapper(t *testing.T) { + require := New(t) + a := time.Now() + b := a.Add(10 * time.Second) + + require.WithinDuration(a, b, 15*time.Second) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.WithinDuration(a, b, 5*time.Second) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestInDeltaWrapper(t *testing.T) { + require := New(t) + require.InDelta(1.001, 1, 0.01) + + mockT := new(MockT) + mockRequire := New(mockT) + mockRequire.InDelta(1, 2, 0.5) + if !mockT.Failed { + t.Error("Check should fail") + } +} diff --git a/vendor/_nuts/github.com/stretchr/testify/require/requirements.go b/vendor/_nuts/github.com/stretchr/testify/require/requirements.go new file mode 100644 index 0000000..122a3f3 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/require/requirements.go @@ -0,0 +1,271 @@ +package require + +import ( + "time" + + "github.com/stretchr/testify/assert" +) + +type TestingT interface { + Errorf(format string, args ...interface{}) + FailNow() +} + +// Fail reports a failure through +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + assert.Fail(t, failureMessage, msgAndArgs...) + t.FailNow() +} + +// Implements asserts that an object is implemented by the specified interface. +// +// require.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject") +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if !assert.Implements(t, interfaceObject, object, msgAndArgs...) { + t.FailNow() + } +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if !assert.IsType(t, expectedType, object, msgAndArgs...) { + t.FailNow() + } +} + +// Equal asserts that two objects are equal. +// +// require.Equal(t, 123, 123, "123 and 123 should be equal") +func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) { + if !assert.Equal(t, expected, actual, msgAndArgs...) { + t.FailNow() + } +} + +// EqualValues asserts that two objects are equal or convertable to each other. +// +// require.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal") +func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) { + if !assert.EqualValues(t, expected, actual, msgAndArgs...) { + t.FailNow() + } +} + +// Exactly asserts that two objects are equal is value and type. +// +// require.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal") +func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) { + if !assert.Exactly(t, expected, actual, msgAndArgs...) { + t.FailNow() + } +} + +// NotNil asserts that the specified object is not nil. +// +// require.NotNil(t, err, "err should be something") +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if !assert.NotNil(t, object, msgAndArgs...) { + t.FailNow() + } +} + +// Nil asserts that the specified object is nil. +// +// require.Nil(t, err, "err should be nothing") +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if !assert.Nil(t, object, msgAndArgs...) { + t.FailNow() + } +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// require.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if !assert.Empty(t, object, msgAndArgs...) { + t.FailNow() + } +} + +// 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. +// +// require.NotEmpty(t, obj) +// require.Equal(t, "one", obj[0]) +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if !assert.NotEmpty(t, object, msgAndArgs...) { + t.FailNow() + } +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// require.Len(t, mySlice, 3, "The size of slice is not 3") +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { + if !assert.Len(t, object, length, msgAndArgs...) { + t.FailNow() + } +} + +// True asserts that the specified value is true. +// +// require.True(t, myBool, "myBool should be true") +func True(t TestingT, value bool, msgAndArgs ...interface{}) { + if !assert.True(t, value, msgAndArgs...) { + t.FailNow() + } +} + +// False asserts that the specified value is true. +// +// require.False(t, myBool, "myBool should be false") +func False(t TestingT, value bool, msgAndArgs ...interface{}) { + if !assert.False(t, value, msgAndArgs...) { + t.FailNow() + } +} + +// NotEqual asserts that the specified values are NOT equal. +// +// require.NotEqual(t, obj1, obj2, "two objects shouldn't be equal") +func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) { + if !assert.NotEqual(t, expected, actual, msgAndArgs...) { + t.FailNow() + } +} + +// Contains asserts that the specified string contains the specified substring. +// +// require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'") +func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) { + if !assert.Contains(t, s, contains, msgAndArgs...) { + t.FailNow() + } +} + +// NotContains asserts that the specified string does NOT contain the specified substring. +// +// require.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") +func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) { + if !assert.NotContains(t, s, contains, msgAndArgs...) { + t.FailNow() + } +} + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { + if !assert.Condition(t, comp, msgAndArgs...) { + t.FailNow() + } +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// require.Panics(t, func(){ +// GoCrazy() +// }, "Calling GoCrazy() should panic") +func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if !assert.Panics(t, f, msgAndArgs...) { + t.FailNow() + } +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// require.NotPanics(t, func(){ +// RemainCalm() +// }, "Calling RemainCalm() should NOT panic") +func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if !assert.NotPanics(t, f, msgAndArgs...) { + t.FailNow() + } +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") +func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { + t.FailNow() + } +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// require.InDelta(t, math.Pi, (22 / 7.0), 0.01) +func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) { + t.FailNow() + } +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { + t.FailNow() + } +} + +// Regexp asserts that a specified regexp matches a string. +// +// require.Regexp(t, regexp.MustCompile("start"), "it's starting") +// require.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if !assert.Regexp(t, rx, str, msgAndArgs...) { + t.FailNow() + } +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// require.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if !assert.NotRegexp(t, rx, str, msgAndArgs...) { + t.FailNow() + } +} + +/* + Errors +*/ + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// require.NoError(t, err) +// require.Equal(t, actualObj, expectedObj) +// +// Returns whether the assertion was successful (true) or not (false). +func NoError(t TestingT, err error, msgAndArgs ...interface{}) { + if !assert.NoError(t, err, msgAndArgs...) { + t.FailNow() + } +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// require.Error(t, err, "An error was expected") +// require.Equal(t, err, expectedError) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) { + if !assert.Error(t, err, msgAndArgs...) { + t.FailNow() + } +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// require.Error(t, err, "An error was expected") +// require.Equal(t, err, expectedError) +// } +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { + if !assert.EqualError(t, theError, errString, msgAndArgs...) { + t.FailNow() + } +} diff --git a/vendor/_nuts/github.com/stretchr/testify/require/requirements_test.go b/vendor/_nuts/github.com/stretchr/testify/require/requirements_test.go new file mode 100644 index 0000000..9131b2f --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/require/requirements_test.go @@ -0,0 +1,266 @@ +package require + +import ( + "errors" + "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 { +} + +type MockT struct { + Failed bool +} + +func (t *MockT) FailNow() { + t.Failed = true +} + +func (t *MockT) Errorf(format string, args ...interface{}) { + _, _ = format, args +} + +func TestImplements(t *testing.T) { + + Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) + + mockT := new(MockT) + Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestIsType(t *testing.T) { + + IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) + + mockT := new(MockT) + IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestEqual(t *testing.T) { + + Equal(t, 1, 1) + + mockT := new(MockT) + Equal(mockT, 1, 2) + if !mockT.Failed { + t.Error("Check should fail") + } + +} + +func TestNotEqual(t *testing.T) { + + NotEqual(t, 1, 2) + mockT := new(MockT) + NotEqual(mockT, 2, 2) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestExactly(t *testing.T) { + + a := float32(1) + b := float32(1) + c := float64(1) + + Exactly(t, a, b) + + mockT := new(MockT) + Exactly(mockT, a, c) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotNil(t *testing.T) { + + NotNil(t, new(AssertionTesterConformingObject)) + + mockT := new(MockT) + NotNil(mockT, nil) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNil(t *testing.T) { + + Nil(t, nil) + + mockT := new(MockT) + Nil(mockT, new(AssertionTesterConformingObject)) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestTrue(t *testing.T) { + + True(t, true) + + mockT := new(MockT) + True(mockT, false) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestFalse(t *testing.T) { + + False(t, false) + + mockT := new(MockT) + False(mockT, true) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestContains(t *testing.T) { + + Contains(t, "Hello World", "Hello") + + mockT := new(MockT) + Contains(mockT, "Hello World", "Salut") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotContains(t *testing.T) { + + NotContains(t, "Hello World", "Hello!") + + mockT := new(MockT) + NotContains(mockT, "Hello World", "Hello") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestPanics(t *testing.T) { + + Panics(t, func() { + panic("Panic!") + }) + + mockT := new(MockT) + Panics(mockT, func() {}) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotPanics(t *testing.T) { + + NotPanics(t, func() {}) + + mockT := new(MockT) + NotPanics(mockT, func() { + panic("Panic!") + }) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNoError(t *testing.T) { + + NoError(t, nil) + + mockT := new(MockT) + NoError(mockT, errors.New("some error")) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestError(t *testing.T) { + + Error(t, errors.New("some error")) + + mockT := new(MockT) + Error(mockT, nil) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestEqualError(t *testing.T) { + + EqualError(t, errors.New("some error"), "some error") + + mockT := new(MockT) + EqualError(mockT, errors.New("some error"), "Not some error") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestEmpty(t *testing.T) { + + Empty(t, "") + + mockT := new(MockT) + Empty(mockT, "x") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestNotEmpty(t *testing.T) { + + NotEmpty(t, "x") + + mockT := new(MockT) + NotEmpty(mockT, "") + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestWithinDuration(t *testing.T) { + + a := time.Now() + b := a.Add(10 * time.Second) + + WithinDuration(t, a, b, 15*time.Second) + + mockT := new(MockT) + WithinDuration(mockT, a, b, 5*time.Second) + if !mockT.Failed { + t.Error("Check should fail") + } +} + +func TestInDelta(t *testing.T) { + + InDelta(t, 1.001, 1, 0.01) + + mockT := new(MockT) + InDelta(mockT, 1, 2, 0.5) + if !mockT.Failed { + t.Error("Check should fail") + } +} diff --git a/vendor/_nuts/github.com/stretchr/testify/suite/doc.go b/vendor/_nuts/github.com/stretchr/testify/suite/doc.go new file mode 100644 index 0000000..3731eaa --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/suite/doc.go @@ -0,0 +1,65 @@ +// The suite package contains logic for creating testing suite structs +// and running the methods on those structs as tests. The most useful +// piece of this package is that you can create setup/teardown methods +// on your testing suites, which will run before/after the whole suite +// or individual tests (depending on which interface(s) you +// implement). +// +// A testing suite is usually built by first extending the built-in +// suite functionality from suite.Suite in testify. Alternatively, +// you could reproduce that logic on your own if you wanted (you +// just need to implement the TestingSuite interface from +// suite/interfaces.go). +// +// After that, you can implement any of the interfaces in +// suite/interfaces.go to add setup/teardown functionality to your +// suite, and add any methods that start with "Test" to add tests. +// Methods that do not match any suite interfaces and do not begin +// with "Test" will not be run by testify, and can safely be used as +// helper methods. +// +// Once you've built your testing suite, you need to run the suite +// (using suite.Run from testify) inside any function that matches the +// identity that "go test" is already looking for (i.e. +// func(*testing.T)). +// +// Regular expression to select test suites specified command-line +// argument "-run". Regular expression to select the methods +// of test suites specified command-line argument "-m". +// Suite object has assertion methods. +// +// A crude example: +// // Basic imports +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/suite" +// ) +// +// // Define the suite, and absorb the built-in basic suite +// // functionality from testify - including a T() method which +// // returns the current testing context +// type ExampleTestSuite struct { +// suite.Suite +// VariableThatShouldStartAtFive int +// } +// +// // Make sure that VariableThatShouldStartAtFive is set to five +// // before each test +// func (suite *ExampleTestSuite) SetupTest() { +// suite.VariableThatShouldStartAtFive = 5 +// } +// +// // All methods that begin with "Test" are run as tests within a +// // suite. +// func (suite *ExampleTestSuite) TestExample() { +// assert.Equal(suite.T(), suite.VariableThatShouldStartAtFive, 5) +// suite.Equal(suite.VariableThatShouldStartAtFive, 5) +// } +// +// // In order for 'go test' to run this suite, we need to create +// // a normal test function and pass our suite to suite.Run +// func TestExampleTestSuite(t *testing.T) { +// suite.Run(t, new(ExampleTestSuite)) +// } +package suite diff --git a/vendor/_nuts/github.com/stretchr/testify/suite/interfaces.go b/vendor/_nuts/github.com/stretchr/testify/suite/interfaces.go new file mode 100644 index 0000000..2096947 --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/suite/interfaces.go @@ -0,0 +1,34 @@ +package suite + +import "testing" + +// TestingSuite can store and return the current *testing.T context +// generated by 'go test'. +type TestingSuite interface { + T() *testing.T + SetT(*testing.T) +} + +// SetupAllSuite has a SetupSuite method, which will run before the +// tests in the suite are run. +type SetupAllSuite interface { + SetupSuite() +} + +// SetupTestSuite has a SetupTest method, which will run before each +// test in the suite. +type SetupTestSuite interface { + SetupTest() +} + +// TearDownAllSuite has a TearDownSuite method, which will run after +// all the tests in the suite have been run. +type TearDownAllSuite interface { + TearDownSuite() +} + +// TearDownTestSuite has a TearDownTest method, which will run after +// each test in the suite. +type TearDownTestSuite interface { + TearDownTest() +} diff --git a/vendor/_nuts/github.com/stretchr/testify/suite/suite.go b/vendor/_nuts/github.com/stretchr/testify/suite/suite.go new file mode 100644 index 0000000..ac6744d --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/suite/suite.go @@ -0,0 +1,114 @@ +package suite + +import ( + "flag" + "fmt" + "os" + "reflect" + "regexp" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var matchMethod = flag.String("m", "", "regular expression to select tests of the suite to run") + +// Suite is a basic testing suite with methods for storing and +// retrieving the current *testing.T context. +type Suite struct { + *assert.Assertions + require *require.Assertions + t *testing.T +} + +// T retrieves the current *testing.T context. +func (suite *Suite) T() *testing.T { + return suite.t +} + +// SetT sets the current *testing.T context. +func (suite *Suite) SetT(t *testing.T) { + suite.t = t + suite.Assertions = assert.New(t) +} + +// Require returns a require context for suite. +func (suite *Suite) Require() *require.Assertions { + if suite.require == nil { + suite.require = require.New(suite.T()) + } + return suite.require +} + +// Assert returns an assert context for suite. Normally, you can call +// `suite.NoError(expected, actual)`, but for situations where the embedded +// methods are overridden (for example, you might want to override +// assert.Assertions with require.Assertions), this method is provided so you +// can call `suite.Assert().NoError()`. +func (suite *Suite) Assert() *assert.Assertions { + if suite.Assertions == nil { + suite.Assertions = assert.New(suite.T()) + } + return suite.Assertions +} + +// Run takes a testing suite and runs all of the tests attached +// to it. +func Run(t *testing.T, suite TestingSuite) { + suite.SetT(t) + + if setupAllSuite, ok := suite.(SetupAllSuite); ok { + setupAllSuite.SetupSuite() + } + defer func() { + if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { + tearDownAllSuite.TearDownSuite() + } + }() + + methodFinder := reflect.TypeOf(suite) + tests := []testing.InternalTest{} + for index := 0; index < methodFinder.NumMethod(); index++ { + method := methodFinder.Method(index) + ok, err := methodFilter(method.Name) + if err != nil { + fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) + os.Exit(1) + } + if ok { + test := testing.InternalTest{ + Name: method.Name, + F: func(t *testing.T) { + parentT := suite.T() + suite.SetT(t) + if setupTestSuite, ok := suite.(SetupTestSuite); ok { + setupTestSuite.SetupTest() + } + defer func() { + if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { + tearDownTestSuite.TearDownTest() + } + suite.SetT(parentT) + }() + method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) + }, + } + tests = append(tests, test) + } + } + + if !testing.RunTests(func(_, _ string) (bool, error) { return true, nil }, + tests) { + t.Fail() + } +} + +// Filtering method according to set regular expression +// specified command-line argument -m +func methodFilter(name string) (bool, error) { + if ok, _ := regexp.MatchString("^Test", name); !ok { + return false, nil + } + return regexp.MatchString(*matchMethod, name) +} diff --git a/vendor/_nuts/github.com/stretchr/testify/suite/suite_test.go b/vendor/_nuts/github.com/stretchr/testify/suite/suite_test.go new file mode 100644 index 0000000..6a1bb2c --- /dev/null +++ b/vendor/_nuts/github.com/stretchr/testify/suite/suite_test.go @@ -0,0 +1,208 @@ +package suite + +import ( + "errors" + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +// This suite is intended to store values to make sure that only +// testing-suite-related methods are run. It's also a fully +// functional example of a testing suite, using setup/teardown methods +// and a helper method that is ignored by testify. To make this look +// more like a real world example, all tests in the suite perform some +// type of assertion. +type SuiteTester struct { + // Include our basic suite logic. + Suite + + // Keep counts of how many times each method is run. + SetupSuiteRunCount int + TearDownSuiteRunCount int + SetupTestRunCount int + TearDownTestRunCount int + TestOneRunCount int + TestTwoRunCount int + NonTestMethodRunCount int +} + +type SuiteSkipTester struct { + // Include our basic suite logic. + Suite + + // Keep counts of how many times each method is run. + SetupSuiteRunCount int + TearDownSuiteRunCount int +} + +// The SetupSuite method will be run by testify once, at the very +// start of the testing suite, before any tests are run. +func (suite *SuiteTester) SetupSuite() { + suite.SetupSuiteRunCount++ +} + +func (suite *SuiteSkipTester) SetupSuite() { + suite.SetupSuiteRunCount++ + suite.T().Skip() +} + +// The TearDownSuite method will be run by testify once, at the very +// end of the testing suite, after all tests have been run. +func (suite *SuiteTester) TearDownSuite() { + suite.TearDownSuiteRunCount++ +} + +func (suite *SuiteSkipTester) TearDownSuite() { + suite.TearDownSuiteRunCount++ +} + +// The SetupTest method will be run before every test in the suite. +func (suite *SuiteTester) SetupTest() { + suite.SetupTestRunCount++ +} + +// The TearDownTest method will be run after every test in the suite. +func (suite *SuiteTester) TearDownTest() { + suite.TearDownTestRunCount++ +} + +// Every method in a testing suite that begins with "Test" will be run +// as a test. TestOne is an example of a test. For the purposes of +// this example, we've included assertions in the tests, since most +// tests will issue assertions. +func (suite *SuiteTester) TestOne() { + beforeCount := suite.TestOneRunCount + suite.TestOneRunCount++ + assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1) + suite.Equal(suite.TestOneRunCount, beforeCount+1) +} + +// TestTwo is another example of a test. +func (suite *SuiteTester) TestTwo() { + beforeCount := suite.TestTwoRunCount + suite.TestTwoRunCount++ + assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount) + suite.NotEqual(suite.TestTwoRunCount, beforeCount) +} + +func (suite *SuiteTester) TestSkip() { + suite.T().Skip() +} + +// NonTestMethod does not begin with "Test", so it will not be run by +// testify as a test in the suite. This is useful for creating helper +// methods for your tests. +func (suite *SuiteTester) NonTestMethod() { + suite.NonTestMethodRunCount++ +} + +// TestRunSuite will be run by the 'go test' command, so within it, we +// can run our suite using the Run(*testing.T, TestingSuite) function. +func TestRunSuite(t *testing.T) { + suiteTester := new(SuiteTester) + Run(t, suiteTester) + + // Normally, the test would end here. The following are simply + // some assertions to ensure that the Run function is working as + // intended - they are not part of the example. + + // The suite was only run once, so the SetupSuite and TearDownSuite + // methods should have each been run only once. + assert.Equal(t, suiteTester.SetupSuiteRunCount, 1) + assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1) + + // There are three test methods (TestOne, TestTwo, and TestSkip), so + // the SetupTest and TearDownTest methods (which should be run once for + // each test) should have been run three times. + assert.Equal(t, suiteTester.SetupTestRunCount, 3) + assert.Equal(t, suiteTester.TearDownTestRunCount, 3) + + // Each test should have been run once. + assert.Equal(t, suiteTester.TestOneRunCount, 1) + assert.Equal(t, suiteTester.TestTwoRunCount, 1) + + // Methods that don't match the test method identifier shouldn't + // have been run at all. + assert.Equal(t, suiteTester.NonTestMethodRunCount, 0) + + suiteSkipTester := new(SuiteSkipTester) + Run(t, suiteSkipTester) + + // The suite was only run once, so the SetupSuite and TearDownSuite + // methods should have each been run only once, even though SetupSuite + // called Skip() + assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1) + assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1) + +} + +func TestSuiteGetters(t *testing.T) { + suite := new(SuiteTester) + suite.SetT(t) + assert.NotNil(t, suite.Assert()) + assert.Equal(t, suite.Assertions, suite.Assert()) + assert.NotNil(t, suite.Require()) + assert.Equal(t, suite.require, suite.Require()) +} + +type SuiteLoggingTester struct { + Suite +} + +func (s *SuiteLoggingTester) TestLoggingPass() { + s.T().Log("TESTLOGPASS") +} + +func (s *SuiteLoggingTester) TestLoggingFail() { + s.T().Log("TESTLOGFAIL") + assert.NotNil(s.T(), nil) // expected to fail +} + +type StdoutCapture struct { + oldStdout *os.File + readPipe *os.File +} + +func (sc *StdoutCapture) StartCapture() { + sc.oldStdout = os.Stdout + sc.readPipe, os.Stdout, _ = os.Pipe() +} + +func (sc *StdoutCapture) StopCapture() (string, error) { + if sc.oldStdout == nil || sc.readPipe == nil { + return "", errors.New("StartCapture not called before StopCapture") + } + os.Stdout.Close() + os.Stdout = sc.oldStdout + bytes, err := ioutil.ReadAll(sc.readPipe) + if err != nil { + return "", err + } + return string(bytes), nil +} + +func TestSuiteLogging(t *testing.T) { + testT := testing.T{} + + suiteLoggingTester := new(SuiteLoggingTester) + + capture := StdoutCapture{} + capture.StartCapture() + Run(&testT, suiteLoggingTester) + output, err := capture.StopCapture() + + assert.Nil(t, err, "Got an error trying to capture stdout!") + + // Failed tests' output is always printed + assert.Contains(t, output, "TESTLOGFAIL") + + if testing.Verbose() { + // In verbose mode, output from successful tests is also printed + assert.Contains(t, output, "TESTLOGPASS") + } else { + assert.NotContains(t, output, "TESTLOGPASS") + } +} |
