diff --git a/Gopkg.lock b/Gopkg.lock index d99a75605..acca26f7b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,12 +1,6 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. -[[projects]] - name = "cloud.google.com/go" - packages = ["compute/metadata"] - revision = "0f0b8420cb699ac4ce059c63bac263f4301fe95b" - version = "v0.12.0" - [[projects]] name = "github.com/PuerkitoBio/purell" packages = ["."] @@ -31,42 +25,30 @@ revision = "b2a4d4ae21c789b689dd162deb819665567f481c" version = "0.10.0" +[[projects]] + name = "github.com/asaskevich/govalidator" + packages = ["."] + revision = "73945b6115bfbbcc57d89b7316e28109364124e1" + version = "v7" + [[projects]] branch = "master" name = "github.com/beorn7/perks" packages = ["quantile"] revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9" -[[projects]] - name = "github.com/blang/semver" - packages = ["."] - revision = "2ee87856327ba09384cabd113bc6b5d174e9ec0f" - version = "v3.5.1" - [[projects]] name = "github.com/coreos/etcd" packages = ["client","pkg/pathutil","pkg/srv","pkg/types","version"] revision = "9d43462d174c664f5edf313dec0de31e1ef4ed47" version = "v3.2.6" -[[projects]] - branch = "master" - name = "github.com/coreos/go-oidc" - packages = ["http","jose","key","oauth2","oidc"] - revision = "a4973d9a4225417aecf5d450a9522f00c1f7130f" - [[projects]] name = "github.com/coreos/go-semver" packages = ["semver"] revision = "8ab6407b697782a06568d4b7f1db25550ec2e4c6" version = "v0.2.0" -[[projects]] - name = "github.com/coreos/pkg" - packages = ["health","httputil","timeutil"] - revision = "3ac0863d7acf3bc44daf49afef8919af12f704ef" - version = "v3" - [[projects]] name = "github.com/davecgh/go-spew" packages = ["spew"] @@ -105,22 +87,22 @@ [[projects]] name = "github.com/emicklei/go-restful" - packages = [".","log","swagger"] + packages = [".","log"] revision = "777bb3f19bcafe2575ffb2a3e46af92509ae9594" version = "v1.2" +[[projects]] + name = "github.com/emicklei/go-restful-swagger12" + packages = ["."] + revision = "dcef7f55730566d41eae5db10e7d6981829720f6" + version = "1.0.1" + [[projects]] branch = "master" name = "github.com/farsightsec/golang-framestream" packages = ["."] revision = "dec85654e8b8cf6712870afb14ee53d1c98cd5e2" -[[projects]] - name = "github.com/fsnotify/fsnotify" - packages = ["."] - revision = "629574ca2a5df945712d3079857300b5e4da0236" - version = "v1.4.2" - [[projects]] name = "github.com/ghodss/yaml" packages = ["."] @@ -133,6 +115,18 @@ revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" version = "v0.3.0" +[[projects]] + branch = "master" + name = "github.com/go-openapi/analysis" + packages = ["."] + revision = "8ed83f2ea9f00f945516462951a288eaa68bf0d6" + +[[projects]] + branch = "master" + name = "github.com/go-openapi/errors" + packages = ["."] + revision = "03cfca65330da08a5a440053faf994a3c682b5bf" + [[projects]] branch = "master" name = "github.com/go-openapi/jsonpointer" @@ -145,12 +139,24 @@ packages = ["."] revision = "36d33bfe519efae5632669801b180bf1a245da3b" +[[projects]] + branch = "master" + name = "github.com/go-openapi/loads" + packages = ["."] + revision = "a80dea3052f00e5f032e860dd7355cd0cc67e24d" + [[projects]] branch = "master" name = "github.com/go-openapi/spec" packages = ["."] revision = "3faa0055dbbf2110abc1f3b4e3adbb22721e96e7" +[[projects]] + branch = "master" + name = "github.com/go-openapi/strfmt" + packages = ["."] + revision = "610b6cacdcde6852f4de68998bd20ce1dac85b22" + [[projects]] branch = "master" name = "github.com/go-openapi/swag" @@ -193,6 +199,12 @@ packages = ["go/otgrpc"] revision = "6c130eed1e297e1aa4d415a50c90d0c81c52677e" +[[projects]] + branch = "master" + name = "github.com/hashicorp/golang-lru" + packages = [".","simplelru"] + revision = "0a025b7e63adc15a622f29b0b2c4c3848243bbf6" + [[projects]] branch = "master" name = "github.com/howeyc/gopass" @@ -205,12 +217,6 @@ revision = "3e95a51e0639b4cf372f2ccf74c86749d747fbdc" version = "0.2.2" -[[projects]] - name = "github.com/jonboulle/clockwork" - packages = ["."] - revision = "2eee05ed794112d45db504eb05aa693efd2b8b09" - version = "v0.1.0" - [[projects]] branch = "master" name = "github.com/juju/ratelimit" @@ -235,6 +241,12 @@ revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" version = "v1.0.0" +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "d0303fe809921458f417bcf828397a65db30a7e4" + [[projects]] name = "github.com/opentracing/opentracing-go" packages = [".","ext","log"] @@ -247,12 +259,6 @@ revision = "d88c90182f3fb514be54a1c7adc11a04d41c7da9" version = "v0.2.4" -[[projects]] - name = "github.com/pborman/uuid" - packages = ["."] - revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53" - version = "v1.1" - [[projects]] name = "github.com/pierrec/lz4" packages = ["."] @@ -313,12 +319,6 @@ packages = ["ssh/terminal"] revision = "81e90905daefcd6fd217b62423c0908922eadb30" -[[projects]] - branch = "master" - name = "golang.org/x/oauth2" - packages = [".","google","internal","jws","jwt"] - revision = "9a379c6b3e95a790ffc43293c2a78dee0d7b6e20" - [[projects]] branch = "master" name = "golang.org/x/sys" @@ -331,12 +331,6 @@ packages = ["internal/gen","internal/triegen","internal/ucd","transform","unicode/cldr","unicode/norm","width"] revision = "ac87088df8ef557f1e32cd00ed0b6fbc3f7ddafb" -[[projects]] - name = "google.golang.org/appengine" - packages = [".","internal","internal/app_identity","internal/base","internal/datastore","internal/log","internal/modules","internal/remote_api","internal/urlfetch","urlfetch"] - revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" - version = "v1.0.0" - [[projects]] branch = "master" name = "google.golang.org/genproto" @@ -355,21 +349,32 @@ revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" version = "v0.9.0" +[[projects]] + branch = "v2" + name = "gopkg.in/mgo.v2" + packages = ["bson","internal/json"] + revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655" + [[projects]] branch = "v2" name = "gopkg.in/yaml.v2" packages = ["."] revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f" +[[projects]] + name = "k8s.io/apimachinery" + packages = ["pkg/api/equality","pkg/api/errors","pkg/api/meta","pkg/api/resource","pkg/apimachinery","pkg/apimachinery/announced","pkg/apimachinery/registered","pkg/apis/meta/v1","pkg/apis/meta/v1/unstructured","pkg/apis/meta/v1alpha1","pkg/conversion","pkg/conversion/queryparams","pkg/conversion/unstructured","pkg/fields","pkg/labels","pkg/openapi","pkg/runtime","pkg/runtime/schema","pkg/runtime/serializer","pkg/runtime/serializer/json","pkg/runtime/serializer/protobuf","pkg/runtime/serializer/recognizer","pkg/runtime/serializer/streaming","pkg/runtime/serializer/versioning","pkg/selection","pkg/types","pkg/util/cache","pkg/util/clock","pkg/util/diff","pkg/util/errors","pkg/util/framer","pkg/util/intstr","pkg/util/json","pkg/util/net","pkg/util/rand","pkg/util/runtime","pkg/util/sets","pkg/util/validation","pkg/util/validation/field","pkg/util/wait","pkg/util/yaml","pkg/version","pkg/watch","third_party/forked/golang/reflect"] + revision = "1fd2e63a9a370677308a42f24fd40c86438afddf" + [[projects]] name = "k8s.io/client-go" - packages = ["1.5/discovery","1.5/kubernetes","1.5/kubernetes/typed/apps/v1alpha1","1.5/kubernetes/typed/authentication/v1beta1","1.5/kubernetes/typed/authorization/v1beta1","1.5/kubernetes/typed/autoscaling/v1","1.5/kubernetes/typed/batch/v1","1.5/kubernetes/typed/certificates/v1alpha1","1.5/kubernetes/typed/core/v1","1.5/kubernetes/typed/extensions/v1beta1","1.5/kubernetes/typed/policy/v1alpha1","1.5/kubernetes/typed/rbac/v1alpha1","1.5/kubernetes/typed/storage/v1beta1","1.5/pkg/api","1.5/pkg/api/errors","1.5/pkg/api/install","1.5/pkg/api/meta","1.5/pkg/api/meta/metatypes","1.5/pkg/api/resource","1.5/pkg/api/unversioned","1.5/pkg/api/v1","1.5/pkg/api/validation/path","1.5/pkg/apimachinery","1.5/pkg/apimachinery/announced","1.5/pkg/apimachinery/registered","1.5/pkg/apis/apps","1.5/pkg/apis/apps/install","1.5/pkg/apis/apps/v1alpha1","1.5/pkg/apis/authentication","1.5/pkg/apis/authentication/install","1.5/pkg/apis/authentication/v1beta1","1.5/pkg/apis/authorization","1.5/pkg/apis/authorization/install","1.5/pkg/apis/authorization/v1beta1","1.5/pkg/apis/autoscaling","1.5/pkg/apis/autoscaling/install","1.5/pkg/apis/autoscaling/v1","1.5/pkg/apis/batch","1.5/pkg/apis/batch/install","1.5/pkg/apis/batch/v1","1.5/pkg/apis/batch/v2alpha1","1.5/pkg/apis/certificates","1.5/pkg/apis/certificates/install","1.5/pkg/apis/certificates/v1alpha1","1.5/pkg/apis/extensions","1.5/pkg/apis/extensions/install","1.5/pkg/apis/extensions/v1beta1","1.5/pkg/apis/policy","1.5/pkg/apis/policy/install","1.5/pkg/apis/policy/v1alpha1","1.5/pkg/apis/rbac","1.5/pkg/apis/rbac/install","1.5/pkg/apis/rbac/v1alpha1","1.5/pkg/apis/storage","1.5/pkg/apis/storage/install","1.5/pkg/apis/storage/v1beta1","1.5/pkg/auth/user","1.5/pkg/conversion","1.5/pkg/conversion/queryparams","1.5/pkg/fields","1.5/pkg/genericapiserver/openapi/common","1.5/pkg/labels","1.5/pkg/runtime","1.5/pkg/runtime/serializer","1.5/pkg/runtime/serializer/json","1.5/pkg/runtime/serializer/protobuf","1.5/pkg/runtime/serializer/recognizer","1.5/pkg/runtime/serializer/streaming","1.5/pkg/runtime/serializer/versioning","1.5/pkg/selection","1.5/pkg/third_party/forked/golang/reflect","1.5/pkg/types","1.5/pkg/util","1.5/pkg/util/cert","1.5/pkg/util/clock","1.5/pkg/util/errors","1.5/pkg/util/flowcontrol","1.5/pkg/util/framer","1.5/pkg/util/homedir","1.5/pkg/util/integer","1.5/pkg/util/intstr","1.5/pkg/util/json","1.5/pkg/util/labels","1.5/pkg/util/net","1.5/pkg/util/parsers","1.5/pkg/util/rand","1.5/pkg/util/runtime","1.5/pkg/util/sets","1.5/pkg/util/uuid","1.5/pkg/util/validation","1.5/pkg/util/validation/field","1.5/pkg/util/wait","1.5/pkg/util/yaml","1.5/pkg/version","1.5/pkg/watch","1.5/pkg/watch/versioned","1.5/plugin/pkg/client/auth","1.5/plugin/pkg/client/auth/gcp","1.5/plugin/pkg/client/auth/oidc","1.5/rest","1.5/tools/auth","1.5/tools/cache","1.5/tools/clientcmd","1.5/tools/clientcmd/api","1.5/tools/clientcmd/api/latest","1.5/tools/clientcmd/api/v1","1.5/tools/metrics","1.5/transport"] - revision = "1195e3a8ee1a529d53eed7c624527a68555ddf1f" - version = "v1.5.1" + packages = ["discovery","kubernetes","kubernetes/scheme","kubernetes/typed/admissionregistration/v1alpha1","kubernetes/typed/apps/v1beta1","kubernetes/typed/authentication/v1","kubernetes/typed/authentication/v1beta1","kubernetes/typed/authorization/v1","kubernetes/typed/authorization/v1beta1","kubernetes/typed/autoscaling/v1","kubernetes/typed/autoscaling/v2alpha1","kubernetes/typed/batch/v1","kubernetes/typed/batch/v2alpha1","kubernetes/typed/certificates/v1beta1","kubernetes/typed/core/v1","kubernetes/typed/extensions/v1beta1","kubernetes/typed/networking/v1","kubernetes/typed/policy/v1beta1","kubernetes/typed/rbac/v1alpha1","kubernetes/typed/rbac/v1beta1","kubernetes/typed/settings/v1alpha1","kubernetes/typed/storage/v1","kubernetes/typed/storage/v1beta1","pkg/api","pkg/api/v1","pkg/api/v1/ref","pkg/apis/admissionregistration","pkg/apis/admissionregistration/v1alpha1","pkg/apis/apps","pkg/apis/apps/v1beta1","pkg/apis/authentication","pkg/apis/authentication/v1","pkg/apis/authentication/v1beta1","pkg/apis/authorization","pkg/apis/authorization/v1","pkg/apis/authorization/v1beta1","pkg/apis/autoscaling","pkg/apis/autoscaling/v1","pkg/apis/autoscaling/v2alpha1","pkg/apis/batch","pkg/apis/batch/v1","pkg/apis/batch/v2alpha1","pkg/apis/certificates","pkg/apis/certificates/v1beta1","pkg/apis/extensions","pkg/apis/extensions/v1beta1","pkg/apis/networking","pkg/apis/networking/v1","pkg/apis/policy","pkg/apis/policy/v1beta1","pkg/apis/rbac","pkg/apis/rbac/v1alpha1","pkg/apis/rbac/v1beta1","pkg/apis/settings","pkg/apis/settings/v1alpha1","pkg/apis/storage","pkg/apis/storage/v1","pkg/apis/storage/v1beta1","pkg/util","pkg/util/parsers","pkg/version","rest","rest/watch","tools/auth","tools/cache","tools/clientcmd","tools/clientcmd/api","tools/clientcmd/api/latest","tools/clientcmd/api/v1","tools/metrics","transport","util/cert","util/flowcontrol","util/homedir","util/integer"] + revision = "d92e8497f71b7b4e0494e5bd204b48d34bd6f254" + version = "v4.0.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "0ddaab68018c7f38bccad1d9932df961ae52544dc56e3c0060ce1c28e5da0a47" + inputs-digest = "916c5fe7d9ce3a19d3956068cae5daf94be1269ae86400dfed36308fbd88a539" solver-name = "gps-cdcl" solver-version = 1 diff --git a/plugin/federation/kubernetes_api_test.go b/plugin/federation/kubernetes_api_test.go index 48a03666e..3900ae0b8 100644 --- a/plugin/federation/kubernetes_api_test.go +++ b/plugin/federation/kubernetes_api_test.go @@ -3,7 +3,8 @@ package federation import ( "github.com/coredns/coredns/plugin/kubernetes" - "k8s.io/client-go/1.5/pkg/api" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/client-go/pkg/api/v1" ) type APIConnFederationTest struct{} @@ -11,23 +12,22 @@ type APIConnFederationTest struct{} func (APIConnFederationTest) Run() { return } func (APIConnFederationTest) Stop() error { return nil } -func (APIConnFederationTest) PodIndex(string) []interface{} { - a := make([]interface{}, 1) - a[0] = &api.Pod{ - ObjectMeta: api.ObjectMeta{ +func (APIConnFederationTest) PodIndex(string) []*api.Pod { + a := []*api.Pod{{ + ObjectMeta: meta.ObjectMeta{ Namespace: "podns", }, Status: api.PodStatus{ PodIP: "10.240.0.1", // Remote IP set in test.ResponseWriter }, - } + }} return a } func (APIConnFederationTest) ServiceList() []*api.Service { svcs := []*api.Service{ { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "svc1", Namespace: "testns", }, @@ -41,7 +41,7 @@ func (APIConnFederationTest) ServiceList() []*api.Service { }, }, { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "hdls1", Namespace: "testns", }, @@ -50,7 +50,7 @@ func (APIConnFederationTest) ServiceList() []*api.Service { }, }, { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "external", Namespace: "testns", }, @@ -65,42 +65,40 @@ func (APIConnFederationTest) ServiceList() []*api.Service { }, } return svcs - } -func (APIConnFederationTest) EndpointsList() api.EndpointsList { - return api.EndpointsList{ - Items: []api.Endpoints{ - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.1", - Hostname: "ep1a", - }, +func (APIConnFederationTest) EndpointsList() []*api.Endpoints { + eps := []*api.Endpoints{ + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.1", + Hostname: "ep1a", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "svc1", - Namespace: "testns", - }, + }, + ObjectMeta: meta.ObjectMeta{ + Name: "svc1", + Namespace: "testns", }, }, } + return eps } -func (APIConnFederationTest) GetNodeByName(name string) (api.Node, error) { - return api.Node{ - ObjectMeta: api.ObjectMeta{ +func (APIConnFederationTest) GetNodeByName(name string) (*api.Node, error) { + return &api.Node{ + ObjectMeta: meta.ObjectMeta{ Name: "test.node.foo.bar", Labels: map[string]string{ kubernetes.LabelRegion: "fd-r", diff --git a/plugin/kubernetes/autopath.go b/plugin/kubernetes/autopath.go index f758869f1..feab430a9 100644 --- a/plugin/kubernetes/autopath.go +++ b/plugin/kubernetes/autopath.go @@ -4,7 +4,7 @@ import ( "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/request" - "k8s.io/client-go/1.5/pkg/api" + api "k8s.io/client-go/pkg/api/v1" ) // AutoPath implements the AutoPathFunc call from the autopath plugin. @@ -40,14 +40,10 @@ func (k *Kubernetes) AutoPath(state request.Request) []string { } // podWithIP return the api.Pod for source IP ip. It returns nil if nothing can be found. -func (k *Kubernetes) podWithIP(ip string) (p *api.Pod) { - objList := k.APIConn.PodIndex(ip) - for _, o := range objList { - p, ok := o.(*api.Pod) - if !ok { - return nil - } - return p +func (k *Kubernetes) podWithIP(ip string) *api.Pod { + ps := k.APIConn.PodIndex(ip) + if len(ps) == 0 { + return nil } - return nil + return ps[0] } diff --git a/plugin/kubernetes/controller.go b/plugin/kubernetes/controller.go index fa2e749bb..a5b697c88 100644 --- a/plugin/kubernetes/controller.go +++ b/plugin/kubernetes/controller.go @@ -3,45 +3,31 @@ package kubernetes import ( "errors" "fmt" - "log" "sync" "time" - "k8s.io/client-go/1.5/kubernetes" - "k8s.io/client-go/1.5/pkg/api" - unversionedapi "k8s.io/client-go/1.5/pkg/api/unversioned" - "k8s.io/client-go/1.5/pkg/api/v1" - "k8s.io/client-go/1.5/pkg/labels" - "k8s.io/client-go/1.5/pkg/runtime" - "k8s.io/client-go/1.5/pkg/watch" - "k8s.io/client-go/1.5/tools/cache" + "k8s.io/client-go/kubernetes" + api "k8s.io/client-go/pkg/api/v1" + "k8s.io/client-go/tools/cache" + + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" ) var ( namespace = api.NamespaceAll ) -// storeToNamespaceLister makes a Store that lists Namespaces. -type storeToNamespaceLister struct { - cache.Store -} - const podIPIndex = "PodIP" -// List lists all Namespaces in the store. -func (s *storeToNamespaceLister) List() (ns api.NamespaceList, err error) { - for _, m := range s.Store.List() { - ns.Items = append(ns.Items, *(m.(*api.Namespace))) - } - return ns, nil -} - type dnsController interface { ServiceList() []*api.Service - PodIndex(string) []interface{} - EndpointsList() api.EndpointsList + PodIndex(string) []*api.Pod + EndpointsList() []*api.Endpoints - GetNodeByName(string) (api.Node, error) + GetNodeByName(string) (*api.Node, error) Run() Stop() error @@ -52,15 +38,13 @@ type dnsControl struct { selector *labels.Selector - svcController *cache.Controller - podController *cache.Controller - nsController *cache.Controller - epController *cache.Controller + svcController cache.Controller + podController cache.Controller + epController cache.Controller - svcLister cache.StoreToServiceLister - podLister cache.StoreToPodLister - nsLister storeToNamespaceLister - epLister cache.StoreToEndpointsLister + svcLister cache.Indexer + podLister cache.Indexer + epLister cache.Store // stopLock is used to enforce only a single call to Stop is active. // Needed because we allow stopping through an http endpoint and @@ -74,7 +58,7 @@ type dnsControlOpts struct { initPodCache bool resyncPeriod time.Duration // Label handling. - labelSelector *unversionedapi.LabelSelector + labelSelector *meta.LabelSelector selector *labels.Selector } @@ -85,8 +69,7 @@ func newdnsController(kubeClient *kubernetes.Clientset, opts dnsControlOpts) *dn selector: opts.selector, stopCh: make(chan struct{}), } - - dns.svcLister.Indexer, dns.svcController = cache.NewIndexerInformer( + dns.svcLister, dns.svcController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: serviceListFunc(dns.client, namespace, dns.selector), WatchFunc: serviceWatchFunc(dns.client, namespace, dns.selector), @@ -97,7 +80,7 @@ func newdnsController(kubeClient *kubernetes.Clientset, opts dnsControlOpts) *dn cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) if opts.initPodCache { - dns.podLister.Indexer, dns.podController = cache.NewIndexerInformer( + dns.podLister, dns.podController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: podListFunc(dns.client, namespace, dns.selector), WatchFunc: podWatchFunc(dns.client, namespace, dns.selector), @@ -107,17 +90,7 @@ func newdnsController(kubeClient *kubernetes.Clientset, opts dnsControlOpts) *dn cache.ResourceEventHandlerFuncs{}, cache.Indexers{podIPIndex: podIPIndexFunc}) } - - dns.nsLister.Store, dns.nsController = cache.NewInformer( - &cache.ListWatch{ - ListFunc: namespaceListFunc(dns.client, dns.selector), - WatchFunc: namespaceWatchFunc(dns.client, dns.selector), - }, - &api.Namespace{}, - opts.resyncPeriod, - cache.ResourceEventHandlerFuncs{}) - - dns.epLister.Store, dns.epController = cache.NewInformer( + dns.epLister, dns.epController = cache.NewInformer( &cache.ListWatch{ ListFunc: endpointsListFunc(dns.client, namespace, dns.selector), WatchFunc: endpointsWatchFunc(dns.client, namespace, dns.selector), @@ -137,182 +110,86 @@ func podIPIndexFunc(obj interface{}) ([]string, error) { return []string{p.Status.PodIP}, nil } -func serviceListFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) { - return func(opts api.ListOptions) (runtime.Object, error) { +func serviceListFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(meta.ListOptions) (runtime.Object, error) { + return func(opts meta.ListOptions) (runtime.Object, error) { if s != nil { - opts.LabelSelector = *s + opts.LabelSelector = (*s).String() } - listV1, err := c.Core().Services(ns).List(opts) - + listV1, err := c.Services(ns).List(opts) if err != nil { return nil, err } - var listAPI api.ServiceList - err = v1.Convert_v1_ServiceList_To_api_ServiceList(listV1, &listAPI, nil) - if err != nil { - return nil, err - } - return &listAPI, err + return listV1, err } } -func podListFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) { - return func(opts api.ListOptions) (runtime.Object, error) { +func podListFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(meta.ListOptions) (runtime.Object, error) { + return func(opts meta.ListOptions) (runtime.Object, error) { if s != nil { - opts.LabelSelector = *s + opts.LabelSelector = (*s).String() } - listV1, err := c.Core().Pods(ns).List(opts) - + listV1, err := c.Pods(ns).List(opts) if err != nil { return nil, err } - var listAPI api.PodList - err = v1.Convert_v1_PodList_To_api_PodList(listV1, &listAPI, nil) - if err != nil { - return nil, err - } - - return &listAPI, err + return listV1, err } } -func v1ToAPIFilter(in watch.Event) (out watch.Event, keep bool) { - if in.Type == watch.Error { - return in, true - } - - switch v1Obj := in.Object.(type) { - case *v1.Service: - var apiObj api.Service - err := v1.Convert_v1_Service_To_api_Service(v1Obj, &apiObj, nil) - if err != nil { - log.Printf("[ERROR] Could not convert v1.Service: %s", err) - return in, true - } - return watch.Event{Type: in.Type, Object: &apiObj}, true - case *v1.Pod: - var apiObj api.Pod - err := v1.Convert_v1_Pod_To_api_Pod(v1Obj, &apiObj, nil) - if err != nil { - log.Printf("[ERROR] Could not convert v1.Pod: %s", err) - return in, true - } - return watch.Event{Type: in.Type, Object: &apiObj}, true - case *v1.Namespace: - var apiObj api.Namespace - err := v1.Convert_v1_Namespace_To_api_Namespace(v1Obj, &apiObj, nil) - if err != nil { - log.Printf("[ERROR] Could not convert v1.Namespace: %s", err) - return in, true - } - return watch.Event{Type: in.Type, Object: &apiObj}, true - case *v1.Endpoints: - var apiObj api.Endpoints - err := v1.Convert_v1_Endpoints_To_api_Endpoints(v1Obj, &apiObj, nil) - if err != nil { - log.Printf("[ERROR] Could not convert v1.Endpoint: %s", err) - return in, true - } - return watch.Event{Type: in.Type, Object: &apiObj}, true - } - - log.Printf("[WARN] Unhandled v1 type in event: %v", in) - return in, true -} - -func serviceWatchFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) { - return func(options api.ListOptions) (watch.Interface, error) { +func serviceWatchFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(options meta.ListOptions) (watch.Interface, error) { + return func(options meta.ListOptions) (watch.Interface, error) { if s != nil { - options.LabelSelector = *s + options.LabelSelector = (*s).String() } - w, err := c.Core().Services(ns).Watch(options) + w, err := c.Services(ns).Watch(options) if err != nil { return nil, err } - return watch.Filter(w, v1ToAPIFilter), nil + return w, nil } } -func podWatchFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) { - return func(options api.ListOptions) (watch.Interface, error) { +func podWatchFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(options meta.ListOptions) (watch.Interface, error) { + return func(options meta.ListOptions) (watch.Interface, error) { if s != nil { - options.LabelSelector = *s + options.LabelSelector = (*s).String() } - w, err := c.Core().Pods(ns).Watch(options) - + w, err := c.Pods(ns).Watch(options) if err != nil { return nil, err } - return watch.Filter(w, v1ToAPIFilter), nil + return w, nil } } -func namespaceListFunc(c *kubernetes.Clientset, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) { - return func(opts api.ListOptions) (runtime.Object, error) { +func endpointsListFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(meta.ListOptions) (runtime.Object, error) { + return func(opts meta.ListOptions) (runtime.Object, error) { if s != nil { - opts.LabelSelector = *s + opts.LabelSelector = (*s).String() } - listV1, err := c.Core().Namespaces().List(opts) + listV1, err := c.Endpoints(ns).List(opts) if err != nil { return nil, err } - var listAPI api.NamespaceList - err = v1.Convert_v1_NamespaceList_To_api_NamespaceList(listV1, &listAPI, nil) - if err != nil { - return nil, err - } - return &listAPI, err + return listV1, err } } -func namespaceWatchFunc(c *kubernetes.Clientset, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) { - return func(options api.ListOptions) (watch.Interface, error) { +func endpointsWatchFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(options meta.ListOptions) (watch.Interface, error) { + return func(options meta.ListOptions) (watch.Interface, error) { if s != nil { - options.LabelSelector = *s + options.LabelSelector = (*s).String() } - w, err := c.Core().Namespaces().Watch(options) + w, err := c.Endpoints(ns).Watch(options) if err != nil { return nil, err } - return watch.Filter(w, v1ToAPIFilter), nil - } -} - -func endpointsListFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(api.ListOptions) (runtime.Object, error) { - return func(opts api.ListOptions) (runtime.Object, error) { - if s != nil { - opts.LabelSelector = *s - } - listV1, err := c.Core().Endpoints(ns).List(opts) - - if err != nil { - return nil, err - } - var listAPI api.EndpointsList - err = v1.Convert_v1_EndpointsList_To_api_EndpointsList(listV1, &listAPI, nil) - if err != nil { - return nil, err - } - return &listAPI, err - } -} - -func endpointsWatchFunc(c *kubernetes.Clientset, ns string, s *labels.Selector) func(options api.ListOptions) (watch.Interface, error) { - return func(options api.ListOptions) (watch.Interface, error) { - if s != nil { - options.LabelSelector = *s - } - w, err := c.Core().Endpoints(ns).Watch(options) - if err != nil { - return nil, err - } - return watch.Filter(w, v1ToAPIFilter), nil + return w, nil } } func (dns *dnsControl) controllersInSync() bool { hs := dns.svcController.HasSynced() && - dns.nsController.HasSynced() && dns.epController.HasSynced() if dns.podController != nil { @@ -341,7 +218,6 @@ func (dns *dnsControl) Stop() error { // Run starts the controller. func (dns *dnsControl) Run() { go dns.svcController.Run(dns.stopCh) - go dns.nsController.Run(dns.stopCh) go dns.epController.Run(dns.stopCh) if dns.podController != nil { go dns.podController.Run(dns.stopCh) @@ -349,54 +225,52 @@ func (dns *dnsControl) Run() { <-dns.stopCh } -func (dns *dnsControl) NamespaceList() *api.NamespaceList { - nsList, err := dns.nsLister.List() - if err != nil { - return &api.NamespaceList{} +func (dns *dnsControl) ServiceList() (svcs []*api.Service) { + os := dns.svcLister.List() + for _, o := range os { + s, ok := o.(*api.Service) + if !ok { + continue + } + svcs = append(svcs, s) } - - return &nsList -} - -func (dns *dnsControl) ServiceList() []*api.Service { - svcs, err := dns.svcLister.List(labels.Everything()) - if err != nil { - return []*api.Service{} - } - return svcs } -func (dns *dnsControl) PodIndex(ip string) []interface{} { - if dns.podLister.Indexer == nil { +func (dns *dnsControl) PodIndex(ip string) (pods []*api.Pod) { + if dns.podLister == nil { return nil } - pods, err := dns.podLister.Indexer.ByIndex(podIPIndex, ip) + os, err := dns.podLister.ByIndex(podIPIndex, ip) if err != nil { return nil } - + for _, o := range os { + p, ok := o.(*api.Pod) + if !ok { + continue + } + pods = append(pods, p) + } return pods } -func (dns *dnsControl) EndpointsList() api.EndpointsList { - epl, err := dns.epLister.List() - if err != nil { - return api.EndpointsList{} +func (dns *dnsControl) EndpointsList() (eps []*api.Endpoints) { + os := dns.epLister.List() + for _, o := range os { + ep, ok := o.(*api.Endpoints) + if !ok { + continue + } + eps = append(eps, ep) } - - return epl + return eps } -func (dns *dnsControl) GetNodeByName(name string) (api.Node, error) { - v1node, err := dns.client.Core().Nodes().Get(name) +func (dns *dnsControl) GetNodeByName(name string) (*api.Node, error) { + v1node, err := dns.client.Nodes().Get(name, meta.GetOptions{}) if err != nil { - return api.Node{}, err + return &api.Node{}, err } - var apinode api.Node - err = v1.Convert_v1_Node_To_api_Node(v1node, &apinode, nil) - if err != nil { - return api.Node{}, err - } - return apinode, nil + return v1node, nil } diff --git a/plugin/kubernetes/handler_test.go b/plugin/kubernetes/handler_test.go index 1dd7ea621..388428e3a 100644 --- a/plugin/kubernetes/handler_test.go +++ b/plugin/kubernetes/handler_test.go @@ -8,7 +8,8 @@ import ( "github.com/miekg/dns" "golang.org/x/net/context" - "k8s.io/client-go/1.5/pkg/api" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/client-go/pkg/api/v1" ) var dnsTestCases = []test.Case{ @@ -193,23 +194,22 @@ type APIConnServeTest struct{} func (APIConnServeTest) Run() { return } func (APIConnServeTest) Stop() error { return nil } -func (APIConnServeTest) PodIndex(string) []interface{} { - a := make([]interface{}, 1) - a[0] = &api.Pod{ - ObjectMeta: api.ObjectMeta{ +func (APIConnServeTest) PodIndex(string) []*api.Pod { + a := []*api.Pod{{ + ObjectMeta: meta.ObjectMeta{ Namespace: "podns", }, Status: api.PodStatus{ PodIP: "10.240.0.1", // Remote IP set in test.ResponseWriter }, - } + }} return a } func (APIConnServeTest) ServiceList() []*api.Service { svcs := []*api.Service{ { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "svc1", Namespace: "testns", }, @@ -223,7 +223,7 @@ func (APIConnServeTest) ServiceList() []*api.Service { }, }, { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "hdls1", Namespace: "testns", }, @@ -232,7 +232,7 @@ func (APIConnServeTest) ServiceList() []*api.Service { }, }, { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "external", Namespace: "testns", }, @@ -247,100 +247,98 @@ func (APIConnServeTest) ServiceList() []*api.Service { }, } return svcs - } -func (APIConnServeTest) EndpointsList() api.EndpointsList { +func (APIConnServeTest) EndpointsList() []*api.Endpoints { n := "test.node.foo.bar" - return api.EndpointsList{ - Items: []api.Endpoints{ - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.1", - Hostname: "ep1a", - }, + eps := []*api.Endpoints{ + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.1", + Hostname: "ep1a", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "svc1", - Namespace: "testns", - }, }, - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.2", - }, + ObjectMeta: meta.ObjectMeta{ + Name: "svc1", + Namespace: "testns", + }, + }, + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.2", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "hdls1", - Namespace: "testns", - }, }, - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.3", - }, + ObjectMeta: meta.ObjectMeta{ + Name: "hdls1", + Namespace: "testns", + }, + }, + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.3", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "hdls1", - Namespace: "testns", - }, }, - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "10.9.8.7", - NodeName: &n, - }, + ObjectMeta: meta.ObjectMeta{ + Name: "hdls1", + Namespace: "testns", + }, + }, + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "10.9.8.7", + NodeName: &n, }, }, }, }, }, } + return eps } -func (APIConnServeTest) GetNodeByName(name string) (api.Node, error) { - return api.Node{ - ObjectMeta: api.ObjectMeta{ +func (APIConnServeTest) GetNodeByName(name string) (*api.Node, error) { + return &api.Node{ + ObjectMeta: meta.ObjectMeta{ Name: "test.node.foo.bar", }, }, nil diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go index afc48d0e0..211d2573c 100644 --- a/plugin/kubernetes/kubernetes.go +++ b/plugin/kubernetes/kubernetes.go @@ -17,13 +17,13 @@ import ( "github.com/coredns/coredns/request" "github.com/miekg/dns" - "k8s.io/client-go/1.5/kubernetes" - "k8s.io/client-go/1.5/pkg/api" - unversionedapi "k8s.io/client-go/1.5/pkg/api/unversioned" - "k8s.io/client-go/1.5/pkg/labels" - "k8s.io/client-go/1.5/rest" - "k8s.io/client-go/1.5/tools/clientcmd" - clientcmdapi "k8s.io/client-go/1.5/tools/clientcmd/api" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/kubernetes" + api "k8s.io/client-go/pkg/api/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) // Kubernetes implements a plugin that connects to a Kubernetes cluster. @@ -76,7 +76,6 @@ var ( errNoItems = errors.New("no items found") errNsNotExposed = errors.New("namespace is not exposed") errInvalidRequest = errors.New("invalid query name") - errAPIBadPodType = errors.New("expected type *api.Pod") errPodsDisabled = errors.New("pod records disabled") ) @@ -152,14 +151,17 @@ func (k *Kubernetes) getClientConfig() (*rest.Config, error) { clusterinfo := clientcmdapi.Cluster{} authinfo := clientcmdapi.AuthInfo{} + // Connect to API from in cluster if len(k.APIServerList) == 0 { cc, err := rest.InClusterConfig() if err != nil { return nil, err } + cc.ContentType = "application/vnd.kubernetes.protobuf" return cc, err } + // Connect to API from out of cluster endpoint := k.APIServerList[0] if len(k.APIServerList) > 1 { // Use a random port for api proxy, will get the value later through listener.Addr() @@ -230,7 +232,10 @@ func (k *Kubernetes) getClientConfig() (*rest.Config, error) { overrides.AuthInfo = authinfo clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) - return clientConfig.ClientConfig() + cc, err := clientConfig.ClientConfig() + cc.ContentType = "application/vnd.kubernetes.protobuf" + return cc, err + } // initKubeCache initializes a new Kubernetes cache. @@ -248,7 +253,7 @@ func (k *Kubernetes) initKubeCache(opts dnsControlOpts) (err error) { if opts.labelSelector != nil { var selector labels.Selector - selector, err = unversionedapi.LabelSelectorAsSelector(opts.labelSelector) + selector, err = meta.LabelSelectorAsSelector(opts.labelSelector) if err != nil { return fmt.Errorf("unable to create Selector for LabelSelector '%s': %q", opts.labelSelector, err) } @@ -317,13 +322,7 @@ func (k *Kubernetes) findPods(r recordRequest, zone string) (pods []msg.Service, } // PodModeVerified - objList := k.APIConn.PodIndex(ip) - - for _, o := range objList { - p, ok := o.(*api.Pod) - if !ok { - return nil, errAPIBadPodType - } + for _, p := range k.APIConn.PodIndex(ip) { // If namespace has a wildcard, filter results against Corefile namespace list. if wildcard(namespace) && !k.namespaceExposed(p.Namespace) { continue @@ -341,11 +340,11 @@ func (k *Kubernetes) findPods(r recordRequest, zone string) (pods []msg.Service, // findServices returns the services matching r from the cache. func (k *Kubernetes) findServices(r recordRequest, zone string) (services []msg.Service, err error) { - serviceList := k.APIConn.ServiceList() zonePath := msg.Path(zone, "coredns") err = errNoItems // Set to errNoItems to signal really nothing found, gets reset when name is matched. - for _, svc := range serviceList { + for _, svc := range k.APIConn.ServiceList() { + if !(match(r.namespace, svc.Namespace) && match(r.service, svc.Name)) { continue } @@ -358,8 +357,8 @@ func (k *Kubernetes) findServices(r recordRequest, zone string) (services []msg. // Endpoint query or headless service if svc.Spec.ClusterIP == api.ClusterIPNone || r.endpoint != "" { - endpointsList := k.APIConn.EndpointsList() - for _, ep := range endpointsList.Items { + + for _, ep := range k.APIConn.EndpointsList() { if ep.ObjectMeta.Name != svc.Name || ep.ObjectMeta.Namespace != svc.Namespace { continue } diff --git a/plugin/kubernetes/kubernetes_apex_test.go b/plugin/kubernetes/kubernetes_apex_test.go index ce9cf59d4..b292b90d5 100644 --- a/plugin/kubernetes/kubernetes_apex_test.go +++ b/plugin/kubernetes/kubernetes_apex_test.go @@ -10,7 +10,7 @@ import ( "golang.org/x/net/context" ) -var kubeApexCases = [](test.Case){ +var kubeApexCases = []test.Case{ { Qname: "cluster.local.", Qtype: dns.TypeSOA, Rcode: dns.RcodeSuccess, diff --git a/plugin/kubernetes/kubernetes_test.go b/plugin/kubernetes/kubernetes_test.go index f347f10fc..4a3bb3d07 100644 --- a/plugin/kubernetes/kubernetes_test.go +++ b/plugin/kubernetes/kubernetes_test.go @@ -7,7 +7,8 @@ import ( "github.com/coredns/coredns/request" "github.com/miekg/dns" - "k8s.io/client-go/1.5/pkg/api" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/client-go/pkg/api/v1" ) func TestWildcard(t *testing.T) { @@ -50,14 +51,14 @@ func TestEndpointHostname(t *testing.T) { type APIConnServiceTest struct{} -func (APIConnServiceTest) Run() { return } -func (APIConnServiceTest) Stop() error { return nil } -func (APIConnServiceTest) PodIndex(string) []interface{} { return nil } +func (APIConnServiceTest) Run() { return } +func (APIConnServiceTest) Stop() error { return nil } +func (APIConnServiceTest) PodIndex(string) []*api.Pod { return nil } func (APIConnServiceTest) ServiceList() []*api.Service { svcs := []*api.Service{ { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "svc1", Namespace: "testns", }, @@ -71,7 +72,7 @@ func (APIConnServiceTest) ServiceList() []*api.Service { }, }, { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "hdls1", Namespace: "testns", }, @@ -80,7 +81,7 @@ func (APIConnServiceTest) ServiceList() []*api.Service { }, }, { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "external", Namespace: "testns", }, @@ -97,97 +98,96 @@ func (APIConnServiceTest) ServiceList() []*api.Service { return svcs } -func (APIConnServiceTest) EndpointsList() api.EndpointsList { +func (APIConnServiceTest) EndpointsList() []*api.Endpoints { n := "test.node.foo.bar" - return api.EndpointsList{ - Items: []api.Endpoints{ - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.1", - Hostname: "ep1a", - }, + eps := []*api.Endpoints{ + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.1", + Hostname: "ep1a", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "svc1", - Namespace: "testns", - }, }, - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.2", - }, + ObjectMeta: meta.ObjectMeta{ + Name: "svc1", + Namespace: "testns", + }, + }, + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.2", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "hdls1", - Namespace: "testns", - }, }, - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "172.0.0.3", - }, + ObjectMeta: meta.ObjectMeta{ + Name: "hdls1", + Namespace: "testns", + }, + }, + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "172.0.0.3", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "hdls1", - Namespace: "testns", - }, }, - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "10.9.8.7", - NodeName: &n, - }, + ObjectMeta: meta.ObjectMeta{ + Name: "hdls1", + Namespace: "testns", + }, + }, + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "10.9.8.7", + NodeName: &n, }, }, }, }, }, } + return eps } -func (APIConnServiceTest) GetNodeByName(name string) (api.Node, error) { - return api.Node{ - ObjectMeta: api.ObjectMeta{ +func (APIConnServiceTest) GetNodeByName(name string) (*api.Node, error) { + return &api.Node{ + ObjectMeta: meta.ObjectMeta{ Name: "test.node.foo.bar", }, }, nil diff --git a/plugin/kubernetes/local.go b/plugin/kubernetes/local.go index e5b7f1e0f..ef3651a91 100644 --- a/plugin/kubernetes/local.go +++ b/plugin/kubernetes/local.go @@ -1,6 +1,8 @@ package kubernetes -import "net" +import ( + "net" +) func localPodIP() net.IP { addrs, err := net.InterfaceAddrs() @@ -26,8 +28,7 @@ func (k *Kubernetes) localNodeName() string { } // Find endpoint matching localIP - endpointsList := k.APIConn.EndpointsList() - for _, ep := range endpointsList.Items { + for _, ep := range k.APIConn.EndpointsList() { for _, eps := range ep.Subsets { for _, addr := range eps.Addresses { if localIP.Equal(net.ParseIP(addr.IP)) { diff --git a/plugin/kubernetes/ns.go b/plugin/kubernetes/ns.go index 4cacc382f..c4b05d5b5 100644 --- a/plugin/kubernetes/ns.go +++ b/plugin/kubernetes/ns.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/miekg/dns" - "k8s.io/client-go/1.5/pkg/api" + api "k8s.io/client-go/pkg/api/v1" ) func isDefaultNS(name, zone string) bool { @@ -20,12 +20,10 @@ func (k *Kubernetes) nsAddr() *dns.A { rr := new(dns.A) localIP := k.interfaceAddrsFunc() - endpointsList := k.APIConn.EndpointsList() - rr.A = localIP FindEndpoint: - for _, ep := range endpointsList.Items { + for _, ep := range k.APIConn.EndpointsList() { for _, eps := range ep.Subsets { for _, addr := range eps.Addresses { if localIP.Equal(net.ParseIP(addr.IP)) { @@ -42,11 +40,9 @@ FindEndpoint: rr.A = localIP return rr } - // Find service to get ClusterIP - serviceList := k.APIConn.ServiceList() FindService: - for _, svc := range serviceList { + for _, svc := range k.APIConn.ServiceList() { if svcName == svc.Name && svcNamespace == svc.Namespace { if svc.Spec.ClusterIP == api.ClusterIPNone { rr.A = localIP diff --git a/plugin/kubernetes/ns_test.go b/plugin/kubernetes/ns_test.go index 8e9e80c71..20dfef1ec 100644 --- a/plugin/kubernetes/ns_test.go +++ b/plugin/kubernetes/ns_test.go @@ -3,53 +3,53 @@ package kubernetes import ( "testing" - "k8s.io/client-go/1.5/pkg/api" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/client-go/pkg/api/v1" ) type APIConnTest struct{} -func (APIConnTest) Run() { return } -func (APIConnTest) Stop() error { return nil } -func (APIConnTest) PodIndex(string) []interface{} { return nil } +func (APIConnTest) Run() { return } +func (APIConnTest) Stop() error { return nil } +func (APIConnTest) PodIndex(string) []*api.Pod { return nil } func (APIConnTest) ServiceList() []*api.Service { - svc := api.Service{ - ObjectMeta: api.ObjectMeta{ - Name: "dns-service", - Namespace: "kube-system", - }, - Spec: api.ServiceSpec{ - ClusterIP: "10.0.0.111", - }, - } - - return []*api.Service{&svc} - -} - -func (APIConnTest) EndpointsList() api.EndpointsList { - return api.EndpointsList{ - Items: []api.Endpoints{ - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "127.0.0.1", - }, - }, - }, - }, - ObjectMeta: api.ObjectMeta{ - Name: "dns-service", - Namespace: "kube-system", - }, + svcs := []*api.Service{ + { + ObjectMeta: meta.ObjectMeta{ + Name: "dns-service", + Namespace: "kube-system", + }, + Spec: api.ServiceSpec{ + ClusterIP: "10.0.0.111", }, }, } + return svcs } -func (APIConnTest) GetNodeByName(name string) (api.Node, error) { return api.Node{}, nil } +func (APIConnTest) EndpointsList() []*api.Endpoints { + eps := []*api.Endpoints{ + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "127.0.0.1", + }, + }, + }, + }, + ObjectMeta: meta.ObjectMeta{ + Name: "dns-service", + Namespace: "kube-system", + }, + }, + } + return eps +} + +func (APIConnTest) GetNodeByName(name string) (*api.Node, error) { return &api.Node{}, nil } func TestNsAddr(t *testing.T) { diff --git a/plugin/kubernetes/reverse.go b/plugin/kubernetes/reverse.go index 0143b721a..84baae964 100644 --- a/plugin/kubernetes/reverse.go +++ b/plugin/kubernetes/reverse.go @@ -25,9 +25,7 @@ func (k *Kubernetes) Reverse(state request.Request, exact bool, opt plugin.Optio // If a service cluster ip does not match, it checks all endpoints func (k *Kubernetes) serviceRecordForIP(ip, name string) []msg.Service { // First check services with cluster ips - svcList := k.APIConn.ServiceList() - - for _, service := range svcList { + for _, service := range k.APIConn.ServiceList() { if (len(k.Namespaces) > 0) && !k.namespaceExposed(service.Namespace) { continue } @@ -37,8 +35,7 @@ func (k *Kubernetes) serviceRecordForIP(ip, name string) []msg.Service { } } // If no cluster ips match, search endpoints - epList := k.APIConn.EndpointsList() - for _, ep := range epList.Items { + for _, ep := range k.APIConn.EndpointsList() { if (len(k.Namespaces) > 0) && !k.namespaceExposed(ep.ObjectMeta.Namespace) { continue } diff --git a/plugin/kubernetes/reverse_test.go b/plugin/kubernetes/reverse_test.go index d5b673be7..ca3d5a8b9 100644 --- a/plugin/kubernetes/reverse_test.go +++ b/plugin/kubernetes/reverse_test.go @@ -8,19 +8,20 @@ import ( "github.com/miekg/dns" "golang.org/x/net/context" - "k8s.io/client-go/1.5/pkg/api" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/client-go/pkg/api/v1" ) type APIConnReverseTest struct{} -func (APIConnReverseTest) Run() { return } -func (APIConnReverseTest) Stop() error { return nil } -func (APIConnReverseTest) PodIndex(string) []interface{} { return nil } +func (APIConnReverseTest) Run() { return } +func (APIConnReverseTest) Stop() error { return nil } +func (APIConnReverseTest) PodIndex(string) []*api.Pod { return nil } func (APIConnReverseTest) ServiceList() []*api.Service { svcs := []*api.Service{ { - ObjectMeta: api.ObjectMeta{ + ObjectMeta: meta.ObjectMeta{ Name: "svc1", Namespace: "testns", }, @@ -37,39 +38,38 @@ func (APIConnReverseTest) ServiceList() []*api.Service { return svcs } -func (APIConnReverseTest) EndpointsList() api.EndpointsList { - return api.EndpointsList{ - Items: []api.Endpoints{ - { - Subsets: []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{ - { - IP: "10.0.0.100", - Hostname: "ep1a", - }, +func (APIConnReverseTest) EndpointsList() []*api.Endpoints { + eps := []*api.Endpoints{ + { + Subsets: []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{ + { + IP: "10.0.0.100", + Hostname: "ep1a", }, - Ports: []api.EndpointPort{ - { - Port: 80, - Protocol: "tcp", - Name: "http", - }, + }, + Ports: []api.EndpointPort{ + { + Port: 80, + Protocol: "tcp", + Name: "http", }, }, }, - ObjectMeta: api.ObjectMeta{ - Name: "svc1", - Namespace: "testns", - }, + }, + ObjectMeta: meta.ObjectMeta{ + Name: "svc1", + Namespace: "testns", }, }, } + return eps } -func (APIConnReverseTest) GetNodeByName(name string) (api.Node, error) { - return api.Node{ - ObjectMeta: api.ObjectMeta{ +func (APIConnReverseTest) GetNodeByName(name string) (*api.Node, error) { + return &api.Node{ + ObjectMeta: meta.ObjectMeta{ Name: "test.node.foo.bar", }, }, nil diff --git a/plugin/kubernetes/setup.go b/plugin/kubernetes/setup.go index e60239d42..cc823d54e 100644 --- a/plugin/kubernetes/setup.go +++ b/plugin/kubernetes/setup.go @@ -11,10 +11,10 @@ import ( "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin/pkg/dnsutil" "github.com/coredns/coredns/plugin/proxy" - "github.com/miekg/dns" "github.com/mholt/caddy" - unversionedapi "k8s.io/client-go/1.5/pkg/api/unversioned" + "github.com/miekg/dns" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" ) func init() { @@ -150,7 +150,7 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, dnsControlOpts, error) { args := c.RemainingArgs() if len(args) > 0 { labelSelectorString := strings.Join(args, " ") - ls, err := unversionedapi.ParseToLabelSelector(labelSelectorString) + ls, err := meta.ParseToLabelSelector(labelSelectorString) if err != nil { return nil, opts, fmt.Errorf("unable to parse label selector value: '%v': %v", labelSelectorString, err) } diff --git a/plugin/kubernetes/setup_test.go b/plugin/kubernetes/setup_test.go index 2fdc38a9c..3f15ead06 100644 --- a/plugin/kubernetes/setup_test.go +++ b/plugin/kubernetes/setup_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/mholt/caddy" - "k8s.io/client-go/1.5/pkg/api/unversioned" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestKubernetesParse(t *testing.T) { @@ -431,7 +431,7 @@ func TestKubernetesParse(t *testing.T) { // Labels if opts.labelSelector != nil { - foundLabelSelectorString := unversioned.FormatLabelSelector(opts.labelSelector) + foundLabelSelectorString := meta.FormatLabelSelector(opts.labelSelector) if foundLabelSelectorString != test.expectedLabelSelector { t.Errorf("Test %d: Expected kubernetes controller to be initialized with label selector '%s'. Instead found selector '%s' for input '%s'", i, test.expectedLabelSelector, foundLabelSelectorString, test.input) } diff --git a/vendor/cloud.google.com/go/.travis.yml b/vendor/cloud.google.com/go/.travis.yml deleted file mode 100644 index 8c769d71f..000000000 --- a/vendor/cloud.google.com/go/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -sudo: false -language: go -go: -- 1.6 -- 1.7 -- 1.8 -install: -- go get -v cloud.google.com/go/... -script: -- openssl aes-256-cbc -K $encrypted_a8b3f4fc85f4_key -iv $encrypted_a8b3f4fc85f4_iv -in key.json.enc -out key.json -d -- GCLOUD_TESTS_GOLANG_PROJECT_ID="dulcet-port-762" GCLOUD_TESTS_GOLANG_KEY="$(pwd)/key.json" - ./run-tests.sh $TRAVIS_COMMIT -env: - matrix: - # The GCLOUD_TESTS_API_KEY environment variable. - secure: VdldogUOoubQ60LhuHJ+g/aJoBiujkSkWEWl79Zb8cvQorcQbxISS+JsOOp4QkUOU4WwaHAm8/3pIH1QMWOR6O78DaLmDKi5Q4RpkVdCpUXy+OAfQaZIcBsispMrjxLXnqFjo9ELnrArfjoeCTzaX0QTCfwQwVmigC8rR30JBKI= diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS deleted file mode 100644 index c364af1da..000000000 --- a/vendor/cloud.google.com/go/AUTHORS +++ /dev/null @@ -1,15 +0,0 @@ -# This is the official list of cloud authors for copyright purposes. -# This file is distinct from the CONTRIBUTORS files. -# See the latter for an explanation. - -# Names should be added to this file as: -# Name or Organization -# The email address is not required for organizations. - -Filippo Valsorda -Google Inc. -Ingo Oeser -Palm Stone Games, Inc. -Paweł Knap -Péter Szilágyi -Tyler Treat diff --git a/vendor/cloud.google.com/go/CONTRIBUTING.md b/vendor/cloud.google.com/go/CONTRIBUTING.md deleted file mode 100644 index aed05dc4f..000000000 --- a/vendor/cloud.google.com/go/CONTRIBUTING.md +++ /dev/null @@ -1,138 +0,0 @@ -# Contributing - -1. Sign one of the contributor license agreements below. -1. `go get golang.org/x/review/git-codereview` to install the code reviewing tool. - 1. You will need to ensure that your `GOBIN` directory (by default - `$GOPATH/bin`) is in your `PATH` so that git can find the command. - 1. If you would like, you may want to set up aliases for git-codereview, - such that `git codereview change` becomes `git change`. See the - [godoc](https://godoc.org/golang.org/x/review/git-codereview) for details. - 1. Should you run into issues with the git-codereview tool, please note - that all error messages will assume that you have set up these - aliases. -1. Get the cloud package by running `go get -d cloud.google.com/go`. - 1. If you have already checked out the source, make sure that the remote git - origin is https://code.googlesource.com/gocloud: - - git remote set-url origin https://code.googlesource.com/gocloud -1. Make sure your auth is configured correctly by visiting - https://code.googlesource.com, clicking "Generate Password", and following - the directions. -1. Make changes and create a change by running `git codereview change `, -provide a commit message, and use `git codereview mail` to create a Gerrit CL. -1. Keep amending to the change with `git codereview change` and mail as your receive -feedback. Each new mailed amendment will create a new patch set for your change in Gerrit. - -## Integration Tests - -In addition to the unit tests, you may run the integration test suite. - -To run the integrations tests, creating and configuration of a project in the -Google Developers Console is required. - -After creating a project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount). -Ensure the project-level **Owner** [IAM role](console.cloud.google.com/iam-admin/iam/project) -(or **Editor** and **Logs Configuration Writer** roles) are added to the -service account. - -Once you create a project, set the following environment variables to be able to -run the against the actual APIs. - -- **GCLOUD_TESTS_GOLANG_PROJECT_ID**: Developers Console project's ID (e.g. bamboo-shift-455) -- **GCLOUD_TESTS_GOLANG_KEY**: The path to the JSON key file. -- **GCLOUD_TESTS_API_KEY**: Your API key. - -Install the [gcloud command-line tool][gcloudcli] to your machine and use it -to create some resources used in integration tests. - -From the project's root directory: - -``` sh -# Set the default project in your env. -$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID - -# Authenticate the gcloud tool with your account. -$ gcloud auth login - -# Create the indexes used in the datastore integration tests. -$ gcloud preview datastore create-indexes datastore/testdata/index.yaml - -# Create a Google Cloud storage bucket with the same name as your test project, -# and with the Stackdriver Logging service account as owner, for the sink -# integration tests in logging. -$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID -$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID - -# Create a Spanner instance for the spanner integration tests. -$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 1 --description 'Instance for go client test' -# NOTE: Spanner instances are priced by the node-hour, so you may want to delete -# the instance after testing with 'gcloud beta spanner instances delete'. -``` - -Once you've set the environment variables, you can run the integration tests by -running: - -``` sh -$ go test -v cloud.google.com/go/... -``` - -## Contributor License Agreements - -Before we can accept your pull requests you'll need to sign a Contributor -License Agreement (CLA): - -- **If you are an individual writing original source code** and **you own the -- intellectual property**, then you'll need to sign an [individual CLA][indvcla]. -- **If you work for a company that wants to allow you to contribute your work**, -then you'll need to sign a [corporate CLA][corpcla]. - -You can sign these electronically (just scroll to the bottom). After that, -we'll be able to accept your pull requests. - -## Contributor Code of Conduct - -As contributors and maintainers of this project, -and in the interest of fostering an open and welcoming community, -we pledge to respect all people who contribute through reporting issues, -posting feature requests, updating documentation, -submitting pull requests or patches, and other activities. - -We are committed to making participation in this project -a harassment-free experience for everyone, -regardless of level of experience, gender, gender identity and expression, -sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, -such as physical or electronic -addresses, without explicit permission -* Other unethical or unprofessional conduct. - -Project maintainers have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct. -By adopting this Code of Conduct, -project maintainers commit themselves to fairly and consistently -applying these principles to every aspect of managing this project. -Project maintainers who do not follow or enforce the Code of Conduct -may be permanently removed from the project team. - -This code of conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. - -Instances of abusive, harassing, or otherwise unacceptable behavior -may be reported by opening an issue -or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, -available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) - -[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ -[indvcla]: https://developers.google.com/open-source/cla/individual -[corpcla]: https://developers.google.com/open-source/cla/corporate diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS deleted file mode 100644 index d4b376c7c..000000000 --- a/vendor/cloud.google.com/go/CONTRIBUTORS +++ /dev/null @@ -1,37 +0,0 @@ -# People who have agreed to one of the CLAs and can contribute patches. -# The AUTHORS file lists the copyright holders; this file -# lists people. For example, Google employees are listed here -# but not in AUTHORS, because Google holds the copyright. -# -# https://developers.google.com/open-source/cla/individual -# https://developers.google.com/open-source/cla/corporate -# -# Names should be added to this file as: -# Name - -# Keep the list alphabetically sorted. - -Alexis Hunt -Andreas Litt -Andrew Gerrand -Brad Fitzpatrick -Burcu Dogan -Dave Day -David Sansome -David Symonds -Filippo Valsorda -Glenn Lewis -Ingo Oeser -Johan Euphrosine -Jonathan Amsterdam -Luna Duclos -Magnus Hiie -Michael McGreevy -Omar Jarjur -Paweł Knap -Péter Szilágyi -Sarah Adams -Thanatat Tamtan -Toby Burress -Tuo Shan -Tyler Treat diff --git a/vendor/cloud.google.com/go/MIGRATION.md b/vendor/cloud.google.com/go/MIGRATION.md deleted file mode 100644 index 791210de1..000000000 --- a/vendor/cloud.google.com/go/MIGRATION.md +++ /dev/null @@ -1,54 +0,0 @@ -# Code Changes - -## v0.10.0 - -- pubsub: Replace - - ``` - sub.ModifyPushConfig(ctx, pubsub.PushConfig{Endpoint: "https://example.com/push"}) - ``` - - with - - ``` - sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{ - PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"}, - }) - ``` - -- trace: traceGRPCServerInterceptor will be provided from *trace.Client. -Given an initialized `*trace.Client` named `tc`, instead of - - ``` - s := grpc.NewServer(grpc.UnaryInterceptor(trace.GRPCServerInterceptor(tc))) - ``` - - write - - ``` - s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor())) - ``` - -- trace trace.GRPCClientInterceptor will also provided from *trace.Client. -Instead of - - ``` - conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor())) - ``` - - write - - ``` - conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) - ``` - -- trace: We removed the deprecated `trace.EnableGRPCTracing`. Use the gRPC -interceptor as a dial option as shown below when initializing Cloud package -clients: - - ``` - c, err := pubsub.NewClient(ctx, "project-id", option.WithGRPCDialOption(grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor()))) - if err != nil { - ... - } - ``` diff --git a/vendor/cloud.google.com/go/README.md b/vendor/cloud.google.com/go/README.md deleted file mode 100644 index 937a528b9..000000000 --- a/vendor/cloud.google.com/go/README.md +++ /dev/null @@ -1,482 +0,0 @@ -# Google Cloud Client Libraries for Go - -[![GoDoc](https://godoc.org/cloud.google.com/go?status.svg)](https://godoc.org/cloud.google.com/go) - -Go packages for [Google Cloud Platform](https://cloud.google.com) services. - -``` go -import "cloud.google.com/go" -``` - -To install the packages on your system, - -``` -$ go get -u cloud.google.com/go/... -``` - -**NOTE:** Some of these packages are under development, and may occasionally -make backwards-incompatible changes. - -**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud). - - * [News](#news) - * [Supported APIs](#supported-apis) - * [Go Versions Supported](#go-versions-supported) - * [Authorization](#authorization) - * [Cloud Datastore](#cloud-datastore-) - * [Cloud Storage](#cloud-storage-) - * [Cloud Pub/Sub](#cloud-pub-sub-) - * [Cloud BigQuery](#cloud-bigquery-) - * [Stackdriver Logging](#stackdriver-logging-) - * [Cloud Spanner](#cloud-spanner-) - - -## News - -_August 22, 2017+ - -*v0.12.0* - -- pubsub: Subscription.Receive now uses streaming pull. - -- pubsub: add Client.TopicInProject to access topics in a different project - than the client. - -- errors: renamed errorreporting. The errors package will be removed shortly. - -- datastore: improved retry behavior. - -- bigquery: support updates to dataset metadata, with etags. - -- bigquery: add etag support to Table.Update (BREAKING: etag argument added). - -- bigquery: generate all job IDs on the client. - -- storage: support bucket lifecycle configurations. - - -_July 31, 2017_ - -*v0.11.0* - -- Clients for spanner, pubsub and video are now in beta. - -- New client for DLP. - -- spanner: performance and testing improvements. - -- storage: requester-pays buckets are supported. - -- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements. - -- pubsub: bug fixes and other minor improvements - -_June 17, 2017_ - - -*v0.10.0* - -- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update. - -- pubsub: Subscription.Receive now runs concurrently for higher throughput. - -- vision: cloud.google.com/go/vision is deprecated. Use -cloud.google.com/go/vision/apiv1 instead. - -- translation: now stable. - -- trace: several changes to the surface. See the link below. - -[Code changes required from v0.9.0.](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/MIGRATION.md) - - -[Older news](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/old-news.md) - -## Supported APIs - -Google API | Status | Package ----------------------------------|--------------|----------------------------------------------------------- -[Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`][cloud-datastore-ref] -[Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`][cloud-storage-ref] -[Bigtable][cloud-bigtable] | beta | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref] -[BigQuery][cloud-bigquery] | beta | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref] -[Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`][cloud-logging-ref] -[Monitoring][cloud-monitoring] | alpha | [`cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref] -[Pub/Sub][cloud-pubsub] | beta | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref] -[Vision][cloud-vision] | beta | [`cloud.google.com/go/vision/apiv1`][cloud-vision-ref] -[Language][cloud-language] | beta | [`cloud.google.com/go/language/apiv1`][cloud-language-ref] -[Speech][cloud-speech] | beta | [`cloud.google.com/go/speech/apiv1`][cloud-speech-ref] -[Spanner][cloud-spanner] | beta | [`cloud.google.com/go/spanner`][cloud-spanner-ref] -[Translation][cloud-translation] | stable | [`cloud.google.com/go/translate`][cloud-translation-ref] -[Trace][cloud-trace] | alpha | [`cloud.google.com/go/trace`][cloud-trace-ref] -[Video Intelligence][cloud-video]| beta | [`cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref] -[ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`][cloud-errors-ref] - - -> **Alpha status**: the API is still being actively developed. As a -> result, it might change in backward-incompatible ways and is not recommended -> for production use. -> -> **Beta status**: the API is largely complete, but still has outstanding -> features and bugs to be addressed. There may be minor backwards-incompatible -> changes where necessary. -> -> **Stable status**: the API is mature and ready for production use. We will -> continue addressing bugs and feature requests. - -Documentation and examples are available at -https://godoc.org/cloud.google.com/go - -Visit or join the -[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce) -for updates on these packages. - -## Go Versions Supported - -We support the two most recent major versions of Go. If Google App Engine uses -an older version, we support that as well. You can see which versions are -currently supported by looking at the lines following `go:` in -[`.travis.yml`](.travis.yml). - -## Authorization - -By default, each API will use [Google Application Default Credentials][default-creds] -for authorization credentials used in calling the API endpoints. This will allow your -application to run in many environments without requiring explicit configuration. - -[snip]:# (auth) -```go -client, err := storage.NewClient(ctx) -``` - -To authorize using a -[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys), -pass -[`option.WithServiceAccountFile`](https://godoc.org/google.golang.org/api/option#WithServiceAccountFile) -to the `NewClient` function of the desired package. For example: - -[snip]:# (auth-JSON) -```go -client, err := storage.NewClient(ctx, option.WithServiceAccountFile("path/to/keyfile.json")) -``` - -You can exert more control over authorization by using the -[`golang.org/x/oauth2`](https://godoc.org/golang.org/x/oauth2) package to -create an `oauth2.TokenSource`. Then pass -[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource) -to the `NewClient` function: -[snip]:# (auth-ts) -```go -tokenSource := ... -client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource)) -``` - -## Cloud Datastore [![GoDoc](https://godoc.org/cloud.google.com/go/datastore?status.svg)](https://godoc.org/cloud.google.com/go/datastore) - -- [About Cloud Datastore][cloud-datastore] -- [Activating the API for your project][cloud-datastore-activation] -- [API documentation][cloud-datastore-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore) -- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks) - -### Example Usage - -First create a `datastore.Client` to use throughout your application: - -[snip]:# (datastore-1) -```go -client, err := datastore.NewClient(ctx, "my-project-id") -if err != nil { - log.Fatal(err) -} -``` - -Then use that client to interact with the API: - -[snip]:# (datastore-2) -```go -type Post struct { - Title string - Body string `datastore:",noindex"` - PublishedAt time.Time -} -keys := []*datastore.Key{ - datastore.NameKey("Post", "post1", nil), - datastore.NameKey("Post", "post2", nil), -} -posts := []*Post{ - {Title: "Post 1", Body: "...", PublishedAt: time.Now()}, - {Title: "Post 2", Body: "...", PublishedAt: time.Now()}, -} -if _, err := client.PutMulti(ctx, keys, posts); err != nil { - log.Fatal(err) -} -``` - -## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage) - -- [About Cloud Storage][cloud-storage] -- [API documentation][cloud-storage-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/storage) -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage) - -### Example Usage - -First create a `storage.Client` to use throughout your application: - -[snip]:# (storage-1) -```go -client, err := storage.NewClient(ctx) -if err != nil { - log.Fatal(err) -} -``` - -[snip]:# (storage-2) -```go -// Read the object1 from bucket. -rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx) -if err != nil { - log.Fatal(err) -} -defer rc.Close() -body, err := ioutil.ReadAll(rc) -if err != nil { - log.Fatal(err) -} -``` - -## Cloud Pub/Sub [![GoDoc](https://godoc.org/cloud.google.com/go/pubsub?status.svg)](https://godoc.org/cloud.google.com/go/pubsub) - -- [About Cloud Pubsub][cloud-pubsub] -- [API documentation][cloud-pubsub-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub) -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub) - -### Example Usage - -First create a `pubsub.Client` to use throughout your application: - -[snip]:# (pubsub-1) -```go -client, err := pubsub.NewClient(ctx, "project-id") -if err != nil { - log.Fatal(err) -} -``` - -Then use the client to publish and subscribe: - -[snip]:# (pubsub-2) -```go -// Publish "hello world" on topic1. -topic := client.Topic("topic1") -res := topic.Publish(ctx, &pubsub.Message{ - Data: []byte("hello world"), -}) -// The publish happens asynchronously. -// Later, you can get the result from res: -... -msgID, err := res.Get(ctx) -if err != nil { - log.Fatal(err) -} - -// Use a callback to receive messages via subscription1. -sub := client.Subscription("subscription1") -err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { - fmt.Println(m.Data) - m.Ack() // Acknowledge that we've consumed the message. -}) -if err != nil { - log.Println(err) -} -``` - -## Cloud BigQuery [![GoDoc](https://godoc.org/cloud.google.com/go/bigquery?status.svg)](https://godoc.org/cloud.google.com/go/bigquery) - -- [About Cloud BigQuery][cloud-bigquery] -- [API documentation][cloud-bigquery-docs] -- [Go client documentation][cloud-bigquery-ref] -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery) - -### Example Usage - -First create a `bigquery.Client` to use throughout your application: -[snip]:# (bq-1) -```go -c, err := bigquery.NewClient(ctx, "my-project-ID") -if err != nil { - // TODO: Handle error. -} -``` - -Then use that client to interact with the API: -[snip]:# (bq-2) -```go -// Construct a query. -q := c.Query(` - SELECT year, SUM(number) - FROM [bigquery-public-data:usa_names.usa_1910_2013] - WHERE name = "William" - GROUP BY year - ORDER BY year -`) -// Execute the query. -it, err := q.Read(ctx) -if err != nil { - // TODO: Handle error. -} -// Iterate through the results. -for { - var values []bigquery.Value - err := it.Next(&values) - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - fmt.Println(values) -} -``` - - -## Stackdriver Logging [![GoDoc](https://godoc.org/cloud.google.com/go/logging?status.svg)](https://godoc.org/cloud.google.com/go/logging) - -- [About Stackdriver Logging][cloud-logging] -- [API documentation][cloud-logging-docs] -- [Go client documentation][cloud-logging-ref] -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging) - -### Example Usage - -First create a `logging.Client` to use throughout your application: -[snip]:# (logging-1) -```go -ctx := context.Background() -client, err := logging.NewClient(ctx, "my-project") -if err != nil { - // TODO: Handle error. -} -``` - -Usually, you'll want to add log entries to a buffer to be periodically flushed -(automatically and asynchronously) to the Stackdriver Logging service. -[snip]:# (logging-2) -```go -logger := client.Logger("my-log") -logger.Log(logging.Entry{Payload: "something happened!"}) -``` - -Close your client before your program exits, to flush any buffered log entries. -[snip]:# (logging-3) -```go -err = client.Close() -if err != nil { - // TODO: Handle error. -} -``` - -## Cloud Spanner [![GoDoc](https://godoc.org/cloud.google.com/go/spanner?status.svg)](https://godoc.org/cloud.google.com/go/spanner) - -- [About Cloud Spanner][cloud-spanner] -- [API documentation][cloud-spanner-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner) - -### Example Usage - -First create a `spanner.Client` to use throughout your application: - -[snip]:# (spanner-1) -```go -client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D") -if err != nil { - log.Fatal(err) -} -``` - -[snip]:# (spanner-2) -```go -// Simple Reads And Writes -_, err = client.Apply(ctx, []*spanner.Mutation{ - spanner.Insert("Users", - []string{"name", "email"}, - []interface{}{"alice", "a@example.com"})}) -if err != nil { - log.Fatal(err) -} -row, err := client.Single().ReadRow(ctx, "Users", - spanner.Key{"alice"}, []string{"email"}) -if err != nil { - log.Fatal(err) -} -``` - - -## Contributing - -Contributions are welcome. Please, see the -[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md) -document for details. We're using Gerrit for our code reviews. Please don't open pull -requests against this repo, new pull requests will be automatically closed. - -Please note that this project is released with a Contributor Code of Conduct. -By participating in this project you agree to abide by its terms. -See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct) -for more information. - -[cloud-datastore]: https://cloud.google.com/datastore/ -[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore -[cloud-datastore-docs]: https://cloud.google.com/datastore/docs -[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate - -[cloud-pubsub]: https://cloud.google.com/pubsub/ -[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub -[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs - -[cloud-storage]: https://cloud.google.com/storage/ -[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage -[cloud-storage-docs]: https://cloud.google.com/storage/docs -[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets - -[cloud-bigtable]: https://cloud.google.com/bigtable/ -[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable - -[cloud-bigquery]: https://cloud.google.com/bigquery/ -[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs -[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery - -[cloud-logging]: https://cloud.google.com/logging/ -[cloud-logging-docs]: https://cloud.google.com/logging/docs -[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging - -[cloud-monitoring]: https://cloud.google.com/monitoring/ -[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3 - -[cloud-vision]: https://cloud.google.com/vision -[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1 - -[cloud-language]: https://cloud.google.com/natural-language -[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1 - -[cloud-speech]: https://cloud.google.com/speech -[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1 - -[cloud-spanner]: https://cloud.google.com/spanner/ -[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner -[cloud-spanner-docs]: https://cloud.google.com/spanner/docs - -[cloud-translation]: https://cloud.google.com/translation -[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation - -[cloud-trace]: https://cloud.google.com/trace/ -[cloud-trace-ref]: https://godoc.org/cloud.google.com/go/trace - -[cloud-video]: https://cloud.google.com/video-intelligence/ -[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1 - -[cloud-errors]: https://cloud.google.com/error-reporting/ -[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting - -[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials diff --git a/vendor/cloud.google.com/go/appveyor.yml b/vendor/cloud.google.com/go/appveyor.yml deleted file mode 100644 index e66cd00af..000000000 --- a/vendor/cloud.google.com/go/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -# This file configures AppVeyor (http://www.appveyor.com), -# a Windows-based CI service similar to Travis. - -# Identifier for this run -version: "{build}" - -# Clone the repo into this path, which conforms to the standard -# Go workspace structure. -clone_folder: c:\gopath\src\cloud.google.com\go - -environment: - GOPATH: c:\gopath - GCLOUD_TESTS_GOLANG_PROJECT_ID: dulcet-port-762 - GCLOUD_TESTS_GOLANG_KEY: c:\gopath\src\cloud.google.com\go\key.json - KEYFILE_CONTENTS: - secure: IvRbDAhM2PIQqzVkjzJ4FjizUvoQ+c3vG/qhJQG+HlZ/L5KEkqLu+x6WjLrExrNMyGku4znB2jmbTrUW3Ob4sGG+R5vvqeQ3YMHCVIkw5CxY+/bUDkW5RZWsVbuCnNa/vKsWmCP+/sZW6ICe29yKJ2ZOb6QaauI4s9R6j+cqBbU9pumMGYFRb0Rw3uUU7DKmVFCy+NjTENZIlDP9rmjANgAzigowJJEb2Tg9sLlQKmQeKiBSRN8lKc5Nq60a+fIzHGKvql4eIitDDDpOpyHv15/Xr1BzFw2yDoiR4X1lng0u7q0X9RgX4VIYa6gT16NXBEmQgbuX8gh7SfPMp9RhiZD9sVUaV+yogEabYpyPnmUURo0hXwkctKaBkQlEmKvjHwF5dvbg8+yqGhwtjAgFNimXG3INrwQsfQsZskkQWanutbJf9xy50GyWWFZZdi0uT4oXP/b5P7aklPXKXsvrJKBh7RjEaqBrhi86IJwOjBspvoR4l2WmcQyxb2xzQS1pjbBJFQfYJJ8+JgsstTL8PBO9d4ybJC0li1Om1qnWxkaewvPxxuoHJ9LpRKof19yRYWBmhTXb2tTASKG/zslvl4fgG4DmQBS93WC7dsiGOhAraGw2eCTgd0lYZOhk1FjWl9TS80aktXxzH/7nTvem5ohm+eDl6O0wnTL4KXjQVNSQ1PyLn4lGRJ5MNGzBTRFWIr2API2rca4Fysyfh/UdmazPGlNbY9JPGqb9+F04QzLfqm+Zz/cHy59E7lOSMBlUI4KD6d6ZNNKNRH+/g9i+fSiyiXKugTfda8KBnWGyPwprxuWGYaiQUGUYOwJY5R6x5c4mjImAB310V+Wo33UbWFJiwxEDsiCNqW1meVkBzt2er26vh4qbgCUIQ3iM3gFPfHgy+QxkmIhic7Q1HYacQElt8AAP41M7cCKWCuZidegP37MBB//mjjiNt047ZSQEvB4tqsX/OvfbByVef+cbtVw9T0yjHvmCdPW1XrhyrCCgclu6oYYdbmc5D7BBDRbjjMWGv6YvceAbfGf6ukdB5PuV+TGEN/FoQ1QTRA6Aqf+3fLMg4mS4oyTfw5xyYNbv3qoyLPrp+BnxI53WB9p0hfMg4n9FD6NntBxjDq+Q3Lk/bjC/Y4MaRWdzbMzF9a0lgGfcw9DURlK5p7uGJC9vg34feNoQprxVEZRQ01cHLeob6eGkYm4HxSRx8JY39Mh+9wzJo+k/aIvFleNC3e35NOrkXr6wb5e42n2DwBdPqdNolTLtLFRglAL1LTpp27UjvjieWJAKfoDTR5CKl01sZqt0wPdLLcvsMj6CiPFmccUIOYeZMe86kLBD61Qa5F1EwkgO3Om2qSjW96FzL4skRc+BmU5RrHlAFSldR1wpUgtkUMv9vH5Cy+UJdcvpZ8KbmhZ2PsjF7ddJ1ve9RAw3cP325AyIMwZ77Ef1mgTM0NJze6eSW1qKlEsgt1FADPyeUu1NQTA2H2dueMPGlArWTSUgyWR9AdfpqouT7eg0JWI5w+yUZZC+/rPglYbt84oLmYpwuli0z8FyEQRPIc3EtkfWIv/yYgDr2TZ0N2KvGfpi/MAUWgxI1gleC2uKgEOEtuJthd3XZjF2NoE7IBqjQOINybcJOjyeB5vRLDY1FLuxYzdg1y1etkV4XQig/vje - -install: - # Info for debugging. - - echo %PATH% - - go version - - go env - - go get -v -d -t ./... - - -# Provide a build script, or AppVeyor will call msbuild. -build_script: - - go install -v ./... - - echo %KEYFILE_CONTENTS% > %GCLOUD_TESTS_GOLANG_KEY% - -test_script: - - go test -v ./... diff --git a/vendor/cloud.google.com/go/authexample_test.go b/vendor/cloud.google.com/go/authexample_test.go deleted file mode 100644 index fe75467f9..000000000 --- a/vendor/cloud.google.com/go/authexample_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloud_test - -import ( - "cloud.google.com/go/datastore" - "golang.org/x/net/context" - "google.golang.org/api/option" -) - -func Example_applicationDefaultCredentials() { - // Google Application Default Credentials is the recommended way to authorize - // and authenticate clients. - // - // See the following link on how to create and obtain Application Default Credentials: - // https://developers.google.com/identity/protocols/application-default-credentials. - client, err := datastore.NewClient(context.Background(), "project-id") - if err != nil { - // TODO: handle error. - } - _ = client // Use the client. -} - -func Example_serviceAccountFile() { - // Use a JSON key file associated with a Google service account to - // authenticate and authorize. Service Account keys can be created and - // downloaded from https://console.developers.google.com/permissions/serviceaccounts. - // - // Note: This example uses the datastore client, but the same steps apply to - // the other client libraries underneath this package. - client, err := datastore.NewClient(context.Background(), - "project-id", option.WithServiceAccountFile("/path/to/service-account-key.json")) - if err != nil { - // TODO: handle error. - } - _ = client // Use the client. -} diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go deleted file mode 100644 index e708c031b..000000000 --- a/vendor/cloud.google.com/go/compute/metadata/metadata.go +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package metadata provides access to Google Compute Engine (GCE) -// metadata and API service accounts. -// -// This package is a wrapper around the GCE metadata service, -// as documented at https://developers.google.com/compute/docs/metadata. -package metadata // import "cloud.google.com/go/compute/metadata" - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "runtime" - "strings" - "sync" - "time" - - "golang.org/x/net/context" - "golang.org/x/net/context/ctxhttp" -) - -const ( - // metadataIP is the documented metadata server IP address. - metadataIP = "169.254.169.254" - - // metadataHostEnv is the environment variable specifying the - // GCE metadata hostname. If empty, the default value of - // metadataIP ("169.254.169.254") is used instead. - // This is variable name is not defined by any spec, as far as - // I know; it was made up for the Go package. - metadataHostEnv = "GCE_METADATA_HOST" - - userAgent = "gcloud-golang/0.1" -) - -type cachedValue struct { - k string - trim bool - mu sync.Mutex - v string -} - -var ( - projID = &cachedValue{k: "project/project-id", trim: true} - projNum = &cachedValue{k: "project/numeric-project-id", trim: true} - instID = &cachedValue{k: "instance/id", trim: true} -) - -var ( - metaClient = &http.Client{ - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 2 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - ResponseHeaderTimeout: 2 * time.Second, - }, - } - subscribeClient = &http.Client{ - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 2 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - }, - } -) - -// NotDefinedError is returned when requested metadata is not defined. -// -// The underlying string is the suffix after "/computeMetadata/v1/". -// -// This error is not returned if the value is defined to be the empty -// string. -type NotDefinedError string - -func (suffix NotDefinedError) Error() string { - return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix)) -} - -// Get returns a value from the metadata service. -// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". -// -// If the GCE_METADATA_HOST environment variable is not defined, a default of -// 169.254.169.254 will be used instead. -// -// If the requested metadata is not defined, the returned error will -// be of type NotDefinedError. -func Get(suffix string) (string, error) { - val, _, err := getETag(metaClient, suffix) - return val, err -} - -// getETag returns a value from the metadata service as well as the associated -// ETag using the provided client. This func is otherwise equivalent to Get. -func getETag(client *http.Client, suffix string) (value, etag string, err error) { - // Using a fixed IP makes it very difficult to spoof the metadata service in - // a container, which is an important use-case for local testing of cloud - // deployments. To enable spoofing of the metadata service, the environment - // variable GCE_METADATA_HOST is first inspected to decide where metadata - // requests shall go. - host := os.Getenv(metadataHostEnv) - if host == "" { - // Using 169.254.169.254 instead of "metadata" here because Go - // binaries built with the "netgo" tag and without cgo won't - // know the search suffix for "metadata" is - // ".google.internal", and this IP address is documented as - // being stable anyway. - host = metadataIP - } - url := "http://" + host + "/computeMetadata/v1/" + suffix - req, _ := http.NewRequest("GET", url, nil) - req.Header.Set("Metadata-Flavor", "Google") - req.Header.Set("User-Agent", userAgent) - res, err := client.Do(req) - if err != nil { - return "", "", err - } - defer res.Body.Close() - if res.StatusCode == http.StatusNotFound { - return "", "", NotDefinedError(suffix) - } - if res.StatusCode != 200 { - return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url) - } - all, err := ioutil.ReadAll(res.Body) - if err != nil { - return "", "", err - } - return string(all), res.Header.Get("Etag"), nil -} - -func getTrimmed(suffix string) (s string, err error) { - s, err = Get(suffix) - s = strings.TrimSpace(s) - return -} - -func (c *cachedValue) get() (v string, err error) { - defer c.mu.Unlock() - c.mu.Lock() - if c.v != "" { - return c.v, nil - } - if c.trim { - v, err = getTrimmed(c.k) - } else { - v, err = Get(c.k) - } - if err == nil { - c.v = v - } - return -} - -var ( - onGCEOnce sync.Once - onGCE bool -) - -// OnGCE reports whether this process is running on Google Compute Engine. -func OnGCE() bool { - onGCEOnce.Do(initOnGCE) - return onGCE -} - -func initOnGCE() { - onGCE = testOnGCE() -} - -func testOnGCE() bool { - // The user explicitly said they're on GCE, so trust them. - if os.Getenv(metadataHostEnv) != "" { - return true - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resc := make(chan bool, 2) - - // Try two strategies in parallel. - // See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194 - go func() { - req, _ := http.NewRequest("GET", "http://"+metadataIP, nil) - req.Header.Set("User-Agent", userAgent) - res, err := ctxhttp.Do(ctx, metaClient, req) - if err != nil { - resc <- false - return - } - defer res.Body.Close() - resc <- res.Header.Get("Metadata-Flavor") == "Google" - }() - - go func() { - addrs, err := net.LookupHost("metadata.google.internal") - if err != nil || len(addrs) == 0 { - resc <- false - return - } - resc <- strsContains(addrs, metadataIP) - }() - - tryHarder := systemInfoSuggestsGCE() - if tryHarder { - res := <-resc - if res { - // The first strategy succeeded, so let's use it. - return true - } - // Wait for either the DNS or metadata server probe to - // contradict the other one and say we are running on - // GCE. Give it a lot of time to do so, since the system - // info already suggests we're running on a GCE BIOS. - timer := time.NewTimer(5 * time.Second) - defer timer.Stop() - select { - case res = <-resc: - return res - case <-timer.C: - // Too slow. Who knows what this system is. - return false - } - } - - // There's no hint from the system info that we're running on - // GCE, so use the first probe's result as truth, whether it's - // true or false. The goal here is to optimize for speed for - // users who are NOT running on GCE. We can't assume that - // either a DNS lookup or an HTTP request to a blackholed IP - // address is fast. Worst case this should return when the - // metaClient's Transport.ResponseHeaderTimeout or - // Transport.Dial.Timeout fires (in two seconds). - return <-resc -} - -// systemInfoSuggestsGCE reports whether the local system (without -// doing network requests) suggests that we're running on GCE. If this -// returns true, testOnGCE tries a bit harder to reach its metadata -// server. -func systemInfoSuggestsGCE() bool { - if runtime.GOOS != "linux" { - // We don't have any non-Linux clues available, at least yet. - return false - } - slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name") - name := strings.TrimSpace(string(slurp)) - return name == "Google" || name == "Google Compute Engine" -} - -// Subscribe subscribes to a value from the metadata service. -// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". -// The suffix may contain query parameters. -// -// Subscribe calls fn with the latest metadata value indicated by the provided -// suffix. If the metadata value is deleted, fn is called with the empty string -// and ok false. Subscribe blocks until fn returns a non-nil error or the value -// is deleted. Subscribe returns the error value returned from the last call to -// fn, which may be nil when ok == false. -func Subscribe(suffix string, fn func(v string, ok bool) error) error { - const failedSubscribeSleep = time.Second * 5 - - // First check to see if the metadata value exists at all. - val, lastETag, err := getETag(subscribeClient, suffix) - if err != nil { - return err - } - - if err := fn(val, true); err != nil { - return err - } - - ok := true - if strings.ContainsRune(suffix, '?') { - suffix += "&wait_for_change=true&last_etag=" - } else { - suffix += "?wait_for_change=true&last_etag=" - } - for { - val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag)) - if err != nil { - if _, deleted := err.(NotDefinedError); !deleted { - time.Sleep(failedSubscribeSleep) - continue // Retry on other errors. - } - ok = false - } - lastETag = etag - - if err := fn(val, ok); err != nil || !ok { - return err - } - } -} - -// ProjectID returns the current instance's project ID string. -func ProjectID() (string, error) { return projID.get() } - -// NumericProjectID returns the current instance's numeric project ID. -func NumericProjectID() (string, error) { return projNum.get() } - -// InternalIP returns the instance's primary internal IP address. -func InternalIP() (string, error) { - return getTrimmed("instance/network-interfaces/0/ip") -} - -// ExternalIP returns the instance's primary external (public) IP address. -func ExternalIP() (string, error) { - return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip") -} - -// Hostname returns the instance's hostname. This will be of the form -// ".c..internal". -func Hostname() (string, error) { - return getTrimmed("instance/hostname") -} - -// InstanceTags returns the list of user-defined instance tags, -// assigned when initially creating a GCE instance. -func InstanceTags() ([]string, error) { - var s []string - j, err := Get("instance/tags") - if err != nil { - return nil, err - } - if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil { - return nil, err - } - return s, nil -} - -// InstanceID returns the current VM's numeric instance ID. -func InstanceID() (string, error) { - return instID.get() -} - -// InstanceName returns the current VM's instance ID string. -func InstanceName() (string, error) { - host, err := Hostname() - if err != nil { - return "", err - } - return strings.Split(host, ".")[0], nil -} - -// Zone returns the current VM's zone, such as "us-central1-b". -func Zone() (string, error) { - zone, err := getTrimmed("instance/zone") - // zone is of the form "projects//zones/". - if err != nil { - return "", err - } - return zone[strings.LastIndex(zone, "/")+1:], nil -} - -// InstanceAttributes returns the list of user-defined attributes, -// assigned when initially creating a GCE VM instance. The value of an -// attribute can be obtained with InstanceAttributeValue. -func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") } - -// ProjectAttributes returns the list of user-defined attributes -// applying to the project as a whole, not just this VM. The value of -// an attribute can be obtained with ProjectAttributeValue. -func ProjectAttributes() ([]string, error) { return lines("project/attributes/") } - -func lines(suffix string) ([]string, error) { - j, err := Get(suffix) - if err != nil { - return nil, err - } - s := strings.Split(strings.TrimSpace(j), "\n") - for i := range s { - s[i] = strings.TrimSpace(s[i]) - } - return s, nil -} - -// InstanceAttributeValue returns the value of the provided VM -// instance attribute. -// -// If the requested attribute is not defined, the returned error will -// be of type NotDefinedError. -// -// InstanceAttributeValue may return ("", nil) if the attribute was -// defined to be the empty string. -func InstanceAttributeValue(attr string) (string, error) { - return Get("instance/attributes/" + attr) -} - -// ProjectAttributeValue returns the value of the provided -// project attribute. -// -// If the requested attribute is not defined, the returned error will -// be of type NotDefinedError. -// -// ProjectAttributeValue may return ("", nil) if the attribute was -// defined to be the empty string. -func ProjectAttributeValue(attr string) (string, error) { - return Get("project/attributes/" + attr) -} - -// Scopes returns the service account scopes for the given account. -// The account may be empty or the string "default" to use the instance's -// main account. -func Scopes(serviceAccount string) ([]string, error) { - if serviceAccount == "" { - serviceAccount = "default" - } - return lines("instance/service-accounts/" + serviceAccount + "/scopes") -} - -func strsContains(ss []string, s string) bool { - for _, v := range ss { - if v == s { - return true - } - } - return false -} diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go deleted file mode 100644 index 9ac592691..000000000 --- a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metadata - -import ( - "os" - "sync" - "testing" -) - -func TestOnGCE_Stress(t *testing.T) { - if testing.Short() { - t.Skip("skipping in -short mode") - } - var last bool - for i := 0; i < 100; i++ { - onGCEOnce = sync.Once{} - - now := OnGCE() - if i > 0 && now != last { - t.Errorf("%d. changed from %v to %v", i, last, now) - } - last = now - } - t.Logf("OnGCE() = %v", last) -} - -func TestOnGCE_Force(t *testing.T) { - onGCEOnce = sync.Once{} - old := os.Getenv(metadataHostEnv) - defer os.Setenv(metadataHostEnv, old) - os.Setenv(metadataHostEnv, "127.0.0.1") - if !OnGCE() { - t.Error("OnGCE() = false; want true") - } -} diff --git a/vendor/cloud.google.com/go/key.json.enc b/vendor/cloud.google.com/go/key.json.enc deleted file mode 100644 index a8978a901..000000000 Binary files a/vendor/cloud.google.com/go/key.json.enc and /dev/null differ diff --git a/vendor/cloud.google.com/go/license_test.go b/vendor/cloud.google.com/go/license_test.go deleted file mode 100644 index 4b87878a0..000000000 --- a/vendor/cloud.google.com/go/license_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloud - -import ( - "bytes" - "io/ioutil" - "os" - "path/filepath" - "strings" - "testing" -) - -var sentinels = []string{ - "Copyright", - "Google Inc", - `Licensed under the Apache License, Version 2.0 (the "License");`, -} - -func TestLicense(t *testing.T) { - err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if ext := filepath.Ext(path); ext != ".go" && ext != ".proto" { - return nil - } - if strings.HasSuffix(path, ".pb.go") { - // .pb.go files are generated from the proto files. - // .proto files must have license headers. - return nil - } - if path == "bigtable/cmd/cbt/cbtdoc.go" { - // Automatically generated. - return nil - } - - src, err := ioutil.ReadFile(path) - if err != nil { - return nil - } - src = src[:140] // Ensure all of the sentinel values are at the top of the file. - - // Find license - for _, sentinel := range sentinels { - if !bytes.Contains(src, []byte(sentinel)) { - t.Errorf("%v: license header not present. want %q", path, sentinel) - return nil - } - } - - return nil - }) - if err != nil { - t.Fatal(err) - } -} diff --git a/vendor/cloud.google.com/go/old-news.md b/vendor/cloud.google.com/go/old-news.md deleted file mode 100644 index 7b3ee4448..000000000 --- a/vendor/cloud.google.com/go/old-news.md +++ /dev/null @@ -1,451 +0,0 @@ -_March 17, 2017_ - -Breaking Pubsub changes. -* Publish is now asynchronous -([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)). -* Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)). -* Message.Done replaced with Message.Ack and Message.Nack. - -_February 14, 2017_ - -Release of a client library for Spanner. See -the -[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html). - -Note that although the Spanner service is beta, the Go client library is alpha. - -_December 12, 2016_ - -Beta release of BigQuery, DataStore, Logging and Storage. See the -[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html). - -Also, BigQuery now supports structs. Read a row directly into a struct with -`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`. -You can also use field tags. See the [package documentation][cloud-bigquery-ref] -for details. - -_December 5, 2016_ - -More changes to BigQuery: - -* The `ValueList` type was removed. It is no longer necessary. Instead of - ```go - var v ValueList - ... it.Next(&v) .. - ``` - use - - ```go - var v []Value - ... it.Next(&v) ... - ``` - -* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or - `ValueList` would append to the slice. Now each call resets the size to zero first. - -* Schema inference will infer the SQL type BYTES for a struct field of - type []byte. Previously it inferred STRING. - -* The types `uint`, `uint64` and `uintptr` are no longer supported in schema - inference. BigQuery's integer type is INT64, and those types may hold values - that are not correctly represented in a 64-bit signed integer. - -* The SQL types DATE, TIME and DATETIME are now supported. They correspond to - the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil` - package. - -_November 17, 2016_ - -Change to BigQuery: values from INTEGER columns will now be returned as int64, -not int. This will avoid errors arising from large values on 32-bit systems. - -_November 8, 2016_ - -New datastore feature: datastore now encodes your nested Go structs as Entity values, -instead of a flattened list of the embedded struct's fields. -This means that you may now have twice-nested slices, eg. -```go -type State struct { - Cities []struct{ - Populations []int - } -} -``` - -See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for -more details. - -_November 8, 2016_ - -Breaking changes to datastore: contexts no longer hold namespaces; instead you -must set a key's namespace explicitly. Also, key functions have been changed -and renamed. - -* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method: - ```go - q := datastore.NewQuery("Kind").Namespace("ns") - ``` - -* All the fields of Key are exported. That means you can construct any Key with a struct literal: - ```go - k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"} - ``` - -* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed. - -* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace - ```go - NewIncompleteKey(ctx, kind, parent) - ``` - with - ```go - IncompleteKey(kind, parent) - ``` - and if you do use namespaces, make sure you set the namespace on the returned key. - -* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace - ```go - NewKey(ctx, kind, name, 0, parent) - NewKey(ctx, kind, "", id, parent) - ``` - with - ```go - NameKey(kind, name, parent) - IDKey(kind, id, parent) - ``` - and if you do use namespaces, make sure you set the namespace on the returned key. - -* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`. - -* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection. - -See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for -more details. - -_October 27, 2016_ - -Breaking change to bigquery: `NewGCSReference` is now a function, -not a method on `Client`. - -New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling -loading data into a table from a file or any `io.Reader`. - -_October 21, 2016_ - -Breaking change to pubsub: removed `pubsub.Done`. - -Use `iterator.Done` instead, where `iterator` is the package -`google.golang.org/api/iterator`. - -_October 19, 2016_ - -Breaking changes to cloud.google.com/go/bigquery: - -* Client.Table and Client.OpenTable have been removed. - Replace - ```go - client.OpenTable("project", "dataset", "table") - ``` - with - ```go - client.DatasetInProject("project", "dataset").Table("table") - ``` - -* Client.CreateTable has been removed. - Replace - ```go - client.CreateTable(ctx, "project", "dataset", "table") - ``` - with - ```go - client.DatasetInProject("project", "dataset").Table("table").Create(ctx) - ``` - -* Dataset.ListTables have been replaced with Dataset.Tables. - Replace - ```go - tables, err := ds.ListTables(ctx) - ``` - with - ```go - it := ds.Tables(ctx) - for { - table, err := it.Next() - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - // TODO: use table. - } - ``` - -* Client.Read has been replaced with Job.Read, Table.Read and Query.Read. - Replace - ```go - it, err := client.Read(ctx, job) - ``` - with - ```go - it, err := job.Read(ctx) - ``` - and similarly for reading from tables or queries. - -* The iterator returned from the Read methods is now named RowIterator. Its - behavior is closer to the other iterators in these libraries. It no longer - supports the Schema method; see the next item. - Replace - ```go - for it.Next(ctx) { - var vals ValueList - if err := it.Get(&vals); err != nil { - // TODO: Handle error. - } - // TODO: use vals. - } - if err := it.Err(); err != nil { - // TODO: Handle error. - } - ``` - with - ``` - for { - var vals ValueList - err := it.Next(&vals) - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - // TODO: use vals. - } - ``` - Instead of the `RecordsPerRequest(n)` option, write - ```go - it.PageInfo().MaxSize = n - ``` - Instead of the `StartIndex(i)` option, write - ```go - it.StartIndex = i - ``` - -* ValueLoader.Load now takes a Schema in addition to a slice of Values. - Replace - ```go - func (vl *myValueLoader) Load(v []bigquery.Value) - ``` - with - ```go - func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema) - ``` - - -* Table.Patch is replace by Table.Update. - Replace - ```go - p := table.Patch() - p.Description("new description") - metadata, err := p.Apply(ctx) - ``` - with - ```go - metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{ - Description: "new description", - }) - ``` - -* Client.Copy is replaced by separate methods for each of its four functions. - All options have been replaced by struct fields. - - * To load data from Google Cloud Storage into a table, use Table.LoaderFrom. - - Replace - ```go - client.Copy(ctx, table, gcsRef) - ``` - with - ```go - table.LoaderFrom(gcsRef).Run(ctx) - ``` - Instead of passing options to Copy, set fields on the Loader: - ```go - loader := table.LoaderFrom(gcsRef) - loader.WriteDisposition = bigquery.WriteTruncate - ``` - - * To extract data from a table into Google Cloud Storage, use - Table.ExtractorTo. Set fields on the returned Extractor instead of - passing options. - - Replace - ```go - client.Copy(ctx, gcsRef, table) - ``` - with - ```go - table.ExtractorTo(gcsRef).Run(ctx) - ``` - - * To copy data into a table from one or more other tables, use - Table.CopierFrom. Set fields on the returned Copier instead of passing options. - - Replace - ```go - client.Copy(ctx, dstTable, srcTable) - ``` - with - ```go - dst.Table.CopierFrom(srcTable).Run(ctx) - ``` - - * To start a query job, create a Query and call its Run method. Set fields - on the query instead of passing options. - - Replace - ```go - client.Copy(ctx, table, query) - ``` - with - ```go - query.Run(ctx) - ``` - -* Table.NewUploader has been renamed to Table.Uploader. Instead of options, - configure an Uploader by setting its fields. - Replace - ```go - u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) - ``` - with - ```go - u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) - u.IgnoreUnknownValues = true - ``` - -_October 10, 2016_ - -Breaking changes to cloud.google.com/go/storage: - -* AdminClient replaced by methods on Client. - Replace - ```go - adminClient.CreateBucket(ctx, bucketName, attrs) - ``` - with - ```go - client.Bucket(bucketName).Create(ctx, projectID, attrs) - ``` - -* BucketHandle.List replaced by BucketHandle.Objects. - Replace - ```go - for query != nil { - objs, err := bucket.List(d.ctx, query) - if err != nil { ... } - query = objs.Next - for _, obj := range objs.Results { - fmt.Println(obj) - } - } - ``` - with - ```go - iter := bucket.Objects(d.ctx, query) - for { - obj, err := iter.Next() - if err == iterator.Done { - break - } - if err != nil { ... } - fmt.Println(obj) - } - ``` - (The `iterator` package is at `google.golang.org/api/iterator`.) - - Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`. - - Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`. - - -* ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom. - Replace - ```go - attrs, err := src.CopyTo(ctx, dst, nil) - ``` - with - ```go - attrs, err := dst.CopierFrom(src).Run(ctx) - ``` - - Replace - ```go - attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"}) - ``` - with - ```go - c := dst.CopierFrom(src) - c.ContextType = "text/html" - attrs, err := c.Run(ctx) - ``` - -* ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom. - Replace - ```go - attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil) - ``` - with - ```go - attrs, err := dst.ComposerFrom(src1, src2).Run(ctx) - ``` - -* ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate. - Replace - ```go - attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"}) - ``` - with - ```go - attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"}) - ``` - -* ObjectHandle.WithConditions replaced by ObjectHandle.If. - Replace - ```go - obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen)) - ``` - with - ```go - obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen}) - ``` - - Replace - ```go - obj.WithConditions(storage.IfGenerationMatch(0)) - ``` - with - ```go - obj.If(storage.Conditions{DoesNotExist: true}) - ``` - -* `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`). - -_October 6, 2016_ - -Package preview/logging deleted. Use logging instead. - -_September 27, 2016_ - -Logging client replaced with preview version (see below). - -_September 8, 2016_ - -* New clients for some of Google's Machine Learning APIs: Vision, Speech, and -Natural Language. - -* Preview version of a new [Stackdriver Logging][cloud-logging] client in -[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging). -This client uses gRPC as its transport layer, and supports log reading, sinks -and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly. - diff --git a/vendor/cloud.google.com/go/run-tests.sh b/vendor/cloud.google.com/go/run-tests.sh deleted file mode 100755 index ac0b66a7a..000000000 --- a/vendor/cloud.google.com/go/run-tests.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash - -# Selectively run tests for this repo, based on what has changed -# in a commit. Runs short tests for the whole repo, and full tests -# for changed directories. - -set -e - -prefix=cloud.google.com/go - -dryrun=false -if [[ $1 == "-n" ]]; then - dryrun=true - shift -fi - -if [[ $1 == "" ]]; then - echo >&2 "usage: $0 [-n] COMMIT" - exit 1 -fi - -# Files or directories that cause all tests to run if modified. -declare -A run_all -run_all=([.travis.yml]=1 [run-tests.sh]=1) - -function run { - if $dryrun; then - echo $* - else - (set -x; $*) - fi -} - - -# Find all the packages that have changed in this commit. -declare -A changed_packages - -for f in $(git diff-tree --no-commit-id --name-only -r $1); do - if [[ ${run_all[$f]} == 1 ]]; then - # This change requires a full test. Do it and exit. - run go test -race -v $prefix/... - exit - fi - # Map, e.g., "spanner/client.go" to "$prefix/spanner". - d=$(dirname $f) - if [[ $d == "." ]]; then - pkg=$prefix - else - pkg=$prefix/$d - fi - changed_packages[$pkg]=1 -done - -echo "changed packages: ${!changed_packages[*]}" - - -# Reports whether its argument, a package name, depends (recursively) -# on a changed package. -function depends_on_changed_package { - # According to go list, a package does not depend on itself, so - # we test that separately. - if [[ ${changed_packages[$1]} == 1 ]]; then - return 0 - fi - for dep in $(go list -f '{{range .Deps}}{{.}} {{end}}' $1); do - if [[ ${changed_packages[$dep]} == 1 ]]; then - return 0 - fi - done - return 1 -} - -# Collect the packages into two separate lists. (It is faster go test a list of -# packages than to individually go test each one.) - -shorts= -fulls= -for pkg in $(go list $prefix/...); do # for each package in the repo - if depends_on_changed_package $pkg; then # if it depends on a changed package - fulls="$fulls $pkg" # run the full test - else # otherwise - shorts="$shorts $pkg" # run the short test - fi -done -run go test -race -v -short $shorts -run go test -race -v $fulls diff --git a/vendor/github.com/asaskevich/govalidator/.travis.yml b/vendor/github.com/asaskevich/govalidator/.travis.yml new file mode 100644 index 000000000..e29f8eef5 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.1 + - 1.2 + - 1.3 + - 1.4 + - 1.5 + - 1.6 + - tip + +notifications: + email: + - bwatas@gmail.com diff --git a/vendor/github.com/asaskevich/govalidator/LICENSE b/vendor/github.com/asaskevich/govalidator/LICENSE new file mode 100644 index 000000000..2f9a31fad --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Alex Saskevich + +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/github.com/asaskevich/govalidator/README.md b/vendor/github.com/asaskevich/govalidator/README.md new file mode 100644 index 000000000..9d2e1357b --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/README.md @@ -0,0 +1,423 @@ +govalidator +=========== +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![GoDoc](https://godoc.org/github.com/asaskevich/govalidator?status.png)](https://godoc.org/github.com/asaskevich/govalidator) [![Coverage Status](https://img.shields.io/coveralls/asaskevich/govalidator.svg)](https://coveralls.io/r/asaskevich/govalidator?branch=master) [![wercker status](https://app.wercker.com/status/1ec990b09ea86c910d5f08b0e02c6043/s "wercker status")](https://app.wercker.com/project/bykey/1ec990b09ea86c910d5f08b0e02c6043) +[![Build Status](https://travis-ci.org/asaskevich/govalidator.svg?branch=master)](https://travis-ci.org/asaskevich/govalidator) [![Go Report Card](https://goreportcard.com/badge/github.com/asaskevich/govalidator)](https://goreportcard.com/report/github.com/asaskevich/govalidator) [![GoSearch](http://go-search.org/badge?id=github.com%2Fasaskevich%2Fgovalidator)](http://go-search.org/view?id=github.com%2Fasaskevich%2Fgovalidator) + +A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js). + +#### Installation +Make sure that Go is installed on your computer. +Type the following command in your terminal: + + go get github.com/asaskevich/govalidator + +or you can get specified release of the package with `gopkg.in`: + + go get gopkg.in/asaskevich/govalidator.v4 + +After it the package is ready to use. + + +#### Import package in your project +Add following line in your `*.go` file: +```go +import "github.com/asaskevich/govalidator" +``` +If you are unhappy to use long `govalidator`, you can do something like this: +```go +import ( + valid "github.com/asaskevich/govalidator" +) +``` + +#### Activate behavior to require all fields have a validation tag by default +`SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function. + +```go +import "github.com/asaskevich/govalidator" + +func init() { + govalidator.SetFieldsRequiredByDefault(true) +} +``` + +Here's some code to explain it: +```go +// this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): +type exampleStruct struct { + Name string `` + Email string `valid:"email"` +} + +// this, however, will only fail when Email is empty or an invalid email address: +type exampleStruct2 struct { + Name string `valid:"-"` + Email string `valid:"email"` +} + +// lastly, this will only fail when Email is an invalid email address but not when it's empty: +type exampleStruct2 struct { + Name string `valid:"-"` + Email string `valid:"email,optional"` +} +``` + +#### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123)) +##### Custom validator function signature +A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible. +```go +import "github.com/asaskevich/govalidator" + +// old signature +func(i interface{}) bool + +// new signature +func(i interface{}, o interface{}) bool +``` + +##### Adding a custom validator +This was changed to prevent data races when accessing custom validators. +```go +import "github.com/asaskevich/govalidator" + +// before +govalidator.CustomTypeTagMap["customByteArrayValidator"] = CustomTypeValidator(func(i interface{}, o interface{}) bool { + // ... +}) + +// after +govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + // ... +})) +``` + +#### List of functions: +```go +func Abs(value float64) float64 +func BlackList(str, chars string) string +func ByteLength(str string, params ...string) bool +func CamelCaseToUnderscore(str string) string +func Contains(str, substring string) bool +func Count(array []interface{}, iterator ConditionIterator) int +func Each(array []interface{}, iterator Iterator) +func ErrorByField(e error, field string) string +func ErrorsByField(e error) map[string]string +func Filter(array []interface{}, iterator ConditionIterator) []interface{} +func Find(array []interface{}, iterator ConditionIterator) interface{} +func GetLine(s string, index int) (string, error) +func GetLines(s string) []string +func InRange(value, left, right float64) bool +func IsASCII(str string) bool +func IsAlpha(str string) bool +func IsAlphanumeric(str string) bool +func IsBase64(str string) bool +func IsByteLength(str string, min, max int) bool +func IsCIDR(str string) bool +func IsCreditCard(str string) bool +func IsDNSName(str string) bool +func IsDataURI(str string) bool +func IsDialString(str string) bool +func IsDivisibleBy(str, num string) bool +func IsEmail(str string) bool +func IsFilePath(str string) (bool, int) +func IsFloat(str string) bool +func IsFullWidth(str string) bool +func IsHalfWidth(str string) bool +func IsHexadecimal(str string) bool +func IsHexcolor(str string) bool +func IsHost(str string) bool +func IsIP(str string) bool +func IsIPv4(str string) bool +func IsIPv6(str string) bool +func IsISBN(str string, version int) bool +func IsISBN10(str string) bool +func IsISBN13(str string) bool +func IsISO3166Alpha2(str string) bool +func IsISO3166Alpha3(str string) bool +func IsISO693Alpha2(str string) bool +func IsISO693Alpha3b(str string) bool +func IsISO4217(str string) bool +func IsIn(str string, params ...string) bool +func IsInt(str string) bool +func IsJSON(str string) bool +func IsLatitude(str string) bool +func IsLongitude(str string) bool +func IsLowerCase(str string) bool +func IsMAC(str string) bool +func IsMongoID(str string) bool +func IsMultibyte(str string) bool +func IsNatural(value float64) bool +func IsNegative(value float64) bool +func IsNonNegative(value float64) bool +func IsNonPositive(value float64) bool +func IsNull(str string) bool +func IsNumeric(str string) bool +func IsPort(str string) bool +func IsPositive(value float64) bool +func IsPrintableASCII(str string) bool +func IsRFC3339(str string) bool +func IsRGBcolor(str string) bool +func IsRequestURI(rawurl string) bool +func IsRequestURL(rawurl string) bool +func IsSSN(str string) bool +func IsSemver(str string) bool +func IsTime(str string, format string) bool +func IsURL(str string) bool +func IsUTFDigit(str string) bool +func IsUTFLetter(str string) bool +func IsUTFLetterNumeric(str string) bool +func IsUTFNumeric(str string) bool +func IsUUID(str string) bool +func IsUUIDv3(str string) bool +func IsUUIDv4(str string) bool +func IsUUIDv5(str string) bool +func IsUpperCase(str string) bool +func IsVariableWidth(str string) bool +func IsWhole(value float64) bool +func LeftTrim(str, chars string) string +func Map(array []interface{}, iterator ResultIterator) []interface{} +func Matches(str, pattern string) bool +func NormalizeEmail(str string) (string, error) +func PadBoth(str string, padStr string, padLen int) string +func PadLeft(str string, padStr string, padLen int) string +func PadRight(str string, padStr string, padLen int) string +func Range(str string, params ...string) bool +func RemoveTags(s string) string +func ReplacePattern(str, pattern, replace string) string +func Reverse(s string) string +func RightTrim(str, chars string) string +func RuneLength(str string, params ...string) bool +func SafeFileName(str string) string +func SetFieldsRequiredByDefault(value bool) +func Sign(value float64) float64 +func StringLength(str string, params ...string) bool +func StringMatches(s string, params ...string) bool +func StripLow(str string, keepNewLines bool) string +func ToBoolean(str string) (bool, error) +func ToFloat(str string) (float64, error) +func ToInt(str string) (int64, error) +func ToJSON(obj interface{}) (string, error) +func ToString(obj interface{}) string +func Trim(str, chars string) string +func Truncate(str string, length int, ending string) string +func UnderscoreToCamelCase(s string) string +func ValidateStruct(s interface{}) (bool, error) +func WhiteList(str, chars string) string +type ConditionIterator +type CustomTypeValidator +type Error +func (e Error) Error() string +type Errors +func (es Errors) Error() string +func (es Errors) Errors() []error +type ISO3166Entry +type Iterator +type ParamValidator +type ResultIterator +type UnsupportedTypeError +func (e *UnsupportedTypeError) Error() string +type Validator +``` + +#### Examples +###### IsURL +```go +println(govalidator.IsURL(`http://user@pass:domain.com/path/page`)) +``` +###### ToString +```go +type User struct { + FirstName string + LastName string +} + +str := govalidator.ToString(&User{"John", "Juan"}) +println(str) +``` +###### Each, Map, Filter, Count for slices +Each iterates over the slice/array and calls Iterator for every item +```go +data := []interface{}{1, 2, 3, 4, 5} +var fn govalidator.Iterator = func(value interface{}, index int) { + println(value.(int)) +} +govalidator.Each(data, fn) +``` +```go +data := []interface{}{1, 2, 3, 4, 5} +var fn govalidator.ResultIterator = func(value interface{}, index int) interface{} { + return value.(int) * 3 +} +_ = govalidator.Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15} +``` +```go +data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +var fn govalidator.ConditionIterator = func(value interface{}, index int) bool { + return value.(int)%2 == 0 +} +_ = govalidator.Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10} +_ = govalidator.Count(data, fn) // result = 5 +``` +###### ValidateStruct [#2](https://github.com/asaskevich/govalidator/pull/2) +If you want to validate structs, you can use tag `valid` for any field in your structure. All validators used with this field in one tag are separated by comma. If you want to skip validation, place `-` in your tag. If you need a validator that is not on the list below, you can add it like this: +```go +govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { + return str == "duck" +}) +``` +For completely custom validators (interface-based), see below. + +Here is a list of available validators for struct fields (validator - used function): +```go +"email": IsEmail, +"url": IsURL, +"dialstring": IsDialString, +"requrl": IsRequestURL, +"requri": IsRequestURI, +"alpha": IsAlpha, +"utfletter": IsUTFLetter, +"alphanum": IsAlphanumeric, +"utfletternum": IsUTFLetterNumeric, +"numeric": IsNumeric, +"utfnumeric": IsUTFNumeric, +"utfdigit": IsUTFDigit, +"hexadecimal": IsHexadecimal, +"hexcolor": IsHexcolor, +"rgbcolor": IsRGBcolor, +"lowercase": IsLowerCase, +"uppercase": IsUpperCase, +"int": IsInt, +"float": IsFloat, +"null": IsNull, +"uuid": IsUUID, +"uuidv3": IsUUIDv3, +"uuidv4": IsUUIDv4, +"uuidv5": IsUUIDv5, +"creditcard": IsCreditCard, +"isbn10": IsISBN10, +"isbn13": IsISBN13, +"json": IsJSON, +"multibyte": IsMultibyte, +"ascii": IsASCII, +"printableascii": IsPrintableASCII, +"fullwidth": IsFullWidth, +"halfwidth": IsHalfWidth, +"variablewidth": IsVariableWidth, +"base64": IsBase64, +"datauri": IsDataURI, +"ip": IsIP, +"port": IsPort, +"ipv4": IsIPv4, +"ipv6": IsIPv6, +"dns": IsDNSName, +"host": IsHost, +"mac": IsMAC, +"latitude": IsLatitude, +"longitude": IsLongitude, +"ssn": IsSSN, +"semver": IsSemver, +"rfc3339": IsRFC3339, +"ISO3166Alpha2": IsISO3166Alpha2, +"ISO3166Alpha3": IsISO3166Alpha3, +``` +Validators with parameters + +```go +"range(min|max)": Range, +"length(min|max)": ByteLength, +"runelength(min|max)": RuneLength, +"matches(pattern)": StringMatches, +"in(string1|string2|...|stringN)": IsIn, +``` + +And here is small example of usage: +```go +type Post struct { + Title string `valid:"alphanum,required"` + Message string `valid:"duck,ascii"` + AuthorIP string `valid:"ipv4"` + Date string `valid:"-"` +} +post := &Post{ + Title: "My Example Post", + Message: "duck", + AuthorIP: "123.234.54.3", +} + +// Add your own struct validation tags +govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { + return str == "duck" +}) + +result, err := govalidator.ValidateStruct(post) +if err != nil { + println("error: " + err.Error()) +} +println(result) +``` +###### WhiteList +```go +// Remove all characters from string ignoring characters between "a" and "z" +println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa") +``` + +###### Custom validation functions +Custom validation using your own domain specific validators is also available - here's an example of how to use it: +```go +import "github.com/asaskevich/govalidator" + +type CustomByteArray [6]byte // custom types are supported and can be validated + +type StructWithCustomByteArray struct { + ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence + Email string `valid:"email"` + CustomMinLength int `valid:"-"` +} + +govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool { + switch v := context.(type) { // you can type switch on the context interface being validated + case StructWithCustomByteArray: + // you can check and validate against some other field in the context, + // return early or not validate against the context at all – your choice + case SomeOtherType: + // ... + default: + // expecting some other type? Throw/panic here or continue + } + + switch v := i.(type) { // type switch on the struct field being validated + case CustomByteArray: + for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes + if e != 0 { + return true + } + } + } + return false +})) +govalidator.CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool { + switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation + case StructWithCustomByteArray: + return len(v.ID) >= v.CustomMinLength + } + return false +})) +``` + +#### Notes +Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator). +Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator). + +#### Support +If you do have a contribution for the package feel free to put up a Pull Request or open Issue. + +#### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors) +* [Daniel Lohse](https://github.com/annismckenzie) +* [Attila Oláh](https://github.com/attilaolah) +* [Daniel Korner](https://github.com/Dadie) +* [Steven Wilkin](https://github.com/stevenwilkin) +* [Deiwin Sarjas](https://github.com/deiwin) +* [Noah Shibley](https://github.com/slugmobile) +* [Nathan Davies](https://github.com/nathj07) +* [Matt Sanford](https://github.com/mzsanford) +* [Simon ccl1115](https://github.com/ccl1115) diff --git a/vendor/github.com/asaskevich/govalidator/arrays.go b/vendor/github.com/asaskevich/govalidator/arrays.go new file mode 100644 index 000000000..5bace2654 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/arrays.go @@ -0,0 +1,58 @@ +package govalidator + +// Iterator is the function that accepts element of slice/array and its index +type Iterator func(interface{}, int) + +// ResultIterator is the function that accepts element of slice/array and its index and returns any result +type ResultIterator func(interface{}, int) interface{} + +// ConditionIterator is the function that accepts element of slice/array and its index and returns boolean +type ConditionIterator func(interface{}, int) bool + +// Each iterates over the slice and apply Iterator to every item +func Each(array []interface{}, iterator Iterator) { + for index, data := range array { + iterator(data, index) + } +} + +// Map iterates over the slice and apply ResultIterator to every item. Returns new slice as a result. +func Map(array []interface{}, iterator ResultIterator) []interface{} { + var result = make([]interface{}, len(array)) + for index, data := range array { + result[index] = iterator(data, index) + } + return result +} + +// Find iterates over the slice and apply ConditionIterator to every item. Returns first item that meet ConditionIterator or nil otherwise. +func Find(array []interface{}, iterator ConditionIterator) interface{} { + for index, data := range array { + if iterator(data, index) { + return data + } + } + return nil +} + +// Filter iterates over the slice and apply ConditionIterator to every item. Returns new slice. +func Filter(array []interface{}, iterator ConditionIterator) []interface{} { + var result = make([]interface{}, 0) + for index, data := range array { + if iterator(data, index) { + result = append(result, data) + } + } + return result +} + +// Count iterates over the slice and apply ConditionIterator to every item. Returns count of items that meets ConditionIterator. +func Count(array []interface{}, iterator ConditionIterator) int { + count := 0 + for index, data := range array { + if iterator(data, index) { + count = count + 1 + } + } + return count +} diff --git a/vendor/github.com/asaskevich/govalidator/arrays_test.go b/vendor/github.com/asaskevich/govalidator/arrays_test.go new file mode 100644 index 000000000..1a9ac6696 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/arrays_test.go @@ -0,0 +1,116 @@ +package govalidator + +import "testing" + +func TestEach(t *testing.T) { + // TODO Maybe refactor? + t.Parallel() + acc := 0 + data := []interface{}{1, 2, 3, 4, 5} + var fn Iterator = func(value interface{}, index int) { + acc = acc + value.(int) + } + Each(data, fn) + if acc != 15 { + t.Errorf("Expected Each(..) to be %v, got %v", 15, acc) + } +} + +func ExampleEach() { + data := []interface{}{1, 2, 3, 4, 5} + var fn Iterator = func(value interface{}, index int) { + println(value.(int)) + } + Each(data, fn) +} + +func TestMap(t *testing.T) { + // TODO Maybe refactor? + t.Parallel() + data := []interface{}{1, 2, 3, 4, 5} + var fn ResultIterator = func(value interface{}, index int) interface{} { + return value.(int) * 3 + } + result := Map(data, fn) + for i, d := range result { + if d != fn(data[i], i) { + t.Errorf("Expected Map(..) to be %v, got %v", fn(data[i], i), d) + } + } +} + +func ExampleMap() { + data := []interface{}{1, 2, 3, 4, 5} + var fn ResultIterator = func(value interface{}, index int) interface{} { + return value.(int) * 3 + } + _ = Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15} +} + +func TestFind(t *testing.T) { + // TODO Maybe refactor? + t.Parallel() + findElement := 96 + data := []interface{}{1, 2, 3, 4, findElement, 5} + var fn1 ConditionIterator = func(value interface{}, index int) bool { + return value.(int) == findElement + } + var fn2 ConditionIterator = func(value interface{}, index int) bool { + value, _ = value.(string) + return value == "govalidator" + } + val1 := Find(data, fn1) + val2 := Find(data, fn2) + if val1 != findElement { + t.Errorf("Expected Find(..) to be %v, got %v", findElement, val1) + } + if val2 != nil { + t.Errorf("Expected Find(..) to be %v, got %v", nil, val2) + } +} + +func TestFilter(t *testing.T) { + // TODO Maybe refactor? + t.Parallel() + data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + answer := []interface{}{2, 4, 6, 8, 10} + var fn ConditionIterator = func(value interface{}, index int) bool { + return value.(int)%2 == 0 + } + result := Filter(data, fn) + for i := range result { + if result[i] != answer[i] { + t.Errorf("Expected Filter(..) to be %v, got %v", answer[i], result[i]) + } + } +} + +func ExampleFilter() { + data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + var fn ConditionIterator = func(value interface{}, index int) bool { + return value.(int)%2 == 0 + } + _ = Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10} +} + +func TestCount(t *testing.T) { + // TODO Maybe refactor? + t.Parallel() + data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + count := 5 + var fn ConditionIterator = func(value interface{}, index int) bool { + return value.(int)%2 == 0 + } + result := Count(data, fn) + if result != count { + t.Errorf("Expected Count(..) to be %v, got %v", count, result) + } +} + +func ExampleCount() { + data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + var fn ConditionIterator = func(value interface{}, index int) bool { + return value.(int)%2 == 0 + } + _ = Count(data, fn) // result = 5 +} diff --git a/vendor/github.com/asaskevich/govalidator/converter.go b/vendor/github.com/asaskevich/govalidator/converter.go new file mode 100644 index 000000000..d69114c4b --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/converter.go @@ -0,0 +1,45 @@ +package govalidator + +import ( + "encoding/json" + "fmt" + "strconv" +) + +// ToString convert the input to a string. +func ToString(obj interface{}) string { + res := fmt.Sprintf("%v", obj) + return string(res) +} + +// ToJSON convert the input to a valid JSON string +func ToJSON(obj interface{}) (string, error) { + res, err := json.Marshal(obj) + if err != nil { + res = []byte("") + } + return string(res), err +} + +// ToFloat convert the input string to a float, or 0.0 if the input is not a float. +func ToFloat(str string) (float64, error) { + res, err := strconv.ParseFloat(str, 64) + if err != nil { + res = 0.0 + } + return res, err +} + +// ToInt convert the input string to an integer, or 0 if the input is not an integer. +func ToInt(str string) (int64, error) { + res, err := strconv.ParseInt(str, 0, 64) + if err != nil { + res = 0 + } + return res, err +} + +// ToBoolean convert the input string to a boolean. +func ToBoolean(str string) (bool, error) { + return strconv.ParseBool(str) +} diff --git a/vendor/github.com/asaskevich/govalidator/converter_test.go b/vendor/github.com/asaskevich/govalidator/converter_test.go new file mode 100644 index 000000000..ecc457be8 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/converter_test.go @@ -0,0 +1,78 @@ +package govalidator + +import ( + "fmt" + "testing" +) + +func TestToInt(t *testing.T) { + tests := []string{"1000", "-123", "abcdef", "100000000000000000000000000000000000000000000"} + expected := []int64{1000, -123, 0, 0} + for i := 0; i < len(tests); i++ { + result, _ := ToInt(tests[i]) + if result != expected[i] { + t.Log("Case ", i, ": expected ", expected[i], " when result is ", result) + t.FailNow() + } + } +} + +func TestToBoolean(t *testing.T) { + tests := []string{"true", "1", "True", "false", "0", "abcdef"} + expected := []bool{true, true, true, false, false, false} + for i := 0; i < len(tests); i++ { + res, _ := ToBoolean(tests[i]) + if res != expected[i] { + t.Log("Case ", i, ": expected ", expected[i], " when result is ", res) + t.FailNow() + } + } +} + +func toString(t *testing.T, test interface{}, expected string) { + res := ToString(test) + if res != expected { + t.Log("Case ToString: expected ", expected, " when result is ", res) + t.FailNow() + } +} + +func TestToString(t *testing.T) { + toString(t, "str123", "str123") + toString(t, 123, "123") + toString(t, 12.3, "12.3") + toString(t, true, "true") + toString(t, 1.5+10i, "(1.5+10i)") + // Sprintf function not guarantee that maps with equal keys always will be equal in string representation + //toString(t, struct{ Keys map[int]int }{Keys: map[int]int{1: 2, 3: 4}}, "{map[1:2 3:4]}") +} + +func TestToFloat(t *testing.T) { + tests := []string{"", "123", "-.01", "10.", "string", "1.23e3", ".23e10"} + expected := []float64{0, 123, -0.01, 10.0, 0, 1230, 0.23e10} + for i := 0; i < len(tests); i++ { + res, _ := ToFloat(tests[i]) + if res != expected[i] { + t.Log("Case ", i, ": expected ", expected[i], " when result is ", res) + t.FailNow() + } + } +} + +func TestToJSON(t *testing.T) { + tests := []interface{}{"test", map[string]string{"a": "b", "b": "c"}, func() error { return fmt.Errorf("Error") }} + expected := [][]string{ + {"\"test\"", ""}, + {"{\"a\":\"b\",\"b\":\"c\"}", ""}, + {"", "json: unsupported type: func() error"}, + } + for i, test := range tests { + actual, err := ToJSON(test) + if actual != expected[i][0] { + t.Errorf("Expected toJSON(%v) to return '%v', got '%v'", test, expected[i][0], actual) + } + if fmt.Sprintf("%v", err) != expected[i][1] { + t.Errorf("Expected error returned from toJSON(%v) to return '%v', got '%v'", test, expected[i][1], fmt.Sprintf("%v", err)) + } + } +} diff --git a/vendor/github.com/asaskevich/govalidator/error.go b/vendor/github.com/asaskevich/govalidator/error.go new file mode 100644 index 000000000..280b1c455 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/error.go @@ -0,0 +1,31 @@ +package govalidator + +// Errors is an array of multiple errors and conforms to the error interface. +type Errors []error + +// Errors returns itself. +func (es Errors) Errors() []error { + return es +} + +func (es Errors) Error() string { + var err string + for _, e := range es { + err += e.Error() + ";" + } + return err +} + +// Error encapsulates a name, an error and whether there's a custom error message or not. +type Error struct { + Name string + Err error + CustomErrorMessageExists bool +} + +func (e Error) Error() string { + if e.CustomErrorMessageExists { + return e.Err.Error() + } + return e.Name + ": " + e.Err.Error() +} diff --git a/vendor/github.com/asaskevich/govalidator/error_test.go b/vendor/github.com/asaskevich/govalidator/error_test.go new file mode 100644 index 000000000..274cc0dfa --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/error_test.go @@ -0,0 +1,29 @@ +package govalidator + +import ( + "fmt" + "testing" +) + +func TestErrorsToString(t *testing.T) { + t.Parallel() + customErr := &Error{Name: "Custom Error Name", Err: fmt.Errorf("stdlib error")} + customErrWithCustomErrorMessage := &Error{Name: "Custom Error Name 2", Err: fmt.Errorf("Bad stuff happened"), CustomErrorMessageExists: true} + + var tests = []struct { + param1 Errors + expected string + }{ + {Errors{}, ""}, + {Errors{fmt.Errorf("Error 1")}, "Error 1;"}, + {Errors{fmt.Errorf("Error 1"), fmt.Errorf("Error 2")}, "Error 1;Error 2;"}, + {Errors{customErr, fmt.Errorf("Error 2")}, "Custom Error Name: stdlib error;Error 2;"}, + {Errors{fmt.Errorf("Error 123"), customErrWithCustomErrorMessage}, "Error 123;Bad stuff happened;"}, + } + for _, test := range tests { + actual := test.param1.Error() + if actual != test.expected { + t.Errorf("Expected Error() to return '%v', got '%v'", test.expected, actual) + } + } +} diff --git a/vendor/github.com/asaskevich/govalidator/numerics.go b/vendor/github.com/asaskevich/govalidator/numerics.go new file mode 100644 index 000000000..5be281f24 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/numerics.go @@ -0,0 +1,57 @@ +package govalidator + +import "math" + +// Abs returns absolute value of number +func Abs(value float64) float64 { + return math.Abs(value) +} + +// Sign returns signum of number: 1 in case of value > 0, -1 in case of value < 0, 0 otherwise +func Sign(value float64) float64 { + if value > 0 { + return 1 + } else if value < 0 { + return -1 + } else { + return 0 + } +} + +// IsNegative returns true if value < 0 +func IsNegative(value float64) bool { + return value < 0 +} + +// IsPositive returns true if value > 0 +func IsPositive(value float64) bool { + return value > 0 +} + +// IsNonNegative returns true if value >= 0 +func IsNonNegative(value float64) bool { + return value >= 0 +} + +// IsNonPositive returns true if value <= 0 +func IsNonPositive(value float64) bool { + return value <= 0 +} + +// InRange returns true if value lies between left and right border +func InRange(value, left, right float64) bool { + if left > right { + left, right = right, left + } + return value >= left && value <= right +} + +// IsWhole returns true if value is whole number +func IsWhole(value float64) bool { + return math.Remainder(value, 1) == 0 +} + +// IsNatural returns true if value is natural number (positive and whole) +func IsNatural(value float64) bool { + return IsWhole(value) && IsPositive(value) +} diff --git a/vendor/github.com/asaskevich/govalidator/numerics_test.go b/vendor/github.com/asaskevich/govalidator/numerics_test.go new file mode 100644 index 000000000..1bad52107 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/numerics_test.go @@ -0,0 +1,204 @@ +package govalidator + +import "testing" + +func TestAbs(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected float64 + }{ + {0, 0}, + {-1, 1}, + {10, 10}, + {3.14, 3.14}, + {-96, 96}, + {-10e-12, 10e-12}, + } + for _, test := range tests { + actual := Abs(test.param) + if actual != test.expected { + t.Errorf("Expected Abs(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestSign(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected float64 + }{ + {0, 0}, + {-1, -1}, + {10, 1}, + {3.14, 1}, + {-96, -1}, + {-10e-12, -1}, + } + for _, test := range tests { + actual := Sign(test.param) + if actual != test.expected { + t.Errorf("Expected Sign(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsNegative(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected bool + }{ + {0, false}, + {-1, true}, + {10, false}, + {3.14, false}, + {-96, true}, + {-10e-12, true}, + } + for _, test := range tests { + actual := IsNegative(test.param) + if actual != test.expected { + t.Errorf("Expected IsNegative(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsNonNegative(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected bool + }{ + {0, true}, + {-1, false}, + {10, true}, + {3.14, true}, + {-96, false}, + {-10e-12, false}, + } + for _, test := range tests { + actual := IsNonNegative(test.param) + if actual != test.expected { + t.Errorf("Expected IsNonNegative(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsPositive(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected bool + }{ + {0, false}, + {-1, false}, + {10, true}, + {3.14, true}, + {-96, false}, + {-10e-12, false}, + } + for _, test := range tests { + actual := IsPositive(test.param) + if actual != test.expected { + t.Errorf("Expected IsPositive(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsNonPositive(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected bool + }{ + {0, true}, + {-1, true}, + {10, false}, + {3.14, false}, + {-96, true}, + {-10e-12, true}, + } + for _, test := range tests { + actual := IsNonPositive(test.param) + if actual != test.expected { + t.Errorf("Expected IsNonPositive(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsWhole(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected bool + }{ + {0, true}, + {-1, true}, + {10, true}, + {3.14, false}, + {-96, true}, + {-10e-12, false}, + } + for _, test := range tests { + actual := IsWhole(test.param) + if actual != test.expected { + t.Errorf("Expected IsWhole(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsNatural(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + expected bool + }{ + {0, false}, + {-1, false}, + {10, true}, + {3.14, false}, + {96, true}, + {-10e-12, false}, + } + for _, test := range tests { + actual := IsNatural(test.param) + if actual != test.expected { + t.Errorf("Expected IsNatural(%v) to be %v, got %v", test.param, test.expected, actual) + } + } +} +func TestInRange(t *testing.T) { + t.Parallel() + + var tests = []struct { + param float64 + left float64 + right float64 + expected bool + }{ + {0, 0, 0, true}, + {1, 0, 0, false}, + {-1, 0, 0, false}, + {0, -1, 1, true}, + {0, 0, 1, true}, + {0, -1, 0, true}, + {0, 0, -1, true}, + {0, 10, 5, false}, + } + for _, test := range tests { + actual := InRange(test.param, test.left, test.right) + if actual != test.expected { + t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) + } + } +} diff --git a/vendor/github.com/asaskevich/govalidator/patterns.go b/vendor/github.com/asaskevich/govalidator/patterns.go new file mode 100644 index 000000000..529759559 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/patterns.go @@ -0,0 +1,91 @@ +package govalidator + +import "regexp" + +// Basic regular expressions for validating strings +const ( + Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" + CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$" + ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$" + ISBN13 string = "^(?:[0-9]{13})$" + UUID3 string = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" + UUID4 string = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + UUID5 string = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + UUID string = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" + Alpha string = "^[a-zA-Z]+$" + Alphanumeric string = "^[a-zA-Z0-9]+$" + Numeric string = "^[0-9]+$" + Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$" + Float string = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$" + Hexadecimal string = "^[0-9a-fA-F]+$" + Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" + RGBcolor string = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$" + ASCII string = "^[\x00-\x7F]+$" + Multibyte string = "[^\x00-\x7F]" + FullWidth string = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" + HalfWidth string = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" + Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" + PrintableASCII string = "^[\x20-\x7E]+$" + DataURI string = "^data:.+\\/(.+);base64$" + Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" + Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" + DNSName string = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$` + IP string = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` + URLSchema string = `((ftp|tcp|udp|wss?|https?):\/\/)` + URLUsername string = `(\S+(:\S*)?@)` + Hostname string = `` + URLPath string = `((\/|\?|#)[^\s]*)` + URLPort string = `(:(\d{1,5}))` + URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))` + URLSubdomain string = `((www\.)|([a-zA-Z0-9]([-\.][-\._a-zA-Z0-9]+)*))` + URL string = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$` + SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` + WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$` + UnixPath string = `^(/[^/\x00]*)+/?$` + Semver string = "^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$" + tagName string = "valid" +) + +// Used by IsFilePath func +const ( + // Unknown is unresolved OS type + Unknown = iota + // Win is Windows type + Win + // Unix is *nix OS types + Unix +) + +var ( + rxEmail = regexp.MustCompile(Email) + rxCreditCard = regexp.MustCompile(CreditCard) + rxISBN10 = regexp.MustCompile(ISBN10) + rxISBN13 = regexp.MustCompile(ISBN13) + rxUUID3 = regexp.MustCompile(UUID3) + rxUUID4 = regexp.MustCompile(UUID4) + rxUUID5 = regexp.MustCompile(UUID5) + rxUUID = regexp.MustCompile(UUID) + rxAlpha = regexp.MustCompile(Alpha) + rxAlphanumeric = regexp.MustCompile(Alphanumeric) + rxNumeric = regexp.MustCompile(Numeric) + rxInt = regexp.MustCompile(Int) + rxFloat = regexp.MustCompile(Float) + rxHexadecimal = regexp.MustCompile(Hexadecimal) + rxHexcolor = regexp.MustCompile(Hexcolor) + rxRGBcolor = regexp.MustCompile(RGBcolor) + rxASCII = regexp.MustCompile(ASCII) + rxPrintableASCII = regexp.MustCompile(PrintableASCII) + rxMultibyte = regexp.MustCompile(Multibyte) + rxFullWidth = regexp.MustCompile(FullWidth) + rxHalfWidth = regexp.MustCompile(HalfWidth) + rxBase64 = regexp.MustCompile(Base64) + rxDataURI = regexp.MustCompile(DataURI) + rxLatitude = regexp.MustCompile(Latitude) + rxLongitude = regexp.MustCompile(Longitude) + rxDNSName = regexp.MustCompile(DNSName) + rxURL = regexp.MustCompile(URL) + rxSSN = regexp.MustCompile(SSN) + rxWinPath = regexp.MustCompile(WinPath) + rxUnixPath = regexp.MustCompile(UnixPath) + rxSemver = regexp.MustCompile(Semver) +) diff --git a/vendor/github.com/asaskevich/govalidator/types.go b/vendor/github.com/asaskevich/govalidator/types.go new file mode 100644 index 000000000..9a5207c58 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/types.go @@ -0,0 +1,613 @@ +package govalidator + +import ( + "reflect" + "regexp" + "sync" +) + +// Validator is a wrapper for a validator function that returns bool and accepts string. +type Validator func(str string) bool + +// CustomTypeValidator is a wrapper for validator functions that returns bool and accepts any type. +// The second parameter should be the context (in the case of validating a struct: the whole object being validated). +type CustomTypeValidator func(i interface{}, o interface{}) bool + +// ParamValidator is a wrapper for validator functions that accepts additional parameters. +type ParamValidator func(str string, params ...string) bool +type tagOptionsMap map[string]string + +// UnsupportedTypeError is a wrapper for reflect.Type +type UnsupportedTypeError struct { + Type reflect.Type +} + +// stringValues is a slice of reflect.Value holding *reflect.StringValue. +// It implements the methods to sort by string. +type stringValues []reflect.Value + +// ParamTagMap is a map of functions accept variants parameters +var ParamTagMap = map[string]ParamValidator{ + "length": ByteLength, + "range": Range, + "runelength": RuneLength, + "stringlength": StringLength, + "matches": StringMatches, + "in": isInRaw, +} + +// ParamTagRegexMap maps param tags to their respective regexes. +var ParamTagRegexMap = map[string]*regexp.Regexp{ + "range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"), + "length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"), + "runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"), + "stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"), + "in": regexp.MustCompile(`^in\((.*)\)`), + "matches": regexp.MustCompile(`^matches\((.+)\)$`), +} + +type customTypeTagMap struct { + validators map[string]CustomTypeValidator + + sync.RWMutex +} + +func (tm *customTypeTagMap) Get(name string) (CustomTypeValidator, bool) { + tm.RLock() + defer tm.RUnlock() + v, ok := tm.validators[name] + return v, ok +} + +func (tm *customTypeTagMap) Set(name string, ctv CustomTypeValidator) { + tm.Lock() + defer tm.Unlock() + tm.validators[name] = ctv +} + +// CustomTypeTagMap is a map of functions that can be used as tags for ValidateStruct function. +// Use this to validate compound or custom types that need to be handled as a whole, e.g. +// `type UUID [16]byte` (this would be handled as an array of bytes). +var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeValidator)} + +// TagMap is a map of functions, that can be used as tags for ValidateStruct function. +var TagMap = map[string]Validator{ + "email": IsEmail, + "url": IsURL, + "dialstring": IsDialString, + "requrl": IsRequestURL, + "requri": IsRequestURI, + "alpha": IsAlpha, + "utfletter": IsUTFLetter, + "alphanum": IsAlphanumeric, + "utfletternum": IsUTFLetterNumeric, + "numeric": IsNumeric, + "utfnumeric": IsUTFNumeric, + "utfdigit": IsUTFDigit, + "hexadecimal": IsHexadecimal, + "hexcolor": IsHexcolor, + "rgbcolor": IsRGBcolor, + "lowercase": IsLowerCase, + "uppercase": IsUpperCase, + "int": IsInt, + "float": IsFloat, + "null": IsNull, + "uuid": IsUUID, + "uuidv3": IsUUIDv3, + "uuidv4": IsUUIDv4, + "uuidv5": IsUUIDv5, + "creditcard": IsCreditCard, + "isbn10": IsISBN10, + "isbn13": IsISBN13, + "json": IsJSON, + "multibyte": IsMultibyte, + "ascii": IsASCII, + "printableascii": IsPrintableASCII, + "fullwidth": IsFullWidth, + "halfwidth": IsHalfWidth, + "variablewidth": IsVariableWidth, + "base64": IsBase64, + "datauri": IsDataURI, + "ip": IsIP, + "port": IsPort, + "ipv4": IsIPv4, + "ipv6": IsIPv6, + "dns": IsDNSName, + "host": IsHost, + "mac": IsMAC, + "latitude": IsLatitude, + "longitude": IsLongitude, + "ssn": IsSSN, + "semver": IsSemver, + "rfc3339": IsRFC3339, + "ISO3166Alpha2": IsISO3166Alpha2, + "ISO3166Alpha3": IsISO3166Alpha3, + "ISO4217": IsISO4217, +} + +// ISO3166Entry stores country codes +type ISO3166Entry struct { + EnglishShortName string + FrenchShortName string + Alpha2Code string + Alpha3Code string + Numeric string +} + +//ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes" +var ISO3166List = []ISO3166Entry{ + {"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"}, + {"Albania", "Albanie (l')", "AL", "ALB", "008"}, + {"Antarctica", "Antarctique (l')", "AQ", "ATA", "010"}, + {"Algeria", "Algérie (l')", "DZ", "DZA", "012"}, + {"American Samoa", "Samoa américaines (les)", "AS", "ASM", "016"}, + {"Andorra", "Andorre (l')", "AD", "AND", "020"}, + {"Angola", "Angola (l')", "AO", "AGO", "024"}, + {"Antigua and Barbuda", "Antigua-et-Barbuda", "AG", "ATG", "028"}, + {"Azerbaijan", "Azerbaïdjan (l')", "AZ", "AZE", "031"}, + {"Argentina", "Argentine (l')", "AR", "ARG", "032"}, + {"Australia", "Australie (l')", "AU", "AUS", "036"}, + {"Austria", "Autriche (l')", "AT", "AUT", "040"}, + {"Bahamas (the)", "Bahamas (les)", "BS", "BHS", "044"}, + {"Bahrain", "Bahreïn", "BH", "BHR", "048"}, + {"Bangladesh", "Bangladesh (le)", "BD", "BGD", "050"}, + {"Armenia", "Arménie (l')", "AM", "ARM", "051"}, + {"Barbados", "Barbade (la)", "BB", "BRB", "052"}, + {"Belgium", "Belgique (la)", "BE", "BEL", "056"}, + {"Bermuda", "Bermudes (les)", "BM", "BMU", "060"}, + {"Bhutan", "Bhoutan (le)", "BT", "BTN", "064"}, + {"Bolivia (Plurinational State of)", "Bolivie (État plurinational de)", "BO", "BOL", "068"}, + {"Bosnia and Herzegovina", "Bosnie-Herzégovine (la)", "BA", "BIH", "070"}, + {"Botswana", "Botswana (le)", "BW", "BWA", "072"}, + {"Bouvet Island", "Bouvet (l'Île)", "BV", "BVT", "074"}, + {"Brazil", "Brésil (le)", "BR", "BRA", "076"}, + {"Belize", "Belize (le)", "BZ", "BLZ", "084"}, + {"British Indian Ocean Territory (the)", "Indien (le Territoire britannique de l'océan)", "IO", "IOT", "086"}, + {"Solomon Islands", "Salomon (Îles)", "SB", "SLB", "090"}, + {"Virgin Islands (British)", "Vierges britanniques (les Îles)", "VG", "VGB", "092"}, + {"Brunei Darussalam", "Brunéi Darussalam (le)", "BN", "BRN", "096"}, + {"Bulgaria", "Bulgarie (la)", "BG", "BGR", "100"}, + {"Myanmar", "Myanmar (le)", "MM", "MMR", "104"}, + {"Burundi", "Burundi (le)", "BI", "BDI", "108"}, + {"Belarus", "Bélarus (le)", "BY", "BLR", "112"}, + {"Cambodia", "Cambodge (le)", "KH", "KHM", "116"}, + {"Cameroon", "Cameroun (le)", "CM", "CMR", "120"}, + {"Canada", "Canada (le)", "CA", "CAN", "124"}, + {"Cabo Verde", "Cabo Verde", "CV", "CPV", "132"}, + {"Cayman Islands (the)", "Caïmans (les Îles)", "KY", "CYM", "136"}, + {"Central African Republic (the)", "République centrafricaine (la)", "CF", "CAF", "140"}, + {"Sri Lanka", "Sri Lanka", "LK", "LKA", "144"}, + {"Chad", "Tchad (le)", "TD", "TCD", "148"}, + {"Chile", "Chili (le)", "CL", "CHL", "152"}, + {"China", "Chine (la)", "CN", "CHN", "156"}, + {"Taiwan (Province of China)", "Taïwan (Province de Chine)", "TW", "TWN", "158"}, + {"Christmas Island", "Christmas (l'Île)", "CX", "CXR", "162"}, + {"Cocos (Keeling) Islands (the)", "Cocos (les Îles)/ Keeling (les Îles)", "CC", "CCK", "166"}, + {"Colombia", "Colombie (la)", "CO", "COL", "170"}, + {"Comoros (the)", "Comores (les)", "KM", "COM", "174"}, + {"Mayotte", "Mayotte", "YT", "MYT", "175"}, + {"Congo (the)", "Congo (le)", "CG", "COG", "178"}, + {"Congo (the Democratic Republic of the)", "Congo (la République démocratique du)", "CD", "COD", "180"}, + {"Cook Islands (the)", "Cook (les Îles)", "CK", "COK", "184"}, + {"Costa Rica", "Costa Rica (le)", "CR", "CRI", "188"}, + {"Croatia", "Croatie (la)", "HR", "HRV", "191"}, + {"Cuba", "Cuba", "CU", "CUB", "192"}, + {"Cyprus", "Chypre", "CY", "CYP", "196"}, + {"Czech Republic (the)", "tchèque (la République)", "CZ", "CZE", "203"}, + {"Benin", "Bénin (le)", "BJ", "BEN", "204"}, + {"Denmark", "Danemark (le)", "DK", "DNK", "208"}, + {"Dominica", "Dominique (la)", "DM", "DMA", "212"}, + {"Dominican Republic (the)", "dominicaine (la République)", "DO", "DOM", "214"}, + {"Ecuador", "Équateur (l')", "EC", "ECU", "218"}, + {"El Salvador", "El Salvador", "SV", "SLV", "222"}, + {"Equatorial Guinea", "Guinée équatoriale (la)", "GQ", "GNQ", "226"}, + {"Ethiopia", "Éthiopie (l')", "ET", "ETH", "231"}, + {"Eritrea", "Érythrée (l')", "ER", "ERI", "232"}, + {"Estonia", "Estonie (l')", "EE", "EST", "233"}, + {"Faroe Islands (the)", "Féroé (les Îles)", "FO", "FRO", "234"}, + {"Falkland Islands (the) [Malvinas]", "Falkland (les Îles)/Malouines (les Îles)", "FK", "FLK", "238"}, + {"South Georgia and the South Sandwich Islands", "Géorgie du Sud-et-les Îles Sandwich du Sud (la)", "GS", "SGS", "239"}, + {"Fiji", "Fidji (les)", "FJ", "FJI", "242"}, + {"Finland", "Finlande (la)", "FI", "FIN", "246"}, + {"Åland Islands", "Åland(les Îles)", "AX", "ALA", "248"}, + {"France", "France (la)", "FR", "FRA", "250"}, + {"French Guiana", "Guyane française (la )", "GF", "GUF", "254"}, + {"French Polynesia", "Polynésie française (la)", "PF", "PYF", "258"}, + {"French Southern Territories (the)", "Terres australes françaises (les)", "TF", "ATF", "260"}, + {"Djibouti", "Djibouti", "DJ", "DJI", "262"}, + {"Gabon", "Gabon (le)", "GA", "GAB", "266"}, + {"Georgia", "Géorgie (la)", "GE", "GEO", "268"}, + {"Gambia (the)", "Gambie (la)", "GM", "GMB", "270"}, + {"Palestine, State of", "Palestine, État de", "PS", "PSE", "275"}, + {"Germany", "Allemagne (l')", "DE", "DEU", "276"}, + {"Ghana", "Ghana (le)", "GH", "GHA", "288"}, + {"Gibraltar", "Gibraltar", "GI", "GIB", "292"}, + {"Kiribati", "Kiribati", "KI", "KIR", "296"}, + {"Greece", "Grèce (la)", "GR", "GRC", "300"}, + {"Greenland", "Groenland (le)", "GL", "GRL", "304"}, + {"Grenada", "Grenade (la)", "GD", "GRD", "308"}, + {"Guadeloupe", "Guadeloupe (la)", "GP", "GLP", "312"}, + {"Guam", "Guam", "GU", "GUM", "316"}, + {"Guatemala", "Guatemala (le)", "GT", "GTM", "320"}, + {"Guinea", "Guinée (la)", "GN", "GIN", "324"}, + {"Guyana", "Guyana (le)", "GY", "GUY", "328"}, + {"Haiti", "Haïti", "HT", "HTI", "332"}, + {"Heard Island and McDonald Islands", "Heard-et-Îles MacDonald (l'Île)", "HM", "HMD", "334"}, + {"Holy See (the)", "Saint-Siège (le)", "VA", "VAT", "336"}, + {"Honduras", "Honduras (le)", "HN", "HND", "340"}, + {"Hong Kong", "Hong Kong", "HK", "HKG", "344"}, + {"Hungary", "Hongrie (la)", "HU", "HUN", "348"}, + {"Iceland", "Islande (l')", "IS", "ISL", "352"}, + {"India", "Inde (l')", "IN", "IND", "356"}, + {"Indonesia", "Indonésie (l')", "ID", "IDN", "360"}, + {"Iran (Islamic Republic of)", "Iran (République Islamique d')", "IR", "IRN", "364"}, + {"Iraq", "Iraq (l')", "IQ", "IRQ", "368"}, + {"Ireland", "Irlande (l')", "IE", "IRL", "372"}, + {"Israel", "Israël", "IL", "ISR", "376"}, + {"Italy", "Italie (l')", "IT", "ITA", "380"}, + {"Côte d'Ivoire", "Côte d'Ivoire (la)", "CI", "CIV", "384"}, + {"Jamaica", "Jamaïque (la)", "JM", "JAM", "388"}, + {"Japan", "Japon (le)", "JP", "JPN", "392"}, + {"Kazakhstan", "Kazakhstan (le)", "KZ", "KAZ", "398"}, + {"Jordan", "Jordanie (la)", "JO", "JOR", "400"}, + {"Kenya", "Kenya (le)", "KE", "KEN", "404"}, + {"Korea (the Democratic People's Republic of)", "Corée (la République populaire démocratique de)", "KP", "PRK", "408"}, + {"Korea (the Republic of)", "Corée (la République de)", "KR", "KOR", "410"}, + {"Kuwait", "Koweït (le)", "KW", "KWT", "414"}, + {"Kyrgyzstan", "Kirghizistan (le)", "KG", "KGZ", "417"}, + {"Lao People's Democratic Republic (the)", "Lao, République démocratique populaire", "LA", "LAO", "418"}, + {"Lebanon", "Liban (le)", "LB", "LBN", "422"}, + {"Lesotho", "Lesotho (le)", "LS", "LSO", "426"}, + {"Latvia", "Lettonie (la)", "LV", "LVA", "428"}, + {"Liberia", "Libéria (le)", "LR", "LBR", "430"}, + {"Libya", "Libye (la)", "LY", "LBY", "434"}, + {"Liechtenstein", "Liechtenstein (le)", "LI", "LIE", "438"}, + {"Lithuania", "Lituanie (la)", "LT", "LTU", "440"}, + {"Luxembourg", "Luxembourg (le)", "LU", "LUX", "442"}, + {"Macao", "Macao", "MO", "MAC", "446"}, + {"Madagascar", "Madagascar", "MG", "MDG", "450"}, + {"Malawi", "Malawi (le)", "MW", "MWI", "454"}, + {"Malaysia", "Malaisie (la)", "MY", "MYS", "458"}, + {"Maldives", "Maldives (les)", "MV", "MDV", "462"}, + {"Mali", "Mali (le)", "ML", "MLI", "466"}, + {"Malta", "Malte", "MT", "MLT", "470"}, + {"Martinique", "Martinique (la)", "MQ", "MTQ", "474"}, + {"Mauritania", "Mauritanie (la)", "MR", "MRT", "478"}, + {"Mauritius", "Maurice", "MU", "MUS", "480"}, + {"Mexico", "Mexique (le)", "MX", "MEX", "484"}, + {"Monaco", "Monaco", "MC", "MCO", "492"}, + {"Mongolia", "Mongolie (la)", "MN", "MNG", "496"}, + {"Moldova (the Republic of)", "Moldova , République de", "MD", "MDA", "498"}, + {"Montenegro", "Monténégro (le)", "ME", "MNE", "499"}, + {"Montserrat", "Montserrat", "MS", "MSR", "500"}, + {"Morocco", "Maroc (le)", "MA", "MAR", "504"}, + {"Mozambique", "Mozambique (le)", "MZ", "MOZ", "508"}, + {"Oman", "Oman", "OM", "OMN", "512"}, + {"Namibia", "Namibie (la)", "NA", "NAM", "516"}, + {"Nauru", "Nauru", "NR", "NRU", "520"}, + {"Nepal", "Népal (le)", "NP", "NPL", "524"}, + {"Netherlands (the)", "Pays-Bas (les)", "NL", "NLD", "528"}, + {"Curaçao", "Curaçao", "CW", "CUW", "531"}, + {"Aruba", "Aruba", "AW", "ABW", "533"}, + {"Sint Maarten (Dutch part)", "Saint-Martin (partie néerlandaise)", "SX", "SXM", "534"}, + {"Bonaire, Sint Eustatius and Saba", "Bonaire, Saint-Eustache et Saba", "BQ", "BES", "535"}, + {"New Caledonia", "Nouvelle-Calédonie (la)", "NC", "NCL", "540"}, + {"Vanuatu", "Vanuatu (le)", "VU", "VUT", "548"}, + {"New Zealand", "Nouvelle-Zélande (la)", "NZ", "NZL", "554"}, + {"Nicaragua", "Nicaragua (le)", "NI", "NIC", "558"}, + {"Niger (the)", "Niger (le)", "NE", "NER", "562"}, + {"Nigeria", "Nigéria (le)", "NG", "NGA", "566"}, + {"Niue", "Niue", "NU", "NIU", "570"}, + {"Norfolk Island", "Norfolk (l'Île)", "NF", "NFK", "574"}, + {"Norway", "Norvège (la)", "NO", "NOR", "578"}, + {"Northern Mariana Islands (the)", "Mariannes du Nord (les Îles)", "MP", "MNP", "580"}, + {"United States Minor Outlying Islands (the)", "Îles mineures éloignées des États-Unis (les)", "UM", "UMI", "581"}, + {"Micronesia (Federated States of)", "Micronésie (États fédérés de)", "FM", "FSM", "583"}, + {"Marshall Islands (the)", "Marshall (Îles)", "MH", "MHL", "584"}, + {"Palau", "Palaos (les)", "PW", "PLW", "585"}, + {"Pakistan", "Pakistan (le)", "PK", "PAK", "586"}, + {"Panama", "Panama (le)", "PA", "PAN", "591"}, + {"Papua New Guinea", "Papouasie-Nouvelle-Guinée (la)", "PG", "PNG", "598"}, + {"Paraguay", "Paraguay (le)", "PY", "PRY", "600"}, + {"Peru", "Pérou (le)", "PE", "PER", "604"}, + {"Philippines (the)", "Philippines (les)", "PH", "PHL", "608"}, + {"Pitcairn", "Pitcairn", "PN", "PCN", "612"}, + {"Poland", "Pologne (la)", "PL", "POL", "616"}, + {"Portugal", "Portugal (le)", "PT", "PRT", "620"}, + {"Guinea-Bissau", "Guinée-Bissau (la)", "GW", "GNB", "624"}, + {"Timor-Leste", "Timor-Leste (le)", "TL", "TLS", "626"}, + {"Puerto Rico", "Porto Rico", "PR", "PRI", "630"}, + {"Qatar", "Qatar (le)", "QA", "QAT", "634"}, + {"Réunion", "Réunion (La)", "RE", "REU", "638"}, + {"Romania", "Roumanie (la)", "RO", "ROU", "642"}, + {"Russian Federation (the)", "Russie (la Fédération de)", "RU", "RUS", "643"}, + {"Rwanda", "Rwanda (le)", "RW", "RWA", "646"}, + {"Saint Barthélemy", "Saint-Barthélemy", "BL", "BLM", "652"}, + {"Saint Helena, Ascension and Tristan da Cunha", "Sainte-Hélène, Ascension et Tristan da Cunha", "SH", "SHN", "654"}, + {"Saint Kitts and Nevis", "Saint-Kitts-et-Nevis", "KN", "KNA", "659"}, + {"Anguilla", "Anguilla", "AI", "AIA", "660"}, + {"Saint Lucia", "Sainte-Lucie", "LC", "LCA", "662"}, + {"Saint Martin (French part)", "Saint-Martin (partie française)", "MF", "MAF", "663"}, + {"Saint Pierre and Miquelon", "Saint-Pierre-et-Miquelon", "PM", "SPM", "666"}, + {"Saint Vincent and the Grenadines", "Saint-Vincent-et-les Grenadines", "VC", "VCT", "670"}, + {"San Marino", "Saint-Marin", "SM", "SMR", "674"}, + {"Sao Tome and Principe", "Sao Tomé-et-Principe", "ST", "STP", "678"}, + {"Saudi Arabia", "Arabie saoudite (l')", "SA", "SAU", "682"}, + {"Senegal", "Sénégal (le)", "SN", "SEN", "686"}, + {"Serbia", "Serbie (la)", "RS", "SRB", "688"}, + {"Seychelles", "Seychelles (les)", "SC", "SYC", "690"}, + {"Sierra Leone", "Sierra Leone (la)", "SL", "SLE", "694"}, + {"Singapore", "Singapour", "SG", "SGP", "702"}, + {"Slovakia", "Slovaquie (la)", "SK", "SVK", "703"}, + {"Viet Nam", "Viet Nam (le)", "VN", "VNM", "704"}, + {"Slovenia", "Slovénie (la)", "SI", "SVN", "705"}, + {"Somalia", "Somalie (la)", "SO", "SOM", "706"}, + {"South Africa", "Afrique du Sud (l')", "ZA", "ZAF", "710"}, + {"Zimbabwe", "Zimbabwe (le)", "ZW", "ZWE", "716"}, + {"Spain", "Espagne (l')", "ES", "ESP", "724"}, + {"South Sudan", "Soudan du Sud (le)", "SS", "SSD", "728"}, + {"Sudan (the)", "Soudan (le)", "SD", "SDN", "729"}, + {"Western Sahara*", "Sahara occidental (le)*", "EH", "ESH", "732"}, + {"Suriname", "Suriname (le)", "SR", "SUR", "740"}, + {"Svalbard and Jan Mayen", "Svalbard et l'Île Jan Mayen (le)", "SJ", "SJM", "744"}, + {"Swaziland", "Swaziland (le)", "SZ", "SWZ", "748"}, + {"Sweden", "Suède (la)", "SE", "SWE", "752"}, + {"Switzerland", "Suisse (la)", "CH", "CHE", "756"}, + {"Syrian Arab Republic", "République arabe syrienne (la)", "SY", "SYR", "760"}, + {"Tajikistan", "Tadjikistan (le)", "TJ", "TJK", "762"}, + {"Thailand", "Thaïlande (la)", "TH", "THA", "764"}, + {"Togo", "Togo (le)", "TG", "TGO", "768"}, + {"Tokelau", "Tokelau (les)", "TK", "TKL", "772"}, + {"Tonga", "Tonga (les)", "TO", "TON", "776"}, + {"Trinidad and Tobago", "Trinité-et-Tobago (la)", "TT", "TTO", "780"}, + {"United Arab Emirates (the)", "Émirats arabes unis (les)", "AE", "ARE", "784"}, + {"Tunisia", "Tunisie (la)", "TN", "TUN", "788"}, + {"Turkey", "Turquie (la)", "TR", "TUR", "792"}, + {"Turkmenistan", "Turkménistan (le)", "TM", "TKM", "795"}, + {"Turks and Caicos Islands (the)", "Turks-et-Caïcos (les Îles)", "TC", "TCA", "796"}, + {"Tuvalu", "Tuvalu (les)", "TV", "TUV", "798"}, + {"Uganda", "Ouganda (l')", "UG", "UGA", "800"}, + {"Ukraine", "Ukraine (l')", "UA", "UKR", "804"}, + {"Macedonia (the former Yugoslav Republic of)", "Macédoine (l'ex‑République yougoslave de)", "MK", "MKD", "807"}, + {"Egypt", "Égypte (l')", "EG", "EGY", "818"}, + {"United Kingdom of Great Britain and Northern Ireland (the)", "Royaume-Uni de Grande-Bretagne et d'Irlande du Nord (le)", "GB", "GBR", "826"}, + {"Guernsey", "Guernesey", "GG", "GGY", "831"}, + {"Jersey", "Jersey", "JE", "JEY", "832"}, + {"Isle of Man", "Île de Man", "IM", "IMN", "833"}, + {"Tanzania, United Republic of", "Tanzanie, République-Unie de", "TZ", "TZA", "834"}, + {"United States of America (the)", "États-Unis d'Amérique (les)", "US", "USA", "840"}, + {"Virgin Islands (U.S.)", "Vierges des États-Unis (les Îles)", "VI", "VIR", "850"}, + {"Burkina Faso", "Burkina Faso (le)", "BF", "BFA", "854"}, + {"Uruguay", "Uruguay (l')", "UY", "URY", "858"}, + {"Uzbekistan", "Ouzbékistan (l')", "UZ", "UZB", "860"}, + {"Venezuela (Bolivarian Republic of)", "Venezuela (République bolivarienne du)", "VE", "VEN", "862"}, + {"Wallis and Futuna", "Wallis-et-Futuna", "WF", "WLF", "876"}, + {"Samoa", "Samoa (le)", "WS", "WSM", "882"}, + {"Yemen", "Yémen (le)", "YE", "YEM", "887"}, + {"Zambia", "Zambie (la)", "ZM", "ZMB", "894"}, +} + +// ISO4217List is the list of ISO currency codes +var ISO4217List = []string{ + "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", + "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", + "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK", + "DJF", "DKK", "DOP", "DZD", + "EGP", "ERN", "ETB", "EUR", + "FJD", "FKP", + "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", + "HKD", "HNL", "HRK", "HTG", "HUF", + "IDR", "ILS", "INR", "IQD", "IRR", "ISK", + "JMD", "JOD", "JPY", + "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", + "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", + "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", + "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", + "OMR", + "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", + "QAR", + "RON", "RSD", "RUB", "RWF", + "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STD", "SVC", "SYP", "SZL", + "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", + "UAH", "UGX", "USD", "USN", "UYI", "UYU", "UZS", + "VEF", "VND", "VUV", + "WST", + "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", + "YER", + "ZAR", "ZMW", "ZWL", +} + +// ISO693Entry stores ISO language codes +type ISO693Entry struct { + Alpha3bCode string + Alpha2Code string + English string +} + +//ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json +var ISO693List = []ISO693Entry{ + {Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"}, + {Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"}, + {Alpha3bCode: "afr", Alpha2Code: "af", English: "Afrikaans"}, + {Alpha3bCode: "aka", Alpha2Code: "ak", English: "Akan"}, + {Alpha3bCode: "alb", Alpha2Code: "sq", English: "Albanian"}, + {Alpha3bCode: "amh", Alpha2Code: "am", English: "Amharic"}, + {Alpha3bCode: "ara", Alpha2Code: "ar", English: "Arabic"}, + {Alpha3bCode: "arg", Alpha2Code: "an", English: "Aragonese"}, + {Alpha3bCode: "arm", Alpha2Code: "hy", English: "Armenian"}, + {Alpha3bCode: "asm", Alpha2Code: "as", English: "Assamese"}, + {Alpha3bCode: "ava", Alpha2Code: "av", English: "Avaric"}, + {Alpha3bCode: "ave", Alpha2Code: "ae", English: "Avestan"}, + {Alpha3bCode: "aym", Alpha2Code: "ay", English: "Aymara"}, + {Alpha3bCode: "aze", Alpha2Code: "az", English: "Azerbaijani"}, + {Alpha3bCode: "bak", Alpha2Code: "ba", English: "Bashkir"}, + {Alpha3bCode: "bam", Alpha2Code: "bm", English: "Bambara"}, + {Alpha3bCode: "baq", Alpha2Code: "eu", English: "Basque"}, + {Alpha3bCode: "bel", Alpha2Code: "be", English: "Belarusian"}, + {Alpha3bCode: "ben", Alpha2Code: "bn", English: "Bengali"}, + {Alpha3bCode: "bih", Alpha2Code: "bh", English: "Bihari languages"}, + {Alpha3bCode: "bis", Alpha2Code: "bi", English: "Bislama"}, + {Alpha3bCode: "bos", Alpha2Code: "bs", English: "Bosnian"}, + {Alpha3bCode: "bre", Alpha2Code: "br", English: "Breton"}, + {Alpha3bCode: "bul", Alpha2Code: "bg", English: "Bulgarian"}, + {Alpha3bCode: "bur", Alpha2Code: "my", English: "Burmese"}, + {Alpha3bCode: "cat", Alpha2Code: "ca", English: "Catalan; Valencian"}, + {Alpha3bCode: "cha", Alpha2Code: "ch", English: "Chamorro"}, + {Alpha3bCode: "che", Alpha2Code: "ce", English: "Chechen"}, + {Alpha3bCode: "chi", Alpha2Code: "zh", English: "Chinese"}, + {Alpha3bCode: "chu", Alpha2Code: "cu", English: "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic"}, + {Alpha3bCode: "chv", Alpha2Code: "cv", English: "Chuvash"}, + {Alpha3bCode: "cor", Alpha2Code: "kw", English: "Cornish"}, + {Alpha3bCode: "cos", Alpha2Code: "co", English: "Corsican"}, + {Alpha3bCode: "cre", Alpha2Code: "cr", English: "Cree"}, + {Alpha3bCode: "cze", Alpha2Code: "cs", English: "Czech"}, + {Alpha3bCode: "dan", Alpha2Code: "da", English: "Danish"}, + {Alpha3bCode: "div", Alpha2Code: "dv", English: "Divehi; Dhivehi; Maldivian"}, + {Alpha3bCode: "dut", Alpha2Code: "nl", English: "Dutch; Flemish"}, + {Alpha3bCode: "dzo", Alpha2Code: "dz", English: "Dzongkha"}, + {Alpha3bCode: "eng", Alpha2Code: "en", English: "English"}, + {Alpha3bCode: "epo", Alpha2Code: "eo", English: "Esperanto"}, + {Alpha3bCode: "est", Alpha2Code: "et", English: "Estonian"}, + {Alpha3bCode: "ewe", Alpha2Code: "ee", English: "Ewe"}, + {Alpha3bCode: "fao", Alpha2Code: "fo", English: "Faroese"}, + {Alpha3bCode: "fij", Alpha2Code: "fj", English: "Fijian"}, + {Alpha3bCode: "fin", Alpha2Code: "fi", English: "Finnish"}, + {Alpha3bCode: "fre", Alpha2Code: "fr", English: "French"}, + {Alpha3bCode: "fry", Alpha2Code: "fy", English: "Western Frisian"}, + {Alpha3bCode: "ful", Alpha2Code: "ff", English: "Fulah"}, + {Alpha3bCode: "geo", Alpha2Code: "ka", English: "Georgian"}, + {Alpha3bCode: "ger", Alpha2Code: "de", English: "German"}, + {Alpha3bCode: "gla", Alpha2Code: "gd", English: "Gaelic; Scottish Gaelic"}, + {Alpha3bCode: "gle", Alpha2Code: "ga", English: "Irish"}, + {Alpha3bCode: "glg", Alpha2Code: "gl", English: "Galician"}, + {Alpha3bCode: "glv", Alpha2Code: "gv", English: "Manx"}, + {Alpha3bCode: "gre", Alpha2Code: "el", English: "Greek, Modern (1453-)"}, + {Alpha3bCode: "grn", Alpha2Code: "gn", English: "Guarani"}, + {Alpha3bCode: "guj", Alpha2Code: "gu", English: "Gujarati"}, + {Alpha3bCode: "hat", Alpha2Code: "ht", English: "Haitian; Haitian Creole"}, + {Alpha3bCode: "hau", Alpha2Code: "ha", English: "Hausa"}, + {Alpha3bCode: "heb", Alpha2Code: "he", English: "Hebrew"}, + {Alpha3bCode: "her", Alpha2Code: "hz", English: "Herero"}, + {Alpha3bCode: "hin", Alpha2Code: "hi", English: "Hindi"}, + {Alpha3bCode: "hmo", Alpha2Code: "ho", English: "Hiri Motu"}, + {Alpha3bCode: "hrv", Alpha2Code: "hr", English: "Croatian"}, + {Alpha3bCode: "hun", Alpha2Code: "hu", English: "Hungarian"}, + {Alpha3bCode: "ibo", Alpha2Code: "ig", English: "Igbo"}, + {Alpha3bCode: "ice", Alpha2Code: "is", English: "Icelandic"}, + {Alpha3bCode: "ido", Alpha2Code: "io", English: "Ido"}, + {Alpha3bCode: "iii", Alpha2Code: "ii", English: "Sichuan Yi; Nuosu"}, + {Alpha3bCode: "iku", Alpha2Code: "iu", English: "Inuktitut"}, + {Alpha3bCode: "ile", Alpha2Code: "ie", English: "Interlingue; Occidental"}, + {Alpha3bCode: "ina", Alpha2Code: "ia", English: "Interlingua (International Auxiliary Language Association)"}, + {Alpha3bCode: "ind", Alpha2Code: "id", English: "Indonesian"}, + {Alpha3bCode: "ipk", Alpha2Code: "ik", English: "Inupiaq"}, + {Alpha3bCode: "ita", Alpha2Code: "it", English: "Italian"}, + {Alpha3bCode: "jav", Alpha2Code: "jv", English: "Javanese"}, + {Alpha3bCode: "jpn", Alpha2Code: "ja", English: "Japanese"}, + {Alpha3bCode: "kal", Alpha2Code: "kl", English: "Kalaallisut; Greenlandic"}, + {Alpha3bCode: "kan", Alpha2Code: "kn", English: "Kannada"}, + {Alpha3bCode: "kas", Alpha2Code: "ks", English: "Kashmiri"}, + {Alpha3bCode: "kau", Alpha2Code: "kr", English: "Kanuri"}, + {Alpha3bCode: "kaz", Alpha2Code: "kk", English: "Kazakh"}, + {Alpha3bCode: "khm", Alpha2Code: "km", English: "Central Khmer"}, + {Alpha3bCode: "kik", Alpha2Code: "ki", English: "Kikuyu; Gikuyu"}, + {Alpha3bCode: "kin", Alpha2Code: "rw", English: "Kinyarwanda"}, + {Alpha3bCode: "kir", Alpha2Code: "ky", English: "Kirghiz; Kyrgyz"}, + {Alpha3bCode: "kom", Alpha2Code: "kv", English: "Komi"}, + {Alpha3bCode: "kon", Alpha2Code: "kg", English: "Kongo"}, + {Alpha3bCode: "kor", Alpha2Code: "ko", English: "Korean"}, + {Alpha3bCode: "kua", Alpha2Code: "kj", English: "Kuanyama; Kwanyama"}, + {Alpha3bCode: "kur", Alpha2Code: "ku", English: "Kurdish"}, + {Alpha3bCode: "lao", Alpha2Code: "lo", English: "Lao"}, + {Alpha3bCode: "lat", Alpha2Code: "la", English: "Latin"}, + {Alpha3bCode: "lav", Alpha2Code: "lv", English: "Latvian"}, + {Alpha3bCode: "lim", Alpha2Code: "li", English: "Limburgan; Limburger; Limburgish"}, + {Alpha3bCode: "lin", Alpha2Code: "ln", English: "Lingala"}, + {Alpha3bCode: "lit", Alpha2Code: "lt", English: "Lithuanian"}, + {Alpha3bCode: "ltz", Alpha2Code: "lb", English: "Luxembourgish; Letzeburgesch"}, + {Alpha3bCode: "lub", Alpha2Code: "lu", English: "Luba-Katanga"}, + {Alpha3bCode: "lug", Alpha2Code: "lg", English: "Ganda"}, + {Alpha3bCode: "mac", Alpha2Code: "mk", English: "Macedonian"}, + {Alpha3bCode: "mah", Alpha2Code: "mh", English: "Marshallese"}, + {Alpha3bCode: "mal", Alpha2Code: "ml", English: "Malayalam"}, + {Alpha3bCode: "mao", Alpha2Code: "mi", English: "Maori"}, + {Alpha3bCode: "mar", Alpha2Code: "mr", English: "Marathi"}, + {Alpha3bCode: "may", Alpha2Code: "ms", English: "Malay"}, + {Alpha3bCode: "mlg", Alpha2Code: "mg", English: "Malagasy"}, + {Alpha3bCode: "mlt", Alpha2Code: "mt", English: "Maltese"}, + {Alpha3bCode: "mon", Alpha2Code: "mn", English: "Mongolian"}, + {Alpha3bCode: "nau", Alpha2Code: "na", English: "Nauru"}, + {Alpha3bCode: "nav", Alpha2Code: "nv", English: "Navajo; Navaho"}, + {Alpha3bCode: "nbl", Alpha2Code: "nr", English: "Ndebele, South; South Ndebele"}, + {Alpha3bCode: "nde", Alpha2Code: "nd", English: "Ndebele, North; North Ndebele"}, + {Alpha3bCode: "ndo", Alpha2Code: "ng", English: "Ndonga"}, + {Alpha3bCode: "nep", Alpha2Code: "ne", English: "Nepali"}, + {Alpha3bCode: "nno", Alpha2Code: "nn", English: "Norwegian Nynorsk; Nynorsk, Norwegian"}, + {Alpha3bCode: "nob", Alpha2Code: "nb", English: "Bokmål, Norwegian; Norwegian Bokmål"}, + {Alpha3bCode: "nor", Alpha2Code: "no", English: "Norwegian"}, + {Alpha3bCode: "nya", Alpha2Code: "ny", English: "Chichewa; Chewa; Nyanja"}, + {Alpha3bCode: "oci", Alpha2Code: "oc", English: "Occitan (post 1500); Provençal"}, + {Alpha3bCode: "oji", Alpha2Code: "oj", English: "Ojibwa"}, + {Alpha3bCode: "ori", Alpha2Code: "or", English: "Oriya"}, + {Alpha3bCode: "orm", Alpha2Code: "om", English: "Oromo"}, + {Alpha3bCode: "oss", Alpha2Code: "os", English: "Ossetian; Ossetic"}, + {Alpha3bCode: "pan", Alpha2Code: "pa", English: "Panjabi; Punjabi"}, + {Alpha3bCode: "per", Alpha2Code: "fa", English: "Persian"}, + {Alpha3bCode: "pli", Alpha2Code: "pi", English: "Pali"}, + {Alpha3bCode: "pol", Alpha2Code: "pl", English: "Polish"}, + {Alpha3bCode: "por", Alpha2Code: "pt", English: "Portuguese"}, + {Alpha3bCode: "pus", Alpha2Code: "ps", English: "Pushto; Pashto"}, + {Alpha3bCode: "que", Alpha2Code: "qu", English: "Quechua"}, + {Alpha3bCode: "roh", Alpha2Code: "rm", English: "Romansh"}, + {Alpha3bCode: "rum", Alpha2Code: "ro", English: "Romanian; Moldavian; Moldovan"}, + {Alpha3bCode: "run", Alpha2Code: "rn", English: "Rundi"}, + {Alpha3bCode: "rus", Alpha2Code: "ru", English: "Russian"}, + {Alpha3bCode: "sag", Alpha2Code: "sg", English: "Sango"}, + {Alpha3bCode: "san", Alpha2Code: "sa", English: "Sanskrit"}, + {Alpha3bCode: "sin", Alpha2Code: "si", English: "Sinhala; Sinhalese"}, + {Alpha3bCode: "slo", Alpha2Code: "sk", English: "Slovak"}, + {Alpha3bCode: "slv", Alpha2Code: "sl", English: "Slovenian"}, + {Alpha3bCode: "sme", Alpha2Code: "se", English: "Northern Sami"}, + {Alpha3bCode: "smo", Alpha2Code: "sm", English: "Samoan"}, + {Alpha3bCode: "sna", Alpha2Code: "sn", English: "Shona"}, + {Alpha3bCode: "snd", Alpha2Code: "sd", English: "Sindhi"}, + {Alpha3bCode: "som", Alpha2Code: "so", English: "Somali"}, + {Alpha3bCode: "sot", Alpha2Code: "st", English: "Sotho, Southern"}, + {Alpha3bCode: "spa", Alpha2Code: "es", English: "Spanish; Castilian"}, + {Alpha3bCode: "srd", Alpha2Code: "sc", English: "Sardinian"}, + {Alpha3bCode: "srp", Alpha2Code: "sr", English: "Serbian"}, + {Alpha3bCode: "ssw", Alpha2Code: "ss", English: "Swati"}, + {Alpha3bCode: "sun", Alpha2Code: "su", English: "Sundanese"}, + {Alpha3bCode: "swa", Alpha2Code: "sw", English: "Swahili"}, + {Alpha3bCode: "swe", Alpha2Code: "sv", English: "Swedish"}, + {Alpha3bCode: "tah", Alpha2Code: "ty", English: "Tahitian"}, + {Alpha3bCode: "tam", Alpha2Code: "ta", English: "Tamil"}, + {Alpha3bCode: "tat", Alpha2Code: "tt", English: "Tatar"}, + {Alpha3bCode: "tel", Alpha2Code: "te", English: "Telugu"}, + {Alpha3bCode: "tgk", Alpha2Code: "tg", English: "Tajik"}, + {Alpha3bCode: "tgl", Alpha2Code: "tl", English: "Tagalog"}, + {Alpha3bCode: "tha", Alpha2Code: "th", English: "Thai"}, + {Alpha3bCode: "tib", Alpha2Code: "bo", English: "Tibetan"}, + {Alpha3bCode: "tir", Alpha2Code: "ti", English: "Tigrinya"}, + {Alpha3bCode: "ton", Alpha2Code: "to", English: "Tonga (Tonga Islands)"}, + {Alpha3bCode: "tsn", Alpha2Code: "tn", English: "Tswana"}, + {Alpha3bCode: "tso", Alpha2Code: "ts", English: "Tsonga"}, + {Alpha3bCode: "tuk", Alpha2Code: "tk", English: "Turkmen"}, + {Alpha3bCode: "tur", Alpha2Code: "tr", English: "Turkish"}, + {Alpha3bCode: "twi", Alpha2Code: "tw", English: "Twi"}, + {Alpha3bCode: "uig", Alpha2Code: "ug", English: "Uighur; Uyghur"}, + {Alpha3bCode: "ukr", Alpha2Code: "uk", English: "Ukrainian"}, + {Alpha3bCode: "urd", Alpha2Code: "ur", English: "Urdu"}, + {Alpha3bCode: "uzb", Alpha2Code: "uz", English: "Uzbek"}, + {Alpha3bCode: "ven", Alpha2Code: "ve", English: "Venda"}, + {Alpha3bCode: "vie", Alpha2Code: "vi", English: "Vietnamese"}, + {Alpha3bCode: "vol", Alpha2Code: "vo", English: "Volapük"}, + {Alpha3bCode: "wel", Alpha2Code: "cy", English: "Welsh"}, + {Alpha3bCode: "wln", Alpha2Code: "wa", English: "Walloon"}, + {Alpha3bCode: "wol", Alpha2Code: "wo", English: "Wolof"}, + {Alpha3bCode: "xho", Alpha2Code: "xh", English: "Xhosa"}, + {Alpha3bCode: "yid", Alpha2Code: "yi", English: "Yiddish"}, + {Alpha3bCode: "yor", Alpha2Code: "yo", English: "Yoruba"}, + {Alpha3bCode: "zha", Alpha2Code: "za", English: "Zhuang; Chuang"}, + {Alpha3bCode: "zul", Alpha2Code: "zu", English: "Zulu"}, +} diff --git a/vendor/github.com/asaskevich/govalidator/utils.go b/vendor/github.com/asaskevich/govalidator/utils.go new file mode 100644 index 000000000..888c12751 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/utils.go @@ -0,0 +1,262 @@ +package govalidator + +import ( + "errors" + "fmt" + "html" + "math" + "path" + "regexp" + "strings" + "unicode" + "unicode/utf8" +) + +// Contains check if the string contains the substring. +func Contains(str, substring string) bool { + return strings.Contains(str, substring) +} + +// Matches check if string matches the pattern (pattern is regular expression) +// In case of error return false +func Matches(str, pattern string) bool { + match, _ := regexp.MatchString(pattern, str) + return match +} + +// LeftTrim trim characters from the left-side of the input. +// If second argument is empty, it's will be remove leading spaces. +func LeftTrim(str, chars string) string { + if chars == "" { + return strings.TrimLeftFunc(str, unicode.IsSpace) + } + r, _ := regexp.Compile("^[" + chars + "]+") + return r.ReplaceAllString(str, "") +} + +// RightTrim trim characters from the right-side of the input. +// If second argument is empty, it's will be remove spaces. +func RightTrim(str, chars string) string { + if chars == "" { + return strings.TrimRightFunc(str, unicode.IsSpace) + } + r, _ := regexp.Compile("[" + chars + "]+$") + return r.ReplaceAllString(str, "") +} + +// Trim trim characters from both sides of the input. +// If second argument is empty, it's will be remove spaces. +func Trim(str, chars string) string { + return LeftTrim(RightTrim(str, chars), chars) +} + +// WhiteList remove characters that do not appear in the whitelist. +func WhiteList(str, chars string) string { + pattern := "[^" + chars + "]+" + r, _ := regexp.Compile(pattern) + return r.ReplaceAllString(str, "") +} + +// BlackList remove characters that appear in the blacklist. +func BlackList(str, chars string) string { + pattern := "[" + chars + "]+" + r, _ := regexp.Compile(pattern) + return r.ReplaceAllString(str, "") +} + +// StripLow remove characters with a numerical value < 32 and 127, mostly control characters. +// If keep_new_lines is true, newline characters are preserved (\n and \r, hex 0xA and 0xD). +func StripLow(str string, keepNewLines bool) string { + chars := "" + if keepNewLines { + chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F" + } else { + chars = "\x00-\x1F\x7F" + } + return BlackList(str, chars) +} + +// ReplacePattern replace regular expression pattern in string +func ReplacePattern(str, pattern, replace string) string { + r, _ := regexp.Compile(pattern) + return r.ReplaceAllString(str, replace) +} + +// Escape replace <, >, & and " with HTML entities. +var Escape = html.EscapeString + +func addSegment(inrune, segment []rune) []rune { + if len(segment) == 0 { + return inrune + } + if len(inrune) != 0 { + inrune = append(inrune, '_') + } + inrune = append(inrune, segment...) + return inrune +} + +// UnderscoreToCamelCase converts from underscore separated form to camel case form. +// Ex.: my_func => MyFunc +func UnderscoreToCamelCase(s string) string { + return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1) +} + +// CamelCaseToUnderscore converts from camel case form to underscore separated form. +// Ex.: MyFunc => my_func +func CamelCaseToUnderscore(str string) string { + var output []rune + var segment []rune + for _, r := range str { + if !unicode.IsLower(r) { + output = addSegment(output, segment) + segment = nil + } + segment = append(segment, unicode.ToLower(r)) + } + output = addSegment(output, segment) + return string(output) +} + +// Reverse return reversed string +func Reverse(s string) string { + r := []rune(s) + for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 { + r[i], r[j] = r[j], r[i] + } + return string(r) +} + +// GetLines split string by "\n" and return array of lines +func GetLines(s string) []string { + return strings.Split(s, "\n") +} + +// GetLine return specified line of multiline string +func GetLine(s string, index int) (string, error) { + lines := GetLines(s) + if index < 0 || index >= len(lines) { + return "", errors.New("line index out of bounds") + } + return lines[index], nil +} + +// RemoveTags remove all tags from HTML string +func RemoveTags(s string) string { + return ReplacePattern(s, "<[^>]*>", "") +} + +// SafeFileName return safe string that can be used in file names +func SafeFileName(str string) string { + name := strings.ToLower(str) + name = path.Clean(path.Base(name)) + name = strings.Trim(name, " ") + separators, err := regexp.Compile(`[ &_=+:]`) + if err == nil { + name = separators.ReplaceAllString(name, "-") + } + legal, err := regexp.Compile(`[^[:alnum:]-.]`) + if err == nil { + name = legal.ReplaceAllString(name, "") + } + for strings.Contains(name, "--") { + name = strings.Replace(name, "--", "-", -1) + } + return name +} + +// NormalizeEmail canonicalize an email address. +// The local part of the email address is lowercased for all domains; the hostname is always lowercased and +// the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail). +// Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and +// are stripped of tags (e.g. some.one+tag@gmail.com becomes someone@gmail.com) and all @googlemail.com addresses are +// normalized to @gmail.com. +func NormalizeEmail(str string) (string, error) { + if !IsEmail(str) { + return "", fmt.Errorf("%s is not an email", str) + } + parts := strings.Split(str, "@") + parts[0] = strings.ToLower(parts[0]) + parts[1] = strings.ToLower(parts[1]) + if parts[1] == "gmail.com" || parts[1] == "googlemail.com" { + parts[1] = "gmail.com" + parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0] + } + return strings.Join(parts, "@"), nil +} + +// Truncate a string to the closest length without breaking words. +func Truncate(str string, length int, ending string) string { + var aftstr, befstr string + if len(str) > length { + words := strings.Fields(str) + before, present := 0, 0 + for i := range words { + befstr = aftstr + before = present + aftstr = aftstr + words[i] + " " + present = len(aftstr) + if present > length && i != 0 { + if (length - before) < (present - length) { + return Trim(befstr, " /\\.,\"'#!?&@+-") + ending + } + return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending + } + } + } + + return str +} + +// PadLeft pad left side of string if size of string is less then indicated pad length +func PadLeft(str string, padStr string, padLen int) string { + return buildPadStr(str, padStr, padLen, true, false) +} + +// PadRight pad right side of string if size of string is less then indicated pad length +func PadRight(str string, padStr string, padLen int) string { + return buildPadStr(str, padStr, padLen, false, true) +} + +// PadBoth pad sides of string if size of string is less then indicated pad length +func PadBoth(str string, padStr string, padLen int) string { + return buildPadStr(str, padStr, padLen, true, true) +} + +// PadString either left, right or both sides, not the padding string can be unicode and more then one +// character +func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string { + + // When padded length is less then the current string size + if padLen < utf8.RuneCountInString(str) { + return str + } + + padLen -= utf8.RuneCountInString(str) + + targetLen := padLen + + targetLenLeft := targetLen + targetLenRight := targetLen + if padLeft && padRight { + targetLenLeft = padLen / 2 + targetLenRight = padLen - targetLenLeft + } + + strToRepeatLen := utf8.RuneCountInString(padStr) + + repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen))) + repeatedString := strings.Repeat(padStr, repeatTimes) + + leftSide := "" + if padLeft { + leftSide = repeatedString[0:targetLenLeft] + } + + rightSide := "" + if padRight { + rightSide = repeatedString[0:targetLenRight] + } + + return leftSide + str + rightSide +} diff --git a/vendor/github.com/asaskevich/govalidator/utils_test.go b/vendor/github.com/asaskevich/govalidator/utils_test.go new file mode 100644 index 000000000..154f31594 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/utils_test.go @@ -0,0 +1,500 @@ +package govalidator + +import ( + "reflect" + "testing" +) + +func TestContains(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected bool + }{ + {"abacada", "", true}, + {"abacada", "ritir", false}, + {"abacada", "a", true}, + {"abacada", "aca", true}, + } + for _, test := range tests { + actual := Contains(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected Contains(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestMatches(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected bool + }{ + {"123456789", "[0-9]+", true}, + {"abacada", "cab$", false}, + {"111222333", "((111|222|333)+)+", true}, + {"abacaba", "((123+]", false}, + } + for _, test := range tests { + actual := Matches(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected Matches(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestLeftTrim(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected string + }{ + {" \r\n\tfoo \r\n\t ", "", "foo \r\n\t "}, + {"010100201000", "01", "201000"}, + } + for _, test := range tests { + actual := LeftTrim(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected LeftTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestRightTrim(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected string + }{ + {" \r\n\tfoo \r\n\t ", "", " \r\n\tfoo"}, + {"010100201000", "01", "0101002"}, + } + for _, test := range tests { + actual := RightTrim(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected RightTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestTrim(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected string + }{ + {" \r\n\tfoo \r\n\t ", "", "foo"}, + {"010100201000", "01", "2"}, + {"1234567890987654321", "1-8", "909"}, + } + for _, test := range tests { + actual := Trim(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected Trim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +// This small example illustrate how to work with Trim function. +func ExampleTrim() { + // Remove from left and right spaces and "\r", "\n", "\t" characters + println(Trim(" \r\r\ntext\r \t\n", "") == "text") + // Remove from left and right characters that are between "1" and "8". + // "1-8" is like full list "12345678". + println(Trim("1234567890987654321", "1-8") == "909") +} + +func TestWhiteList(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected string + }{ + {"abcdef", "abc", "abc"}, + {"aaaaaaaaaabbbbbbbbbb", "abc", "aaaaaaaaaabbbbbbbbbb"}, + {"a1b2c3", "abc", "abc"}, + {" ", "abc", ""}, + {"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "aaaaaaaaaaaa"}, + } + for _, test := range tests { + actual := WhiteList(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected WhiteList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +// This small example illustrate how to work with WhiteList function. +func ExampleWhiteList() { + // Remove all characters from string ignoring characters between "a" and "z" + println(WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa") +} + +func TestBlackList(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected string + }{ + {"abcdef", "abc", "def"}, + {"aaaaaaaaaabbbbbbbbbb", "abc", ""}, + {"a1b2c3", "abc", "123"}, + {" ", "abc", " "}, + {"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "34354322345434"}, + } + for _, test := range tests { + actual := BlackList(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected BlackList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestStripLow(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 bool + expected string + }{ + {"foo\x00", false, "foo"}, + {"\x7Ffoo\x02", false, "foo"}, + {"\x01\x09", false, ""}, + {"foo\x0A\x0D", false, "foo"}, + {"perch\u00e9", false, "perch\u00e9"}, + {"\u20ac", false, "\u20ac"}, + {"\u2206\x0A", false, "\u2206"}, + {"foo\x0A\x0D", true, "foo\x0A\x0D"}, + {"\x03foo\x0A\x0D", true, "foo\x0A\x0D"}, + } + for _, test := range tests { + actual := StripLow(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected StripLow(%q,%t) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestReplacePattern(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + param3 string + expected string + }{ + {"ab123ba", "[0-9]+", "aca", "abacaba"}, + {"abacaba", "[0-9]+", "aca", "abacaba"}, + {"httpftp://github.comio", "(ftp|io)", "", "http://github.com"}, + {"aaaaaaaaaa", "a", "", ""}, + {"http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "", "http://github.com"}, + } + for _, test := range tests { + actual := ReplacePattern(test.param1, test.param2, test.param3) + if actual != test.expected { + t.Errorf("Expected ReplacePattern(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) + } + } +} + +// This small example illustrate how to work with ReplacePattern function. +func ExampleReplacePattern() { + // Replace in "http123123ftp://git534543hub.comio" following (pattern "(ftp|io|[0-9]+)"): + // - Sequence "ftp". + // - Sequence "io". + // - Sequence of digits. + // with empty string. + println(ReplacePattern("http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "") == "http://github.com") +} + +func TestEscape(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {`foo&bar`, "<img alt="foo&bar">"}, + } + for _, test := range tests { + actual := Escape(test.param) + if actual != test.expected { + t.Errorf("Expected Escape(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestUnderscoreToCamelCase(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"a_b_c", "ABC"}, + {"my_func", "MyFunc"}, + {"1ab_cd", "1abCd"}, + } + for _, test := range tests { + actual := UnderscoreToCamelCase(test.param) + if actual != test.expected { + t.Errorf("Expected UnderscoreToCamelCase(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestCamelCaseToUnderscore(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"MyFunc", "my_func"}, + {"ABC", "a_b_c"}, + {"1B", "1_b"}, + } + for _, test := range tests { + actual := CamelCaseToUnderscore(test.param) + if actual != test.expected { + t.Errorf("Expected CamelCaseToUnderscore(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestReverse(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"abc", "cba"}, + {"カタカナ", "ナカタカ"}, + } + for _, test := range tests { + actual := Reverse(test.param) + if actual != test.expected { + t.Errorf("Expected Reverse(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestGetLines(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected []string + }{ + {"abc", []string{"abc"}}, + {"a\nb\nc", []string{"a", "b", "c"}}, + } + for _, test := range tests { + actual := GetLines(test.param) + if !reflect.DeepEqual(actual, test.expected) { + t.Errorf("Expected GetLines(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestGetLine(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 int + expected string + }{ + {"abc", 0, "abc"}, + {"a\nb\nc", 0, "a"}, + {"abc", -1, ""}, + {"abacaba\n", 1, ""}, + {"abc", 3, ""}, + } + for _, test := range tests { + actual, _ := GetLine(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected GetLine(%q, %d) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +func TestRemoveTags(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"abc", "abc"}, + {"", ""}, + {"", "Text"}, + {`Link`, "Link"}, + } + for _, test := range tests { + actual := RemoveTags(test.param) + if actual != test.expected { + t.Errorf("Expected RemoveTags(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestSafeFileName(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"abc", "abc"}, + {"123456789 '_-?ASDF@£$%£%^é.html", "123456789-asdf.html"}, + {"ReadMe.md", "readme.md"}, + {"file:///c:/test.go", "test.go"}, + {"../../../Hello World!.txt", "hello-world.txt"}, + } + for _, test := range tests { + actual := SafeFileName(test.param) + if actual != test.expected { + t.Errorf("Expected SafeFileName(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestNormalizeEmail(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {`test@me.com`, `test@me.com`}, + {`some.name@gmail.com`, `somename@gmail.com`}, + {`some.name@googlemail.com`, `somename@gmail.com`}, + {`some.name+extension@gmail.com`, `somename@gmail.com`}, + {`some.name+extension@googlemail.com`, `somename@gmail.com`}, + {`some.name.middlename+extension@gmail.com`, `somenamemiddlename@gmail.com`}, + {`some.name.middlename+extension@googlemail.com`, `somenamemiddlename@gmail.com`}, + {`some.name.midd.lena.me.+extension@gmail.com`, `somenamemiddlename@gmail.com`}, + {`some.name.midd.lena.me.+extension@googlemail.com`, `somenamemiddlename@gmail.com`}, + {`some.name+extension@unknown.com`, `some.name+extension@unknown.com`}, + {`hans@m端ller.com`, `hans@m端ller.com`}, + {`hans`, ``}, + } + for _, test := range tests { + actual, err := NormalizeEmail(test.param) + if actual != test.expected { + t.Errorf("Expected NormalizeEmail(%q) to be %v, got %v, err %v", test.param, test.expected, actual, err) + } + } +} + +func TestTruncate(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 int + param3 string + expected string + }{ + {`Lorem ipsum dolor sit amet, consectetur adipiscing elit.`, 25, `...`, `Lorem ipsum dolor sit amet...`}, + {`Measuring programming progress by lines of code is like measuring aircraft building progress by weight.`, 35, ` new born babies!`, `Measuring programming progress by new born babies!`}, + {`Testestestestestestestestestest testestestestestestestestest`, 7, `...`, `Testestestestestestestestestest...`}, + {`Testing`, 7, `...`, `Testing`}, + } + for _, test := range tests { + actual := Truncate(test.param1, test.param2, test.param3) + if actual != test.expected { + t.Errorf("Expected Truncate(%q, %d, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) + } + } +} + +func TestPadLeft(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + param3 int + expected string + }{ + {"こんにちは", "xyz", 12, "xyzxyzxこんにちは"}, + {"こんにちは", "xyz", 11, "xyzxyzこんにちは"}, + {"abc", "x", 5, "xxabc"}, + {"abc", "xyz", 5, "xyabc"}, + {"abcde", "xyz", 5, "abcde"}, + {"abcde", "xyz", 4, "abcde"}, + } + for _, test := range tests { + actual := PadLeft(test.param1, test.param2, test.param3) + if actual != test.expected { + t.Errorf("Expected PadLeft(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) + } + } +} + +func TestPadRight(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + param3 int + expected string + }{ + {"こんにちは", "xyz", 12, "こんにちはxyzxyzx"}, + {"こんにちは", "xyz", 11, "こんにちはxyzxyz"}, + {"abc", "x", 5, "abcxx"}, + {"abc", "xyz", 5, "abcxy"}, + {"abcde", "xyz", 5, "abcde"}, + {"abcde", "xyz", 4, "abcde"}, + } + for _, test := range tests { + actual := PadRight(test.param1, test.param2, test.param3) + if actual != test.expected { + t.Errorf("Expected PadRight(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) + } + } +} + +func TestPadBoth(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + param3 int + expected string + }{ + {"こんにちは", "xyz", 12, "xyzこんにちはxyzx"}, + {"こんにちは", "xyz", 11, "xyzこんにちはxyz"}, + {"abc", "x", 5, "xabcx"}, + {"abc", "xyz", 5, "xabcx"}, + {"abcde", "xyz", 5, "abcde"}, + {"abcde", "xyz", 4, "abcde"}, + } + for _, test := range tests { + actual := PadBoth(test.param1, test.param2, test.param3) + if actual != test.expected { + t.Errorf("Expected PadBoth(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) + } + } +} diff --git a/vendor/github.com/asaskevich/govalidator/validator.go b/vendor/github.com/asaskevich/govalidator/validator.go new file mode 100644 index 000000000..b699e4449 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/validator.go @@ -0,0 +1,1044 @@ +// Package govalidator is package of validators and sanitizers for strings, structs and collections. +package govalidator + +import ( + "encoding/json" + "fmt" + "net" + "net/url" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" +) + +var ( + fieldsRequiredByDefault bool + notNumberRegexp = regexp.MustCompile("[^0-9]+") + whiteSpacesAndMinus = regexp.MustCompile("[\\s-]+") +) + +const maxURLRuneCount = 2083 +const minURLRuneCount = 3 + +// SetFieldsRequiredByDefault causes validation to fail when struct fields +// do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). +// This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): +// type exampleStruct struct { +// Name string `` +// Email string `valid:"email"` +// This, however, will only fail when Email is empty or an invalid email address: +// type exampleStruct2 struct { +// Name string `valid:"-"` +// Email string `valid:"email"` +// Lastly, this will only fail when Email is an invalid email address but not when it's empty: +// type exampleStruct2 struct { +// Name string `valid:"-"` +// Email string `valid:"email,optional"` +func SetFieldsRequiredByDefault(value bool) { + fieldsRequiredByDefault = value +} + +// IsEmail check if the string is an email. +func IsEmail(str string) bool { + // TODO uppercase letters are not supported + return rxEmail.MatchString(str) +} + +// IsURL check if the string is an URL. +func IsURL(str string) bool { + if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") { + return false + } + u, err := url.Parse(str) + if err != nil { + return false + } + if strings.HasPrefix(u.Host, ".") { + return false + } + if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { + return false + } + return rxURL.MatchString(str) + +} + +// IsRequestURL check if the string rawurl, assuming +// it was received in an HTTP request, is a valid +// URL confirm to RFC 3986 +func IsRequestURL(rawurl string) bool { + url, err := url.ParseRequestURI(rawurl) + if err != nil { + return false //Couldn't even parse the rawurl + } + if len(url.Scheme) == 0 { + return false //No Scheme found + } + return true +} + +// IsRequestURI check if the string rawurl, assuming +// it was received in an HTTP request, is an +// absolute URI or an absolute path. +func IsRequestURI(rawurl string) bool { + _, err := url.ParseRequestURI(rawurl) + return err == nil +} + +// IsAlpha check if the string contains only letters (a-zA-Z). Empty string is valid. +func IsAlpha(str string) bool { + if IsNull(str) { + return true + } + return rxAlpha.MatchString(str) +} + +//IsUTFLetter check if the string contains only unicode letter characters. +//Similar to IsAlpha but for all languages. Empty string is valid. +func IsUTFLetter(str string) bool { + if IsNull(str) { + return true + } + + for _, c := range str { + if !unicode.IsLetter(c) { + return false + } + } + return true + +} + +// IsAlphanumeric check if the string contains only letters and numbers. Empty string is valid. +func IsAlphanumeric(str string) bool { + if IsNull(str) { + return true + } + return rxAlphanumeric.MatchString(str) +} + +// IsUTFLetterNumeric check if the string contains only unicode letters and numbers. Empty string is valid. +func IsUTFLetterNumeric(str string) bool { + if IsNull(str) { + return true + } + for _, c := range str { + if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok + return false + } + } + return true + +} + +// IsNumeric check if the string contains only numbers. Empty string is valid. +func IsNumeric(str string) bool { + if IsNull(str) { + return true + } + return rxNumeric.MatchString(str) +} + +// IsUTFNumeric check if the string contains only unicode numbers of any kind. +// Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid. +func IsUTFNumeric(str string) bool { + if IsNull(str) { + return true + } + if strings.IndexAny(str, "+-") > 0 { + return false + } + if len(str) > 1 { + str = strings.TrimPrefix(str, "-") + str = strings.TrimPrefix(str, "+") + } + for _, c := range str { + if unicode.IsNumber(c) == false { //numbers && minus sign are ok + return false + } + } + return true + +} + +// IsUTFDigit check if the string contains only unicode radix-10 decimal digits. Empty string is valid. +func IsUTFDigit(str string) bool { + if IsNull(str) { + return true + } + if strings.IndexAny(str, "+-") > 0 { + return false + } + if len(str) > 1 { + str = strings.TrimPrefix(str, "-") + str = strings.TrimPrefix(str, "+") + } + for _, c := range str { + if !unicode.IsDigit(c) { //digits && minus sign are ok + return false + } + } + return true + +} + +// IsHexadecimal check if the string is a hexadecimal number. +func IsHexadecimal(str string) bool { + return rxHexadecimal.MatchString(str) +} + +// IsHexcolor check if the string is a hexadecimal color. +func IsHexcolor(str string) bool { + return rxHexcolor.MatchString(str) +} + +// IsRGBcolor check if the string is a valid RGB color in form rgb(RRR, GGG, BBB). +func IsRGBcolor(str string) bool { + return rxRGBcolor.MatchString(str) +} + +// IsLowerCase check if the string is lowercase. Empty string is valid. +func IsLowerCase(str string) bool { + if IsNull(str) { + return true + } + return str == strings.ToLower(str) +} + +// IsUpperCase check if the string is uppercase. Empty string is valid. +func IsUpperCase(str string) bool { + if IsNull(str) { + return true + } + return str == strings.ToUpper(str) +} + +// IsInt check if the string is an integer. Empty string is valid. +func IsInt(str string) bool { + if IsNull(str) { + return true + } + return rxInt.MatchString(str) +} + +// IsFloat check if the string is a float. +func IsFloat(str string) bool { + return str != "" && rxFloat.MatchString(str) +} + +// IsDivisibleBy check if the string is a number that's divisible by another. +// If second argument is not valid integer or zero, it's return false. +// Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero). +func IsDivisibleBy(str, num string) bool { + f, _ := ToFloat(str) + p := int64(f) + q, _ := ToInt(num) + if q == 0 { + return false + } + return (p == 0) || (p%q == 0) +} + +// IsNull check if the string is null. +func IsNull(str string) bool { + return len(str) == 0 +} + +// IsByteLength check if the string's length (in bytes) falls in a range. +func IsByteLength(str string, min, max int) bool { + return len(str) >= min && len(str) <= max +} + +// IsUUIDv3 check if the string is a UUID version 3. +func IsUUIDv3(str string) bool { + return rxUUID3.MatchString(str) +} + +// IsUUIDv4 check if the string is a UUID version 4. +func IsUUIDv4(str string) bool { + return rxUUID4.MatchString(str) +} + +// IsUUIDv5 check if the string is a UUID version 5. +func IsUUIDv5(str string) bool { + return rxUUID5.MatchString(str) +} + +// IsUUID check if the string is a UUID (version 3, 4 or 5). +func IsUUID(str string) bool { + return rxUUID.MatchString(str) +} + +// IsCreditCard check if the string is a credit card. +func IsCreditCard(str string) bool { + sanitized := notNumberRegexp.ReplaceAllString(str, "") + if !rxCreditCard.MatchString(sanitized) { + return false + } + var sum int64 + var digit string + var tmpNum int64 + var shouldDouble bool + for i := len(sanitized) - 1; i >= 0; i-- { + digit = sanitized[i:(i + 1)] + tmpNum, _ = ToInt(digit) + if shouldDouble { + tmpNum *= 2 + if tmpNum >= 10 { + sum += ((tmpNum % 10) + 1) + } else { + sum += tmpNum + } + } else { + sum += tmpNum + } + shouldDouble = !shouldDouble + } + + if sum%10 == 0 { + return true + } + return false +} + +// IsISBN10 check if the string is an ISBN version 10. +func IsISBN10(str string) bool { + return IsISBN(str, 10) +} + +// IsISBN13 check if the string is an ISBN version 13. +func IsISBN13(str string) bool { + return IsISBN(str, 13) +} + +// IsISBN check if the string is an ISBN (version 10 or 13). +// If version value is not equal to 10 or 13, it will be check both variants. +func IsISBN(str string, version int) bool { + sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "") + var checksum int32 + var i int32 + if version == 10 { + if !rxISBN10.MatchString(sanitized) { + return false + } + for i = 0; i < 9; i++ { + checksum += (i + 1) * int32(sanitized[i]-'0') + } + if sanitized[9] == 'X' { + checksum += 10 * 10 + } else { + checksum += 10 * int32(sanitized[9]-'0') + } + if checksum%11 == 0 { + return true + } + return false + } else if version == 13 { + if !rxISBN13.MatchString(sanitized) { + return false + } + factor := []int32{1, 3} + for i = 0; i < 12; i++ { + checksum += factor[i%2] * int32(sanitized[i]-'0') + } + if (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0 { + return true + } + return false + } + return IsISBN(str, 10) || IsISBN(str, 13) +} + +// IsJSON check if the string is valid JSON (note: uses json.Unmarshal). +func IsJSON(str string) bool { + var js json.RawMessage + return json.Unmarshal([]byte(str), &js) == nil +} + +// IsMultibyte check if the string contains one or more multibyte chars. Empty string is valid. +func IsMultibyte(str string) bool { + if IsNull(str) { + return true + } + return rxMultibyte.MatchString(str) +} + +// IsASCII check if the string contains ASCII chars only. Empty string is valid. +func IsASCII(str string) bool { + if IsNull(str) { + return true + } + return rxASCII.MatchString(str) +} + +// IsPrintableASCII check if the string contains printable ASCII chars only. Empty string is valid. +func IsPrintableASCII(str string) bool { + if IsNull(str) { + return true + } + return rxPrintableASCII.MatchString(str) +} + +// IsFullWidth check if the string contains any full-width chars. Empty string is valid. +func IsFullWidth(str string) bool { + if IsNull(str) { + return true + } + return rxFullWidth.MatchString(str) +} + +// IsHalfWidth check if the string contains any half-width chars. Empty string is valid. +func IsHalfWidth(str string) bool { + if IsNull(str) { + return true + } + return rxHalfWidth.MatchString(str) +} + +// IsVariableWidth check if the string contains a mixture of full and half-width chars. Empty string is valid. +func IsVariableWidth(str string) bool { + if IsNull(str) { + return true + } + return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str) +} + +// IsBase64 check if a string is base64 encoded. +func IsBase64(str string) bool { + return rxBase64.MatchString(str) +} + +// IsFilePath check is a string is Win or Unix file path and returns it's type. +func IsFilePath(str string) (bool, int) { + if rxWinPath.MatchString(str) { + //check windows path limit see: + // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath + if len(str[3:]) > 32767 { + return false, Win + } + return true, Win + } else if rxUnixPath.MatchString(str) { + return true, Unix + } + return false, Unknown +} + +// IsDataURI checks if a string is base64 encoded data URI such as an image +func IsDataURI(str string) bool { + dataURI := strings.Split(str, ",") + if !rxDataURI.MatchString(dataURI[0]) { + return false + } + return IsBase64(dataURI[1]) +} + +// IsISO3166Alpha2 checks if a string is valid two-letter country code +func IsISO3166Alpha2(str string) bool { + for _, entry := range ISO3166List { + if str == entry.Alpha2Code { + return true + } + } + return false +} + +// IsISO3166Alpha3 checks if a string is valid three-letter country code +func IsISO3166Alpha3(str string) bool { + for _, entry := range ISO3166List { + if str == entry.Alpha3Code { + return true + } + } + return false +} + +// IsISO693Alpha2 checks if a string is valid two-letter language code +func IsISO693Alpha2(str string) bool { + for _, entry := range ISO693List { + if str == entry.Alpha2Code { + return true + } + } + return false +} + +// IsISO693Alpha3b checks if a string is valid three-letter language code +func IsISO693Alpha3b(str string) bool { + for _, entry := range ISO693List { + if str == entry.Alpha3bCode { + return true + } + } + return false +} + +// IsDNSName will validate the given string as a DNS name +func IsDNSName(str string) bool { + if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 { + // constraints already violated + return false + } + return !IsIP(str) && rxDNSName.MatchString(str) +} + +// IsDialString validates the given string for usage with the various Dial() functions +func IsDialString(str string) bool { + + if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) { + return true + } + + return false +} + +// IsIP checks if a string is either IP version 4 or 6. +func IsIP(str string) bool { + return net.ParseIP(str) != nil +} + +// IsPort checks if a string represents a valid port +func IsPort(str string) bool { + if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 { + return true + } + return false +} + +// IsIPv4 check if the string is an IP version 4. +func IsIPv4(str string) bool { + ip := net.ParseIP(str) + return ip != nil && strings.Contains(str, ".") +} + +// IsIPv6 check if the string is an IP version 6. +func IsIPv6(str string) bool { + ip := net.ParseIP(str) + return ip != nil && strings.Contains(str, ":") +} + +// IsCIDR check if the string is an valid CIDR notiation (IPV4 & IPV6) +func IsCIDR(str string) bool { + _, _, err := net.ParseCIDR(str) + return err == nil +} + +// IsMAC check if a string is valid MAC address. +// Possible MAC formats: +// 01:23:45:67:89:ab +// 01:23:45:67:89:ab:cd:ef +// 01-23-45-67-89-ab +// 01-23-45-67-89-ab-cd-ef +// 0123.4567.89ab +// 0123.4567.89ab.cdef +func IsMAC(str string) bool { + _, err := net.ParseMAC(str) + return err == nil +} + +// IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name +func IsHost(str string) bool { + return IsIP(str) || IsDNSName(str) +} + +// IsMongoID check if the string is a valid hex-encoded representation of a MongoDB ObjectId. +func IsMongoID(str string) bool { + return rxHexadecimal.MatchString(str) && (len(str) == 24) +} + +// IsLatitude check if a string is valid latitude. +func IsLatitude(str string) bool { + return rxLatitude.MatchString(str) +} + +// IsLongitude check if a string is valid longitude. +func IsLongitude(str string) bool { + return rxLongitude.MatchString(str) +} + +func toJSONName(tag string) string { + if tag == "" { + return "" + } + + // JSON name always comes first. If there's no options then split[0] is + // JSON name, if JSON name is not set, then split[0] is an empty string. + split := strings.SplitN(tag, ",", 2) + return split[0] +} + +// ValidateStruct use tags for fields. +// result will be equal to `false` if there are any errors. +func ValidateStruct(s interface{}) (bool, error) { + if s == nil { + return true, nil + } + result := true + var err error + val := reflect.ValueOf(s) + if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { + val = val.Elem() + } + // we only accept structs + if val.Kind() != reflect.Struct { + return false, fmt.Errorf("function only accepts structs; got %s", val.Kind()) + } + var errs Errors + for i := 0; i < val.NumField(); i++ { + valueField := val.Field(i) + typeField := val.Type().Field(i) + if typeField.PkgPath != "" { + continue // Private field + } + structResult := true + if valueField.Kind() == reflect.Struct && typeField.Tag.Get(tagName) != "-" { + var err error + structResult, err = ValidateStruct(valueField.Interface()) + if err != nil { + errs = append(errs, err) + } + } + resultField, err2 := typeCheck(valueField, typeField, val, nil) + if err2 != nil { + + // Replace structure name with JSON name if there is a tag on the variable + jsonTag := toJSONName(typeField.Tag.Get("json")) + if jsonTag != "" { + switch jsonError := err2.(type) { + case Error: + jsonError.Name = jsonTag + err2 = jsonError + case Errors: + err2 = jsonError + } + } + + errs = append(errs, err2) + } + result = result && resultField && structResult + } + if len(errs) > 0 { + err = errs + } + return result, err +} + +// parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""} +func parseTagIntoMap(tag string) tagOptionsMap { + optionsMap := make(tagOptionsMap) + options := strings.SplitN(tag, ",", -1) + for _, option := range options { + validationOptions := strings.Split(option, "~") + if !isValidTag(validationOptions[0]) { + continue + } + if len(validationOptions) == 2 { + optionsMap[validationOptions[0]] = validationOptions[1] + } else { + optionsMap[validationOptions[0]] = "" + } + } + return optionsMap +} + +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("\\'\"!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + default: + if !unicode.IsLetter(c) && !unicode.IsDigit(c) { + return false + } + } + } + return true +} + +// IsSSN will validate the given string as a U.S. Social Security Number +func IsSSN(str string) bool { + if str == "" || len(str) != 11 { + return false + } + return rxSSN.MatchString(str) +} + +// IsSemver check if string is valid semantic version +func IsSemver(str string) bool { + return rxSemver.MatchString(str) +} + +// IsTime check if string is valid according to given format +func IsTime(str string, format string) bool { + _, err := time.Parse(format, str) + return err == nil +} + +// IsRFC3339 check if string is valid timestamp value according to RFC3339 +func IsRFC3339(str string) bool { + return IsTime(str, time.RFC3339) +} + +// IsISO4217 check if string is valid ISO currency code +func IsISO4217(str string) bool { + for _, currency := range ISO4217List { + if str == currency { + return true + } + } + + return false +} + +// ByteLength check string's length +func ByteLength(str string, params ...string) bool { + if len(params) == 2 { + min, _ := ToInt(params[0]) + max, _ := ToInt(params[1]) + return len(str) >= int(min) && len(str) <= int(max) + } + + return false +} + +// RuneLength check string's length +// Alias for StringLength +func RuneLength(str string, params ...string) bool { + return StringLength(str, params...) +} + +// StringMatches checks if a string matches a given pattern. +func StringMatches(s string, params ...string) bool { + if len(params) == 1 { + pattern := params[0] + return Matches(s, pattern) + } + return false +} + +// StringLength check string's length (including multi byte strings) +func StringLength(str string, params ...string) bool { + + if len(params) == 2 { + strLength := utf8.RuneCountInString(str) + min, _ := ToInt(params[0]) + max, _ := ToInt(params[1]) + return strLength >= int(min) && strLength <= int(max) + } + + return false +} + +// Range check string's length +func Range(str string, params ...string) bool { + if len(params) == 2 { + value, _ := ToFloat(str) + min, _ := ToFloat(params[0]) + max, _ := ToFloat(params[1]) + return InRange(value, min, max) + } + + return false +} + +func isInRaw(str string, params ...string) bool { + if len(params) == 1 { + rawParams := params[0] + + parsedParams := strings.Split(rawParams, "|") + + return IsIn(str, parsedParams...) + } + + return false +} + +// IsIn check if string str is a member of the set of strings params +func IsIn(str string, params ...string) bool { + for _, param := range params { + if str == param { + return true + } + } + + return false +} + +func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) { + if requiredOption, isRequired := options["required"]; isRequired { + if len(requiredOption) > 0 { + return false, Error{t.Name, fmt.Errorf(requiredOption), true} + } + return false, Error{t.Name, fmt.Errorf("non zero value required"), false} + } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional { + return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false} + } + // not required and empty is valid + return true, nil +} + +func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) { + if !v.IsValid() { + return false, nil + } + + tag := t.Tag.Get(tagName) + + // Check if the field should be ignored + switch tag { + case "": + if !fieldsRequiredByDefault { + return true, nil + } + return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false} + case "-": + return true, nil + } + + isRootType := false + if options == nil { + isRootType = true + options = parseTagIntoMap(tag) + } + + if isEmptyValue(v) { + // an empty value is not validated, check only required + return checkRequired(v, t, options) + } + + var customTypeErrors Errors + for validatorName, customErrorMessage := range options { + if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok { + delete(options, validatorName) + + if result := validatefunc(v.Interface(), o.Interface()); !result { + if len(customErrorMessage) > 0 { + customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf(customErrorMessage), CustomErrorMessageExists: true}) + continue + } + customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false}) + } + } + } + + if len(customTypeErrors.Errors()) > 0 { + return false, customTypeErrors + } + + if isRootType { + // Ensure that we've checked the value by all specified validators before report that the value is valid + defer func() { + delete(options, "optional") + delete(options, "required") + + if isValid && resultErr == nil && len(options) != 0 { + for validator := range options { + isValid = false + resultErr = Error{t.Name, fmt.Errorf( + "The following validator is invalid or can't be applied to the field: %q", validator), false} + return + } + } + }() + } + + switch v.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, + reflect.String: + // for each tag option check the map of validator functions + for validatorSpec, customErrorMessage := range options { + var negate bool + validator := validatorSpec + customMsgExists := len(customErrorMessage) > 0 + + // Check whether the tag looks like '!something' or 'something' + if validator[0] == '!' { + validator = validator[1:] + negate = true + } + + // Check for param validators + for key, value := range ParamTagRegexMap { + ps := value.FindStringSubmatch(validator) + if len(ps) == 0 { + continue + } + + validatefunc, ok := ParamTagMap[key] + if !ok { + continue + } + + delete(options, validatorSpec) + + switch v.Kind() { + case reflect.String: + field := fmt.Sprint(v) // make value into string, then validate with regex + if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) { + if customMsgExists { + return false, Error{t.Name, fmt.Errorf(customErrorMessage), customMsgExists} + } + if negate { + return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists} + } + return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists} + } + default: + // type not yet supported, fail + return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false} + } + } + + if validatefunc, ok := TagMap[validator]; ok { + delete(options, validatorSpec) + + switch v.Kind() { + case reflect.String: + field := fmt.Sprint(v) // make value into string, then validate with regex + if result := validatefunc(field); !result && !negate || result && negate { + if customMsgExists { + return false, Error{t.Name, fmt.Errorf(customErrorMessage), customMsgExists} + } + if negate { + return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists} + } + return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists} + } + default: + //Not Yet Supported Types (Fail here!) + err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v) + return false, Error{t.Name, err, false} + } + } + } + return true, nil + case reflect.Map: + if v.Type().Key().Kind() != reflect.String { + return false, &UnsupportedTypeError{v.Type()} + } + var sv stringValues + sv = v.MapKeys() + sort.Sort(sv) + result := true + for _, k := range sv { + resultItem, err := ValidateStruct(v.MapIndex(k).Interface()) + if err != nil { + return false, err + } + result = result && resultItem + } + return result, nil + case reflect.Slice, reflect.Array: + result := true + for i := 0; i < v.Len(); i++ { + var resultItem bool + var err error + if v.Index(i).Kind() != reflect.Struct { + resultItem, err = typeCheck(v.Index(i), t, o, options) + if err != nil { + return false, err + } + } else { + resultItem, err = ValidateStruct(v.Index(i).Interface()) + if err != nil { + return false, err + } + } + result = result && resultItem + } + return result, nil + case reflect.Interface: + // If the value is an interface then encode its element + if v.IsNil() { + return true, nil + } + return ValidateStruct(v.Interface()) + case reflect.Ptr: + // If the value is a pointer then check its element + if v.IsNil() { + return true, nil + } + return typeCheck(v.Elem(), t, o, options) + case reflect.Struct: + return ValidateStruct(v.Interface()) + default: + return false, &UnsupportedTypeError{v.Type()} + } +} + +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.String, reflect.Array: + return v.Len() == 0 + case reflect.Map, reflect.Slice: + return v.Len() == 0 || v.IsNil() + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + + return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) +} + +// ErrorByField returns error for specified field of the struct +// validated by ValidateStruct or empty string if there are no errors +// or this field doesn't exists or doesn't have any errors. +func ErrorByField(e error, field string) string { + if e == nil { + return "" + } + return ErrorsByField(e)[field] +} + +// ErrorsByField returns map of errors of the struct validated +// by ValidateStruct or empty map if there are no errors. +func ErrorsByField(e error) map[string]string { + m := make(map[string]string) + if e == nil { + return m + } + // prototype for ValidateStruct + + switch e.(type) { + case Error: + m[e.(Error).Name] = e.(Error).Err.Error() + case Errors: + for _, item := range e.(Errors).Errors() { + n := ErrorsByField(item) + for k, v := range n { + m[k] = v + } + } + } + + return m +} + +// Error returns string equivalent for reflect.Type +func (e *UnsupportedTypeError) Error() string { + return "validator: unsupported type: " + e.Type.String() +} + +func (sv stringValues) Len() int { return len(sv) } +func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } +func (sv stringValues) get(i int) string { return sv[i].String() } diff --git a/vendor/github.com/asaskevich/govalidator/validator_test.go b/vendor/github.com/asaskevich/govalidator/validator_test.go new file mode 100644 index 000000000..3537232d5 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/validator_test.go @@ -0,0 +1,2864 @@ +package govalidator + +import ( + "fmt" + "strings" + "testing" + "time" +) + +func init() { + CustomTypeTagMap.Set("customFalseValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + return false + })) + CustomTypeTagMap.Set("customTrueValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + return true + })) +} + +func TestIsAlpha(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"\n", false}, + {"\r", false}, + {"Ⅸ", false}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc1", false}, + {"abc〩", false}, + {"abc", true}, + {"소주", false}, + {"ABC", true}, + {"FoObAr", true}, + {"소aBC", false}, + {"소", false}, + {"달기&Co.", false}, + {"〩Hours", false}, + {"\ufff0", false}, + {"\u0070", true}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", false}, //UTF-8(ASCII): 0 + {"123", false}, + {"0123", false}, + {"-00123", false}, + {"0", false}, + {"-0", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"-1¾", false}, + {"1¾", false}, + {"〥〩", false}, + {"모자", false}, + {"ix", true}, + {"۳۵۶۰", false}, + {"1--", false}, + {"1-1", false}, + {"-", false}, + {"--", false}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", false}, + } + for _, test := range tests { + actual := IsAlpha(test.param) + if actual != test.expected { + t.Errorf("Expected IsAlpha(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsUTFLetter(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"\n", false}, + {"\r", false}, + {"Ⅸ", false}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc1", false}, + {"abc〩", false}, + {"", true}, + {"abc", true}, + {"소주", true}, + {"ABC", true}, + {"FoObAr", true}, + {"소aBC", true}, + {"소", true}, + {"달기&Co.", false}, + {"〩Hours", false}, + {"\ufff0", false}, + {"\u0070", true}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", false}, //UTF-8(ASCII): 0 + {"123", false}, + {"0123", false}, + {"-00123", false}, + {"0", false}, + {"-0", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"-1¾", false}, + {"1¾", false}, + {"〥〩", false}, + {"모자", true}, + {"ix", true}, + {"۳۵۶۰", false}, + {"1--", false}, + {"1-1", false}, + {"-", false}, + {"--", false}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", false}, + } + for _, test := range tests { + actual := IsUTFLetter(test.param) + if actual != test.expected { + t.Errorf("Expected IsUTFLetter(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsAlphanumeric(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"\n", false}, + {"\r", false}, + {"Ⅸ", false}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc123", true}, + {"ABC111", true}, + {"abc1", true}, + {"abc〩", false}, + {"abc", true}, + {"소주", false}, + {"ABC", true}, + {"FoObAr", true}, + {"소aBC", false}, + {"소", false}, + {"달기&Co.", false}, + {"〩Hours", false}, + {"\ufff0", false}, + {"\u0070", true}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", true}, //UTF-8(ASCII): 0 + {"123", true}, + {"0123", true}, + {"-00123", false}, + {"0", true}, + {"-0", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"-1¾", false}, + {"1¾", false}, + {"〥〩", false}, + {"모자", false}, + {"ix", true}, + {"۳۵۶۰", false}, + {"1--", false}, + {"1-1", false}, + {"-", false}, + {"--", false}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", false}, + } + for _, test := range tests { + actual := IsAlphanumeric(test.param) + if actual != test.expected { + t.Errorf("Expected IsAlphanumeric(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsUTFLetterNumeric(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"\n", false}, + {"\r", false}, + {"Ⅸ", true}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc1", true}, + {"abc〩", true}, + {"abc", true}, + {"소주", true}, + {"ABC", true}, + {"FoObAr", true}, + {"소aBC", true}, + {"소", true}, + {"달기&Co.", false}, + {"〩Hours", true}, + {"\ufff0", false}, + {"\u0070", true}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", true}, //UTF-8(ASCII): 0 + {"123", true}, + {"0123", true}, + {"-00123", false}, + {"0", true}, + {"-0", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"-1¾", false}, + {"1¾", true}, + {"〥〩", true}, + {"모자", true}, + {"ix", true}, + {"۳۵۶۰", true}, + {"1--", false}, + {"1-1", false}, + {"-", false}, + {"--", false}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", false}, + } + for _, test := range tests { + actual := IsUTFLetterNumeric(test.param) + if actual != test.expected { + t.Errorf("Expected IsUTFLetterNumeric(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsNumeric(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"\n", false}, + {"\r", false}, + {"Ⅸ", false}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc1", false}, + {"abc〩", false}, + {"abc", false}, + {"소주", false}, + {"ABC", false}, + {"FoObAr", false}, + {"소aBC", false}, + {"소", false}, + {"달기&Co.", false}, + {"〩Hours", false}, + {"\ufff0", false}, + {"\u0070", false}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", true}, //UTF-8(ASCII): 0 + {"123", true}, + {"0123", true}, + {"-00123", false}, + {"+00123", false}, + {"0", true}, + {"-0", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"12𐅪3", false}, + {"-1¾", false}, + {"1¾", false}, + {"〥〩", false}, + {"모자", false}, + {"ix", false}, + {"۳۵۶۰", false}, + {"1--", false}, + {"1-1", false}, + {"-", false}, + {"--", false}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", false}, + } + for _, test := range tests { + actual := IsNumeric(test.param) + if actual != test.expected { + t.Errorf("Expected IsNumeric(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsUTFNumeric(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"\n", false}, + {"\r", false}, + {"Ⅸ", true}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc1", false}, + {"abc〩", false}, + {"abc", false}, + {"소주", false}, + {"ABC", false}, + {"FoObAr", false}, + {"소aBC", false}, + {"소", false}, + {"달기&Co.", false}, + {"〩Hours", false}, + {"\ufff0", false}, + {"\u0070", false}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", true}, //UTF-8(ASCII): 0 + {"123", true}, + {"0123", true}, + {"-00123", true}, + {"0", true}, + {"-0", true}, + {"--0", false}, + {"-0-", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"12𐅪3", true}, + {"-1¾", true}, + {"1¾", true}, + {"〥〩", true}, + {"모자", false}, + {"ix", false}, + {"۳۵۶۰", true}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", true}, + } + for _, test := range tests { + actual := IsUTFNumeric(test.param) + if actual != test.expected { + t.Errorf("Expected IsUTFNumeric(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsUTFDigit(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + + {"\n", false}, + {"\r", false}, + {"Ⅸ", false}, + {"", true}, + {" fooo ", false}, + {"abc!!!", false}, + {"abc1", false}, + {"abc〩", false}, + {"abc", false}, + {"소주", false}, + {"ABC", false}, + {"FoObAr", false}, + {"소aBC", false}, + {"소", false}, + {"달기&Co.", false}, + {"〩Hours", false}, + {"\ufff0", false}, + {"\u0070", false}, //UTF-8(ASCII): p + {"\u0026", false}, //UTF-8(ASCII): & + {"\u0030", true}, //UTF-8(ASCII): 0 + {"123", true}, + {"0123", true}, + {"-00123", true}, + {"0", true}, + {"-0", true}, + {"--0", false}, + {"-0-", false}, + {"123.123", false}, + {" ", false}, + {".", false}, + {"12𐅪3", false}, + {"1483920", true}, + {"", true}, + {"۳۵۶۰", true}, + {"-29", true}, + {"-1¾", false}, + {"1¾", false}, + {"〥〩", false}, + {"모자", false}, + {"ix", false}, + {"۳۵۶۰", true}, + {"1++", false}, + {"1+1", false}, + {"+", false}, + {"++", false}, + {"+1", true}, + } + for _, test := range tests { + actual := IsUTFDigit(test.param) + if actual != test.expected { + t.Errorf("Expected IsUTFDigit(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsLowerCase(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"abc123", true}, + {"abc", true}, + {"a b c", true}, + {"abcß", true}, + {"abcẞ", false}, + {"ABCẞ", false}, + {"tr竪s 端ber", true}, + {"fooBar", false}, + {"123ABC", false}, + {"ABC123", false}, + {"ABC", false}, + {"S T R", false}, + {"fooBar", false}, + {"abacaba123", true}, + } + for _, test := range tests { + actual := IsLowerCase(test.param) + if actual != test.expected { + t.Errorf("Expected IsLowerCase(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsUpperCase(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"abc123", false}, + {"abc", false}, + {"a b c", false}, + {"abcß", false}, + {"abcẞ", false}, + {"ABCẞ", true}, + {"tr竪s 端ber", false}, + {"fooBar", false}, + {"123ABC", true}, + {"ABC123", true}, + {"ABC", true}, + {"S T R", true}, + {"fooBar", false}, + {"abacaba123", false}, + } + for _, test := range tests { + actual := IsUpperCase(test.param) + if actual != test.expected { + t.Errorf("Expected IsUpperCase(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsInt(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"-2147483648", true}, //Signed 32 Bit Min Int + {"2147483647", true}, //Signed 32 Bit Max Int + {"-2147483649", true}, //Signed 32 Bit Min Int - 1 + {"2147483648", true}, //Signed 32 Bit Max Int + 1 + {"4294967295", true}, //Unsigned 32 Bit Max Int + {"4294967296", true}, //Unsigned 32 Bit Max Int + 1 + {"-9223372036854775808", true}, //Signed 64 Bit Min Int + {"9223372036854775807", true}, //Signed 64 Bit Max Int + {"-9223372036854775809", true}, //Signed 64 Bit Min Int - 1 + {"9223372036854775808", true}, //Signed 64 Bit Max Int + 1 + {"18446744073709551615", true}, //Unsigned 64 Bit Max Int + {"18446744073709551616", true}, //Unsigned 64 Bit Max Int + 1 + {"", true}, + {"123", true}, + {"0", true}, + {"-0", true}, + {"+0", true}, + {"01", false}, + {"123.123", false}, + {" ", false}, + {"000", false}, + } + for _, test := range tests { + actual := IsInt(test.param) + if actual != test.expected { + t.Errorf("Expected IsInt(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsEmail(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"foo@bar.com", true}, + {"x@x.x", true}, + {"foo@bar.com.au", true}, + {"foo+bar@bar.com", true}, + {"foo@bar.coffee", true}, + {"foo@bar.coffee..coffee", false}, + {"foo@bar.bar.coffee", true}, + {"foo@bar.中文网", true}, + {"invalidemail@", false}, + {"invalid.com", false}, + {"@invalid.com", false}, + {"test|123@m端ller.com", true}, + {"hans@m端ller.com", true}, + {"hans.m端ller@test.com", true}, + {"NathAn.daVIeS@DomaIn.cOM", true}, + {"NATHAN.DAVIES@DOMAIN.CO.UK", true}, + } + for _, test := range tests { + actual := IsEmail(test.param) + if actual != test.expected { + t.Errorf("Expected IsEmail(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsURL(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"http://foo.bar#com", true}, + {"http://foobar.com", true}, + {"https://foobar.com", true}, + {"foobar.com", true}, + {"http://foobar.coffee/", true}, + {"http://foobar.中文网/", true}, + {"http://foobar.org/", true}, + {"http://foobar.ORG", true}, + {"http://foobar.org:8080/", true}, + {"ftp://foobar.ru/", true}, + {"ftp.foo.bar", true}, + {"http://user:pass@www.foobar.com/", true}, + {"http://user:pass@www.foobar.com/path/file", true}, + {"http://127.0.0.1/", true}, + {"http://duckduckgo.com/?q=%2F", true}, + {"http://localhost:3000/", true}, + {"http://foobar.com/?foo=bar#baz=qux", true}, + {"http://foobar.com?foo=bar", true}, + {"http://www.xn--froschgrn-x9a.net/", true}, + {"http://foobar.com/a-", true}, + {"http://foobar.پاکستان/", true}, + {"http://foobar.c_o_m", false}, + {"", false}, + {"xyz://foobar.com", false}, + // {"invalid.", false}, is it false like "localhost."? + {".com", false}, + {"rtmp://foobar.com", false}, + {"http://www.foo_bar.com/", false}, + {"http://localhost:3000/", true}, + {"http://foobar.com#baz=qux", true}, + {"http://foobar.com/t$-_.+!*\\'(),", true}, + {"http://www.foobar.com/~foobar", true}, + {"http://www.-foobar.com/", false}, + {"http://www.foo---bar.com/", false}, + {"http://r6---snnvoxuioq6.googlevideo.com", true}, + {"mailto:someone@example.com", true}, + {"irc://irc.server.org/channel", false}, + {"irc://#channel@network", true}, + {"/abs/test/dir", false}, + {"./rel/test/dir", false}, + {"http://foo^bar.org", false}, + {"http://foo&*bar.org", false}, + {"http://foo&bar.org", false}, + {"http://foo bar.org", false}, + {"http://foo.bar.org", true}, + {"http://www.foo.bar.org", true}, + {"http://www.foo.co.uk", true}, + {"foo", false}, + {"http://.foo.com", false}, + {"http://,foo.com", false}, + {",foo.com", false}, + {"http://myservice.:9093/", true}, + // according to issues #62 #66 + {"https://pbs.twimg.com/profile_images/560826135676588032/j8fWrmYY_normal.jpeg", true}, + // according to #125 + {"http://prometheus-alertmanager.service.q:9093", true}, + {"https://www.logn-123-123.url.with.sigle.letter.d:12345/url/path/foo?bar=zzz#user", true}, + {"http://me.example.com", true}, + {"http://www.me.example.com", true}, + {"https://farm6.static.flickr.com", true}, + {"https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5", true}, + {"google", false}, + // According to #87 + {"http://hyphenated-host-name.example.co.in", true}, + {"http://cant-end-with-hyphen-.example.com", false}, + {"http://-cant-start-with-hyphen.example.com", false}, + {"http://www.domain-can-have-dashes.com", true}, + {"http://m.abcd.com/test.html", true}, + {"http://m.abcd.com/a/b/c/d/test.html?args=a&b=c", true}, + {"http://[::1]:9093", true}, + {"http://[::1]:909388", false}, + {"1200::AB00:1234::2552:7777:1313", false}, + {"http://[2001:db8:a0b:12f0::1]/index.html", true}, + {"http://[1200:0000:AB00:1234:0000:2552:7777:1313]", true}, + {"http://user:pass@[::1]:9093/a/b/c/?a=v#abc", true}, + {"https://127.0.0.1/a/b/c?a=v&c=11d", true}, + {"https://foo_bar.example.com", true}, + {"http://foo_bar.example.com", true}, + {"http://foo_bar_fizz_buzz.example.com", true}, + {"http://_cant_start_with_underescore", false}, + {"http://cant_end_with_underescore_", false}, + {"foo_bar.example.com", true}, + {"foo_bar_fizz_buzz.example.com", true}, + {"http://hello_world.example.com", true}, + } + for _, test := range tests { + actual := IsURL(test.param) + if actual != test.expected { + t.Errorf("Expected IsURL(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsRequestURL(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"http://foo.bar/#com", true}, + {"http://foobar.com", true}, + {"https://foobar.com", true}, + {"foobar.com", false}, + {"http://foobar.coffee/", true}, + {"http://foobar.中文网/", true}, + {"http://foobar.org/", true}, + {"http://foobar.org:8080/", true}, + {"ftp://foobar.ru/", true}, + {"http://user:pass@www.foobar.com/", true}, + {"http://127.0.0.1/", true}, + {"http://duckduckgo.com/?q=%2F", true}, + {"http://localhost:3000/", true}, + {"http://foobar.com/?foo=bar#baz=qux", true}, + {"http://foobar.com?foo=bar", true}, + {"http://www.xn--froschgrn-x9a.net/", true}, + {"", false}, + {"xyz://foobar.com", true}, + {"invalid.", false}, + {".com", false}, + {"rtmp://foobar.com", true}, + {"http://www.foo_bar.com/", true}, + {"http://localhost:3000/", true}, + {"http://foobar.com/#baz=qux", true}, + {"http://foobar.com/t$-_.+!*\\'(),", true}, + {"http://www.foobar.com/~foobar", true}, + {"http://www.-foobar.com/", true}, + {"http://www.foo---bar.com/", true}, + {"mailto:someone@example.com", true}, + {"irc://irc.server.org/channel", true}, + {"irc://#channel@network", true}, + {"/abs/test/dir", false}, + {"./rel/test/dir", false}, + } + for _, test := range tests { + actual := IsRequestURL(test.param) + if actual != test.expected { + t.Errorf("Expected IsRequestURL(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsRequestURI(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"http://foo.bar/#com", true}, + {"http://foobar.com", true}, + {"https://foobar.com", true}, + {"foobar.com", false}, + {"http://foobar.coffee/", true}, + {"http://foobar.中文网/", true}, + {"http://foobar.org/", true}, + {"http://foobar.org:8080/", true}, + {"ftp://foobar.ru/", true}, + {"http://user:pass@www.foobar.com/", true}, + {"http://127.0.0.1/", true}, + {"http://duckduckgo.com/?q=%2F", true}, + {"http://localhost:3000/", true}, + {"http://foobar.com/?foo=bar#baz=qux", true}, + {"http://foobar.com?foo=bar", true}, + {"http://www.xn--froschgrn-x9a.net/", true}, + {"xyz://foobar.com", true}, + {"invalid.", false}, + {".com", false}, + {"rtmp://foobar.com", true}, + {"http://www.foo_bar.com/", true}, + {"http://localhost:3000/", true}, + {"http://foobar.com/#baz=qux", true}, + {"http://foobar.com/t$-_.+!*\\'(),", true}, + {"http://www.foobar.com/~foobar", true}, + {"http://www.-foobar.com/", true}, + {"http://www.foo---bar.com/", true}, + {"mailto:someone@example.com", true}, + {"irc://irc.server.org/channel", true}, + {"irc://#channel@network", true}, + {"/abs/test/dir", true}, + {"./rel/test/dir", false}, + } + for _, test := range tests { + actual := IsRequestURI(test.param) + if actual != test.expected { + t.Errorf("Expected IsRequestURI(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsFloat(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {" ", false}, + {"-.123", false}, + {"abacaba", false}, + {"1f", false}, + {"-1f", false}, + {"+1f", false}, + {"123", true}, + {"123.", true}, + {"123.123", true}, + {"-123.123", true}, + {"+123.123", true}, + {"0.123", true}, + {"-0.123", true}, + {"+0.123", true}, + {".0", true}, + {"01.123", true}, + {"-0.22250738585072011e-307", true}, + {"+0.22250738585072011e-307", true}, + } + for _, test := range tests { + actual := IsFloat(test.param) + if actual != test.expected { + t.Errorf("Expected IsFloat(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsHexadecimal(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"abcdefg", false}, + {"", false}, + {"..", false}, + {"deadBEEF", true}, + {"ff0044", true}, + } + for _, test := range tests { + actual := IsHexadecimal(test.param) + if actual != test.expected { + t.Errorf("Expected IsHexadecimal(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsHexcolor(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"#ff", false}, + {"fff0", false}, + {"#ff12FG", false}, + {"CCccCC", true}, + {"fff", true}, + {"#f00", true}, + } + for _, test := range tests { + actual := IsHexcolor(test.param) + if actual != test.expected { + t.Errorf("Expected IsHexcolor(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsRGBcolor(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"rgb(0,31,255)", true}, + {"rgb(1,349,275)", false}, + {"rgb(01,31,255)", false}, + {"rgb(0.6,31,255)", false}, + {"rgba(0,31,255)", false}, + {"rgb(0, 31, 255)", true}, + } + for _, test := range tests { + actual := IsRGBcolor(test.param) + if actual != test.expected { + t.Errorf("Expected IsRGBcolor(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsNull(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"abacaba", false}, + {"", true}, + } + for _, test := range tests { + actual := IsNull(test.param) + if actual != test.expected { + t.Errorf("Expected IsNull(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsDivisibleBy(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 string + expected bool + }{ + {"4", "2", true}, + {"100", "10", true}, + {"", "1", true}, + {"123", "foo", false}, + {"123", "0", false}, + } + for _, test := range tests { + actual := IsDivisibleBy(test.param1, test.param2) + if actual != test.expected { + t.Errorf("Expected IsDivisibleBy(%q, %q) to be %v, got %v", test.param1, test.param2, test.expected, actual) + } + } +} + +// This small example illustrate how to work with IsDivisibleBy function. +func ExampleIsDivisibleBy() { + println("1024 is divisible by 64: ", IsDivisibleBy("1024", "64")) +} + +func TestIsByteLength(t *testing.T) { + t.Parallel() + + var tests = []struct { + param1 string + param2 int + param3 int + expected bool + }{ + {"abacaba", 100, -1, false}, + {"abacaba", 1, 3, false}, + {"abacaba", 1, 7, true}, + {"abacaba", 0, 8, true}, + {"\ufff0", 1, 1, false}, + } + for _, test := range tests { + actual := IsByteLength(test.param1, test.param2, test.param3) + if actual != test.expected { + t.Errorf("Expected IsByteLength(%q, %q, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) + } + } +} + +func TestIsJSON(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"145", true}, + {"asdf", false}, + {"123:f00", false}, + {"{\"Name\":\"Alice\",\"Body\":\"Hello\",\"Time\":1294706395881547000}", true}, + {"{}", true}, + {"{\"Key\":{\"Key\":{\"Key\":123}}}", true}, + {"[]", true}, + {"null", true}, + } + for _, test := range tests { + actual := IsJSON(test.param) + if actual != test.expected { + t.Errorf("Expected IsJSON(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsMultibyte(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"abc", false}, + {"123", false}, + {"<>@;.-=", false}, + {"ひらがな・カタカナ、.漢字", true}, + {"あいうえお foobar", true}, + {"test@example.com", true}, + {"test@example.com", true}, + {"1234abcDExyz", true}, + {"カタカナ", true}, + } + for _, test := range tests { + actual := IsMultibyte(test.param) + if actual != test.expected { + t.Errorf("Expected IsMultibyte(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsASCII(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"foobar", false}, + {"xyz098", false}, + {"123456", false}, + {"カタカナ", false}, + {"foobar", true}, + {"0987654321", true}, + {"test@example.com", true}, + {"1234abcDEF", true}, + {"", true}, + } + for _, test := range tests { + actual := IsASCII(test.param) + if actual != test.expected { + t.Errorf("Expected IsASCII(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsPrintableASCII(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"foobar", false}, + {"xyz098", false}, + {"123456", false}, + {"カタカナ", false}, + {"foobar", true}, + {"0987654321", true}, + {"test@example.com", true}, + {"1234abcDEF", true}, + {"newline\n", false}, + {"\x19test\x7F", false}, + } + for _, test := range tests { + actual := IsPrintableASCII(test.param) + if actual != test.expected { + t.Errorf("Expected IsPrintableASCII(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsFullWidth(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"abc", false}, + {"abc123", false}, + {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false}, + {"ひらがな・カタカナ、.漢字", true}, + {"3ー0 a@com", true}, + {"Fカタカナ゙ᆲ", true}, + {"Good=Parts", true}, + {"", true}, + } + for _, test := range tests { + actual := IsFullWidth(test.param) + if actual != test.expected { + t.Errorf("Expected IsFullWidth(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsHalfWidth(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"あいうえお", false}, + {"0011", false}, + {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", true}, + {"l-btn_02--active", true}, + {"abc123い", true}, + {"カタカナ゙ᆲ←", true}, + {"", true}, + } + for _, test := range tests { + actual := IsHalfWidth(test.param) + if actual != test.expected { + t.Errorf("Expected IsHalfWidth(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsVariableWidth(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {"ひらがなカタカナ漢字ABCDE", true}, + {"3ー0123", true}, + {"Fカタカナ゙ᆲ", true}, + {"", true}, + {"Good=Parts", true}, + {"abc", false}, + {"abc123", false}, + {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false}, + {"ひらがな・カタカナ、.漢字", false}, + {"123456", false}, + {"カタカナ゙ᆲ", false}, + } + for _, test := range tests { + actual := IsVariableWidth(test.param) + if actual != test.expected { + t.Errorf("Expected IsVariableWidth(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsUUID(t *testing.T) { + t.Parallel() + + // Tests without version + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, + {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, + {"a987fbc94bed3078cf079141ba07c9f3", false}, + {"934859", false}, + {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, + {"aaaaaaaa-1111-1111-aaag-111111111111", false}, + {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, + } + for _, test := range tests { + actual := IsUUID(test.param) + if actual != test.expected { + t.Errorf("Expected IsUUID(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // UUID ver. 3 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"412452646", false}, + {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, + {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, + {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, + } + for _, test := range tests { + actual := IsUUIDv3(test.param) + if actual != test.expected { + t.Errorf("Expected IsUUIDv3(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // UUID ver. 4 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, + {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, + {"934859", false}, + {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, + {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, + } + for _, test := range tests { + actual := IsUUIDv4(test.param) + if actual != test.expected { + t.Errorf("Expected IsUUIDv4(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // UUID ver. 5 + tests = []struct { + param string + expected bool + }{ + + {"", false}, + {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, + {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, + {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, + {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, + {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, + } + for _, test := range tests { + actual := IsUUIDv5(test.param) + if actual != test.expected { + t.Errorf("Expected IsUUIDv5(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsCreditCard(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"foo", false}, + {"5398228707871528", false}, + {"375556917985515", true}, + {"36050234196908", true}, + {"4716461583322103", true}, + {"4716-2210-5188-5662", true}, + {"4929 7226 5379 7141", true}, + {"5398228707871527", true}, + } + for _, test := range tests { + actual := IsCreditCard(test.param) + if actual != test.expected { + t.Errorf("Expected IsCreditCard(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsISBN(t *testing.T) { + t.Parallel() + + // Without version + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"foo", false}, + {"3836221195", true}, + {"1-61729-085-8", true}, + {"3 423 21412 0", true}, + {"3 401 01319 X", true}, + {"9784873113685", true}, + {"978-4-87311-368-5", true}, + {"978 3401013190", true}, + {"978-3-8362-2119-1", true}, + } + for _, test := range tests { + actual := IsISBN(test.param, -1) + if actual != test.expected { + t.Errorf("Expected IsISBN(%q, -1) to be %v, got %v", test.param, test.expected, actual) + } + } + + // ISBN 10 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"foo", false}, + {"3423214121", false}, + {"978-3836221191", false}, + {"3-423-21412-1", false}, + {"3 423 21412 1", false}, + {"3836221195", true}, + {"1-61729-085-8", true}, + {"3 423 21412 0", true}, + {"3 401 01319 X", true}, + } + for _, test := range tests { + actual := IsISBN10(test.param) + if actual != test.expected { + t.Errorf("Expected IsISBN10(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // ISBN 13 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"foo", false}, + {"3-8362-2119-5", false}, + {"01234567890ab", false}, + {"978 3 8362 2119 0", false}, + {"9784873113685", true}, + {"978-4-87311-368-5", true}, + {"978 3401013190", true}, + {"978-3-8362-2119-1", true}, + } + for _, test := range tests { + actual := IsISBN13(test.param) + if actual != test.expected { + t.Errorf("Expected IsISBN13(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsDataURI(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, + {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, + {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, + {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + + "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + + "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + + "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + + "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + + "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, + {"data:image/png;base64,12345", false}, + {"", false}, + {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, + } + for _, test := range tests { + actual := IsDataURI(test.param) + if actual != test.expected { + t.Errorf("Expected IsDataURI(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsBase64(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, + {"Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, + {"U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", true}, + {"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + + "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + + "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + + "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + + "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + + "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, + {"12345", false}, + {"", false}, + {"Vml2YW11cyBmZXJtZtesting123", false}, + } + for _, test := range tests { + actual := IsBase64(test.param) + if actual != test.expected { + t.Errorf("Expected IsBase64(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsISO3166Alpha2(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"ABCD", false}, + {"A", false}, + {"AC", false}, + {"AP", false}, + {"GER", false}, + {"NU", true}, + {"DE", true}, + {"JP", true}, + {"JPN", false}, + {"ZWE", false}, + {"GER", false}, + {"DEU", false}, + } + for _, test := range tests { + actual := IsISO3166Alpha2(test.param) + if actual != test.expected { + t.Errorf("Expected IsISO3166Alpha2(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsISO3166Alpha3(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"ABCD", false}, + {"A", false}, + {"AC", false}, + {"AP", false}, + {"NU", false}, + {"DE", false}, + {"JP", false}, + {"ZWE", true}, + {"JPN", true}, + {"GER", false}, + {"DEU", true}, + } + for _, test := range tests { + actual := IsISO3166Alpha3(test.param) + if actual != test.expected { + t.Errorf("Expected IsISO3166Alpha3(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsISO693Alpha2(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"abcd", false}, + {"a", false}, + {"ac", false}, + {"ap", false}, + {"de", true}, + {"DE", false}, + {"mk", true}, + {"mac", false}, + {"sw", true}, + {"SW", false}, + {"ger", false}, + {"deu", false}, + } + for _, test := range tests { + actual := IsISO693Alpha2(test.param) + if actual != test.expected { + t.Errorf("Expected IsISO693Alpha2(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsISO693Alpha3b(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"abcd", false}, + {"a", false}, + {"ac", false}, + {"ap", false}, + {"de", false}, + {"DE", false}, + {"mkd", false}, + {"mac", true}, + {"sw", false}, + {"SW", false}, + {"ger", true}, + {"deu", false}, + } + for _, test := range tests { + actual := IsISO693Alpha3b(test.param) + if actual != test.expected { + t.Errorf("Expected IsISO693Alpha3b(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsIP(t *testing.T) { + t.Parallel() + + // Without version + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"0.0.0.0", true}, + {"255.255.255.255", true}, + {"1.2.3.4", true}, + {"::1", true}, + {"2001:db8:0000:1:1:1:1:1", true}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsIP(test.param) + if actual != test.expected { + t.Errorf("Expected IsIP(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // IPv4 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"0.0.0.0", true}, + {"255.255.255.255", true}, + {"1.2.3.4", true}, + {"::1", false}, + {"2001:db8:0000:1:1:1:1:1", false}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsIPv4(test.param) + if actual != test.expected { + t.Errorf("Expected IsIPv4(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // IPv6 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", false}, + {"0.0.0.0", false}, + {"255.255.255.255", false}, + {"1.2.3.4", false}, + {"::1", true}, + {"2001:db8:0000:1:1:1:1:1", true}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsIPv6(test.param) + if actual != test.expected { + t.Errorf("Expected IsIPv6(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsPort(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"1", true}, + {"65535", true}, + {"0", false}, + {"65536", false}, + {"65538", false}, + } + + for _, test := range tests { + actual := IsPort(test.param) + if actual != test.expected { + t.Errorf("Expected IsPort(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsDNSName(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"localhost", true}, + {"a.bc", true}, + {"a.b.", true}, + {"a.b..", false}, + {"localhost.local", true}, + {"localhost.localdomain.intern", true}, + {"l.local.intern", true}, + {"ru.link.n.svpncloud.com", true}, + {"-localhost", false}, + {"localhost.-localdomain", false}, + {"localhost.localdomain.-int", false}, + {"_localhost", true}, + {"localhost._localdomain", true}, + {"localhost.localdomain._int", true}, + {"lÖcalhost", false}, + {"localhost.lÖcaldomain", false}, + {"localhost.localdomain.üntern", false}, + {"__", true}, + {"localhost/", false}, + {"127.0.0.1", false}, + {"[::1]", false}, + {"50.50.50.50", false}, + {"localhost.localdomain.intern:65535", false}, + {"漢字汉字", false}, + {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de", false}, + } + + for _, test := range tests { + actual := IsDNSName(test.param) + if actual != test.expected { + t.Errorf("Expected IsDNS(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsHost(t *testing.T) { + t.Parallel() + var tests = []struct { + param string + expected bool + }{ + {"localhost", true}, + {"localhost.localdomain", true}, + {"2001:db8:0000:1:1:1:1:1", true}, + {"::1", true}, + {"play.golang.org", true}, + {"localhost.localdomain.intern:65535", false}, + {"-[::1]", false}, + {"-localhost", false}, + {".localhost", false}, + } + for _, test := range tests { + actual := IsHost(test.param) + if actual != test.expected { + t.Errorf("Expected IsHost(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + +} + +func TestIsDialString(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"localhost.local:1", true}, + {"localhost.localdomain:9090", true}, + {"localhost.localdomain.intern:65535", true}, + {"127.0.0.1:30000", true}, + {"[::1]:80", true}, + {"[1200::AB00:1234::2552:7777:1313]:22", false}, + {"-localhost:1", false}, + {"localhost.-localdomain:9090", false}, + {"localhost.localdomain.-int:65535", false}, + {"localhost.loc:100000", false}, + {"漢字汉字:2", false}, + {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de:20000", false}, + } + + for _, test := range tests { + actual := IsDialString(test.param) + if actual != test.expected { + t.Errorf("Expected IsDialString(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsMAC(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"3D:F2:C9:A6:B3:4F", true}, + {"3D-F2-C9-A6-B3:4F", false}, + {"123", false}, + {"", false}, + {"abacaba", false}, + } + for _, test := range tests { + actual := IsMAC(test.param) + if actual != test.expected { + t.Errorf("Expected IsMAC(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestFilePath(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + osType int + }{ + {"c:\\" + strings.Repeat("a", 32767), true, Win}, //See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath + {"c:\\" + strings.Repeat("a", 32768), false, Win}, + {"c:\\path\\file (x86)\bar", true, Win}, + {"c:\\path\\file", true, Win}, + {"c:\\path\\file:exe", false, Unknown}, + {"C:\\", true, Win}, + {"c:\\path\\file\\", true, Win}, + {"c:/path/file/", false, Unknown}, + {"/path/file/", true, Unix}, + {"/path/file:SAMPLE/", true, Unix}, + {"/path/file:/.txt", true, Unix}, + {"/path", true, Unix}, + {"/path/__bc/file.txt", true, Unix}, + {"/path/a--ac/file.txt", true, Unix}, + {"/_path/file.txt", true, Unix}, + {"/path/__bc/file.txt", true, Unix}, + {"/path/a--ac/file.txt", true, Unix}, + {"/__path/--file.txt", true, Unix}, + {"/path/a bc", true, Unix}, + } + for _, test := range tests { + actual, osType := IsFilePath(test.param) + if actual != test.expected || osType != test.osType { + t.Errorf("Expected IsFilePath(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsLatitude(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"-90.000", true}, + {"+90", true}, + {"47.1231231", true}, + {"+99.9", false}, + {"108", false}, + } + for _, test := range tests { + actual := IsLatitude(test.param) + if actual != test.expected { + t.Errorf("Expected IsLatitude(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsLongitude(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"-180.000", true}, + {"180.1", false}, + {"+73.234", true}, + {"+382.3811", false}, + {"23.11111111", true}, + } + for _, test := range tests { + actual := IsLongitude(test.param) + if actual != test.expected { + t.Errorf("Expected IsLongitude(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsSSN(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"00-90-8787", false}, + {"66690-76", false}, + {"191 60 2869", true}, + {"191-60-2869", true}, + } + for _, test := range tests { + actual := IsSSN(test.param) + if actual != test.expected { + t.Errorf("Expected IsSSN(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsMongoID(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"507f1f77bcf86cd799439011", true}, + {"507f1f77bcf86cd7994390", false}, + {"507f1f77bcf86cd79943901z", false}, + {"507f1f77bcf86cd799439011 ", false}, + {"", false}, + } + for _, test := range tests { + actual := IsMongoID(test.param) + if actual != test.expected { + t.Errorf("Expected IsMongoID(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsSemver(t *testing.T) { + t.Parallel() + var tests = []struct { + param string + expected bool + }{ + {"v1.0.0", true}, + {"1.0.0", true}, + {"1.1.01", false}, + {"1.01.0", false}, + {"01.1.0", false}, + {"v1.1.01", false}, + {"v1.01.0", false}, + {"v01.1.0", false}, + {"1.0.0-alpha", true}, + {"1.0.0-alpha.1", true}, + {"1.0.0-0.3.7", true}, + {"1.0.0-0.03.7", false}, + {"1.0.0-00.3.7", false}, + {"1.0.0-x.7.z.92", true}, + {"1.0.0-alpha+001", true}, + {"1.0.0+20130313144700", true}, + {"1.0.0-beta+exp.sha.5114f85", true}, + {"1.0.0-beta+exp.sha.05114f85", true}, + {"1.0.0-+beta", false}, + {"1.0.0-b+-9+eta", false}, + {"v+1.8.0-b+-9+eta", false}, + } + for _, test := range tests { + actual := IsSemver(test.param) + if actual != test.expected { + t.Errorf("Expected IsSemver(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsTime(t *testing.T) { + t.Parallel() + var tests = []struct { + param string + format string + expected bool + }{ + {"2016-12-31 11:00", time.RFC3339, false}, + {"2016-12-31 11:00:00", time.RFC3339, false}, + {"2016-12-31T11:00", time.RFC3339, false}, + {"2016-12-31T11:00:00", time.RFC3339, false}, + {"2016-12-31T11:00:00Z", time.RFC3339, true}, + {"2016-12-31T11:00:00+01:00", time.RFC3339, true}, + {"2016-12-31T11:00:00-01:00", time.RFC3339, true}, + {"2016-12-31T11:00:00.05Z", time.RFC3339, true}, + {"2016-12-31T11:00:00.05-01:00", time.RFC3339, true}, + {"2016-12-31T11:00:00.05+01:00", time.RFC3339, true}, + } + for _, test := range tests { + actual := IsTime(test.param, test.format) + if actual != test.expected { + t.Errorf("Expected IsTime(%q, time.RFC3339) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsRFC3339(t *testing.T) { + t.Parallel() + var tests = []struct { + param string + expected bool + }{ + {"2016-12-31 11:00", false}, + {"2016-12-31 11:00:00", false}, + {"2016-12-31T11:00", false}, + {"2016-12-31T11:00:00", false}, + {"2016-12-31T11:00:00Z", true}, + {"2016-12-31T11:00:00+01:00", true}, + {"2016-12-31T11:00:00-01:00", true}, + {"2016-12-31T11:00:00.05Z", true}, + {"2016-12-31T11:00:00.05-01:00", true}, + {"2016-12-31T11:00:00.05+01:00", true}, + } + for _, test := range tests { + actual := IsRFC3339(test.param) + if actual != test.expected { + t.Errorf("Expected IsRFC3339(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestIsISO4217(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"ABCD", false}, + {"A", false}, + {"ZZZ", false}, + {"usd", false}, + {"USD", true}, + } + for _, test := range tests { + actual := IsISO4217(test.param) + if actual != test.expected { + t.Errorf("Expected IsISO4217(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestByteLength(t *testing.T) { + t.Parallel() + + var tests = []struct { + value string + min string + max string + expected bool + }{ + {"123456", "0", "100", true}, + {"1239999", "0", "0", false}, + {"1239asdfasf99", "100", "200", false}, + {"1239999asdff29", "10", "30", true}, + {"你", "0", "1", false}, + } + for _, test := range tests { + actual := ByteLength(test.value, test.min, test.max) + if actual != test.expected { + t.Errorf("Expected ByteLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) + } + } +} + +func TestRuneLength(t *testing.T) { + t.Parallel() + + var tests = []struct { + value string + min string + max string + expected bool + }{ + {"123456", "0", "100", true}, + {"1239999", "0", "0", false}, + {"1239asdfasf99", "100", "200", false}, + {"1239999asdff29", "10", "30", true}, + {"你", "0", "1", true}, + } + for _, test := range tests { + actual := RuneLength(test.value, test.min, test.max) + if actual != test.expected { + t.Errorf("Expected RuneLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) + } + } +} + +func TestStringLength(t *testing.T) { + t.Parallel() + + var tests = []struct { + value string + min string + max string + expected bool + }{ + {"123456", "0", "100", true}, + {"1239999", "0", "0", false}, + {"1239asdfasf99", "100", "200", false}, + {"1239999asdff29", "10", "30", true}, + {"あいうえお", "0", "5", true}, + {"あいうえおか", "0", "5", false}, + {"あいうえお", "0", "0", false}, + {"あいうえ", "5", "10", false}, + } + for _, test := range tests { + actual := StringLength(test.value, test.min, test.max) + if actual != test.expected { + t.Errorf("Expected StringLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) + } + } +} + +func TestIsIn(t *testing.T) { + t.Parallel() + + var tests = []struct { + value string + params []string + expected bool + }{ + {"PRESENT", []string{"PRESENT"}, true}, + {"PRESENT", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, true}, + {"PRÉSENTE", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, true}, + {"PRESENT", []string{}, false}, + {"PRESENT", nil, false}, + {"ABSENT", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, false}, + {"", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, false}, + } + for _, test := range tests { + actual := IsIn(test.value, test.params...) + if actual != test.expected { + t.Errorf("Expected IsIn(%s, %v) to be %v, got %v", test.value, test.params, test.expected, actual) + } + } +} + +type Address struct { + Street string `valid:"-"` + Zip string `json:"zip" valid:"numeric,required"` +} + +type User struct { + Name string `valid:"required"` + Email string `valid:"required,email"` + Password string `valid:"required"` + Age int `valid:"required,numeric,@#\u0000"` + Home *Address + Work []Address +} + +type UserValid struct { + Name string `valid:"required"` + Email string `valid:"required,email"` + Password string `valid:"required"` + Age int `valid:"required"` + Home *Address + Work []Address `valid:"required"` +} + +type PrivateStruct struct { + privateField string `valid:"required,alpha,d_k"` + NonZero int + ListInt []int + ListString []string `valid:"alpha"` + Work [2]Address + Home Address + Map map[string]Address +} + +type NegationStruct struct { + NotInt string `valid:"!int"` + Int string `valid:"int"` +} + +type LengthStruct struct { + Length string `valid:"length(10|20)"` +} + +type StringLengthStruct struct { + Length string `valid:"stringlength(10|20)"` +} + +type StringMatchesStruct struct { + StringMatches string `valid:"matches(^[0-9]{3}$)"` +} + +// TODO: this testcase should be fixed +// type StringMatchesComplexStruct struct { +// StringMatches string `valid:"matches(^\\$\\([\"']\\w+[\"']\\)$)"` +// } + +type IsInStruct struct { + IsIn string `valid:"in(PRESENT|PRÉSENTE|NOTABSENT)"` +} + +type Post struct { + Title string `valid:"alpha,required"` + Message string `valid:"ascii"` + AuthorIP string `valid:"ipv4"` +} + +type MissingValidationDeclarationStruct struct { + Name string `` + Email string `valid:"required,email"` +} + +type FieldsRequiredByDefaultButExemptStruct struct { + Name string `valid:"-"` + Email string `valid:"email"` +} + +type FieldsRequiredByDefaultButExemptOrOptionalStruct struct { + Name string `valid:"-"` + Email string `valid:"optional,email"` +} + +type MessageWithSeveralFieldsStruct struct { + Title string `valid:"length(1|10)"` + Body string `valid:"length(1|10)"` +} + +func TestValidateMissingValidationDeclarationStruct(t *testing.T) { + var tests = []struct { + param MissingValidationDeclarationStruct + expected bool + }{ + {MissingValidationDeclarationStruct{}, false}, + {MissingValidationDeclarationStruct{Name: "TEST", Email: "test@example.com"}, false}, + } + SetFieldsRequiredByDefault(true) + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } + SetFieldsRequiredByDefault(false) +} + +func TestFieldsRequiredByDefaultButExemptStruct(t *testing.T) { + var tests = []struct { + param FieldsRequiredByDefaultButExemptStruct + expected bool + }{ + {FieldsRequiredByDefaultButExemptStruct{}, false}, + {FieldsRequiredByDefaultButExemptStruct{Name: "TEST"}, false}, + {FieldsRequiredByDefaultButExemptStruct{Email: ""}, false}, + {FieldsRequiredByDefaultButExemptStruct{Email: "test@example.com"}, true}, + } + SetFieldsRequiredByDefault(true) + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } + SetFieldsRequiredByDefault(false) +} + +func TestFieldsRequiredByDefaultButExemptOrOptionalStruct(t *testing.T) { + var tests = []struct { + param FieldsRequiredByDefaultButExemptOrOptionalStruct + expected bool + }{ + {FieldsRequiredByDefaultButExemptOrOptionalStruct{}, true}, + {FieldsRequiredByDefaultButExemptOrOptionalStruct{Name: "TEST"}, true}, + {FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: ""}, true}, + {FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: "test@example.com"}, true}, + {FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: "test@example"}, false}, + } + SetFieldsRequiredByDefault(true) + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } + SetFieldsRequiredByDefault(false) +} + +func TestInvalidValidator(t *testing.T) { + type InvalidStruct struct { + Field int `valid:"someInvalidValidator"` + } + + invalidStruct := InvalidStruct{1} + if valid, err := ValidateStruct(&invalidStruct); valid || err == nil || + err.Error() != `Field: The following validator is invalid or can't be applied to the field: "someInvalidValidator";` { + t.Errorf("Got an unexpected result for struct with invalid validator: %t %s", valid, err) + } +} + +func TestCustomValidator(t *testing.T) { + type ValidStruct struct { + Field int `valid:"customTrueValidator"` + } + + type InvalidStruct struct { + Field int `valid:"customFalseValidator~Custom validator error"` + } + + type StructWithCustomAndBuiltinValidator struct { + Field int `valid:"customTrueValidator,required"` + } + + if valid, err := ValidateStruct(&ValidStruct{Field: 1}); !valid || err != nil { + t.Errorf("Got an unexpected result for struct with custom always true validator: %t %s", valid, err) + } + + if valid, err := ValidateStruct(&InvalidStruct{Field: 1}); valid || err == nil || err.Error() != "Custom validator error;;" { + t.Errorf("Got an unexpected result for struct with custom always false validator: %t %s", valid, err) + } + + mixedStruct := StructWithCustomAndBuiltinValidator{} + if valid, err := ValidateStruct(&mixedStruct); valid || err == nil || err.Error() != "Field: non zero value required;" { + t.Errorf("Got an unexpected result for invalid struct with custom and built-in validators: %t %s", valid, err) + } + + mixedStruct.Field = 1 + if valid, err := ValidateStruct(&mixedStruct); !valid || err != nil { + t.Errorf("Got an unexpected result for valid struct with custom and built-in validators: %t %s", valid, err) + } +} + +type CustomByteArray [6]byte + +type StructWithCustomByteArray struct { + ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` + Email string `valid:"email"` + CustomMinLength int `valid:"-"` +} + +func TestStructWithCustomByteArray(t *testing.T) { + t.Parallel() + + // add our custom byte array validator that fails when the byte array is pristine (all zeroes) + CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + switch v := o.(type) { + case StructWithCustomByteArray: + if len(v.Email) > 0 { + if v.Email != "test@example.com" { + t.Errorf("v.Email should have been 'test@example.com' but was '%s'", v.Email) + } + } + default: + t.Errorf("Context object passed to custom validator should have been a StructWithCustomByteArray but was %T (%+v)", o, o) + } + + switch v := i.(type) { + case CustomByteArray: + for _, e := range v { // check if v is empty, i.e. all zeroes + if e != 0 { + return true + } + } + } + return false + })) + CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + switch v := o.(type) { + case StructWithCustomByteArray: + return len(v.ID) >= v.CustomMinLength + } + return false + })) + testCustomByteArray := CustomByteArray{'1', '2', '3', '4', '5', '6'} + var tests = []struct { + param StructWithCustomByteArray + expected bool + }{ + {StructWithCustomByteArray{}, false}, + {StructWithCustomByteArray{Email: "test@example.com"}, false}, + {StructWithCustomByteArray{ID: testCustomByteArray, Email: "test@example.com"}, true}, + {StructWithCustomByteArray{ID: testCustomByteArray, Email: "test@example.com", CustomMinLength: 7}, false}, + } + SetFieldsRequiredByDefault(true) + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } + SetFieldsRequiredByDefault(false) +} + +func TestValidateNegationStruct(t *testing.T) { + var tests = []struct { + param NegationStruct + expected bool + }{ + {NegationStruct{"a1", "11"}, true}, + {NegationStruct{"email@email.email", "11"}, true}, + {NegationStruct{"123456----", "11"}, true}, + {NegationStruct{"::1", "11"}, true}, + {NegationStruct{"123.123", "11"}, true}, + {NegationStruct{"a1", "a1"}, false}, + {NegationStruct{"11", "a1"}, false}, + {NegationStruct{"11", "11"}, false}, + } + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestLengthStruct(t *testing.T) { + var tests = []struct { + param interface{} + expected bool + }{ + {LengthStruct{"11111"}, false}, + {LengthStruct{"11111111111111111110000000000000000"}, false}, + {LengthStruct{"11dfffdf0099"}, true}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestStringLengthStruct(t *testing.T) { + var tests = []struct { + param interface{} + expected bool + }{ + {StringLengthStruct{"11111"}, false}, + {StringLengthStruct{"11111111111111111110000000000000000"}, false}, + {StringLengthStruct{"11dfffdf0099"}, true}, + {StringLengthStruct{"あいうえお"}, false}, + {StringLengthStruct{"あいうえおかきくけこ"}, true}, + {StringLengthStruct{"あいうえおかきくけこさしすせそたちつてと"}, true}, + {StringLengthStruct{"あいうえおかきくけこさしすせそたちつてとな"}, false}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestStringMatchesStruct(t *testing.T) { + var tests = []struct { + param interface{} + expected bool + }{ + {StringMatchesStruct{"123"}, true}, + {StringMatchesStruct{"123456"}, false}, + {StringMatchesStruct{"123abcd"}, false}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestIsInStruct(t *testing.T) { + var tests = []struct { + param interface{} + expected bool + }{ + {IsInStruct{"PRESENT"}, true}, + {IsInStruct{""}, true}, + {IsInStruct{" "}, false}, + {IsInStruct{"ABSENT"}, false}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestRequiredIsInStruct(t *testing.T) { + type RequiredIsInStruct struct { + IsIn string `valid:"in(PRESENT|PRÉSENTE|NOTABSENT),required"` + } + + var tests = []struct { + param interface{} + expected bool + }{ + {RequiredIsInStruct{"PRESENT"}, true}, + {RequiredIsInStruct{""}, false}, + {RequiredIsInStruct{" "}, false}, + {RequiredIsInStruct{"ABSENT"}, false}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestEmptyRequiredIsInStruct(t *testing.T) { + type EmptyRequiredIsInStruct struct { + IsIn string `valid:"in(),required"` + } + + var tests = []struct { + param interface{} + expected bool + }{ + {EmptyRequiredIsInStruct{"PRESENT"}, false}, + {EmptyRequiredIsInStruct{""}, false}, + {EmptyRequiredIsInStruct{" "}, false}, + {EmptyRequiredIsInStruct{"ABSENT"}, false}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestFunkyIsInStruct(t *testing.T) { + type FunkyIsInStruct struct { + IsIn string `valid:"in(PRESENT|| |PRÉSENTE|NOTABSENT)"` + } + + var tests = []struct { + param interface{} + expected bool + }{ + {FunkyIsInStruct{"PRESENT"}, true}, + {FunkyIsInStruct{""}, true}, + {FunkyIsInStruct{" "}, true}, + {FunkyIsInStruct{"ABSENT"}, false}, + } + + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +// TODO: test case broken +// func TestStringMatchesComplexStruct(t *testing.T) { +// var tests = []struct { +// param interface{} +// expected bool +// }{ +// {StringMatchesComplexStruct{"$()"}, false}, +// {StringMatchesComplexStruct{"$('AZERTY')"}, true}, +// {StringMatchesComplexStruct{`$("AZERTY")`}, true}, +// {StringMatchesComplexStruct{`$("")`}, false}, +// {StringMatchesComplexStruct{"AZERTY"}, false}, +// {StringMatchesComplexStruct{"$AZERTY"}, false}, +// } + +// for _, test := range tests { +// actual, err := ValidateStruct(test.param) +// if actual != test.expected { +// t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) +// if err != nil { +// t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) +// } +// } +// } +// } + +func TestValidateStruct(t *testing.T) { + + var tests = []struct { + param interface{} + expected bool + }{ + {User{"John", "john@yahoo.com", "123G#678", 20, &Address{"Street", "123456"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, false}, + {User{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, + {User{"John", "", "12345", 0, &Address{"Street", "123456789"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, + {UserValid{"John", "john@yahoo.com", "123G#678", 20, &Address{"Street", "123456"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, true}, + {UserValid{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{}}, false}, + {UserValid{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, + {UserValid{"John", "", "12345", 0, &Address{"Street", "123456789"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false}, + {nil, true}, + {User{"John", "john@yahoo.com", "123G#678", 0, &Address{"Street", "123456"}, []Address{}}, false}, + {"im not a struct", false}, + } + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } + + TagMap["d_k"] = Validator(func(str string) bool { + return str == "d_k" + }) + result, err := ValidateStruct(PrivateStruct{"d_k", 0, []int{1, 2}, []string{"hi", "super"}, [2]Address{{"Street", "123456"}, + {"Street", "123456"}}, Address{"Street", "123456"}, map[string]Address{"address": {"Street", "123456"}}}) + if result != true { + t.Log("Case ", 6, ": expected ", true, " when result is ", result) + t.Error(err) + t.FailNow() + } +} + +type testByteArray [8]byte +type testByteMap map[byte]byte +type testByteSlice []byte + +func TestRequired(t *testing.T) { + + testString := "foobar" + var tests = []struct { + param interface{} + expected bool + }{ + { + struct { + Pointer *string `valid:"required"` + }{}, + false, + }, + { + struct { + Pointer *string `valid:"required"` + }{ + Pointer: &testString, + }, + true, + }, + { + struct { + Addr Address `valid:"required"` + }{}, + false, + }, + { + struct { + Addr Address `valid:"required"` + }{ + Addr: Address{"", "123"}, + }, + true, + }, + { + struct { + Pointer *Address `valid:"required"` + }{}, + false, + }, + { + struct { + Pointer *Address `valid:"required"` + }{ + Pointer: &Address{"", "123"}, + }, + true, + }, + { + struct { + TestByteArray testByteArray `valid:"required"` + }{}, + false, + }, + { + struct { + TestByteArray testByteArray `valid:"required"` + }{ + testByteArray{}, + }, + false, + }, + { + struct { + TestByteArray testByteArray `valid:"required"` + }{ + testByteArray{'1', '2', '3', '4', '5', '6', '7', 'A'}, + }, + true, + }, + { + struct { + TestByteMap testByteMap `valid:"required"` + }{}, + false, + }, + { + struct { + TestByteSlice testByteSlice `valid:"required"` + }{}, + false, + }, + } + for _, test := range tests { + actual, err := ValidateStruct(test.param) + if actual != test.expected { + t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual) + if err != nil { + t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err) + } + } + } +} + +func TestErrorByField(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"message", ""}, + {"Message", ""}, + {"title", ""}, + {"Title", "My123 does not validate as alpha"}, + {"AuthorIP", "123 does not validate as ipv4"}, + } + post := &Post{"My123", "duck13126", "123"} + _, err := ValidateStruct(post) + + for _, test := range tests { + actual := ErrorByField(err, test.param) + if actual != test.expected { + t.Errorf("Expected ErrorByField(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestErrorsByField(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected string + }{ + {"Title", "My123 does not validate as alpha"}, + {"AuthorIP", "123 does not validate as ipv4"}, + } + post := &Post{Title: "My123", Message: "duck13126", AuthorIP: "123"} + _, err := ValidateStruct(post) + errs := ErrorsByField(err) + if len(errs) != 2 { + t.Errorf("There should only be 2 errors but got %v", len(errs)) + } + + for _, test := range tests { + if actual, ok := errs[test.param]; !ok || actual != test.expected { + t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + tests = []struct { + param string + expected string + }{ + {"Title", ";:;message;:; does not validate as length(1|10)"}, + {"Body", ";:;message;:; does not validate as length(1|10)"}, + } + + message := &MessageWithSeveralFieldsStruct{Title: ";:;message;:;", Body: ";:;message;:;"} + _, err = ValidateStruct(message) + errs = ErrorsByField(err) + if len(errs) != 2 { + t.Errorf("There should only be 2 errors but got %v", len(errs)) + } + + for _, test := range tests { + if actual, ok := errs[test.param]; !ok || actual != test.expected { + t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + tests = []struct { + param string + expected string + }{ + {"CustomField", "An error occurred"}, + } + + err = Error{"CustomField", fmt.Errorf("An error occurred"), false} + errs = ErrorsByField(err) + + if len(errs) != 1 { + t.Errorf("There should only be 1 errors but got %v", len(errs)) + } + + for _, test := range tests { + if actual, ok := errs[test.param]; !ok || actual != test.expected { + t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + type StructWithCustomValidation struct { + Email string `valid:"email"` + ID string `valid:"falseValidation"` + } + + CustomTypeTagMap.Set("falseValidation", CustomTypeValidator(func(i interface{}, o interface{}) bool { + return false + })) + + tests = []struct { + param string + expected string + }{ + {"Email", "My123 does not validate as email"}, + {"ID", "duck13126 does not validate as falseValidation"}, + } + s := &StructWithCustomValidation{Email: "My123", ID: "duck13126"} + _, err = ValidateStruct(s) + errs = ErrorsByField(err) + if len(errs) != 2 { + t.Errorf("There should only be 2 errors but got %v", len(errs)) + } + + for _, test := range tests { + if actual, ok := errs[test.param]; !ok || actual != test.expected { + t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestValidateStructPointers(t *testing.T) { + // Struct which uses pointers for values + type UserWithPointers struct { + Name *string `valid:"-"` + Email *string `valid:"email"` + FavoriteFood *string `valid:"length(0|32)"` + Nerd *bool `valid:"-"` + } + + var tests = []struct { + param string + expected string + }{ + {"Name", ""}, + {"Email", "invalid does not validate as email"}, + {"FavoriteFood", ""}, + {"Nerd", ""}, + } + + name := "Herman" + email := "invalid" + food := "Pizza" + nerd := true + user := &UserWithPointers{&name, &email, &food, &nerd} + _, err := ValidateStruct(user) + + for _, test := range tests { + actual := ErrorByField(err, test.param) + if actual != test.expected { + t.Errorf("Expected ErrorByField(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func ExampleValidateStruct() { + type Post struct { + Title string `valid:"alphanum,required"` + Message string `valid:"duck,ascii"` + AuthorIP string `valid:"ipv4"` + } + post := &Post{"My Example Post", "duck", "123.234.54.3"} + + //Add your own struct validation tags + TagMap["duck"] = Validator(func(str string) bool { + return str == "duck" + }) + + result, err := ValidateStruct(post) + if err != nil { + println("error: " + err.Error()) + } + println(result) +} + +func TestIsCIDR(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"193.168.3.20/7", true}, + {"2001:db8::/32", true}, + {"2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", true}, + {"193.138.3.20/60", false}, + {"500.323.2.23/43", false}, + {"", false}, + } + for _, test := range tests { + actual := IsCIDR(test.param) + if actual != test.expected { + t.Errorf("Expected IsCIDR(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +func TestOptionalCustomValidators(t *testing.T) { + + CustomTypeTagMap.Set("f2", CustomTypeValidator(func(i interface{}, o interface{}) bool { + return false + })) + + var val struct { + WithCustomError string `valid:"f2~boom,optional"` + WithoutCustomError string `valid:"f2,optional"` + OptionalFirst string `valid:"optional,f2"` + } + + ok, err := ValidateStruct(val) + + if err != nil { + t.Errorf("Expected nil err with optional validation, got %v", err) + } + + if !ok { + t.Error("Expected validation to return true, got false") + } +} + +func TestJSONValidator(t *testing.T) { + + var val struct { + WithJSONName string `json:"with_json_name" valid:"-,required"` + WithoutJSONName string `valid:"-,required"` + WithJSONOmit string `json:"with_other_json_name,omitempty" valid:"-,required"` + WithJSONOption string `json:",omitempty" valid:"-,required"` + } + + _, err := ValidateStruct(val) + + if err == nil { + t.Error("Expected error but got no error") + } + + if Contains(err.Error(), "WithJSONName") { + t.Errorf("Expected error message to contain with_json_name but actual error is: %s", err.Error()) + } + + if Contains(err.Error(), "WithoutJSONName") == false { + t.Errorf("Expected error message to contain WithoutJSONName but actual error is: %s", err.Error()) + } + + if Contains(err.Error(), "omitempty") { + t.Errorf("Expected error message to not contain ',omitempty' but actual error is: %s", err.Error()) + } +} diff --git a/vendor/github.com/asaskevich/govalidator/wercker.yml b/vendor/github.com/asaskevich/govalidator/wercker.yml new file mode 100644 index 000000000..cac7a5fcf --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/wercker.yml @@ -0,0 +1,15 @@ +box: golang +build: + steps: + - setup-go-workspace + + - script: + name: go get + code: | + go version + go get -t ./... + + - script: + name: go test + code: | + go test -race ./... diff --git a/vendor/github.com/blang/semver/.travis.yml b/vendor/github.com/blang/semver/.travis.yml deleted file mode 100644 index 102fb9a69..000000000 --- a/vendor/github.com/blang/semver/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go -matrix: - include: - - go: 1.4.3 - - go: 1.5.4 - - go: 1.6.3 - - go: 1.7 - - go: tip - allow_failures: - - go: tip -install: -- go get golang.org/x/tools/cmd/cover -- go get github.com/mattn/goveralls -script: -- echo "Test and track coverage" ; $HOME/gopath/bin/goveralls -package "." -service=travis-ci - -repotoken $COVERALLS_TOKEN -- echo "Build examples" ; cd examples && go build -- echo "Check if gofmt'd" ; diff -u <(echo -n) <(gofmt -d -s .) -env: - global: - secure: HroGEAUQpVq9zX1b1VIkraLiywhGbzvNnTZq2TMxgK7JHP8xqNplAeF1izrR2i4QLL9nsY+9WtYss4QuPvEtZcVHUobw6XnL6radF7jS1LgfYZ9Y7oF+zogZ2I5QUMRLGA7rcxQ05s7mKq3XZQfeqaNts4bms/eZRefWuaFZbkw= diff --git a/vendor/github.com/blang/semver/README.md b/vendor/github.com/blang/semver/README.md deleted file mode 100644 index 08b2e4a3d..000000000 --- a/vendor/github.com/blang/semver/README.md +++ /dev/null @@ -1,194 +0,0 @@ -semver for golang [![Build Status](https://travis-ci.org/blang/semver.svg?branch=master)](https://travis-ci.org/blang/semver) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) -====== - -semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`. - -Usage ------ -```bash -$ go get github.com/blang/semver -``` -Note: Always vendor your dependencies or fix on a specific version tag. - -```go -import github.com/blang/semver -v1, err := semver.Make("1.0.0-beta") -v2, err := semver.Make("2.0.0-beta") -v1.Compare(v2) -``` - -Also check the [GoDocs](http://godoc.org/github.com/blang/semver). - -Why should I use this lib? ------ - -- Fully spec compatible -- No reflection -- No regex -- Fully tested (Coverage >99%) -- Readable parsing/validation errors -- Fast (See [Benchmarks](#benchmarks)) -- Only Stdlib -- Uses values instead of pointers -- Many features, see below - - -Features ------ - -- Parsing and validation at all levels -- Comparator-like comparisons -- Compare Helper Methods -- InPlace manipulation -- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1` -- Wildcards `>=1.x`, `<=2.5.x` -- Sortable (implements sort.Interface) -- database/sql compatible (sql.Scanner/Valuer) -- encoding/json compatible (json.Marshaler/Unmarshaler) - -Ranges ------- - -A `Range` is a set of conditions which specify which versions satisfy the range. - -A condition is composed of an operator and a version. The supported operators are: - -- `<1.0.0` Less than `1.0.0` -- `<=1.0.0` Less than or equal to `1.0.0` -- `>1.0.0` Greater than `1.0.0` -- `>=1.0.0` Greater than or equal to `1.0.0` -- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0` -- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`. - -Note that spaces between the operator and the version will be gracefully tolerated. - -A `Range` can link multiple `Ranges` separated by space: - -Ranges can be linked by logical AND: - - - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0` - - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2` - -Ranges can also be linked by logical OR: - - - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x` - -AND has a higher precedence than OR. It's not possible to use brackets. - -Ranges can be combined by both AND and OR - - - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` - -Range usage: - -``` -v, err := semver.Parse("1.2.3") -range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0") -if range(v) { - //valid -} - -``` - -Example ------ - -Have a look at full examples in [examples/main.go](examples/main.go) - -```go -import github.com/blang/semver - -v, err := semver.Make("0.0.1-alpha.preview+123.github") -fmt.Printf("Major: %d\n", v.Major) -fmt.Printf("Minor: %d\n", v.Minor) -fmt.Printf("Patch: %d\n", v.Patch) -fmt.Printf("Pre: %s\n", v.Pre) -fmt.Printf("Build: %s\n", v.Build) - -// Prerelease versions array -if len(v.Pre) > 0 { - fmt.Println("Prerelease versions:") - for i, pre := range v.Pre { - fmt.Printf("%d: %q\n", i, pre) - } -} - -// Build meta data array -if len(v.Build) > 0 { - fmt.Println("Build meta data:") - for i, build := range v.Build { - fmt.Printf("%d: %q\n", i, build) - } -} - -v001, err := semver.Make("0.0.1") -// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE -v001.GT(v) == true -v.LT(v001) == true -v.GTE(v) == true -v.LTE(v) == true - -// Or use v.Compare(v2) for comparisons (-1, 0, 1): -v001.Compare(v) == 1 -v.Compare(v001) == -1 -v.Compare(v) == 0 - -// Manipulate Version in place: -v.Pre[0], err = semver.NewPRVersion("beta") -if err != nil { - fmt.Printf("Error parsing pre release version: %q", err) -} - -fmt.Println("\nValidate versions:") -v.Build[0] = "?" - -err = v.Validate() -if err != nil { - fmt.Printf("Validation failed: %s\n", err) -} -``` - - -Benchmarks ------ - - BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op - BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op - BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op - BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op - BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op - BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op - BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op - BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op - BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op - BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op - BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op - BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op - BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op - BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op - BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op - BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op - BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op - BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op - BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op - BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op - -See benchmark cases at [semver_test.go](semver_test.go) - - -Motivation ------ - -I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like. - - -Contribution ------ - -Feel free to make a pull request. For bigger changes create a issue first to discuss about it. - - -License ------ - -See [LICENSE](LICENSE) file. diff --git a/vendor/github.com/blang/semver/json.go b/vendor/github.com/blang/semver/json.go deleted file mode 100644 index a74bf7c44..000000000 --- a/vendor/github.com/blang/semver/json.go +++ /dev/null @@ -1,23 +0,0 @@ -package semver - -import ( - "encoding/json" -) - -// MarshalJSON implements the encoding/json.Marshaler interface. -func (v Version) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -// UnmarshalJSON implements the encoding/json.Unmarshaler interface. -func (v *Version) UnmarshalJSON(data []byte) (err error) { - var versionString string - - if err = json.Unmarshal(data, &versionString); err != nil { - return - } - - *v, err = Parse(versionString) - - return -} diff --git a/vendor/github.com/blang/semver/json_test.go b/vendor/github.com/blang/semver/json_test.go deleted file mode 100644 index c635dea16..000000000 --- a/vendor/github.com/blang/semver/json_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package semver - -import ( - "encoding/json" - "strconv" - "testing" -) - -func TestJSONMarshal(t *testing.T) { - versionString := "3.1.4-alpha.1.5.9+build.2.6.5" - v, err := Parse(versionString) - if err != nil { - t.Fatal(err) - } - - versionJSON, err := json.Marshal(v) - if err != nil { - t.Fatal(err) - } - - quotedVersionString := strconv.Quote(versionString) - - if string(versionJSON) != quotedVersionString { - t.Fatalf("JSON marshaled semantic version not equal: expected %q, got %q", quotedVersionString, string(versionJSON)) - } -} - -func TestJSONUnmarshal(t *testing.T) { - versionString := "3.1.4-alpha.1.5.9+build.2.6.5" - quotedVersionString := strconv.Quote(versionString) - - var v Version - if err := json.Unmarshal([]byte(quotedVersionString), &v); err != nil { - t.Fatal(err) - } - - if v.String() != versionString { - t.Fatalf("JSON unmarshaled semantic version not equal: expected %q, got %q", versionString, v.String()) - } - - badVersionString := strconv.Quote("3.1.4.1.5.9.2.6.5-other-digits-of-pi") - if err := json.Unmarshal([]byte(badVersionString), &v); err == nil { - t.Fatal("expected JSON unmarshal error, got nil") - } - - if err := json.Unmarshal([]byte("3.1"), &v); err == nil { - t.Fatal("expected JSON unmarshal error, got nil") - } -} diff --git a/vendor/github.com/blang/semver/package.json b/vendor/github.com/blang/semver/package.json deleted file mode 100644 index 1cf8ebdd9..000000000 --- a/vendor/github.com/blang/semver/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "author": "blang", - "bugs": { - "URL": "https://github.com/blang/semver/issues", - "url": "https://github.com/blang/semver/issues" - }, - "gx": { - "dvcsimport": "github.com/blang/semver" - }, - "gxVersion": "0.10.0", - "language": "go", - "license": "MIT", - "name": "semver", - "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "3.5.1" -} - diff --git a/vendor/github.com/blang/semver/range.go b/vendor/github.com/blang/semver/range.go deleted file mode 100644 index fca406d47..000000000 --- a/vendor/github.com/blang/semver/range.go +++ /dev/null @@ -1,416 +0,0 @@ -package semver - -import ( - "fmt" - "strconv" - "strings" - "unicode" -) - -type wildcardType int - -const ( - noneWildcard wildcardType = iota - majorWildcard wildcardType = 1 - minorWildcard wildcardType = 2 - patchWildcard wildcardType = 3 -) - -func wildcardTypefromInt(i int) wildcardType { - switch i { - case 1: - return majorWildcard - case 2: - return minorWildcard - case 3: - return patchWildcard - default: - return noneWildcard - } -} - -type comparator func(Version, Version) bool - -var ( - compEQ comparator = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == 0 - } - compNE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) != 0 - } - compGT = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == 1 - } - compGE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) >= 0 - } - compLT = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == -1 - } - compLE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) <= 0 - } -) - -type versionRange struct { - v Version - c comparator -} - -// rangeFunc creates a Range from the given versionRange. -func (vr *versionRange) rangeFunc() Range { - return Range(func(v Version) bool { - return vr.c(v, vr.v) - }) -} - -// Range represents a range of versions. -// A Range can be used to check if a Version satisfies it: -// -// range, err := semver.ParseRange(">1.0.0 <2.0.0") -// range(semver.MustParse("1.1.1") // returns true -type Range func(Version) bool - -// OR combines the existing Range with another Range using logical OR. -func (rf Range) OR(f Range) Range { - return Range(func(v Version) bool { - return rf(v) || f(v) - }) -} - -// AND combines the existing Range with another Range using logical AND. -func (rf Range) AND(f Range) Range { - return Range(func(v Version) bool { - return rf(v) && f(v) - }) -} - -// ParseRange parses a range and returns a Range. -// If the range could not be parsed an error is returned. -// -// Valid ranges are: -// - "<1.0.0" -// - "<=1.0.0" -// - ">1.0.0" -// - ">=1.0.0" -// - "1.0.0", "=1.0.0", "==1.0.0" -// - "!1.0.0", "!=1.0.0" -// -// A Range can consist of multiple ranges separated by space: -// Ranges can be linked by logical AND: -// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" -// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 -// -// Ranges can also be linked by logical OR: -// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" -// -// AND has a higher precedence than OR. It's not possible to use brackets. -// -// Ranges can be combined by both AND and OR -// -// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` -func ParseRange(s string) (Range, error) { - parts := splitAndTrim(s) - orParts, err := splitORParts(parts) - if err != nil { - return nil, err - } - expandedParts, err := expandWildcardVersion(orParts) - if err != nil { - return nil, err - } - var orFn Range - for _, p := range expandedParts { - var andFn Range - for _, ap := range p { - opStr, vStr, err := splitComparatorVersion(ap) - if err != nil { - return nil, err - } - vr, err := buildVersionRange(opStr, vStr) - if err != nil { - return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) - } - rf := vr.rangeFunc() - - // Set function - if andFn == nil { - andFn = rf - } else { // Combine with existing function - andFn = andFn.AND(rf) - } - } - if orFn == nil { - orFn = andFn - } else { - orFn = orFn.OR(andFn) - } - - } - return orFn, nil -} - -// splitORParts splits the already cleaned parts by '||'. -// Checks for invalid positions of the operator and returns an -// error if found. -func splitORParts(parts []string) ([][]string, error) { - var ORparts [][]string - last := 0 - for i, p := range parts { - if p == "||" { - if i == 0 { - return nil, fmt.Errorf("First element in range is '||'") - } - ORparts = append(ORparts, parts[last:i]) - last = i + 1 - } - } - if last == len(parts) { - return nil, fmt.Errorf("Last element in range is '||'") - } - ORparts = append(ORparts, parts[last:]) - return ORparts, nil -} - -// buildVersionRange takes a slice of 2: operator and version -// and builds a versionRange, otherwise an error. -func buildVersionRange(opStr, vStr string) (*versionRange, error) { - c := parseComparator(opStr) - if c == nil { - return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) - } - v, err := Parse(vStr) - if err != nil { - return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) - } - - return &versionRange{ - v: v, - c: c, - }, nil - -} - -// inArray checks if a byte is contained in an array of bytes -func inArray(s byte, list []byte) bool { - for _, el := range list { - if el == s { - return true - } - } - return false -} - -// splitAndTrim splits a range string by spaces and cleans whitespaces -func splitAndTrim(s string) (result []string) { - last := 0 - var lastChar byte - excludeFromSplit := []byte{'>', '<', '='} - for i := 0; i < len(s); i++ { - if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) { - if last < i-1 { - result = append(result, s[last:i]) - } - last = i + 1 - } else if s[i] != ' ' { - lastChar = s[i] - } - } - if last < len(s)-1 { - result = append(result, s[last:]) - } - - for i, v := range result { - result[i] = strings.Replace(v, " ", "", -1) - } - - // parts := strings.Split(s, " ") - // for _, x := range parts { - // if s := strings.TrimSpace(x); len(s) != 0 { - // result = append(result, s) - // } - // } - return -} - -// splitComparatorVersion splits the comparator from the version. -// Input must be free of leading or trailing spaces. -func splitComparatorVersion(s string) (string, string, error) { - i := strings.IndexFunc(s, unicode.IsDigit) - if i == -1 { - return "", "", fmt.Errorf("Could not get version from string: %q", s) - } - return strings.TrimSpace(s[0:i]), s[i:], nil -} - -// getWildcardType will return the type of wildcard that the -// passed version contains -func getWildcardType(vStr string) wildcardType { - parts := strings.Split(vStr, ".") - nparts := len(parts) - wildcard := parts[nparts-1] - - possibleWildcardType := wildcardTypefromInt(nparts) - if wildcard == "x" { - return possibleWildcardType - } - - return noneWildcard -} - -// createVersionFromWildcard will convert a wildcard version -// into a regular version, replacing 'x's with '0's, handling -// special cases like '1.x.x' and '1.x' -func createVersionFromWildcard(vStr string) string { - // handle 1.x.x - vStr2 := strings.Replace(vStr, ".x.x", ".x", 1) - vStr2 = strings.Replace(vStr2, ".x", ".0", 1) - parts := strings.Split(vStr2, ".") - - // handle 1.x - if len(parts) == 2 { - return vStr2 + ".0" - } - - return vStr2 -} - -// incrementMajorVersion will increment the major version -// of the passed version -func incrementMajorVersion(vStr string) (string, error) { - parts := strings.Split(vStr, ".") - i, err := strconv.Atoi(parts[0]) - if err != nil { - return "", err - } - parts[0] = strconv.Itoa(i + 1) - - return strings.Join(parts, "."), nil -} - -// incrementMajorVersion will increment the minor version -// of the passed version -func incrementMinorVersion(vStr string) (string, error) { - parts := strings.Split(vStr, ".") - i, err := strconv.Atoi(parts[1]) - if err != nil { - return "", err - } - parts[1] = strconv.Itoa(i + 1) - - return strings.Join(parts, "."), nil -} - -// expandWildcardVersion will expand wildcards inside versions -// following these rules: -// -// * when dealing with patch wildcards: -// >= 1.2.x will become >= 1.2.0 -// <= 1.2.x will become < 1.3.0 -// > 1.2.x will become >= 1.3.0 -// < 1.2.x will become < 1.2.0 -// != 1.2.x will become < 1.2.0 >= 1.3.0 -// -// * when dealing with minor wildcards: -// >= 1.x will become >= 1.0.0 -// <= 1.x will become < 2.0.0 -// > 1.x will become >= 2.0.0 -// < 1.0 will become < 1.0.0 -// != 1.x will become < 1.0.0 >= 2.0.0 -// -// * when dealing with wildcards without -// version operator: -// 1.2.x will become >= 1.2.0 < 1.3.0 -// 1.x will become >= 1.0.0 < 2.0.0 -func expandWildcardVersion(parts [][]string) ([][]string, error) { - var expandedParts [][]string - for _, p := range parts { - var newParts []string - for _, ap := range p { - if strings.Index(ap, "x") != -1 { - opStr, vStr, err := splitComparatorVersion(ap) - if err != nil { - return nil, err - } - - versionWildcardType := getWildcardType(vStr) - flatVersion := createVersionFromWildcard(vStr) - - var resultOperator string - var shouldIncrementVersion bool - switch opStr { - case ">": - resultOperator = ">=" - shouldIncrementVersion = true - case ">=": - resultOperator = ">=" - case "<": - resultOperator = "<" - case "<=": - resultOperator = "<" - shouldIncrementVersion = true - case "", "=", "==": - newParts = append(newParts, ">="+flatVersion) - resultOperator = "<" - shouldIncrementVersion = true - case "!=", "!": - newParts = append(newParts, "<"+flatVersion) - resultOperator = ">=" - shouldIncrementVersion = true - } - - var resultVersion string - if shouldIncrementVersion { - switch versionWildcardType { - case patchWildcard: - resultVersion, _ = incrementMinorVersion(flatVersion) - case minorWildcard: - resultVersion, _ = incrementMajorVersion(flatVersion) - } - } else { - resultVersion = flatVersion - } - - ap = resultOperator + resultVersion - } - newParts = append(newParts, ap) - } - expandedParts = append(expandedParts, newParts) - } - - return expandedParts, nil -} - -func parseComparator(s string) comparator { - switch s { - case "==": - fallthrough - case "": - fallthrough - case "=": - return compEQ - case ">": - return compGT - case ">=": - return compGE - case "<": - return compLT - case "<=": - return compLE - case "!": - fallthrough - case "!=": - return compNE - } - - return nil -} - -// MustParseRange is like ParseRange but panics if the range cannot be parsed. -func MustParseRange(s string) Range { - r, err := ParseRange(s) - if err != nil { - panic(`semver: ParseRange(` + s + `): ` + err.Error()) - } - return r -} diff --git a/vendor/github.com/blang/semver/range_test.go b/vendor/github.com/blang/semver/range_test.go deleted file mode 100644 index 83ee9c787..000000000 --- a/vendor/github.com/blang/semver/range_test.go +++ /dev/null @@ -1,581 +0,0 @@ -package semver - -import ( - "reflect" - "strings" - "testing" -) - -type wildcardTypeTest struct { - input string - wildcardType wildcardType -} - -type comparatorTest struct { - input string - comparator func(comparator) bool -} - -func TestParseComparator(t *testing.T) { - compatorTests := []comparatorTest{ - {">", testGT}, - {">=", testGE}, - {"<", testLT}, - {"<=", testLE}, - {"", testEQ}, - {"=", testEQ}, - {"==", testEQ}, - {"!=", testNE}, - {"!", testNE}, - {"-", nil}, - {"<==", nil}, - {"<<", nil}, - {">>", nil}, - } - - for _, tc := range compatorTests { - if c := parseComparator(tc.input); c == nil { - if tc.comparator != nil { - t.Errorf("Comparator nil for case %q\n", tc.input) - } - } else if !tc.comparator(c) { - t.Errorf("Invalid comparator for case %q\n", tc.input) - } - } -} - -var ( - v1 = MustParse("1.2.2") - v2 = MustParse("1.2.3") - v3 = MustParse("1.2.4") -) - -func testEQ(f comparator) bool { - return f(v1, v1) && !f(v1, v2) -} - -func testNE(f comparator) bool { - return !f(v1, v1) && f(v1, v2) -} - -func testGT(f comparator) bool { - return f(v2, v1) && f(v3, v2) && !f(v1, v2) && !f(v1, v1) -} - -func testGE(f comparator) bool { - return f(v2, v1) && f(v3, v2) && !f(v1, v2) -} - -func testLT(f comparator) bool { - return f(v1, v2) && f(v2, v3) && !f(v2, v1) && !f(v1, v1) -} - -func testLE(f comparator) bool { - return f(v1, v2) && f(v2, v3) && !f(v2, v1) -} - -func TestSplitAndTrim(t *testing.T) { - tests := []struct { - i string - s []string - }{ - {"1.2.3 1.2.3", []string{"1.2.3", "1.2.3"}}, - {" 1.2.3 1.2.3 ", []string{"1.2.3", "1.2.3"}}, // Spaces - {" >= 1.2.3 <= 1.2.3 ", []string{">=1.2.3", "<=1.2.3"}}, // Spaces between operator and version - {"1.2.3 || >=1.2.3 <1.2.3", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}}, - {" 1.2.3 || >=1.2.3 <1.2.3 ", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}}, - } - - for _, tc := range tests { - p := splitAndTrim(tc.i) - if !reflect.DeepEqual(p, tc.s) { - t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p) - } - } -} - -func TestSplitComparatorVersion(t *testing.T) { - tests := []struct { - i string - p []string - }{ - {">1.2.3", []string{">", "1.2.3"}}, - {">=1.2.3", []string{">=", "1.2.3"}}, - {"<1.2.3", []string{"<", "1.2.3"}}, - {"<=1.2.3", []string{"<=", "1.2.3"}}, - {"1.2.3", []string{"", "1.2.3"}}, - {"=1.2.3", []string{"=", "1.2.3"}}, - {"==1.2.3", []string{"==", "1.2.3"}}, - {"!=1.2.3", []string{"!=", "1.2.3"}}, - {"!1.2.3", []string{"!", "1.2.3"}}, - {"error", nil}, - } - for _, tc := range tests { - if op, v, err := splitComparatorVersion(tc.i); err != nil { - if tc.p != nil { - t.Errorf("Invalid for case %q: Expected %q, got error %q", tc.i, tc.p, err) - } - } else if op != tc.p[0] { - t.Errorf("Invalid operator for case %q: Expected %q, got: %q", tc.i, tc.p[0], op) - } else if v != tc.p[1] { - t.Errorf("Invalid version for case %q: Expected %q, got: %q", tc.i, tc.p[1], v) - } - - } -} - -func TestBuildVersionRange(t *testing.T) { - tests := []struct { - opStr string - vStr string - c func(comparator) bool - v string - }{ - {">", "1.2.3", testGT, "1.2.3"}, - {">=", "1.2.3", testGE, "1.2.3"}, - {"<", "1.2.3", testLT, "1.2.3"}, - {"<=", "1.2.3", testLE, "1.2.3"}, - {"", "1.2.3", testEQ, "1.2.3"}, - {"=", "1.2.3", testEQ, "1.2.3"}, - {"==", "1.2.3", testEQ, "1.2.3"}, - {"!=", "1.2.3", testNE, "1.2.3"}, - {"!", "1.2.3", testNE, "1.2.3"}, - {">>", "1.2.3", nil, ""}, // Invalid comparator - {"=", "invalid", nil, ""}, // Invalid version - } - - for _, tc := range tests { - if r, err := buildVersionRange(tc.opStr, tc.vStr); err != nil { - if tc.c != nil { - t.Errorf("Invalid for case %q: Expected %q, got error %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tc.v, err) - } - } else if r == nil { - t.Errorf("Invalid for case %q: got nil", strings.Join([]string{tc.opStr, tc.vStr}, "")) - } else { - // test version - if tv := MustParse(tc.v); !r.v.EQ(tv) { - t.Errorf("Invalid for case %q: Expected version %q, got: %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tv, r.v) - } - // test comparator - if r.c == nil { - t.Errorf("Invalid for case %q: got nil comparator", strings.Join([]string{tc.opStr, tc.vStr}, "")) - continue - } - if !tc.c(r.c) { - t.Errorf("Invalid comparator for case %q\n", strings.Join([]string{tc.opStr, tc.vStr}, "")) - } - } - } - -} - -func TestSplitORParts(t *testing.T) { - tests := []struct { - i []string - o [][]string - }{ - {[]string{">1.2.3", "||", "<1.2.3", "||", "=1.2.3"}, [][]string{ - []string{">1.2.3"}, - []string{"<1.2.3"}, - []string{"=1.2.3"}, - }}, - {[]string{">1.2.3", "<1.2.3", "||", "=1.2.3"}, [][]string{ - []string{">1.2.3", "<1.2.3"}, - []string{"=1.2.3"}, - }}, - {[]string{">1.2.3", "||"}, nil}, - {[]string{"||", ">1.2.3"}, nil}, - } - for _, tc := range tests { - o, err := splitORParts(tc.i) - if err != nil && tc.o != nil { - t.Errorf("Unexpected error for case %q: %s", tc.i, err) - } - if !reflect.DeepEqual(tc.o, o) { - t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o) - } - } -} - -func TestGetWildcardType(t *testing.T) { - wildcardTypeTests := []wildcardTypeTest{ - {"x", majorWildcard}, - {"1.x", minorWildcard}, - {"1.2.x", patchWildcard}, - {"fo.o.b.ar", noneWildcard}, - } - - for _, tc := range wildcardTypeTests { - o := getWildcardType(tc.input) - if o != tc.wildcardType { - t.Errorf("Invalid for case: %q: Expected %q, got: %q", tc.input, tc.wildcardType, o) - } - } -} - -func TestCreateVersionFromWildcard(t *testing.T) { - tests := []struct { - i string - s string - }{ - {"1.2.x", "1.2.0"}, - {"1.x", "1.0.0"}, - } - - for _, tc := range tests { - p := createVersionFromWildcard(tc.i) - if p != tc.s { - t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p) - } - } -} - -func TestIncrementMajorVersion(t *testing.T) { - tests := []struct { - i string - s string - }{ - {"1.2.3", "2.2.3"}, - {"1.2", "2.2"}, - {"foo.bar", ""}, - } - - for _, tc := range tests { - p, _ := incrementMajorVersion(tc.i) - if p != tc.s { - t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p) - } - } -} - -func TestIncrementMinorVersion(t *testing.T) { - tests := []struct { - i string - s string - }{ - {"1.2.3", "1.3.3"}, - {"1.2", "1.3"}, - {"foo.bar", ""}, - } - - for _, tc := range tests { - p, _ := incrementMinorVersion(tc.i) - if p != tc.s { - t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p) - } - } -} - -func TestExpandWildcardVersion(t *testing.T) { - tests := []struct { - i [][]string - o [][]string - }{ - {[][]string{[]string{"foox"}}, nil}, - {[][]string{[]string{">=1.2.x"}}, [][]string{[]string{">=1.2.0"}}}, - {[][]string{[]string{"<=1.2.x"}}, [][]string{[]string{"<1.3.0"}}}, - {[][]string{[]string{">1.2.x"}}, [][]string{[]string{">=1.3.0"}}}, - {[][]string{[]string{"<1.2.x"}}, [][]string{[]string{"<1.2.0"}}}, - {[][]string{[]string{"!=1.2.x"}}, [][]string{[]string{"<1.2.0", ">=1.3.0"}}}, - {[][]string{[]string{">=1.x"}}, [][]string{[]string{">=1.0.0"}}}, - {[][]string{[]string{"<=1.x"}}, [][]string{[]string{"<2.0.0"}}}, - {[][]string{[]string{">1.x"}}, [][]string{[]string{">=2.0.0"}}}, - {[][]string{[]string{"<1.x"}}, [][]string{[]string{"<1.0.0"}}}, - {[][]string{[]string{"!=1.x"}}, [][]string{[]string{"<1.0.0", ">=2.0.0"}}}, - {[][]string{[]string{"1.2.x"}}, [][]string{[]string{">=1.2.0", "<1.3.0"}}}, - {[][]string{[]string{"1.x"}}, [][]string{[]string{">=1.0.0", "<2.0.0"}}}, - } - - for _, tc := range tests { - o, _ := expandWildcardVersion(tc.i) - if !reflect.DeepEqual(tc.o, o) { - t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o) - } - } -} - -func TestVersionRangeToRange(t *testing.T) { - vr := versionRange{ - v: MustParse("1.2.3"), - c: compLT, - } - rf := vr.rangeFunc() - if !rf(MustParse("1.2.2")) || rf(MustParse("1.2.3")) { - t.Errorf("Invalid conversion to range func") - } -} - -func TestRangeAND(t *testing.T) { - v := MustParse("1.2.2") - v1 := MustParse("1.2.1") - v2 := MustParse("1.2.3") - rf1 := Range(func(v Version) bool { - return v.GT(v1) - }) - rf2 := Range(func(v Version) bool { - return v.LT(v2) - }) - rf := rf1.AND(rf2) - if rf(v1) { - t.Errorf("Invalid rangefunc, accepted: %s", v1) - } - if rf(v2) { - t.Errorf("Invalid rangefunc, accepted: %s", v2) - } - if !rf(v) { - t.Errorf("Invalid rangefunc, did not accept: %s", v) - } -} - -func TestRangeOR(t *testing.T) { - tests := []struct { - v Version - b bool - }{ - {MustParse("1.2.0"), true}, - {MustParse("1.2.2"), false}, - {MustParse("1.2.4"), true}, - } - v1 := MustParse("1.2.1") - v2 := MustParse("1.2.3") - rf1 := Range(func(v Version) bool { - return v.LT(v1) - }) - rf2 := Range(func(v Version) bool { - return v.GT(v2) - }) - rf := rf1.OR(rf2) - for _, tc := range tests { - if r := rf(tc.v); r != tc.b { - t.Errorf("Invalid for case %q: Expected %t, got %t", tc.v, tc.b, r) - } - } -} - -func TestParseRange(t *testing.T) { - type tv struct { - v string - b bool - } - tests := []struct { - i string - t []tv - }{ - // Simple expressions - {">1.2.3", []tv{ - {"1.2.2", false}, - {"1.2.3", false}, - {"1.2.4", true}, - }}, - {">=1.2.3", []tv{ - {"1.2.3", true}, - {"1.2.4", true}, - {"1.2.2", false}, - }}, - {"<1.2.3", []tv{ - {"1.2.2", true}, - {"1.2.3", false}, - {"1.2.4", false}, - }}, - {"<=1.2.3", []tv{ - {"1.2.2", true}, - {"1.2.3", true}, - {"1.2.4", false}, - }}, - {"1.2.3", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - }}, - {"=1.2.3", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - }}, - {"==1.2.3", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - }}, - {"!=1.2.3", []tv{ - {"1.2.2", true}, - {"1.2.3", false}, - {"1.2.4", true}, - }}, - {"!1.2.3", []tv{ - {"1.2.2", true}, - {"1.2.3", false}, - {"1.2.4", true}, - }}, - // Simple Expression errors - {">>1.2.3", nil}, - {"!1.2.3", nil}, - {"1.0", nil}, - {"string", nil}, - {"", nil}, - {"fo.ob.ar.x", nil}, - // AND Expressions - {">1.2.2 <1.2.4", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - }}, - {"<1.2.2 <1.2.4", []tv{ - {"1.2.1", true}, - {"1.2.2", false}, - {"1.2.3", false}, - {"1.2.4", false}, - }}, - {">1.2.2 <1.2.5 !=1.2.4", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - {"1.2.5", false}, - }}, - {">1.2.2 <1.2.5 !1.2.4", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - {"1.2.5", false}, - }}, - // OR Expressions - {">1.2.2 || <1.2.4", []tv{ - {"1.2.2", true}, - {"1.2.3", true}, - {"1.2.4", true}, - }}, - {"<1.2.2 || >1.2.4", []tv{ - {"1.2.2", false}, - {"1.2.3", false}, - {"1.2.4", false}, - }}, - // Wildcard expressions - {">1.x", []tv{ - {"0.1.9", false}, - {"1.2.6", false}, - {"1.9.0", false}, - {"2.0.0", true}, - }}, - {">1.2.x", []tv{ - {"1.1.9", false}, - {"1.2.6", false}, - {"1.3.0", true}, - }}, - // Combined Expressions - {">1.2.2 <1.2.4 || >=2.0.0", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - {"2.0.0", true}, - {"2.0.1", true}, - }}, - {"1.x || >=2.0.x <2.2.x", []tv{ - {"0.9.2", false}, - {"1.2.2", true}, - {"2.0.0", true}, - {"2.1.8", true}, - {"2.2.0", false}, - }}, - {">1.2.2 <1.2.4 || >=2.0.0 <3.0.0", []tv{ - {"1.2.2", false}, - {"1.2.3", true}, - {"1.2.4", false}, - {"2.0.0", true}, - {"2.0.1", true}, - {"2.9.9", true}, - {"3.0.0", false}, - }}, - } - - for _, tc := range tests { - r, err := ParseRange(tc.i) - if err != nil && tc.t != nil { - t.Errorf("Error parsing range %q: %s", tc.i, err) - continue - } - for _, tvc := range tc.t { - v := MustParse(tvc.v) - if res := r(v); res != tvc.b { - t.Errorf("Invalid for case %q matching %q: Expected %t, got: %t", tc.i, tvc.v, tvc.b, res) - } - } - - } -} - -func TestMustParseRange(t *testing.T) { - testCase := ">1.2.2 <1.2.4 || >=2.0.0 <3.0.0" - r := MustParseRange(testCase) - if !r(MustParse("1.2.3")) { - t.Errorf("Unexpected range behavior on MustParseRange") - } -} - -func TestMustParseRange_panic(t *testing.T) { - defer func() { - if recover() == nil { - t.Errorf("Should have panicked") - } - }() - _ = MustParseRange("invalid version") -} - -func BenchmarkRangeParseSimple(b *testing.B) { - const VERSION = ">1.0.0" - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - ParseRange(VERSION) - } -} - -func BenchmarkRangeParseAverage(b *testing.B) { - const VERSION = ">=1.0.0 <2.0.0" - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - ParseRange(VERSION) - } -} - -func BenchmarkRangeParseComplex(b *testing.B) { - const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0" - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - ParseRange(VERSION) - } -} - -func BenchmarkRangeMatchSimple(b *testing.B) { - const VERSION = ">1.0.0" - r, _ := ParseRange(VERSION) - v := MustParse("2.0.0") - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - r(v) - } -} - -func BenchmarkRangeMatchAverage(b *testing.B) { - const VERSION = ">=1.0.0 <2.0.0" - r, _ := ParseRange(VERSION) - v := MustParse("1.2.3") - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - r(v) - } -} - -func BenchmarkRangeMatchComplex(b *testing.B) { - const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0" - r, _ := ParseRange(VERSION) - v := MustParse("5.0.1") - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - r(v) - } -} diff --git a/vendor/github.com/blang/semver/semver.go b/vendor/github.com/blang/semver/semver.go deleted file mode 100644 index 8ee0842e6..000000000 --- a/vendor/github.com/blang/semver/semver.go +++ /dev/null @@ -1,418 +0,0 @@ -package semver - -import ( - "errors" - "fmt" - "strconv" - "strings" -) - -const ( - numbers string = "0123456789" - alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" - alphanum = alphas + numbers -) - -// SpecVersion is the latest fully supported spec version of semver -var SpecVersion = Version{ - Major: 2, - Minor: 0, - Patch: 0, -} - -// Version represents a semver compatible version -type Version struct { - Major uint64 - Minor uint64 - Patch uint64 - Pre []PRVersion - Build []string //No Precendence -} - -// Version to string -func (v Version) String() string { - b := make([]byte, 0, 5) - b = strconv.AppendUint(b, v.Major, 10) - b = append(b, '.') - b = strconv.AppendUint(b, v.Minor, 10) - b = append(b, '.') - b = strconv.AppendUint(b, v.Patch, 10) - - if len(v.Pre) > 0 { - b = append(b, '-') - b = append(b, v.Pre[0].String()...) - - for _, pre := range v.Pre[1:] { - b = append(b, '.') - b = append(b, pre.String()...) - } - } - - if len(v.Build) > 0 { - b = append(b, '+') - b = append(b, v.Build[0]...) - - for _, build := range v.Build[1:] { - b = append(b, '.') - b = append(b, build...) - } - } - - return string(b) -} - -// Equals checks if v is equal to o. -func (v Version) Equals(o Version) bool { - return (v.Compare(o) == 0) -} - -// EQ checks if v is equal to o. -func (v Version) EQ(o Version) bool { - return (v.Compare(o) == 0) -} - -// NE checks if v is not equal to o. -func (v Version) NE(o Version) bool { - return (v.Compare(o) != 0) -} - -// GT checks if v is greater than o. -func (v Version) GT(o Version) bool { - return (v.Compare(o) == 1) -} - -// GTE checks if v is greater than or equal to o. -func (v Version) GTE(o Version) bool { - return (v.Compare(o) >= 0) -} - -// GE checks if v is greater than or equal to o. -func (v Version) GE(o Version) bool { - return (v.Compare(o) >= 0) -} - -// LT checks if v is less than o. -func (v Version) LT(o Version) bool { - return (v.Compare(o) == -1) -} - -// LTE checks if v is less than or equal to o. -func (v Version) LTE(o Version) bool { - return (v.Compare(o) <= 0) -} - -// LE checks if v is less than or equal to o. -func (v Version) LE(o Version) bool { - return (v.Compare(o) <= 0) -} - -// Compare compares Versions v to o: -// -1 == v is less than o -// 0 == v is equal to o -// 1 == v is greater than o -func (v Version) Compare(o Version) int { - if v.Major != o.Major { - if v.Major > o.Major { - return 1 - } - return -1 - } - if v.Minor != o.Minor { - if v.Minor > o.Minor { - return 1 - } - return -1 - } - if v.Patch != o.Patch { - if v.Patch > o.Patch { - return 1 - } - return -1 - } - - // Quick comparison if a version has no prerelease versions - if len(v.Pre) == 0 && len(o.Pre) == 0 { - return 0 - } else if len(v.Pre) == 0 && len(o.Pre) > 0 { - return 1 - } else if len(v.Pre) > 0 && len(o.Pre) == 0 { - return -1 - } - - i := 0 - for ; i < len(v.Pre) && i < len(o.Pre); i++ { - if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { - continue - } else if comp == 1 { - return 1 - } else { - return -1 - } - } - - // If all pr versions are the equal but one has further prversion, this one greater - if i == len(v.Pre) && i == len(o.Pre) { - return 0 - } else if i == len(v.Pre) && i < len(o.Pre) { - return -1 - } else { - return 1 - } - -} - -// Validate validates v and returns error in case -func (v Version) Validate() error { - // Major, Minor, Patch already validated using uint64 - - for _, pre := range v.Pre { - if !pre.IsNum { //Numeric prerelease versions already uint64 - if len(pre.VersionStr) == 0 { - return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) - } - if !containsOnly(pre.VersionStr, alphanum) { - return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) - } - } - } - - for _, build := range v.Build { - if len(build) == 0 { - return fmt.Errorf("Build meta data can not be empty %q", build) - } - if !containsOnly(build, alphanum) { - return fmt.Errorf("Invalid character(s) found in build meta data %q", build) - } - } - - return nil -} - -// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error -func New(s string) (vp *Version, err error) { - v, err := Parse(s) - vp = &v - return -} - -// Make is an alias for Parse, parses version string and returns a validated Version or error -func Make(s string) (Version, error) { - return Parse(s) -} - -// ParseTolerant allows for certain version specifications that do not strictly adhere to semver -// specs to be parsed by this library. It does so by normalizing versions before passing them to -// Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions -// with only major and minor components specified -func ParseTolerant(s string) (Version, error) { - s = strings.TrimSpace(s) - s = strings.TrimPrefix(s, "v") - - // Split into major.minor.(patch+pr+meta) - parts := strings.SplitN(s, ".", 3) - if len(parts) < 3 { - if strings.ContainsAny(parts[len(parts)-1], "+-") { - return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data") - } - for len(parts) < 3 { - parts = append(parts, "0") - } - s = strings.Join(parts, ".") - } - - return Parse(s) -} - -// Parse parses version string and returns a validated Version or error -func Parse(s string) (Version, error) { - if len(s) == 0 { - return Version{}, errors.New("Version string empty") - } - - // Split into major.minor.(patch+pr+meta) - parts := strings.SplitN(s, ".", 3) - if len(parts) != 3 { - return Version{}, errors.New("No Major.Minor.Patch elements found") - } - - // Major - if !containsOnly(parts[0], numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) - } - if hasLeadingZeroes(parts[0]) { - return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) - } - major, err := strconv.ParseUint(parts[0], 10, 64) - if err != nil { - return Version{}, err - } - - // Minor - if !containsOnly(parts[1], numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) - } - if hasLeadingZeroes(parts[1]) { - return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) - } - minor, err := strconv.ParseUint(parts[1], 10, 64) - if err != nil { - return Version{}, err - } - - v := Version{} - v.Major = major - v.Minor = minor - - var build, prerelease []string - patchStr := parts[2] - - if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { - build = strings.Split(patchStr[buildIndex+1:], ".") - patchStr = patchStr[:buildIndex] - } - - if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { - prerelease = strings.Split(patchStr[preIndex+1:], ".") - patchStr = patchStr[:preIndex] - } - - if !containsOnly(patchStr, numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) - } - if hasLeadingZeroes(patchStr) { - return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) - } - patch, err := strconv.ParseUint(patchStr, 10, 64) - if err != nil { - return Version{}, err - } - - v.Patch = patch - - // Prerelease - for _, prstr := range prerelease { - parsedPR, err := NewPRVersion(prstr) - if err != nil { - return Version{}, err - } - v.Pre = append(v.Pre, parsedPR) - } - - // Build meta data - for _, str := range build { - if len(str) == 0 { - return Version{}, errors.New("Build meta data is empty") - } - if !containsOnly(str, alphanum) { - return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) - } - v.Build = append(v.Build, str) - } - - return v, nil -} - -// MustParse is like Parse but panics if the version cannot be parsed. -func MustParse(s string) Version { - v, err := Parse(s) - if err != nil { - panic(`semver: Parse(` + s + `): ` + err.Error()) - } - return v -} - -// PRVersion represents a PreRelease Version -type PRVersion struct { - VersionStr string - VersionNum uint64 - IsNum bool -} - -// NewPRVersion creates a new valid prerelease version -func NewPRVersion(s string) (PRVersion, error) { - if len(s) == 0 { - return PRVersion{}, errors.New("Prerelease is empty") - } - v := PRVersion{} - if containsOnly(s, numbers) { - if hasLeadingZeroes(s) { - return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) - } - num, err := strconv.ParseUint(s, 10, 64) - - // Might never be hit, but just in case - if err != nil { - return PRVersion{}, err - } - v.VersionNum = num - v.IsNum = true - } else if containsOnly(s, alphanum) { - v.VersionStr = s - v.IsNum = false - } else { - return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) - } - return v, nil -} - -// IsNumeric checks if prerelease-version is numeric -func (v PRVersion) IsNumeric() bool { - return v.IsNum -} - -// Compare compares two PreRelease Versions v and o: -// -1 == v is less than o -// 0 == v is equal to o -// 1 == v is greater than o -func (v PRVersion) Compare(o PRVersion) int { - if v.IsNum && !o.IsNum { - return -1 - } else if !v.IsNum && o.IsNum { - return 1 - } else if v.IsNum && o.IsNum { - if v.VersionNum == o.VersionNum { - return 0 - } else if v.VersionNum > o.VersionNum { - return 1 - } else { - return -1 - } - } else { // both are Alphas - if v.VersionStr == o.VersionStr { - return 0 - } else if v.VersionStr > o.VersionStr { - return 1 - } else { - return -1 - } - } -} - -// PreRelease version to string -func (v PRVersion) String() string { - if v.IsNum { - return strconv.FormatUint(v.VersionNum, 10) - } - return v.VersionStr -} - -func containsOnly(s string, set string) bool { - return strings.IndexFunc(s, func(r rune) bool { - return !strings.ContainsRune(set, r) - }) == -1 -} - -func hasLeadingZeroes(s string) bool { - return len(s) > 1 && s[0] == '0' -} - -// NewBuildVersion creates a new valid build version -func NewBuildVersion(s string) (string, error) { - if len(s) == 0 { - return "", errors.New("Buildversion is empty") - } - if !containsOnly(s, alphanum) { - return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) - } - return s, nil -} diff --git a/vendor/github.com/blang/semver/semver_test.go b/vendor/github.com/blang/semver/semver_test.go deleted file mode 100644 index b3e1fd43c..000000000 --- a/vendor/github.com/blang/semver/semver_test.go +++ /dev/null @@ -1,458 +0,0 @@ -package semver - -import ( - "testing" -) - -func prstr(s string) PRVersion { - return PRVersion{s, 0, false} -} - -func prnum(i uint64) PRVersion { - return PRVersion{"", i, true} -} - -type formatTest struct { - v Version - result string -} - -var formatTests = []formatTest{ - {Version{1, 2, 3, nil, nil}, "1.2.3"}, - {Version{0, 0, 1, nil, nil}, "0.0.1"}, - {Version{0, 0, 1, []PRVersion{prstr("alpha"), prstr("preview")}, []string{"123", "456"}}, "0.0.1-alpha.preview+123.456"}, - {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, []string{"123", "456"}}, "1.2.3-alpha.1+123.456"}, - {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, nil}, "1.2.3-alpha.1"}, - {Version{1, 2, 3, nil, []string{"123", "456"}}, "1.2.3+123.456"}, - // Prereleases and build metadata hyphens - {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, []string{"123", "b-uild"}}, "1.2.3-alpha.b-eta+123.b-uild"}, - {Version{1, 2, 3, nil, []string{"123", "b-uild"}}, "1.2.3+123.b-uild"}, - {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, nil}, "1.2.3-alpha.b-eta"}, -} - -var tolerantFormatTests = []formatTest{ - {Version{1, 2, 3, nil, nil}, "v1.2.3"}, - {Version{1, 2, 3, nil, nil}, " 1.2.3 "}, - {Version{1, 2, 0, nil, nil}, "1.2"}, - {Version{1, 0, 0, nil, nil}, "1"}, -} - -func TestStringer(t *testing.T) { - for _, test := range formatTests { - if res := test.v.String(); res != test.result { - t.Errorf("Stringer, expected %q but got %q", test.result, res) - } - } -} - -func TestParse(t *testing.T) { - for _, test := range formatTests { - if v, err := Parse(test.result); err != nil { - t.Errorf("Error parsing %q: %q", test.result, err) - } else if comp := v.Compare(test.v); comp != 0 { - t.Errorf("Parsing, expected %q but got %q, comp: %d ", test.v, v, comp) - } else if err := v.Validate(); err != nil { - t.Errorf("Error validating parsed version %q: %q", test.v, err) - } - } -} - -func TestParseTolerant(t *testing.T) { - for _, test := range tolerantFormatTests { - if v, err := ParseTolerant(test.result); err != nil { - t.Errorf("Error parsing %q: %q", test.result, err) - } else if comp := v.Compare(test.v); comp != 0 { - t.Errorf("Parsing, expected %q but got %q, comp: %d ", test.v, v, comp) - } else if err := v.Validate(); err != nil { - t.Errorf("Error validating parsed version %q: %q", test.v, err) - } - } -} - -func TestMustParse(t *testing.T) { - _ = MustParse("32.2.1-alpha") -} - -func TestMustParse_panic(t *testing.T) { - defer func() { - if recover() == nil { - t.Errorf("Should have panicked") - } - }() - _ = MustParse("invalid version") -} - -func TestValidate(t *testing.T) { - for _, test := range formatTests { - if err := test.v.Validate(); err != nil { - t.Errorf("Error validating %q: %q", test.v, err) - } - } -} - -type compareTest struct { - v1 Version - v2 Version - result int -} - -var compareTests = []compareTest{ - {Version{1, 0, 0, nil, nil}, Version{1, 0, 0, nil, nil}, 0}, - {Version{2, 0, 0, nil, nil}, Version{1, 0, 0, nil, nil}, 1}, - {Version{0, 1, 0, nil, nil}, Version{0, 1, 0, nil, nil}, 0}, - {Version{0, 2, 0, nil, nil}, Version{0, 1, 0, nil, nil}, 1}, - {Version{0, 0, 1, nil, nil}, Version{0, 0, 1, nil, nil}, 0}, - {Version{0, 0, 2, nil, nil}, Version{0, 0, 1, nil, nil}, 1}, - {Version{1, 2, 3, nil, nil}, Version{1, 2, 3, nil, nil}, 0}, - {Version{2, 2, 4, nil, nil}, Version{1, 2, 4, nil, nil}, 1}, - {Version{1, 3, 3, nil, nil}, Version{1, 2, 3, nil, nil}, 1}, - {Version{1, 2, 4, nil, nil}, Version{1, 2, 3, nil, nil}, 1}, - - // Spec Examples #11 - {Version{1, 0, 0, nil, nil}, Version{2, 0, 0, nil, nil}, -1}, - {Version{2, 0, 0, nil, nil}, Version{2, 1, 0, nil, nil}, -1}, - {Version{2, 1, 0, nil, nil}, Version{2, 1, 1, nil, nil}, -1}, - - // Spec Examples #9 - {Version{1, 0, 0, nil, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}, 1}, - {Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha"), prnum(1)}, nil}, -1}, - {Version{1, 0, 0, []PRVersion{prstr("alpha"), prnum(1)}, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha"), prstr("beta")}, nil}, -1}, - {Version{1, 0, 0, []PRVersion{prstr("alpha"), prstr("beta")}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta")}, nil}, -1}, - {Version{1, 0, 0, []PRVersion{prstr("beta")}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(2)}, nil}, -1}, - {Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(2)}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(11)}, nil}, -1}, - {Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(11)}, nil}, Version{1, 0, 0, []PRVersion{prstr("rc"), prnum(1)}, nil}, -1}, - {Version{1, 0, 0, []PRVersion{prstr("rc"), prnum(1)}, nil}, Version{1, 0, 0, nil, nil}, -1}, - - // Ignore Build metadata - {Version{1, 0, 0, nil, []string{"1", "2", "3"}}, Version{1, 0, 0, nil, nil}, 0}, -} - -func TestCompare(t *testing.T) { - for _, test := range compareTests { - if res := test.v1.Compare(test.v2); res != test.result { - t.Errorf("Comparing %q : %q, expected %d but got %d", test.v1, test.v2, test.result, res) - } - //Test counterpart - if res := test.v2.Compare(test.v1); res != -test.result { - t.Errorf("Comparing %q : %q, expected %d but got %d", test.v2, test.v1, -test.result, res) - } - } -} - -type wrongformatTest struct { - v *Version - str string -} - -var wrongformatTests = []wrongformatTest{ - {nil, ""}, - {nil, "."}, - {nil, "1."}, - {nil, ".1"}, - {nil, "a.b.c"}, - {nil, "1.a.b"}, - {nil, "1.1.a"}, - {nil, "1.a.1"}, - {nil, "a.1.1"}, - {nil, ".."}, - {nil, "1.."}, - {nil, "1.1."}, - {nil, "1..1"}, - {nil, "1.1.+123"}, - {nil, "1.1.-beta"}, - {nil, "-1.1.1"}, - {nil, "1.-1.1"}, - {nil, "1.1.-1"}, - // giant numbers - {nil, "20000000000000000000.1.1"}, - {nil, "1.20000000000000000000.1"}, - {nil, "1.1.20000000000000000000"}, - {nil, "1.1.1-20000000000000000000"}, - // Leading zeroes - {nil, "01.1.1"}, - {nil, "001.1.1"}, - {nil, "1.01.1"}, - {nil, "1.001.1"}, - {nil, "1.1.01"}, - {nil, "1.1.001"}, - {nil, "1.1.1-01"}, - {nil, "1.1.1-001"}, - {nil, "1.1.1-beta.01"}, - {nil, "1.1.1-beta.001"}, - {&Version{0, 0, 0, []PRVersion{prstr("!")}, nil}, "0.0.0-!"}, - {&Version{0, 0, 0, nil, []string{"!"}}, "0.0.0+!"}, - // empty prversion - {&Version{0, 0, 0, []PRVersion{prstr(""), prstr("alpha")}, nil}, "0.0.0-.alpha"}, - // empty build meta data - {&Version{0, 0, 0, []PRVersion{prstr("alpha")}, []string{""}}, "0.0.0-alpha+"}, - {&Version{0, 0, 0, []PRVersion{prstr("alpha")}, []string{"test", ""}}, "0.0.0-alpha+test."}, -} - -func TestWrongFormat(t *testing.T) { - for _, test := range wrongformatTests { - - if res, err := Parse(test.str); err == nil { - t.Errorf("Parsing wrong format version %q, expected error but got %q", test.str, res) - } - - if test.v != nil { - if err := test.v.Validate(); err == nil { - t.Errorf("Validating wrong format version %q (%q), expected error", test.v, test.str) - } - } - } -} - -var wrongTolerantFormatTests = []wrongformatTest{ - {nil, "1.0+abc"}, - {nil, "1.0-rc.1"}, -} - -func TestWrongTolerantFormat(t *testing.T) { - for _, test := range wrongTolerantFormatTests { - if res, err := ParseTolerant(test.str); err == nil { - t.Errorf("Parsing wrong format version %q, expected error but got %q", test.str, res) - } - } -} - -func TestCompareHelper(t *testing.T) { - v := Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil} - v1 := Version{1, 0, 0, nil, nil} - if !v.EQ(v) { - t.Errorf("%q should be equal to %q", v, v) - } - if !v.Equals(v) { - t.Errorf("%q should be equal to %q", v, v) - } - if !v1.NE(v) { - t.Errorf("%q should not be equal to %q", v1, v) - } - if !v.GTE(v) { - t.Errorf("%q should be greater than or equal to %q", v, v) - } - if !v.LTE(v) { - t.Errorf("%q should be less than or equal to %q", v, v) - } - if !v.LT(v1) { - t.Errorf("%q should be less than %q", v, v1) - } - if !v.LTE(v1) { - t.Errorf("%q should be less than or equal %q", v, v1) - } - if !v.LE(v1) { - t.Errorf("%q should be less than or equal %q", v, v1) - } - if !v1.GT(v) { - t.Errorf("%q should be greater than %q", v1, v) - } - if !v1.GTE(v) { - t.Errorf("%q should be greater than or equal %q", v1, v) - } - if !v1.GE(v) { - t.Errorf("%q should be greater than or equal %q", v1, v) - } -} - -func TestPreReleaseVersions(t *testing.T) { - p1, err := NewPRVersion("123") - if !p1.IsNumeric() { - t.Errorf("Expected numeric prversion, got %q", p1) - } - if p1.VersionNum != 123 { - t.Error("Wrong prversion number") - } - if err != nil { - t.Errorf("Not expected error %q", err) - } - p2, err := NewPRVersion("alpha") - if p2.IsNumeric() { - t.Errorf("Expected non-numeric prversion, got %q", p2) - } - if p2.VersionStr != "alpha" { - t.Error("Wrong prversion string") - } - if err != nil { - t.Errorf("Not expected error %q", err) - } -} - -func TestBuildMetaDataVersions(t *testing.T) { - _, err := NewBuildVersion("123") - if err != nil { - t.Errorf("Unexpected error %q", err) - } - - _, err = NewBuildVersion("build") - if err != nil { - t.Errorf("Unexpected error %q", err) - } - - _, err = NewBuildVersion("test?") - if err == nil { - t.Error("Expected error, got none") - } - - _, err = NewBuildVersion("") - if err == nil { - t.Error("Expected error, got none") - } -} - -func TestNewHelper(t *testing.T) { - v, err := New("1.2.3") - if err != nil { - t.Fatalf("Unexpected error %q", err) - } - - // New returns pointer - if v == nil { - t.Fatal("Version is nil") - } - if v.Compare(Version{1, 2, 3, nil, nil}) != 0 { - t.Fatal("Unexpected comparison problem") - } -} - -func TestMakeHelper(t *testing.T) { - v, err := Make("1.2.3") - if err != nil { - t.Fatalf("Unexpected error %q", err) - } - if v.Compare(Version{1, 2, 3, nil, nil}) != 0 { - t.Fatal("Unexpected comparison problem") - } -} - -func BenchmarkParseSimple(b *testing.B) { - const VERSION = "0.0.1" - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Parse(VERSION) - } -} - -func BenchmarkParseComplex(b *testing.B) { - const VERSION = "0.0.1-alpha.preview+123.456" - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Parse(VERSION) - } -} - -func BenchmarkParseAverage(b *testing.B) { - l := len(formatTests) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Parse(formatTests[n%l].result) - } -} - -func BenchmarkParseTolerantAverage(b *testing.B) { - l := len(tolerantFormatTests) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - ParseTolerant(tolerantFormatTests[n%l].result) - } -} - -func BenchmarkStringSimple(b *testing.B) { - const VERSION = "0.0.1" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.String() - } -} - -func BenchmarkStringLarger(b *testing.B) { - const VERSION = "11.15.2012" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.String() - } -} - -func BenchmarkStringComplex(b *testing.B) { - const VERSION = "0.0.1-alpha.preview+123.456" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.String() - } -} - -func BenchmarkStringAverage(b *testing.B) { - l := len(formatTests) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - formatTests[n%l].v.String() - } -} - -func BenchmarkValidateSimple(b *testing.B) { - const VERSION = "0.0.1" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.Validate() - } -} - -func BenchmarkValidateComplex(b *testing.B) { - const VERSION = "0.0.1-alpha.preview+123.456" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.Validate() - } -} - -func BenchmarkValidateAverage(b *testing.B) { - l := len(formatTests) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - formatTests[n%l].v.Validate() - } -} - -func BenchmarkCompareSimple(b *testing.B) { - const VERSION = "0.0.1" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.Compare(v) - } -} - -func BenchmarkCompareComplex(b *testing.B) { - const VERSION = "0.0.1-alpha.preview+123.456" - v, _ := Parse(VERSION) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - v.Compare(v) - } -} - -func BenchmarkCompareAverage(b *testing.B) { - l := len(compareTests) - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - compareTests[n%l].v1.Compare((compareTests[n%l].v2)) - } -} diff --git a/vendor/github.com/blang/semver/sort.go b/vendor/github.com/blang/semver/sort.go deleted file mode 100644 index e18f88082..000000000 --- a/vendor/github.com/blang/semver/sort.go +++ /dev/null @@ -1,28 +0,0 @@ -package semver - -import ( - "sort" -) - -// Versions represents multiple versions. -type Versions []Version - -// Len returns length of version collection -func (s Versions) Len() int { - return len(s) -} - -// Swap swaps two versions inside the collection by its indices -func (s Versions) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less checks if version at index i is less than version at index j -func (s Versions) Less(i, j int) bool { - return s[i].LT(s[j]) -} - -// Sort sorts a slice of versions -func Sort(versions []Version) { - sort.Sort(Versions(versions)) -} diff --git a/vendor/github.com/blang/semver/sort_test.go b/vendor/github.com/blang/semver/sort_test.go deleted file mode 100644 index 68893972a..000000000 --- a/vendor/github.com/blang/semver/sort_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package semver - -import ( - "reflect" - "testing" -) - -func TestSort(t *testing.T) { - v100, _ := Parse("1.0.0") - v010, _ := Parse("0.1.0") - v001, _ := Parse("0.0.1") - versions := []Version{v010, v100, v001} - Sort(versions) - - correct := []Version{v001, v010, v100} - if !reflect.DeepEqual(versions, correct) { - t.Fatalf("Sort returned wrong order: %s", versions) - } -} - -func BenchmarkSort(b *testing.B) { - v100, _ := Parse("1.0.0") - v010, _ := Parse("0.1.0") - v001, _ := Parse("0.0.1") - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Sort([]Version{v010, v100, v001}) - } -} diff --git a/vendor/github.com/blang/semver/sql.go b/vendor/github.com/blang/semver/sql.go deleted file mode 100644 index eb4d80266..000000000 --- a/vendor/github.com/blang/semver/sql.go +++ /dev/null @@ -1,30 +0,0 @@ -package semver - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements the database/sql.Scanner interface. -func (v *Version) Scan(src interface{}) (err error) { - var str string - switch src := src.(type) { - case string: - str = src - case []byte: - str = string(src) - default: - return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) - } - - if t, err := Parse(str); err == nil { - *v = t - } - - return -} - -// Value implements the database/sql/driver.Valuer interface. -func (v Version) Value() (driver.Value, error) { - return v.String(), nil -} diff --git a/vendor/github.com/blang/semver/sql_test.go b/vendor/github.com/blang/semver/sql_test.go deleted file mode 100644 index ebf48b584..000000000 --- a/vendor/github.com/blang/semver/sql_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package semver - -import ( - "testing" -) - -type scanTest struct { - val interface{} - shouldError bool - expected string -} - -var scanTests = []scanTest{ - {"1.2.3", false, "1.2.3"}, - {[]byte("1.2.3"), false, "1.2.3"}, - {7, true, ""}, - {7e4, true, ""}, - {true, true, ""}, -} - -func TestScanString(t *testing.T) { - for _, tc := range scanTests { - s := &Version{} - err := s.Scan(tc.val) - if tc.shouldError { - if err == nil { - t.Fatalf("Scan did not return an error on %v (%T)", tc.val, tc.val) - } - } else { - if err != nil { - t.Fatalf("Scan returned an unexpected error: %s (%T) on %v (%T)", tc.val, tc.val, tc.val, tc.val) - } - if val, _ := s.Value(); val != tc.expected { - t.Errorf("Wrong Value returned, expected %q, got %q", tc.expected, val) - } - } - } -} diff --git a/vendor/github.com/coreos/go-oidc/.gitignore b/vendor/github.com/coreos/go-oidc/.gitignore deleted file mode 100644 index c96f2f47b..000000000 --- a/vendor/github.com/coreos/go-oidc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin -/gopath diff --git a/vendor/github.com/coreos/go-oidc/.travis.yml b/vendor/github.com/coreos/go-oidc/.travis.yml deleted file mode 100644 index f2f3c9c81..000000000 --- a/vendor/github.com/coreos/go-oidc/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go - -go: - - 1.7.5 - - 1.8 - -install: - - go get -v -t github.com/coreos/go-oidc/... - - go get golang.org/x/tools/cmd/cover - - go get github.com/golang/lint/golint - -script: - - ./test - -notifications: - email: false diff --git a/vendor/github.com/coreos/go-oidc/CONTRIBUTING.md b/vendor/github.com/coreos/go-oidc/CONTRIBUTING.md deleted file mode 100644 index 6662073a8..000000000 --- a/vendor/github.com/coreos/go-oidc/CONTRIBUTING.md +++ /dev/null @@ -1,71 +0,0 @@ -# How to Contribute - -CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via -GitHub pull requests. This document outlines some of the conventions on -development workflow, commit message formatting, contact points and other -resources to make it easier to get your contribution accepted. - -# Certificate of Origin - -By contributing to this project you agree to the Developer Certificate of -Origin (DCO). This document was created by the Linux Kernel community and is a -simple statement that you, as a contributor, have the legal right to make the -contribution. See the [DCO](DCO) file for details. - -# Email and Chat - -The project currently uses the general CoreOS email list and IRC channel: -- Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev) -- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org - -Please avoid emailing maintainers found in the MAINTAINERS file directly. They -are very busy and read the mailing lists. - -## Getting Started - -- Fork the repository on GitHub -- Read the [README](README.md) for build and test instructions -- Play with the project, submit bugs, submit patches! - -## Contribution Flow - -This is a rough outline of what a contributor's workflow looks like: - -- Create a topic branch from where you want to base your work (usually master). -- Make commits of logical units. -- Make sure your commit messages are in the proper format (see below). -- Push your changes to a topic branch in your fork of the repository. -- Make sure the tests pass, and add any new tests as appropriate. -- Submit a pull request to the original repository. - -Thanks for your contributions! - -### Format of the Commit Message - -We follow a rough convention for commit messages that is designed to answer two -questions: what changed and why. The subject line should feature the what and -the body of the commit should describe the why. - -``` -scripts: add the test-cluster command - -this uses tmux to setup a test cluster that you can easily kill and -start for debugging. - -Fixes #38 -``` - -The format can be described more formally as follows: - -``` -: - - - -