diff --git a/Makefile b/Makefile index 7c87d7aa9..ed57e8d1b 100644 --- a/Makefile +++ b/Makefile @@ -112,6 +112,7 @@ run-node:build-node --run-mode=master --kube-conf=`pwd`/test/admin.kubeconfig \ --nodeid-file=`pwd`/test/host_id.conf \ --static-task-path=`pwd`/test/tasks \ + --statsd.mapping-config=`pwd`/test/mapper.yml \ --log-level=debug doc: ## build the docs diff --git a/cmd/README.md b/cmd/README.md index e69de29bb..c75814605 100644 --- a/cmd/README.md +++ b/cmd/README.md @@ -0,0 +1,19 @@ +# Component Description + +## API + +## BUILDER + +## ENTRANCE + +## EVENTLOG + +## GRCTL + +## MQ + +## NODE + +## WEBCLI + +## WORKER \ No newline at end of file diff --git a/cmd/node/option/conf.go b/cmd/node/option/conf.go index 707d13472..440c77bbe 100644 --- a/cmd/node/option/conf.go +++ b/cmd/node/option/conf.go @@ -117,7 +117,17 @@ type Conf struct { // 默认 300 LockTTL int64 - Etcd client.Config + Etcd client.Config + StatsdConfig StatsdConfig +} + +//StatsdConfig StatsdConfig +type StatsdConfig struct { + StatsdListenAddress string + StatsdListenUDP string + StatsdListenTCP string + MappingConfig string + ReadBuffer int } //AddFlags AddFlags @@ -156,6 +166,11 @@ func (a *Conf) AddFlags(fs *pflag.FlagSet) { //fs.StringSliceVar(&a.EventServerAddress, "event-servers", []string{"http://127.0.0.1:6363"}, "event message server address.") fs.StringVar(&a.DBType, "db-type", "mysql", "db type mysql or etcd") fs.StringVar(&a.DBConnectionInfo, "mysql", "admin:admin@tcp(127.0.0.1:3306)/region", "mysql db connection info") + fs.StringVar(&a.StatsdConfig.StatsdListenAddress, "statsd.listen-address", "", "The UDP address on which to receive statsd metric lines. DEPRECATED, use statsd.listen-udp instead.") + fs.StringVar(&a.StatsdConfig.StatsdListenUDP, "statsd.listen-udp", ":9125", "The UDP address on which to receive statsd metric lines. \"\" disables it.") + fs.StringVar(&a.StatsdConfig.StatsdListenTCP, "statsd.listen-tcp", ":9125", "The TCP address on which to receive statsd metric lines. \"\" disables it.") + fs.StringVar(&a.StatsdConfig.MappingConfig, "statsd.mapping-config", "", "Metric mapping configuration file name.") + fs.IntVar(&a.StatsdConfig.ReadBuffer, "statsd.read-buffer", 0, "Size (in bytes) of the operating system's transmit read buffer associated with the UDP connection. Please make sure the kernel parameters net.core.rmem_max is set to a value greater than the value specified.") } //SetLog 设置log diff --git a/cmd/node/server/server.go b/cmd/node/server/server.go index de98ce035..fce8519a0 100644 --- a/cmd/node/server/server.go +++ b/cmd/node/server/server.go @@ -28,6 +28,8 @@ import ( "github.com/goodrain/rainbond/pkg/node/core/store" "github.com/goodrain/rainbond/pkg/node/masterserver" "github.com/goodrain/rainbond/pkg/node/nodeserver" + "github.com/goodrain/rainbond/pkg/node/statsd" + "github.com/prometheus/client_golang/prometheus" "github.com/Sirupsen/logrus" @@ -86,8 +88,16 @@ func Run(c *option.Conf) error { } event.On(event.EXIT, ms.Stop) } + //statsd exporter + registry := prometheus.NewRegistry() + exporter := statsd.CreateExporter(c.StatsdConfig, registry) + if err := exporter.Start(); err != nil { + logrus.Errorf("start statsd exporter server error,%s", err.Error()) + return err + } + //启动API服务 - apiManager := api.NewManager(*s.Conf, s.HostNode, ms) + apiManager := api.NewManager(*s.Conf, s.HostNode, ms, exporter) apiManager.Start(errChan) defer apiManager.Stop() diff --git a/hack/contrib/docker/chaos/plugins/build_work.py b/hack/contrib/docker/chaos/plugins/build_work.py index fbadef758..468f55e91 100644 --- a/hack/contrib/docker/chaos/plugins/build_work.py +++ b/hack/contrib/docker/chaos/plugins/build_work.py @@ -330,7 +330,7 @@ class RepoBuilder(): h = self.user_cs_client try: h.update_service(self.service_id, json.dumps(update_items)) - self.region_client.update_service_region(self.service_id,json.dumps(update_items)) + self.region_client.update_service_region(self.service_id, json.dumps(update_items)) except h.CallApiError, e: self.log.error( "网络异常,更新应用镜像名称失败. {}".format(e.message), diff --git a/pkg/node/api/manager.go b/pkg/node/api/manager.go index 7425431df..6cfda7782 100644 --- a/pkg/node/api/manager.go +++ b/pkg/node/api/manager.go @@ -24,6 +24,9 @@ import ( "time" "github.com/goodrain/rainbond/pkg/node/masterserver" + "github.com/goodrain/rainbond/pkg/node/statsd" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/goodrain/rainbond/pkg/node/api/controller" "github.com/goodrain/rainbond/pkg/node/api/model" @@ -44,28 +47,59 @@ import ( //Manager api manager type Manager struct { - ctx context.Context - cancel context.CancelFunc - conf option.Conf - router *chi.Mux - node *model.HostNode - lID client.LeaseID // lease id - ms *masterserver.MasterServer + ctx context.Context + cancel context.CancelFunc + conf option.Conf + router *chi.Mux + node *model.HostNode + lID client.LeaseID // lease id + ms *masterserver.MasterServer + exporter *statsd.Exporter } //NewManager api manager -func NewManager(c option.Conf, node *model.HostNode, ms *masterserver.MasterServer) *Manager { +func NewManager(c option.Conf, node *model.HostNode, ms *masterserver.MasterServer, exporter *statsd.Exporter) *Manager { r := router.Routers(c.RunMode) ctx, cancel := context.WithCancel(context.Background()) controller.Init(&c, ms) - return &Manager{ - ctx: ctx, - cancel: cancel, - conf: c, - router: r, - node: node, - ms: ms, + m := &Manager{ + ctx: ctx, + cancel: cancel, + conf: c, + router: r, + node: node, + ms: ms, + exporter: exporter, } + m.router.Get("/app/metrics", m.HandleStatsd) + m.router.Get("/-/statsdreload", m.ReloadStatsdMappConfig) + return m +} + +//ReloadStatsdMappConfig ReloadStatsdMappConfig +func (m *Manager) ReloadStatsdMappConfig(w http.ResponseWriter, r *http.Request) { + if err := m.exporter.ReloadConfig(); err != nil { + w.Write([]byte(err.Error())) + w.WriteHeader(500) + } else { + w.Write([]byte("Success reload")) + w.WriteHeader(200) + } +} + +//HandleStatsd statsd handle +func (m *Manager) HandleStatsd(w http.ResponseWriter, r *http.Request) { + gatherers := prometheus.Gatherers{ + prometheus.DefaultGatherer, + m.exporter.GetRegister(), + } + // Delegate http serving to Prometheus client library, which will call collector.Collect. + h := promhttp.HandlerFor(gatherers, + promhttp.HandlerOpts{ + ErrorLog: logrus.StandardLogger(), + ErrorHandling: promhttp.ContinueOnError, + }) + h.ServeHTTP(w, r) } //Start 启动 diff --git a/pkg/node/api/router/router.go b/pkg/node/api/router/router.go index 2bdb7591c..3dc34fda7 100644 --- a/pkg/node/api/router/router.go +++ b/pkg/node/api/router/router.go @@ -55,7 +55,7 @@ func Routers(mode string) *chi.Mux { }) r.Route("/nodes", func(r chi.Router) { - r.Get("/fullres",controller.RegionRes) + r.Get("/fullres", controller.RegionRes) r.Get("/resources", controller.Resources) r.Get("/capres", controller.CapRes) r.Get("/", controller.GetNodes) @@ -67,9 +67,9 @@ func Routers(mode string) *chi.Mux { r.Put("/{node_id}/unschedulable", controller.Cordon) r.Put("/{node_id}/reschedulable", controller.UnCordon) r.Put("/{node_id}/labels", controller.PutLabel) - r.Post("/{node_id}/down", controller.DownNode) //节点下线 - r.Post("/{node_id}/up", controller.UpNode) //节点上线 - r.Get("/{node_id}/instance", controller.Instances) //节点上线 + r.Post("/{node_id}/down", controller.DownNode) //节点下线 + r.Post("/{node_id}/up", controller.UpNode) //节点上线 + r.Get("/{node_id}/instance", controller.Instances) //节点上线 //历史API r.Get("/{node}/details", controller.GetNodeDetails) @@ -114,6 +114,6 @@ func Routers(mode string) *chi.Mux { r.Put("/-/taskreload", controller.ReloadStaticTasks) } //节点监控 - r.Get("/metrics", controller.NodeExporter) + r.Get("/node/metrics", controller.NodeExporter) return r } diff --git a/pkg/node/masterserver/task_engine.go b/pkg/node/masterserver/task_engine.go index 81190feaf..79927b650 100644 --- a/pkg/node/masterserver/task_engine.go +++ b/pkg/node/masterserver/task_engine.go @@ -855,7 +855,7 @@ func (t *TaskEngine) HandleJobRecord() { case <-t.ctx.Done(): return case event := <-ch: - if err:=event.Err();err!=nil{ + if err := event.Err(); err != nil { } for _, ev := range event.Events { diff --git a/pkg/node/statsd/exporter/LICENSE b/pkg/node/statsd/exporter/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/pkg/node/statsd/exporter/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/pkg/node/statsd/exporter/Makefile b/pkg/node/statsd/exporter/Makefile new file mode 100644 index 000000000..163fe771a --- /dev/null +++ b/pkg/node/statsd/exporter/Makefile @@ -0,0 +1,60 @@ +# Copyright 2013 The Prometheus Authors +# 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. + +GO := GO15VENDOREXPERIMENT=1 go +PROMU := $(GOPATH)/bin/promu +pkgs = $(shell $(GO) list ./... | grep -v /vendor/) + +PREFIX ?= $(shell pwd) +BIN_DIR ?= $(shell pwd) +DOCKER_IMAGE_NAME ?= statsd-exporter +DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) + + +all: format build test + +style: + @echo ">> checking code style" + @! gofmt -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' + +test: + @echo ">> running tests" + @$(GO) test -short $(pkgs) + +format: + @echo ">> formatting code" + @$(GO) fmt $(pkgs) + +vet: + @echo ">> vetting code" + @$(GO) vet $(pkgs) + +build: promu + @echo ">> building binaries" + @$(PROMU) build --prefix $(PREFIX) + +tarball: promu + @echo ">> building release tarball" + @$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) + +docker: + @echo ">> building docker image" + @docker build -t "$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . + +promu: + @GOOS=$(shell uname -s | tr A-Z a-z) \ + GOARCH=$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m))) \ + $(GO) get -u github.com/prometheus/promu + + +.PHONY: all style format build test vet tarball docker promu diff --git a/pkg/node/statsd/exporter/exporter.go b/pkg/node/statsd/exporter/exporter.go new file mode 100644 index 000000000..fbc70a4de --- /dev/null +++ b/pkg/node/statsd/exporter/exporter.go @@ -0,0 +1,595 @@ +// Copyright 2013 The Prometheus Authors +// 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 exporter + +import ( + "bufio" + "bytes" + "encoding/binary" + "fmt" + "hash/fnv" + "io" + "net" + "regexp" + "strconv" + "strings" + "unicode/utf8" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/log" + "github.com/prometheus/common/model" +) + +const ( + defaultHelp = "Metric autogenerated by statsd_exporter." + regErrF = "A change of configuration created inconsistent metrics for " + + "%q. You have to restart the statsd_exporter, and you should " + + "consider the effects on your monitoring setup. Error: %s" +) + +var ( + illegalCharsRE = regexp.MustCompile(`[^a-zA-Z0-9_]`) + + hash = fnv.New64a() + strBuf bytes.Buffer // Used for hashing. + intBuf = make([]byte, 8) +) + +// hashNameAndLabels returns a hash value of the provided name string and all +// the label names and values in the provided labels map. +// +// Not safe for concurrent use! (Uses a shared buffer and hasher to save on +// allocations.) +func hashNameAndLabels(name string, labels prometheus.Labels) uint64 { + hash.Reset() + strBuf.Reset() + strBuf.WriteString(name) + hash.Write(strBuf.Bytes()) + binary.BigEndian.PutUint64(intBuf, model.LabelsToSignature(labels)) + hash.Write(intBuf) + return hash.Sum64() +} + +type CounterContainer struct { + Elements map[uint64]prometheus.Counter + Register prometheus.Registerer +} + +func NewCounterContainer(Register prometheus.Registerer) *CounterContainer { + return &CounterContainer{ + Elements: make(map[uint64]prometheus.Counter), + Register: Register, + } +} + +func (c *CounterContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Counter, error) { + hash := hashNameAndLabels(metricName, labels) + counter, ok := c.Elements[hash] + if !ok { + counter = prometheus.NewCounter(prometheus.CounterOpts{ + Name: metricName, + Help: help, + ConstLabels: labels, + }) + if err := c.Register.Register(counter); err != nil { + return nil, err + } + c.Elements[hash] = counter + } + return counter, nil +} + +type GaugeContainer struct { + Elements map[uint64]prometheus.Gauge + Register prometheus.Registerer +} + +func NewGaugeContainer(Register prometheus.Registerer) *GaugeContainer { + return &GaugeContainer{ + Elements: make(map[uint64]prometheus.Gauge), + Register: Register, + } +} + +func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Gauge, error) { + hash := hashNameAndLabels(metricName, labels) + gauge, ok := c.Elements[hash] + if !ok { + gauge = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: metricName, + Help: help, + ConstLabels: labels, + }) + if err := c.Register.Register(gauge); err != nil { + return nil, err + } + c.Elements[hash] = gauge + } + return gauge, nil +} + +type SummaryContainer struct { + Elements map[uint64]prometheus.Summary + Register prometheus.Registerer +} + +func NewSummaryContainer(Register prometheus.Registerer) *SummaryContainer { + return &SummaryContainer{ + Elements: make(map[uint64]prometheus.Summary), + Register: Register, + } +} + +func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Summary, error) { + hash := hashNameAndLabels(metricName, labels) + summary, ok := c.Elements[hash] + if !ok { + summary = prometheus.NewSummary( + prometheus.SummaryOpts{ + Name: metricName, + Help: help, + ConstLabels: labels, + }) + if err := c.Register.Register(summary); err != nil { + return nil, err + } + c.Elements[hash] = summary + } + return summary, nil +} + +type HistogramContainer struct { + Elements map[uint64]prometheus.Histogram + mapper *MetricMapper + Register prometheus.Registerer +} + +func NewHistogramContainer(mapper *MetricMapper, Register prometheus.Registerer) *HistogramContainer { + return &HistogramContainer{ + Elements: make(map[uint64]prometheus.Histogram), + mapper: mapper, + Register: Register, + } +} + +func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *metricMapping) (prometheus.Histogram, error) { + hash := hashNameAndLabels(metricName, labels) + histogram, ok := c.Elements[hash] + if !ok { + buckets := c.mapper.Defaults.Buckets + if mapping != nil && mapping.Buckets != nil && len(mapping.Buckets) > 0 { + buckets = mapping.Buckets + } + histogram = prometheus.NewHistogram( + prometheus.HistogramOpts{ + Name: metricName, + Help: help, + ConstLabels: labels, + Buckets: buckets, + }) + c.Elements[hash] = histogram + if err := c.Register.Register(histogram); err != nil { + return nil, err + } + } + return histogram, nil +} + +type Event interface { + MetricName() string + Value() float64 + Labels() map[string]string +} + +type CounterEvent struct { + metricName string + value float64 + labels map[string]string +} + +func (c *CounterEvent) MetricName() string { return c.metricName } +func (c *CounterEvent) Value() float64 { return c.value } +func (c *CounterEvent) Labels() map[string]string { return c.labels } + +type GaugeEvent struct { + metricName string + value float64 + relative bool + labels map[string]string +} + +func (g *GaugeEvent) MetricName() string { return g.metricName } +func (g *GaugeEvent) Value() float64 { return g.value } +func (c *GaugeEvent) Labels() map[string]string { return c.labels } + +type TimerEvent struct { + metricName string + value float64 + labels map[string]string +} + +func (t *TimerEvent) MetricName() string { return t.metricName } +func (t *TimerEvent) Value() float64 { return t.value } +func (c *TimerEvent) Labels() map[string]string { return c.labels } + +type Events []Event + +type Exporter struct { + Counters *CounterContainer + Gauges *GaugeContainer + Summaries *SummaryContainer + Histograms *HistogramContainer + mapper *MetricMapper +} + +func escapeMetricName(metricName string) string { + // If a metric starts with a digit, prepend an underscore. + if metricName[0] >= '0' && metricName[0] <= '9' { + metricName = "_" + metricName + } + + // Replace all illegal metric chars with underscores. + metricName = illegalCharsRE.ReplaceAllString(metricName, "_") + return metricName +} + +func (b *Exporter) Listen(e <-chan Events) { + for { + events, ok := <-e + if !ok { + log.Debug("Channel is closed. Break out of Exporter.Listener.") + return + } + for _, event := range events { + var help string + metricName := "" + prometheusLabels := event.Labels() + + mapping, labels, present := b.mapper.getMapping(event.MetricName()) + if mapping == nil { + mapping = &metricMapping{} + } + if mapping.HelpText == "" { + help = defaultHelp + } else { + help = mapping.HelpText + } + if present { + metricName = mapping.Name + for label, value := range labels { + prometheusLabels[label] = value + } + } else { + eventsUnmapped.Inc() + metricName = escapeMetricName(event.MetricName()) + } + + switch ev := event.(type) { + case *CounterEvent: + // We don't accept negative values for counters. Incrementing the counter with a negative number + // will cause the exporter to panic. Instead we will warn and continue to the next event. + if event.Value() < 0.0 { + log.Debugf("Counter %q is: '%f' (counter must be non-negative value)", metricName, event.Value()) + eventStats.WithLabelValues("illegal_negative_counter").Inc() + continue + } + + counter, err := b.Counters.Get( + metricName, + prometheusLabels, + help, + ) + if err == nil { + counter.Add(event.Value()) + + eventStats.WithLabelValues("counter").Inc() + } else { + log.Debugf(regErrF, metricName, err) + conflictingEventStats.WithLabelValues("counter").Inc() + } + + case *GaugeEvent: + gauge, err := b.Gauges.Get( + metricName, + prometheusLabels, + help, + ) + + if err == nil { + if ev.relative { + gauge.Add(event.Value()) + } else { + gauge.Set(event.Value()) + } + + eventStats.WithLabelValues("gauge").Inc() + } else { + log.Debugf(regErrF, metricName, err) + conflictingEventStats.WithLabelValues("gauge").Inc() + } + + case *TimerEvent: + t := timerTypeDefault + if mapping != nil { + t = mapping.TimerType + } + if t == timerTypeDefault { + t = b.mapper.Defaults.TimerType + } + + switch t { + case timerTypeHistogram: + histogram, err := b.Histograms.Get( + metricName, + prometheusLabels, + help, + mapping, + ) + if err == nil { + histogram.Observe(event.Value() / 1000) // prometheus presumes seconds, statsd millisecond + eventStats.WithLabelValues("timer").Inc() + } else { + log.Debugf(regErrF, metricName, err) + conflictingEventStats.WithLabelValues("timer").Inc() + } + + case timerTypeDefault, timerTypeSummary: + summary, err := b.Summaries.Get( + metricName, + prometheusLabels, + help, + ) + if err == nil { + summary.Observe(event.Value()) + eventStats.WithLabelValues("timer").Inc() + } else { + log.Debugf(regErrF, metricName, err) + conflictingEventStats.WithLabelValues("timer").Inc() + } + + default: + panic(fmt.Sprintf("unknown timer type '%s'", t)) + } + + default: + log.Debugln("Unsupported event type") + eventStats.WithLabelValues("illegal").Inc() + } + } + } +} + +//NewExporter new exporter +func NewExporter(mapper *MetricMapper, Register prometheus.Registerer) *Exporter { + return &Exporter{ + Counters: NewCounterContainer(Register), + Gauges: NewGaugeContainer(Register), + Summaries: NewSummaryContainer(Register), + Histograms: NewHistogramContainer(mapper, Register), + mapper: mapper, + } +} + +func buildEvent(statType, metric string, value float64, relative bool, labels map[string]string) (Event, error) { + switch statType { + case "c": + return &CounterEvent{ + metricName: metric, + value: float64(value), + labels: labels, + }, nil + case "g": + return &GaugeEvent{ + metricName: metric, + value: float64(value), + relative: relative, + labels: labels, + }, nil + case "ms", "h": + return &TimerEvent{ + metricName: metric, + value: float64(value), + labels: labels, + }, nil + case "s": + return nil, fmt.Errorf("No support for StatsD sets") + default: + return nil, fmt.Errorf("Bad stat type %s", statType) + } +} + +func parseDogStatsDTagsToLabels(component string) map[string]string { + labels := map[string]string{} + tagsReceived.Inc() + tags := strings.Split(component, ",") + for _, t := range tags { + t = strings.TrimPrefix(t, "#") + kv := strings.SplitN(t, ":", 2) + + if len(kv) < 2 || len(kv[1]) == 0 { + tagErrors.Inc() + log.Debugf("Malformed or empty DogStatsD tag %s in component %s", t, component) + continue + } + + labels[escapeMetricName(kv[0])] = kv[1] + } + return labels +} + +func lineToEvents(line string) Events { + events := Events{} + if line == "" { + return events + } + + elements := strings.SplitN(line, ":", 2) + if len(elements) < 2 || len(elements[0]) == 0 || !utf8.ValidString(line) { + sampleErrors.WithLabelValues("malformed_line").Inc() + log.Debugln("Bad line from StatsD:", line) + return events + } + metric := elements[0] + var samples []string + if strings.Contains(elements[1], "|#") { + // using datadog extensions, disable multi-metrics + samples = elements[1:] + } else { + samples = strings.Split(elements[1], ":") + } +samples: + for _, sample := range samples { + samplesReceived.Inc() + components := strings.Split(sample, "|") + samplingFactor := 1.0 + if len(components) < 2 || len(components) > 4 { + sampleErrors.WithLabelValues("malformed_component").Inc() + log.Debugln("Bad component on line:", line) + continue + } + valueStr, statType := components[0], components[1] + + var relative = false + if strings.Index(valueStr, "+") == 0 || strings.Index(valueStr, "-") == 0 { + relative = true + } + + value, err := strconv.ParseFloat(valueStr, 64) + if err != nil { + log.Debugf("Bad value %s on line: %s", valueStr, line) + sampleErrors.WithLabelValues("malformed_value").Inc() + continue + } + + multiplyEvents := 1 + labels := map[string]string{} + if len(components) >= 3 { + for _, component := range components[2:] { + if len(component) == 0 { + log.Debugln("Empty component on line: ", line) + sampleErrors.WithLabelValues("malformed_component").Inc() + continue samples + } + } + + for _, component := range components[2:] { + switch component[0] { + case '@': + if statType != "c" && statType != "ms" { + log.Debugln("Illegal sampling factor for non-counter metric on line", line) + sampleErrors.WithLabelValues("illegal_sample_factor").Inc() + continue + } + samplingFactor, err = strconv.ParseFloat(component[1:], 64) + if err != nil { + log.Debugf("Invalid sampling factor %s on line %s", component[1:], line) + sampleErrors.WithLabelValues("invalid_sample_factor").Inc() + } + if samplingFactor == 0 { + samplingFactor = 1 + } + + if statType == "c" { + value /= samplingFactor + } else if statType == "ms" { + multiplyEvents = int(1 / samplingFactor) + } + case '#': + labels = parseDogStatsDTagsToLabels(component) + default: + log.Debugf("Invalid sampling factor or tag section %s on line %s", components[2], line) + sampleErrors.WithLabelValues("invalid_sample_factor").Inc() + continue + } + } + } + + for i := 0; i < multiplyEvents; i++ { + event, err := buildEvent(statType, metric, value, relative, labels) + if err != nil { + log.Debugf("Error building event on line %s: %s", line, err) + sampleErrors.WithLabelValues("illegal_event").Inc() + continue + } + events = append(events, event) + } + } + return events +} + +type StatsDUDPListener struct { + Conn *net.UDPConn +} + +func (l *StatsDUDPListener) Listen(e chan<- Events) { + buf := make([]byte, 65535) + for { + n, _, err := l.Conn.ReadFromUDP(buf) + if err != nil { + log.Fatal(err) + } + l.handlePacket(buf[0:n], e) + } +} + +func (l *StatsDUDPListener) handlePacket(packet []byte, e chan<- Events) { + udpPackets.Inc() + lines := strings.Split(string(packet), "\n") + events := Events{} + for _, line := range lines { + linesReceived.Inc() + events = append(events, lineToEvents(line)...) + } + e <- events +} + +type StatsDTCPListener struct { + Conn *net.TCPListener +} + +func (l *StatsDTCPListener) Listen(e chan<- Events) { + defer l.Conn.Close() + for { + c, err := l.Conn.AcceptTCP() + if err != nil { + log.Fatalf("AcceptTCP failed: %v", err) + } + go l.handleConn(c, e) + } +} + +func (l *StatsDTCPListener) handleConn(c *net.TCPConn, e chan<- Events) { + defer c.Close() + + tcpConnections.Inc() + + r := bufio.NewReader(c) + for { + line, isPrefix, err := r.ReadLine() + if err != nil { + if err != io.EOF { + tcpErrors.Inc() + log.Debugf("Read %s failed: %v", c.RemoteAddr(), err) + } + break + } + if isPrefix { + tcpLineTooLong.Inc() + log.Debugf("Read %s failed: line too long", c.RemoteAddr()) + break + } + linesReceived.Inc() + e <- lineToEvents(string(line)) + } +} diff --git a/pkg/node/statsd/exporter/mapper.go b/pkg/node/statsd/exporter/mapper.go new file mode 100644 index 000000000..dd11bd664 --- /dev/null +++ b/pkg/node/statsd/exporter/mapper.go @@ -0,0 +1,158 @@ +// Copyright 2013 The Prometheus Authors +// 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 exporter + +import ( + "fmt" + "io/ioutil" + "regexp" + "strings" + "sync" + + "github.com/prometheus/client_golang/prometheus" + yaml "gopkg.in/yaml.v2" +) + +var ( + identifierRE = `[a-zA-Z_][a-zA-Z0-9_]+` + statsdMetricRE = `[a-zA-Z_](-?[a-zA-Z0-9_])+` + + metricLineRE = regexp.MustCompile(`^(\*\.|` + statsdMetricRE + `\.)+(\*|` + statsdMetricRE + `)$`) + labelLineRE = regexp.MustCompile(`^(` + identifierRE + `)\s*=\s*"(.*)"$`) + metricNameRE = regexp.MustCompile(`^` + identifierRE + `$`) +) + +type mapperConfigDefaults struct { + TimerType timerType `yaml:"timer_type"` + Buckets []float64 `yaml:"buckets"` + MatchType matchType `yaml:"match_type"` +} + +//MetricMapper MetricMapper +type MetricMapper struct { + Defaults mapperConfigDefaults `yaml:"defaults"` + Mappings []metricMapping `yaml:"mappings"` + mutex sync.Mutex +} + +type metricMapping struct { + Match string `yaml:"match"` + Name string `yaml:"name"` + regex *regexp.Regexp + Labels prometheus.Labels `yaml:"labels"` + TimerType timerType `yaml:"timer_type"` + Buckets []float64 `yaml:"buckets"` + MatchType matchType `yaml:"match_type"` + HelpText string `yaml:"help"` +} + +func (m *MetricMapper) InitFromYAMLString(fileContents string) error { + var n MetricMapper + + if err := yaml.Unmarshal([]byte(fileContents), &n); err != nil { + return err + } + + if n.Defaults.Buckets == nil || len(n.Defaults.Buckets) == 0 { + n.Defaults.Buckets = prometheus.DefBuckets + } + + if n.Defaults.MatchType == matchTypeDefault { + n.Defaults.MatchType = matchTypeGlob + } + + for i := range n.Mappings { + currentMapping := &n.Mappings[i] + + // check that label is correct + for k := range currentMapping.Labels { + if !metricNameRE.MatchString(k) { + return fmt.Errorf("invalid label key: %s", k) + } + } + + if currentMapping.Name == "" { + return fmt.Errorf("line %d: metric mapping didn't set a metric name", i) + } + + if !metricNameRE.MatchString(currentMapping.Name) { + return fmt.Errorf("metric name '%s' doesn't match regex '%s'", currentMapping.Name, metricNameRE) + } + + if currentMapping.MatchType == "" { + currentMapping.MatchType = n.Defaults.MatchType + } + + if currentMapping.MatchType == matchTypeGlob { + if !metricLineRE.MatchString(currentMapping.Match) { + return fmt.Errorf("invalid match: %s", currentMapping.Match) + } + // Translate the glob-style metric match line into a proper regex that we + // can use to match metrics later on. + metricRe := strings.Replace(currentMapping.Match, ".", "\\.", -1) + metricRe = strings.Replace(metricRe, "*", "([^.]*)", -1) + currentMapping.regex = regexp.MustCompile("^" + metricRe + "$") + } else { + currentMapping.regex = regexp.MustCompile(currentMapping.Match) + } + + if currentMapping.TimerType == "" { + currentMapping.TimerType = n.Defaults.TimerType + } + + if currentMapping.Buckets == nil || len(currentMapping.Buckets) == 0 { + currentMapping.Buckets = n.Defaults.Buckets + } + + } + + m.mutex.Lock() + defer m.mutex.Unlock() + + m.Defaults = n.Defaults + m.Mappings = n.Mappings + + mappingsCount.Set(float64(len(n.Mappings))) + + return nil +} + +func (m *MetricMapper) InitFromFile(fileName string) error { + mappingStr, err := ioutil.ReadFile(fileName) + if err != nil { + return err + } + return m.InitFromYAMLString(string(mappingStr)) +} + +func (m *MetricMapper) getMapping(statsdMetric string) (*metricMapping, prometheus.Labels, bool) { + m.mutex.Lock() + defer m.mutex.Unlock() + + for _, mapping := range m.Mappings { + matches := mapping.regex.FindStringSubmatchIndex(statsdMetric) + if len(matches) == 0 { + continue + } + + labels := prometheus.Labels{} + for label, valueExpr := range mapping.Labels { + value := mapping.regex.ExpandString([]byte{}, valueExpr, statsdMetric, matches) + labels[label] = string(value) + } + return &mapping, labels, true + } + + return nil, nil, false +} diff --git a/pkg/node/statsd/exporter/match.go b/pkg/node/statsd/exporter/match.go new file mode 100644 index 000000000..f594d43ec --- /dev/null +++ b/pkg/node/statsd/exporter/match.go @@ -0,0 +1,41 @@ +// Copyright 2013 The Prometheus Authors +// 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 exporter + +import "fmt" + +type matchType string + +const ( + matchTypeGlob matchType = "glob" + matchTypeRegex matchType = "regex" + matchTypeDefault matchType = "" +) + +func (t *matchType) UnmarshalYAML(unmarshal func(interface{}) error) error { + var v string + if err := unmarshal(&v); err != nil { + return err + } + + switch matchType(v) { + case matchTypeRegex: + *t = matchTypeRegex + case matchTypeGlob, matchTypeDefault: + *t = matchTypeGlob + default: + return fmt.Errorf("invalid match type %q", v) + } + return nil +} diff --git a/pkg/node/statsd/exporter/telemetry.go b/pkg/node/statsd/exporter/telemetry.go new file mode 100644 index 000000000..bc6459260 --- /dev/null +++ b/pkg/node/statsd/exporter/telemetry.go @@ -0,0 +1,122 @@ +// Copyright 2013 The Prometheus Authors +// 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 exporter + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +var ( + eventStats = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "statsd_exporter_events_total", + Help: "The total number of StatsD events seen.", + }, + []string{"type"}, + ) + eventsUnmapped = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "statsd_exporter_events_unmapped_total", + Help: "The total number of StatsD events no mapping was found for.", + }) + udpPackets = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_udp_packets_total", + Help: "The total number of StatsD packets received over UDP.", + }, + ) + tcpConnections = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_tcp_connections_total", + Help: "The total number of TCP connections handled.", + }, + ) + tcpErrors = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_tcp_connection_errors_total", + Help: "The number of errors encountered reading from TCP.", + }, + ) + tcpLineTooLong = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_tcp_too_long_lines_total", + Help: "The number of lines discarded due to being too long.", + }, + ) + linesReceived = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_lines_total", + Help: "The total number of StatsD lines received.", + }, + ) + samplesReceived = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_samples_total", + Help: "The total number of StatsD samples received.", + }, + ) + sampleErrors = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "statsd_exporter_sample_errors_total", + Help: "The total number of errors parsing StatsD samples.", + }, + []string{"reason"}, + ) + tagsReceived = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_tags_total", + Help: "The total number of DogStatsD tags processed.", + }, + ) + tagErrors = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "statsd_exporter_tag_errors_total", + Help: "The number of errors parsign DogStatsD tags.", + }, + ) + ConfigLoads = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "statsd_exporter_config_reloads_total", + Help: "The number of configuration reloads.", + }, + []string{"outcome"}, + ) + mappingsCount = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "statsd_exporter_loaded_mappings", + Help: "The current number of configured metric mappings.", + }) + conflictingEventStats = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "statsd_exporter_events_conflict_total", + Help: "The total number of StatsD events with conflicting names.", + }, + []string{"type"}, + ) +) + +//MetryInit init +func MetryInit(registry *prometheus.Registry) { + registry.MustRegister(eventStats) + registry.MustRegister(udpPackets) + registry.MustRegister(tcpConnections) + registry.MustRegister(tcpErrors) + registry.MustRegister(tcpLineTooLong) + registry.MustRegister(linesReceived) + registry.MustRegister(samplesReceived) + registry.MustRegister(sampleErrors) + registry.MustRegister(tagsReceived) + registry.MustRegister(tagErrors) + registry.MustRegister(ConfigLoads) + registry.MustRegister(mappingsCount) + registry.MustRegister(conflictingEventStats) +} diff --git a/pkg/node/statsd/exporter/timer.go b/pkg/node/statsd/exporter/timer.go new file mode 100644 index 000000000..f507c9653 --- /dev/null +++ b/pkg/node/statsd/exporter/timer.go @@ -0,0 +1,41 @@ +// Copyright 2013 The Prometheus Authors +// 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 exporter + +import "fmt" + +type timerType string + +const ( + timerTypeHistogram timerType = "histogram" + timerTypeSummary timerType = "summary" + timerTypeDefault timerType = "" +) + +func (t *timerType) UnmarshalYAML(unmarshal func(interface{}) error) error { + var v string + if err := unmarshal(&v); err != nil { + return err + } + + switch timerType(v) { + case timerTypeHistogram: + *t = timerTypeHistogram + case timerTypeSummary, timerTypeDefault: + *t = timerTypeSummary + default: + return fmt.Errorf("invalid timer type '%s'", v) + } + return nil +} diff --git a/pkg/node/statsd/statsd_export.go b/pkg/node/statsd/statsd_export.go new file mode 100644 index 000000000..2500f4eb6 --- /dev/null +++ b/pkg/node/statsd/statsd_export.go @@ -0,0 +1,223 @@ +// RAINBOND, Application Management Platform +// Copyright (C) 2014-2017 Goodrain Co., Ltd. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. For any non-GPL usage of Rainbond, +// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd. +// must be obtained first. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package statsd + +import ( + "fmt" + "net" + "strconv" + "yiyun/common/log" + + "github.com/Sirupsen/logrus" + "github.com/howeyc/fsnotify" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/version" + + "github.com/goodrain/rainbond/cmd/node/option" + "github.com/goodrain/rainbond/pkg/node/statsd/exporter" +) + +//Exporter receive statsd metric and export prometheus metric +type Exporter struct { + statsdListenAddress string + statsdListenUDP string + statsdListenTCP string + mappingConfig string + readBuffer int + exporter *exporter.Exporter + register *prometheus.Registry + mapper *exporter.MetricMapper +} + +//CreateExporter create a exporter +func CreateExporter(sc option.StatsdConfig, register *prometheus.Registry) *Exporter { + exp := &Exporter{ + statsdListenAddress: sc.StatsdListenAddress, + statsdListenTCP: sc.StatsdListenTCP, + statsdListenUDP: sc.StatsdListenUDP, + readBuffer: sc.ReadBuffer, + mappingConfig: sc.MappingConfig, + register: register, + } + exporter.MetryInit(register) + return exp +} + +//Start Start +func (e *Exporter) Start() error { + e.register.Register(version.NewCollector("statsd_exporter")) + if e.statsdListenAddress != "" { + logrus.Warnln("Warning: statsd.listen-address is DEPRECATED, please use statsd.listen-udp instead.") + e.statsdListenUDP = e.statsdListenAddress + } + + if e.statsdListenUDP == "" && e.statsdListenTCP == "" { + logrus.Fatalln("At least one of UDP/TCP listeners must be specified.") + return fmt.Errorf("At least one of UDP/TCP listeners must be specified") + } + + logrus.Infoln("Starting StatsD -> Prometheus Exporter", version.Info()) + logrus.Infoln("Build context", version.BuildContext()) + logrus.Infof("Accepting StatsD Traffic: UDP %v, TCP %v", e.statsdListenUDP, e.statsdListenTCP) + + events := make(chan exporter.Events, 1024) + + if e.statsdListenUDP != "" { + udpListenAddr := udpAddrFromString(e.statsdListenUDP) + uconn, err := net.ListenUDP("udp", udpListenAddr) + if err != nil { + return err + } + if e.readBuffer != 0 { + err = uconn.SetReadBuffer(e.readBuffer) + if err != nil { + return err + } + } + ul := &exporter.StatsDUDPListener{Conn: uconn} + go ul.Listen(events) + } + + if e.statsdListenTCP != "" { + tcpListenAddr := tcpAddrFromString(e.statsdListenTCP) + tconn, err := net.ListenTCP("tcp", tcpListenAddr) + if err != nil { + return err + } + tl := &exporter.StatsDTCPListener{Conn: tconn} + go tl.Listen(events) + } + + mapper := &exporter.MetricMapper{} + if e.mappingConfig != "" { + err := mapper.InitFromFile(e.mappingConfig) + if err != nil { + log.Fatal("Error loading config:", err) + return err + } + //观察文件变化进行重新reload是有风险的,采用API重新加载 + //go watchConfig(e.mappingConfig, mapper) + } + exporter := exporter.NewExporter(mapper, e.register) + e.exporter = exporter + e.mapper = mapper + go exporter.Listen(events) + return nil +} + +// Describe implements the prometheus.Collector interface. +func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { + +} + +// Collect implements the prometheus.Collector interface. +func (e *Exporter) Collect(ch chan<- prometheus.Metric) { +} + +//GetRegister GetRegister +func (e *Exporter) GetRegister() *prometheus.Registry { + return e.register +} + +func ipPortFromString(addr string) (*net.IPAddr, int) { + host, portStr, err := net.SplitHostPort(addr) + if err != nil { + logrus.Fatal("Bad StatsD listening address", addr) + } + + if host == "" { + host = "0.0.0.0" + } + ip, err := net.ResolveIPAddr("ip", host) + if err != nil { + logrus.Fatalf("Unable to resolve %s: %s", host, err) + } + + port, err := strconv.Atoi(portStr) + if err != nil || port < 0 || port > 65535 { + logrus.Fatalf("Bad port %s: %s", portStr, err) + } + + return ip, port +} + +func udpAddrFromString(addr string) *net.UDPAddr { + ip, port := ipPortFromString(addr) + return &net.UDPAddr{ + IP: ip.IP, + Port: port, + Zone: ip.Zone, + } +} + +func tcpAddrFromString(addr string) *net.TCPAddr { + ip, port := ipPortFromString(addr) + return &net.TCPAddr{ + IP: ip.IP, + Port: port, + Zone: ip.Zone, + } +} + +func watchConfig(fileName string, mapper *exporter.MetricMapper) { + watcher, err := fsnotify.NewWatcher() + if err != nil { + logrus.Fatal(err) + } + + err = watcher.WatchFlags(fileName, fsnotify.FSN_MODIFY) + if err != nil { + logrus.Fatal(err) + } + + for { + select { + case ev := <-watcher.Event: + logrus.Infof("Config file changed (%s), attempting reload", ev) + err = mapper.InitFromFile(fileName) + if err != nil { + logrus.Errorln("Error reloading config:", err) + exporter.ConfigLoads.WithLabelValues("failure").Inc() + } else { + logrus.Infoln("Config reloaded successfully") + exporter.ConfigLoads.WithLabelValues("success").Inc() + } + // Re-add the file watcher since it can get lost on some changes. E.g. + // saving a file with vim results in a RENAME-MODIFY-DELETE event + // sequence, after which the newly written file is no longer watched. + err = watcher.WatchFlags(fileName, fsnotify.FSN_MODIFY) + case err := <-watcher.Error: + logrus.Errorln("Error watching config:", err) + } + } +} + +//ReloadConfig reload mapper config file +func (e *Exporter) ReloadConfig() (err error) { + logrus.Infof("Config file changed, attempting reload") + err = e.mapper.InitFromFile(e.mappingConfig) + if err != nil { + logrus.Errorln("Error reloading config:", err) + exporter.ConfigLoads.WithLabelValues("failure").Inc() + } else { + logrus.Infoln("Config reloaded successfully") + exporter.ConfigLoads.WithLabelValues("success").Inc() + } + return +} diff --git a/test/mapper.yml b/test/mapper.yml new file mode 100644 index 000000000..978007169 --- /dev/null +++ b/test/mapper.yml @@ -0,0 +1,16 @@ +# +mappings: +- match: "*.*.*.request.*" + name: "app_http_request" + labels: + service_id: "$1" + port: "$2" + protocol: $3 + method: "$4" +- match: "*.*.*.request.unusual.*" + name: "app_http_request_unusual" + labels: + service_id: "$1" + port: "$2" + protocol: $3 + code: "$4" \ No newline at end of file diff --git a/vendor/github.com/howeyc/fsnotify/AUTHORS b/vendor/github.com/howeyc/fsnotify/AUTHORS new file mode 100644 index 000000000..e52b72f83 --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/AUTHORS @@ -0,0 +1,28 @@ +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# You can update this list using the following command: +# +# $ git shortlog -se | awk '{print $2 " " $3 " " $4}' + +# Please keep the list sorted. + +Adrien Bustany +Caleb Spare +Case Nelson +Chris Howey +Christoffer Buchholz +Dave Cheney +Francisco Souza +John C Barstow +Kelvin Fo +Nathan Youngman +Paul Hammond +Pursuit92 +Rob Figueiredo +Travis Cline +Tudor Golubenco +bronze1man +debrando +henrikedwards diff --git a/vendor/github.com/howeyc/fsnotify/CHANGELOG.md b/vendor/github.com/howeyc/fsnotify/CHANGELOG.md new file mode 100644 index 000000000..761686aa9 --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/CHANGELOG.md @@ -0,0 +1,160 @@ +# Changelog + +## v0.9.0 / 2014-01-17 + +* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) +* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) +* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. + +## v0.8.12 / 2013-11-13 + +* [API] Remove FD_SET and friends from Linux adapter + +## v0.8.11 / 2013-11-02 + +* [Doc] Add Changelog [#72][] (thanks @nathany) +* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond) + +## v0.8.10 / 2013-10-19 + +* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) +* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) +* [Doc] specify OS-specific limits in README (thanks @debrando) + +## v0.8.9 / 2013-09-08 + +* [Doc] Contributing (thanks @nathany) +* [Doc] update package path in example code [#63][] (thanks @paulhammond) +* [Doc] GoCI badge in README (Linux only) [#60][] +* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) + +## v0.8.8 / 2013-06-17 + +* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) + +## v0.8.7 / 2013-06-03 + +* [API] Make syscall flags internal +* [Fix] inotify: ignore event changes +* [Fix] race in symlink test [#45][] (reported by @srid) +* [Fix] tests on Windows +* lower case error messages + +## v0.8.6 / 2013-05-23 + +* kqueue: Use EVT_ONLY flag on Darwin +* [Doc] Update README with full example + +## v0.8.5 / 2013-05-09 + +* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) + +## v0.8.4 / 2013-04-07 + +* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) + +## v0.8.3 / 2013-03-13 + +* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) +* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) + +## v0.8.2 / 2013-02-07 + +* [Doc] add Authors +* [Fix] fix data races for map access [#29][] (thanks @fsouza) + +## v0.8.1 / 2013-01-09 + +* [Fix] Windows path separators +* [Doc] BSD License + +## v0.8.0 / 2012-11-09 + +* kqueue: directory watching improvements (thanks @vmirage) +* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) +* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) + +## v0.7.4 / 2012-10-09 + +* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) +* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) +* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) +* [Fix] kqueue: modify after recreation of file + +## v0.7.3 / 2012-09-27 + +* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) +* [Fix] kqueue: no longer get duplicate CREATE events + +## v0.7.2 / 2012-09-01 + +* kqueue: events for created directories + +## v0.7.1 / 2012-07-14 + +* [Fix] for renaming files + +## v0.7.0 / 2012-07-02 + +* [Feature] FSNotify flags +* [Fix] inotify: Added file name back to event path + +## v0.6.0 / 2012-06-06 + +* kqueue: watch files after directory created (thanks @tmc) + +## v0.5.1 / 2012-05-22 + +* [Fix] inotify: remove all watches before Close() + +## v0.5.0 / 2012-05-03 + +* [API] kqueue: return errors during watch instead of sending over channel +* kqueue: match symlink behavior on Linux +* inotify: add `DELETE_SELF` (requested by @taralx) +* [Fix] kqueue: handle EINTR (reported by @robfig) +* [Doc] Godoc example [#1][] (thanks @davecheney) + +## v0.4.0 / 2012-03-30 + +* Go 1 released: build with go tool +* [Feature] Windows support using winfsnotify +* Windows does not have attribute change notifications +* Roll attribute notifications into IsModify + +## v0.3.0 / 2012-02-19 + +* kqueue: add files when watch directory + +## v0.2.0 / 2011-12-30 + +* update to latest Go weekly code + +## v0.1.0 / 2011-10-19 + +* kqueue: add watch on file creation to match inotify +* kqueue: create file event +* inotify: ignore `IN_IGNORED` events +* event String() +* linux: common FileEvent functions +* initial commit + +[#79]: https://github.com/howeyc/fsnotify/pull/79 +[#77]: https://github.com/howeyc/fsnotify/pull/77 +[#72]: https://github.com/howeyc/fsnotify/issues/72 +[#71]: https://github.com/howeyc/fsnotify/issues/71 +[#70]: https://github.com/howeyc/fsnotify/issues/70 +[#63]: https://github.com/howeyc/fsnotify/issues/63 +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#60]: https://github.com/howeyc/fsnotify/issues/60 +[#59]: https://github.com/howeyc/fsnotify/issues/59 +[#49]: https://github.com/howeyc/fsnotify/issues/49 +[#45]: https://github.com/howeyc/fsnotify/issues/45 +[#40]: https://github.com/howeyc/fsnotify/issues/40 +[#36]: https://github.com/howeyc/fsnotify/issues/36 +[#33]: https://github.com/howeyc/fsnotify/issues/33 +[#29]: https://github.com/howeyc/fsnotify/issues/29 +[#25]: https://github.com/howeyc/fsnotify/issues/25 +[#24]: https://github.com/howeyc/fsnotify/issues/24 +[#21]: https://github.com/howeyc/fsnotify/issues/21 +[#1]: https://github.com/howeyc/fsnotify/issues/1 diff --git a/vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md b/vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md new file mode 100644 index 000000000..b2025d72c --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing + +## Moving Notice + +There is a fork being actively developed with a new API in preparation for the Go Standard Library: +[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify) + diff --git a/vendor/gopkg.in.o/mgo.v2/internal/json/LICENSE b/vendor/github.com/howeyc/fsnotify/LICENSE similarity index 96% rename from vendor/gopkg.in.o/mgo.v2/internal/json/LICENSE rename to vendor/github.com/howeyc/fsnotify/LICENSE index 744875676..f21e54080 100644 --- a/vendor/gopkg.in.o/mgo.v2/internal/json/LICENSE +++ b/vendor/github.com/howeyc/fsnotify/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2012 fsnotify Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/howeyc/fsnotify/README.md b/vendor/github.com/howeyc/fsnotify/README.md new file mode 100644 index 000000000..7fdaf7c99 --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/README.md @@ -0,0 +1,93 @@ +# File system notifications for Go + +[![GoDoc](https://godoc.org/github.com/howeyc/fsnotify?status.png)](http://godoc.org/github.com/howeyc/fsnotify) + +Cross platform: Windows, Linux, BSD and OS X. + +## Moving Notice + +There is a fork being actively developed with a new API in preparation for the Go Standard Library: +[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify) + +## Example: + +```go +package main + +import ( + "log" + + "github.com/howeyc/fsnotify" +) + +func main() { + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + + done := make(chan bool) + + // Process events + go func() { + for { + select { + case ev := <-watcher.Event: + log.Println("event:", ev) + case err := <-watcher.Error: + log.Println("error:", err) + } + } + }() + + err = watcher.Watch("testDir") + if err != nil { + log.Fatal(err) + } + + // Hang so program doesn't exit + <-done + + /* ... do stuff ... */ + watcher.Close() +} +``` + +For each event: +* Name +* IsCreate() +* IsDelete() +* IsModify() +* IsRename() + +## FAQ + +**When a file is moved to another directory is it still being watched?** + +No (it shouldn't be, unless you are watching where it was moved to). + +**When I watch a directory, are all subdirectories watched as well?** + +No, you must add watches for any directory you want to watch (a recursive watcher is in the works [#56][]). + +**Do I have to watch the Error and Event channels in a separate goroutine?** + +As of now, yes. Looking into making this single-thread friendly (see [#7][]) + +**Why am I receiving multiple events for the same file on OS X?** + +Spotlight indexing on OS X can result in multiple events (see [#62][]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#54][]). + +**How many files can be watched at once?** + +There are OS-specific limits as to how many watches can be created: +* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, +reaching this limit results in a "no space left on device" error. +* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. + + +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#56]: https://github.com/howeyc/fsnotify/issues/56 +[#54]: https://github.com/howeyc/fsnotify/issues/54 +[#7]: https://github.com/howeyc/fsnotify/issues/7 + diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify.go b/vendor/github.com/howeyc/fsnotify/fsnotify.go new file mode 100644 index 000000000..9a48d847d --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/fsnotify.go @@ -0,0 +1,111 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package fsnotify implements file system notification. +package fsnotify + +import "fmt" + +const ( + FSN_CREATE = 1 + FSN_MODIFY = 2 + FSN_DELETE = 4 + FSN_RENAME = 8 + + FSN_ALL = FSN_MODIFY | FSN_DELETE | FSN_RENAME | FSN_CREATE +) + +// Purge events from interal chan to external chan if passes filter +func (w *Watcher) purgeEvents() { + for ev := range w.internalEvent { + sendEvent := false + w.fsnmut.Lock() + fsnFlags := w.fsnFlags[ev.Name] + w.fsnmut.Unlock() + + if (fsnFlags&FSN_CREATE == FSN_CREATE) && ev.IsCreate() { + sendEvent = true + } + + if (fsnFlags&FSN_MODIFY == FSN_MODIFY) && ev.IsModify() { + sendEvent = true + } + + if (fsnFlags&FSN_DELETE == FSN_DELETE) && ev.IsDelete() { + sendEvent = true + } + + if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() { + sendEvent = true + } + + if sendEvent { + w.Event <- ev + } + + // If there's no file, then no more events for user + // BSD must keep watch for internal use (watches DELETEs to keep track + // what files exist for create events) + if ev.IsDelete() { + w.fsnmut.Lock() + delete(w.fsnFlags, ev.Name) + w.fsnmut.Unlock() + } + } + + close(w.Event) +} + +// Watch a given file path +func (w *Watcher) Watch(path string) error { + return w.WatchFlags(path, FSN_ALL) +} + +// Watch a given file path for a particular set of notifications (FSN_MODIFY etc.) +func (w *Watcher) WatchFlags(path string, flags uint32) error { + w.fsnmut.Lock() + w.fsnFlags[path] = flags + w.fsnmut.Unlock() + return w.watch(path) +} + +// Remove a watch on a file +func (w *Watcher) RemoveWatch(path string) error { + w.fsnmut.Lock() + delete(w.fsnFlags, path) + w.fsnmut.Unlock() + return w.removeWatch(path) +} + +// String formats the event e in the form +// "filename: DELETE|MODIFY|..." +func (e *FileEvent) String() string { + var events string = "" + + if e.IsCreate() { + events += "|" + "CREATE" + } + + if e.IsDelete() { + events += "|" + "DELETE" + } + + if e.IsModify() { + events += "|" + "MODIFY" + } + + if e.IsRename() { + events += "|" + "RENAME" + } + + if e.IsAttrib() { + events += "|" + "ATTRIB" + } + + if len(events) > 0 { + events = events[1:] + } + + return fmt.Sprintf("%q: %s", e.Name, events) +} diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go b/vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go new file mode 100644 index 000000000..40c84768b --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go @@ -0,0 +1,496 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd openbsd netbsd dragonfly darwin + +package fsnotify + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + "syscall" +) + +const ( + // Flags (from ) + sys_NOTE_DELETE = 0x0001 /* vnode was removed */ + sys_NOTE_WRITE = 0x0002 /* data contents changed */ + sys_NOTE_EXTEND = 0x0004 /* size increased */ + sys_NOTE_ATTRIB = 0x0008 /* attributes changed */ + sys_NOTE_LINK = 0x0010 /* link count changed */ + sys_NOTE_RENAME = 0x0020 /* vnode was renamed */ + sys_NOTE_REVOKE = 0x0040 /* vnode access was revoked */ + + // Watch all events + sys_NOTE_ALLEVENTS = sys_NOTE_DELETE | sys_NOTE_WRITE | sys_NOTE_ATTRIB | sys_NOTE_RENAME + + // Block for 100 ms on each call to kevent + keventWaitTime = 100e6 +) + +type FileEvent struct { + mask uint32 // Mask of events + Name string // File name (optional) + create bool // set by fsnotify package if found new file +} + +// IsCreate reports whether the FileEvent was triggered by a creation +func (e *FileEvent) IsCreate() bool { return e.create } + +// IsDelete reports whether the FileEvent was triggered by a delete +func (e *FileEvent) IsDelete() bool { return (e.mask & sys_NOTE_DELETE) == sys_NOTE_DELETE } + +// IsModify reports whether the FileEvent was triggered by a file modification +func (e *FileEvent) IsModify() bool { + return ((e.mask&sys_NOTE_WRITE) == sys_NOTE_WRITE || (e.mask&sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB) +} + +// IsRename reports whether the FileEvent was triggered by a change name +func (e *FileEvent) IsRename() bool { return (e.mask & sys_NOTE_RENAME) == sys_NOTE_RENAME } + +// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata. +func (e *FileEvent) IsAttrib() bool { + return (e.mask & sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB +} + +type Watcher struct { + mu sync.Mutex // Mutex for the Watcher itself. + kq int // File descriptor (as returned by the kqueue() syscall) + watches map[string]int // Map of watched file descriptors (key: path) + wmut sync.Mutex // Protects access to watches. + fsnFlags map[string]uint32 // Map of watched files to flags used for filter + fsnmut sync.Mutex // Protects access to fsnFlags. + enFlags map[string]uint32 // Map of watched files to evfilt note flags used in kqueue + enmut sync.Mutex // Protects access to enFlags. + paths map[int]string // Map of watched paths (key: watch descriptor) + finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor) + pmut sync.Mutex // Protects access to paths and finfo. + fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events) + femut sync.Mutex // Protects access to fileExists. + externalWatches map[string]bool // Map of watches added by user of the library. + ewmut sync.Mutex // Protects access to externalWatches. + Error chan error // Errors are sent on this channel + internalEvent chan *FileEvent // Events are queued on this channel + Event chan *FileEvent // Events are returned on this channel + done chan bool // Channel for sending a "quit message" to the reader goroutine + isClosed bool // Set to true when Close() is first called +} + +// NewWatcher creates and returns a new kevent instance using kqueue(2) +func NewWatcher() (*Watcher, error) { + fd, errno := syscall.Kqueue() + if fd == -1 { + return nil, os.NewSyscallError("kqueue", errno) + } + w := &Watcher{ + kq: fd, + watches: make(map[string]int), + fsnFlags: make(map[string]uint32), + enFlags: make(map[string]uint32), + paths: make(map[int]string), + finfo: make(map[int]os.FileInfo), + fileExists: make(map[string]bool), + externalWatches: make(map[string]bool), + internalEvent: make(chan *FileEvent), + Event: make(chan *FileEvent), + Error: make(chan error), + done: make(chan bool, 1), + } + + go w.readEvents() + go w.purgeEvents() + return w, nil +} + +// Close closes a kevent watcher instance +// It sends a message to the reader goroutine to quit and removes all watches +// associated with the kevent instance +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + w.mu.Unlock() + + // Send "quit" message to the reader goroutine + w.done <- true + w.wmut.Lock() + ws := w.watches + w.wmut.Unlock() + for path := range ws { + w.removeWatch(path) + } + + return nil +} + +// AddWatch adds path to the watched file set. +// The flags are interpreted as described in kevent(2). +func (w *Watcher) addWatch(path string, flags uint32) error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return errors.New("kevent instance already closed") + } + w.mu.Unlock() + + watchDir := false + + w.wmut.Lock() + watchfd, found := w.watches[path] + w.wmut.Unlock() + if !found { + fi, errstat := os.Lstat(path) + if errstat != nil { + return errstat + } + + // don't watch socket + if fi.Mode()&os.ModeSocket == os.ModeSocket { + return nil + } + + // Follow Symlinks + // Unfortunately, Linux can add bogus symlinks to watch list without + // issue, and Windows can't do symlinks period (AFAIK). To maintain + // consistency, we will act like everything is fine. There will simply + // be no file events for broken symlinks. + // Hence the returns of nil on errors. + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + path, err := filepath.EvalSymlinks(path) + if err != nil { + return nil + } + + fi, errstat = os.Lstat(path) + if errstat != nil { + return nil + } + } + + fd, errno := syscall.Open(path, open_FLAGS, 0700) + if fd == -1 { + return errno + } + watchfd = fd + + w.wmut.Lock() + w.watches[path] = watchfd + w.wmut.Unlock() + + w.pmut.Lock() + w.paths[watchfd] = path + w.finfo[watchfd] = fi + w.pmut.Unlock() + } + // Watch the directory if it has not been watched before. + w.pmut.Lock() + w.enmut.Lock() + if w.finfo[watchfd].IsDir() && + (flags&sys_NOTE_WRITE) == sys_NOTE_WRITE && + (!found || (w.enFlags[path]&sys_NOTE_WRITE) != sys_NOTE_WRITE) { + watchDir = true + } + w.enmut.Unlock() + w.pmut.Unlock() + + w.enmut.Lock() + w.enFlags[path] = flags + w.enmut.Unlock() + + var kbuf [1]syscall.Kevent_t + watchEntry := &kbuf[0] + watchEntry.Fflags = flags + syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR) + entryFlags := watchEntry.Flags + success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil) + if success == -1 { + return errno + } else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR { + return errors.New("kevent add error") + } + + if watchDir { + errdir := w.watchDirectoryFiles(path) + if errdir != nil { + return errdir + } + } + return nil +} + +// Watch adds path to the watched file set, watching all events. +func (w *Watcher) watch(path string) error { + w.ewmut.Lock() + w.externalWatches[path] = true + w.ewmut.Unlock() + return w.addWatch(path, sys_NOTE_ALLEVENTS) +} + +// RemoveWatch removes path from the watched file set. +func (w *Watcher) removeWatch(path string) error { + w.wmut.Lock() + watchfd, ok := w.watches[path] + w.wmut.Unlock() + if !ok { + return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path)) + } + var kbuf [1]syscall.Kevent_t + watchEntry := &kbuf[0] + syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE) + entryFlags := watchEntry.Flags + success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil) + if success == -1 { + return os.NewSyscallError("kevent_rm_watch", errno) + } else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR { + return errors.New("kevent rm error") + } + syscall.Close(watchfd) + w.wmut.Lock() + delete(w.watches, path) + w.wmut.Unlock() + w.enmut.Lock() + delete(w.enFlags, path) + w.enmut.Unlock() + w.pmut.Lock() + delete(w.paths, watchfd) + fInfo := w.finfo[watchfd] + delete(w.finfo, watchfd) + w.pmut.Unlock() + + // Find all watched paths that are in this directory that are not external. + if fInfo.IsDir() { + var pathsToRemove []string + w.pmut.Lock() + for _, wpath := range w.paths { + wdir, _ := filepath.Split(wpath) + if filepath.Clean(wdir) == filepath.Clean(path) { + w.ewmut.Lock() + if !w.externalWatches[wpath] { + pathsToRemove = append(pathsToRemove, wpath) + } + w.ewmut.Unlock() + } + } + w.pmut.Unlock() + for _, p := range pathsToRemove { + // Since these are internal, not much sense in propagating error + // to the user, as that will just confuse them with an error about + // a path they did not explicitly watch themselves. + w.removeWatch(p) + } + } + + return nil +} + +// readEvents reads from the kqueue file descriptor, converts the +// received events into Event objects and sends them via the Event channel +func (w *Watcher) readEvents() { + var ( + eventbuf [10]syscall.Kevent_t // Event buffer + events []syscall.Kevent_t // Received events + twait *syscall.Timespec // Time to block waiting for events + n int // Number of events returned from kevent + errno error // Syscall errno + ) + events = eventbuf[0:0] + twait = new(syscall.Timespec) + *twait = syscall.NsecToTimespec(keventWaitTime) + + for { + // See if there is a message on the "done" channel + var done bool + select { + case done = <-w.done: + default: + } + + // If "done" message is received + if done { + errno := syscall.Close(w.kq) + if errno != nil { + w.Error <- os.NewSyscallError("close", errno) + } + close(w.internalEvent) + close(w.Error) + return + } + + // Get new events + if len(events) == 0 { + n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait) + + // EINTR is okay, basically the syscall was interrupted before + // timeout expired. + if errno != nil && errno != syscall.EINTR { + w.Error <- os.NewSyscallError("kevent", errno) + continue + } + + // Received some events + if n > 0 { + events = eventbuf[0:n] + } + } + + // Flush the events we received to the events channel + for len(events) > 0 { + fileEvent := new(FileEvent) + watchEvent := &events[0] + fileEvent.mask = uint32(watchEvent.Fflags) + w.pmut.Lock() + fileEvent.Name = w.paths[int(watchEvent.Ident)] + fileInfo := w.finfo[int(watchEvent.Ident)] + w.pmut.Unlock() + if fileInfo != nil && fileInfo.IsDir() && !fileEvent.IsDelete() { + // Double check to make sure the directory exist. This can happen when + // we do a rm -fr on a recursively watched folders and we receive a + // modification event first but the folder has been deleted and later + // receive the delete event + if _, err := os.Lstat(fileEvent.Name); os.IsNotExist(err) { + // mark is as delete event + fileEvent.mask |= sys_NOTE_DELETE + } + } + + if fileInfo != nil && fileInfo.IsDir() && fileEvent.IsModify() && !fileEvent.IsDelete() { + w.sendDirectoryChangeEvents(fileEvent.Name) + } else { + // Send the event on the events channel + w.internalEvent <- fileEvent + } + + // Move to next event + events = events[1:] + + if fileEvent.IsRename() { + w.removeWatch(fileEvent.Name) + w.femut.Lock() + delete(w.fileExists, fileEvent.Name) + w.femut.Unlock() + } + if fileEvent.IsDelete() { + w.removeWatch(fileEvent.Name) + w.femut.Lock() + delete(w.fileExists, fileEvent.Name) + w.femut.Unlock() + + // Look for a file that may have overwritten this + // (ie mv f1 f2 will delete f2 then create f2) + fileDir, _ := filepath.Split(fileEvent.Name) + fileDir = filepath.Clean(fileDir) + w.wmut.Lock() + _, found := w.watches[fileDir] + w.wmut.Unlock() + if found { + // make sure the directory exist before we watch for changes. When we + // do a recursive watch and perform rm -fr, the parent directory might + // have gone missing, ignore the missing directory and let the + // upcoming delete event remove the watch form the parent folder + if _, err := os.Lstat(fileDir); !os.IsNotExist(err) { + w.sendDirectoryChangeEvents(fileDir) + } + } + } + } + } +} + +func (w *Watcher) watchDirectoryFiles(dirPath string) error { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + return err + } + + // Search for new files + for _, fileInfo := range files { + filePath := filepath.Join(dirPath, fileInfo.Name()) + + // Inherit fsnFlags from parent directory + w.fsnmut.Lock() + if flags, found := w.fsnFlags[dirPath]; found { + w.fsnFlags[filePath] = flags + } else { + w.fsnFlags[filePath] = FSN_ALL + } + w.fsnmut.Unlock() + + if fileInfo.IsDir() == false { + // Watch file to mimic linux fsnotify + e := w.addWatch(filePath, sys_NOTE_ALLEVENTS) + if e != nil { + return e + } + } else { + // If the user is currently watching directory + // we want to preserve the flags used + w.enmut.Lock() + currFlags, found := w.enFlags[filePath] + w.enmut.Unlock() + var newFlags uint32 = sys_NOTE_DELETE + if found { + newFlags |= currFlags + } + + // Linux gives deletes if not explicitly watching + e := w.addWatch(filePath, newFlags) + if e != nil { + return e + } + } + w.femut.Lock() + w.fileExists[filePath] = true + w.femut.Unlock() + } + + return nil +} + +// sendDirectoryEvents searches the directory for newly created files +// and sends them over the event channel. This functionality is to have +// the BSD version of fsnotify match linux fsnotify which provides a +// create event for files created in a watched directory. +func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + w.Error <- err + } + + // Search for new files + for _, fileInfo := range files { + filePath := filepath.Join(dirPath, fileInfo.Name()) + w.femut.Lock() + _, doesExist := w.fileExists[filePath] + w.femut.Unlock() + if !doesExist { + // Inherit fsnFlags from parent directory + w.fsnmut.Lock() + if flags, found := w.fsnFlags[dirPath]; found { + w.fsnFlags[filePath] = flags + } else { + w.fsnFlags[filePath] = FSN_ALL + } + w.fsnmut.Unlock() + + // Send create event + fileEvent := new(FileEvent) + fileEvent.Name = filePath + fileEvent.create = true + w.internalEvent <- fileEvent + } + w.femut.Lock() + w.fileExists[filePath] = true + w.femut.Unlock() + } + w.watchDirectoryFiles(dirPath) +} diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_linux.go b/vendor/github.com/howeyc/fsnotify/fsnotify_linux.go new file mode 100644 index 000000000..80ade879f --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/fsnotify_linux.go @@ -0,0 +1,304 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "strings" + "sync" + "syscall" + "unsafe" +) + +const ( + // Options for inotify_init() are not exported + // sys_IN_CLOEXEC uint32 = syscall.IN_CLOEXEC + // sys_IN_NONBLOCK uint32 = syscall.IN_NONBLOCK + + // Options for AddWatch + sys_IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW + sys_IN_ONESHOT uint32 = syscall.IN_ONESHOT + sys_IN_ONLYDIR uint32 = syscall.IN_ONLYDIR + + // The "sys_IN_MASK_ADD" option is not exported, as AddWatch + // adds it automatically, if there is already a watch for the given path + // sys_IN_MASK_ADD uint32 = syscall.IN_MASK_ADD + + // Events + sys_IN_ACCESS uint32 = syscall.IN_ACCESS + sys_IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS + sys_IN_ATTRIB uint32 = syscall.IN_ATTRIB + sys_IN_CLOSE uint32 = syscall.IN_CLOSE + sys_IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE + sys_IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE + sys_IN_CREATE uint32 = syscall.IN_CREATE + sys_IN_DELETE uint32 = syscall.IN_DELETE + sys_IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF + sys_IN_MODIFY uint32 = syscall.IN_MODIFY + sys_IN_MOVE uint32 = syscall.IN_MOVE + sys_IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM + sys_IN_MOVED_TO uint32 = syscall.IN_MOVED_TO + sys_IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF + sys_IN_OPEN uint32 = syscall.IN_OPEN + + sys_AGNOSTIC_EVENTS = sys_IN_MOVED_TO | sys_IN_MOVED_FROM | sys_IN_CREATE | sys_IN_ATTRIB | sys_IN_MODIFY | sys_IN_MOVE_SELF | sys_IN_DELETE | sys_IN_DELETE_SELF + + // Special events + sys_IN_ISDIR uint32 = syscall.IN_ISDIR + sys_IN_IGNORED uint32 = syscall.IN_IGNORED + sys_IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW + sys_IN_UNMOUNT uint32 = syscall.IN_UNMOUNT +) + +type FileEvent struct { + mask uint32 // Mask of events + cookie uint32 // Unique cookie associating related events (for rename(2)) + Name string // File name (optional) +} + +// IsCreate reports whether the FileEvent was triggered by a creation +func (e *FileEvent) IsCreate() bool { + return (e.mask&sys_IN_CREATE) == sys_IN_CREATE || (e.mask&sys_IN_MOVED_TO) == sys_IN_MOVED_TO +} + +// IsDelete reports whether the FileEvent was triggered by a delete +func (e *FileEvent) IsDelete() bool { + return (e.mask&sys_IN_DELETE_SELF) == sys_IN_DELETE_SELF || (e.mask&sys_IN_DELETE) == sys_IN_DELETE +} + +// IsModify reports whether the FileEvent was triggered by a file modification or attribute change +func (e *FileEvent) IsModify() bool { + return ((e.mask&sys_IN_MODIFY) == sys_IN_MODIFY || (e.mask&sys_IN_ATTRIB) == sys_IN_ATTRIB) +} + +// IsRename reports whether the FileEvent was triggered by a change name +func (e *FileEvent) IsRename() bool { + return ((e.mask&sys_IN_MOVE_SELF) == sys_IN_MOVE_SELF || (e.mask&sys_IN_MOVED_FROM) == sys_IN_MOVED_FROM) +} + +// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata. +func (e *FileEvent) IsAttrib() bool { + return (e.mask & sys_IN_ATTRIB) == sys_IN_ATTRIB +} + +type watch struct { + wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) + flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) +} + +type Watcher struct { + mu sync.Mutex // Map access + fd int // File descriptor (as returned by the inotify_init() syscall) + watches map[string]*watch // Map of inotify watches (key: path) + fsnFlags map[string]uint32 // Map of watched files to flags used for filter + fsnmut sync.Mutex // Protects access to fsnFlags. + paths map[int]string // Map of watched paths (key: watch descriptor) + Error chan error // Errors are sent on this channel + internalEvent chan *FileEvent // Events are queued on this channel + Event chan *FileEvent // Events are returned on this channel + done chan bool // Channel for sending a "quit message" to the reader goroutine + isClosed bool // Set to true when Close() is first called +} + +// NewWatcher creates and returns a new inotify instance using inotify_init(2) +func NewWatcher() (*Watcher, error) { + fd, errno := syscall.InotifyInit() + if fd == -1 { + return nil, os.NewSyscallError("inotify_init", errno) + } + w := &Watcher{ + fd: fd, + watches: make(map[string]*watch), + fsnFlags: make(map[string]uint32), + paths: make(map[int]string), + internalEvent: make(chan *FileEvent), + Event: make(chan *FileEvent), + Error: make(chan error), + done: make(chan bool, 1), + } + + go w.readEvents() + go w.purgeEvents() + return w, nil +} + +// Close closes an inotify watcher instance +// It sends a message to the reader goroutine to quit and removes all watches +// associated with the inotify instance +func (w *Watcher) Close() error { + if w.isClosed { + return nil + } + w.isClosed = true + + // Remove all watches + for path := range w.watches { + w.RemoveWatch(path) + } + + // Send "quit" message to the reader goroutine + w.done <- true + + return nil +} + +// AddWatch adds path to the watched file set. +// The flags are interpreted as described in inotify_add_watch(2). +func (w *Watcher) addWatch(path string, flags uint32) error { + if w.isClosed { + return errors.New("inotify instance already closed") + } + + w.mu.Lock() + watchEntry, found := w.watches[path] + w.mu.Unlock() + if found { + watchEntry.flags |= flags + flags |= syscall.IN_MASK_ADD + } + wd, errno := syscall.InotifyAddWatch(w.fd, path, flags) + if wd == -1 { + return errno + } + + w.mu.Lock() + w.watches[path] = &watch{wd: uint32(wd), flags: flags} + w.paths[wd] = path + w.mu.Unlock() + + return nil +} + +// Watch adds path to the watched file set, watching all events. +func (w *Watcher) watch(path string) error { + return w.addWatch(path, sys_AGNOSTIC_EVENTS) +} + +// RemoveWatch removes path from the watched file set. +func (w *Watcher) removeWatch(path string) error { + w.mu.Lock() + defer w.mu.Unlock() + watch, ok := w.watches[path] + if !ok { + return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path)) + } + success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) + if success == -1 { + return os.NewSyscallError("inotify_rm_watch", errno) + } + delete(w.watches, path) + return nil +} + +// readEvents reads from the inotify file descriptor, converts the +// received events into Event objects and sends them via the Event channel +func (w *Watcher) readEvents() { + var ( + buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events + n int // Number of bytes read with read() + errno error // Syscall errno + ) + + for { + // See if there is a message on the "done" channel + select { + case <-w.done: + syscall.Close(w.fd) + close(w.internalEvent) + close(w.Error) + return + default: + } + + n, errno = syscall.Read(w.fd, buf[:]) + + // If EOF is received + if n == 0 { + syscall.Close(w.fd) + close(w.internalEvent) + close(w.Error) + return + } + + if n < 0 { + w.Error <- os.NewSyscallError("read", errno) + continue + } + if n < syscall.SizeofInotifyEvent { + w.Error <- errors.New("inotify: short read in readEvents()") + continue + } + + var offset uint32 = 0 + // We don't know how many events we just read into the buffer + // While the offset points to at least one whole event... + for offset <= uint32(n-syscall.SizeofInotifyEvent) { + // Point "raw" to the event in the buffer + raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) + event := new(FileEvent) + event.mask = uint32(raw.Mask) + event.cookie = uint32(raw.Cookie) + nameLen := uint32(raw.Len) + // If the event happened to the watched directory or the watched file, the kernel + // doesn't append the filename to the event, but we would like to always fill the + // the "Name" field with a valid filename. We retrieve the path of the watch from + // the "paths" map. + w.mu.Lock() + event.Name = w.paths[int(raw.Wd)] + w.mu.Unlock() + watchedName := event.Name + if nameLen > 0 { + // Point "bytes" at the first byte of the filename + bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent])) + // The filename is padded with NUL bytes. TrimRight() gets rid of those. + event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + } + + // Send the events that are not ignored on the events channel + if !event.ignoreLinux() { + // Setup FSNotify flags (inherit from directory watch) + w.fsnmut.Lock() + if _, fsnFound := w.fsnFlags[event.Name]; !fsnFound { + if fsnFlags, watchFound := w.fsnFlags[watchedName]; watchFound { + w.fsnFlags[event.Name] = fsnFlags + } else { + w.fsnFlags[event.Name] = FSN_ALL + } + } + w.fsnmut.Unlock() + + w.internalEvent <- event + } + + // Move to the next event in the buffer + offset += syscall.SizeofInotifyEvent + nameLen + } + } +} + +// Certain types of events can be "ignored" and not sent over the Event +// channel. Such as events marked ignore by the kernel, or MODIFY events +// against files that do not exist. +func (e *FileEvent) ignoreLinux() bool { + // Ignore anything the inotify API says to ignore + if e.mask&sys_IN_IGNORED == sys_IN_IGNORED { + return true + } + + // If the event is not a DELETE or RENAME, the file must exist. + // Otherwise the event is ignored. + // *Note*: this was put in place because it was seen that a MODIFY + // event was sent after the DELETE. This ignores that MODIFY and + // assumes a DELETE will come or has come if the file doesn't exist. + if !(e.IsDelete() || e.IsRename()) { + _, statErr := os.Lstat(e.Name) + return os.IsNotExist(statErr) + } + return false +} diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go b/vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go new file mode 100644 index 000000000..f728a6ffd --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go @@ -0,0 +1,11 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd openbsd netbsd dragonfly + +package fsnotify + +import "syscall" + +const open_FLAGS = syscall.O_NONBLOCK | syscall.O_RDONLY diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go b/vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go new file mode 100644 index 000000000..d450318e6 --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go @@ -0,0 +1,11 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package fsnotify + +import "syscall" + +const open_FLAGS = syscall.O_EVTONLY diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_windows.go b/vendor/github.com/howeyc/fsnotify/fsnotify_windows.go new file mode 100644 index 000000000..d88ae6340 --- /dev/null +++ b/vendor/github.com/howeyc/fsnotify/fsnotify_windows.go @@ -0,0 +1,598 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "sync" + "syscall" + "unsafe" +) + +const ( + // Options for AddWatch + sys_FS_ONESHOT = 0x80000000 + sys_FS_ONLYDIR = 0x1000000 + + // Events + sys_FS_ACCESS = 0x1 + sys_FS_ALL_EVENTS = 0xfff + sys_FS_ATTRIB = 0x4 + sys_FS_CLOSE = 0x18 + sys_FS_CREATE = 0x100 + sys_FS_DELETE = 0x200 + sys_FS_DELETE_SELF = 0x400 + sys_FS_MODIFY = 0x2 + sys_FS_MOVE = 0xc0 + sys_FS_MOVED_FROM = 0x40 + sys_FS_MOVED_TO = 0x80 + sys_FS_MOVE_SELF = 0x800 + + // Special events + sys_FS_IGNORED = 0x8000 + sys_FS_Q_OVERFLOW = 0x4000 +) + +const ( + // TODO(nj): Use syscall.ERROR_MORE_DATA from ztypes_windows in Go 1.3+ + sys_ERROR_MORE_DATA syscall.Errno = 234 +) + +// Event is the type of the notification messages +// received on the watcher's Event channel. +type FileEvent struct { + mask uint32 // Mask of events + cookie uint32 // Unique cookie associating related events (for rename) + Name string // File name (optional) +} + +// IsCreate reports whether the FileEvent was triggered by a creation +func (e *FileEvent) IsCreate() bool { return (e.mask & sys_FS_CREATE) == sys_FS_CREATE } + +// IsDelete reports whether the FileEvent was triggered by a delete +func (e *FileEvent) IsDelete() bool { + return ((e.mask&sys_FS_DELETE) == sys_FS_DELETE || (e.mask&sys_FS_DELETE_SELF) == sys_FS_DELETE_SELF) +} + +// IsModify reports whether the FileEvent was triggered by a file modification or attribute change +func (e *FileEvent) IsModify() bool { + return ((e.mask&sys_FS_MODIFY) == sys_FS_MODIFY || (e.mask&sys_FS_ATTRIB) == sys_FS_ATTRIB) +} + +// IsRename reports whether the FileEvent was triggered by a change name +func (e *FileEvent) IsRename() bool { + return ((e.mask&sys_FS_MOVE) == sys_FS_MOVE || (e.mask&sys_FS_MOVE_SELF) == sys_FS_MOVE_SELF || (e.mask&sys_FS_MOVED_FROM) == sys_FS_MOVED_FROM || (e.mask&sys_FS_MOVED_TO) == sys_FS_MOVED_TO) +} + +// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata. +func (e *FileEvent) IsAttrib() bool { + return (e.mask & sys_FS_ATTRIB) == sys_FS_ATTRIB +} + +const ( + opAddWatch = iota + opRemoveWatch +) + +const ( + provisional uint64 = 1 << (32 + iota) +) + +type input struct { + op int + path string + flags uint32 + reply chan error +} + +type inode struct { + handle syscall.Handle + volume uint32 + index uint64 +} + +type watch struct { + ov syscall.Overlapped + ino *inode // i-number + path string // Directory path + mask uint64 // Directory itself is being watched with these notify flags + names map[string]uint64 // Map of names being watched and their notify flags + rename string // Remembers the old name while renaming a file + buf [4096]byte +} + +type indexMap map[uint64]*watch +type watchMap map[uint32]indexMap + +// A Watcher waits for and receives event notifications +// for a specific set of files and directories. +type Watcher struct { + mu sync.Mutex // Map access + port syscall.Handle // Handle to completion port + watches watchMap // Map of watches (key: i-number) + fsnFlags map[string]uint32 // Map of watched files to flags used for filter + fsnmut sync.Mutex // Protects access to fsnFlags. + input chan *input // Inputs to the reader are sent on this channel + internalEvent chan *FileEvent // Events are queued on this channel + Event chan *FileEvent // Events are returned on this channel + Error chan error // Errors are sent on this channel + isClosed bool // Set to true when Close() is first called + quit chan chan<- error + cookie uint32 +} + +// NewWatcher creates and returns a Watcher. +func NewWatcher() (*Watcher, error) { + port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) + if e != nil { + return nil, os.NewSyscallError("CreateIoCompletionPort", e) + } + w := &Watcher{ + port: port, + watches: make(watchMap), + fsnFlags: make(map[string]uint32), + input: make(chan *input, 1), + Event: make(chan *FileEvent, 50), + internalEvent: make(chan *FileEvent), + Error: make(chan error), + quit: make(chan chan<- error, 1), + } + go w.readEvents() + go w.purgeEvents() + return w, nil +} + +// Close closes a Watcher. +// It sends a message to the reader goroutine to quit and removes all watches +// associated with the watcher. +func (w *Watcher) Close() error { + if w.isClosed { + return nil + } + w.isClosed = true + + // Send "quit" message to the reader goroutine + ch := make(chan error) + w.quit <- ch + if err := w.wakeupReader(); err != nil { + return err + } + return <-ch +} + +// AddWatch adds path to the watched file set. +func (w *Watcher) AddWatch(path string, flags uint32) error { + if w.isClosed { + return errors.New("watcher already closed") + } + in := &input{ + op: opAddWatch, + path: filepath.Clean(path), + flags: flags, + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// Watch adds path to the watched file set, watching all events. +func (w *Watcher) watch(path string) error { + return w.AddWatch(path, sys_FS_ALL_EVENTS) +} + +// RemoveWatch removes path from the watched file set. +func (w *Watcher) removeWatch(path string) error { + in := &input{ + op: opRemoveWatch, + path: filepath.Clean(path), + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +func (w *Watcher) wakeupReader() error { + e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) + if e != nil { + return os.NewSyscallError("PostQueuedCompletionStatus", e) + } + return nil +} + +func getDir(pathname string) (dir string, err error) { + attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) + if e != nil { + return "", os.NewSyscallError("GetFileAttributes", e) + } + if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + dir = pathname + } else { + dir, _ = filepath.Split(pathname) + dir = filepath.Clean(dir) + } + return +} + +func getIno(path string) (ino *inode, err error) { + h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), + syscall.FILE_LIST_DIRECTORY, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + nil, syscall.OPEN_EXISTING, + syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) + if e != nil { + return nil, os.NewSyscallError("CreateFile", e) + } + var fi syscall.ByHandleFileInformation + if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { + syscall.CloseHandle(h) + return nil, os.NewSyscallError("GetFileInformationByHandle", e) + } + ino = &inode{ + handle: h, + volume: fi.VolumeSerialNumber, + index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), + } + return ino, nil +} + +// Must run within the I/O thread. +func (m watchMap) get(ino *inode) *watch { + if i := m[ino.volume]; i != nil { + return i[ino.index] + } + return nil +} + +// Must run within the I/O thread. +func (m watchMap) set(ino *inode, watch *watch) { + i := m[ino.volume] + if i == nil { + i = make(indexMap) + m[ino.volume] = i + } + i[ino.index] = watch +} + +// Must run within the I/O thread. +func (w *Watcher) addWatch(pathname string, flags uint64) error { + dir, err := getDir(pathname) + if err != nil { + return err + } + if flags&sys_FS_ONLYDIR != 0 && pathname != dir { + return nil + } + ino, err := getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watchEntry := w.watches.get(ino) + w.mu.Unlock() + if watchEntry == nil { + if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { + syscall.CloseHandle(ino.handle) + return os.NewSyscallError("CreateIoCompletionPort", e) + } + watchEntry = &watch{ + ino: ino, + path: dir, + names: make(map[string]uint64), + } + w.mu.Lock() + w.watches.set(ino, watchEntry) + w.mu.Unlock() + flags |= provisional + } else { + syscall.CloseHandle(ino.handle) + } + if pathname == dir { + watchEntry.mask |= flags + } else { + watchEntry.names[filepath.Base(pathname)] |= flags + } + if err = w.startRead(watchEntry); err != nil { + return err + } + if pathname == dir { + watchEntry.mask &= ^provisional + } else { + watchEntry.names[filepath.Base(pathname)] &= ^provisional + } + return nil +} + +// Must run within the I/O thread. +func (w *Watcher) remWatch(pathname string) error { + dir, err := getDir(pathname) + if err != nil { + return err + } + ino, err := getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watch := w.watches.get(ino) + w.mu.Unlock() + if watch == nil { + return fmt.Errorf("can't remove non-existent watch for: %s", pathname) + } + if pathname == dir { + w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED) + watch.mask = 0 + } else { + name := filepath.Base(pathname) + w.sendEvent(watch.path+"\\"+name, watch.names[name]&sys_FS_IGNORED) + delete(watch.names, name) + } + return w.startRead(watch) +} + +// Must run within the I/O thread. +func (w *Watcher) deleteWatch(watch *watch) { + for name, mask := range watch.names { + if mask&provisional == 0 { + w.sendEvent(watch.path+"\\"+name, mask&sys_FS_IGNORED) + } + delete(watch.names, name) + } + if watch.mask != 0 { + if watch.mask&provisional == 0 { + w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED) + } + watch.mask = 0 + } +} + +// Must run within the I/O thread. +func (w *Watcher) startRead(watch *watch) error { + if e := syscall.CancelIo(watch.ino.handle); e != nil { + w.Error <- os.NewSyscallError("CancelIo", e) + w.deleteWatch(watch) + } + mask := toWindowsFlags(watch.mask) + for _, m := range watch.names { + mask |= toWindowsFlags(m) + } + if mask == 0 { + if e := syscall.CloseHandle(watch.ino.handle); e != nil { + w.Error <- os.NewSyscallError("CloseHandle", e) + } + w.mu.Lock() + delete(w.watches[watch.ino.volume], watch.ino.index) + w.mu.Unlock() + return nil + } + e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], + uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) + if e != nil { + err := os.NewSyscallError("ReadDirectoryChanges", e) + if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { + // Watched directory was probably removed + if w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) { + if watch.mask&sys_FS_ONESHOT != 0 { + watch.mask = 0 + } + } + err = nil + } + w.deleteWatch(watch) + w.startRead(watch) + return err + } + return nil +} + +// readEvents reads from the I/O completion port, converts the +// received events into Event objects and sends them via the Event channel. +// Entry point to the I/O thread. +func (w *Watcher) readEvents() { + var ( + n, key uint32 + ov *syscall.Overlapped + ) + runtime.LockOSThread() + + for { + e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) + watch := (*watch)(unsafe.Pointer(ov)) + + if watch == nil { + select { + case ch := <-w.quit: + w.mu.Lock() + var indexes []indexMap + for _, index := range w.watches { + indexes = append(indexes, index) + } + w.mu.Unlock() + for _, index := range indexes { + for _, watch := range index { + w.deleteWatch(watch) + w.startRead(watch) + } + } + var err error + if e := syscall.CloseHandle(w.port); e != nil { + err = os.NewSyscallError("CloseHandle", e) + } + close(w.internalEvent) + close(w.Error) + ch <- err + return + case in := <-w.input: + switch in.op { + case opAddWatch: + in.reply <- w.addWatch(in.path, uint64(in.flags)) + case opRemoveWatch: + in.reply <- w.remWatch(in.path) + } + default: + } + continue + } + + switch e { + case sys_ERROR_MORE_DATA: + if watch == nil { + w.Error <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") + } else { + // The i/o succeeded but the buffer is full. + // In theory we should be building up a full packet. + // In practice we can get away with just carrying on. + n = uint32(unsafe.Sizeof(watch.buf)) + } + case syscall.ERROR_ACCESS_DENIED: + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) + w.deleteWatch(watch) + w.startRead(watch) + continue + case syscall.ERROR_OPERATION_ABORTED: + // CancelIo was called on this handle + continue + default: + w.Error <- os.NewSyscallError("GetQueuedCompletionPort", e) + continue + case nil: + } + + var offset uint32 + for { + if n == 0 { + w.internalEvent <- &FileEvent{mask: sys_FS_Q_OVERFLOW} + w.Error <- errors.New("short read in readEvents()") + break + } + + // Point "raw" to the event in the buffer + raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) + buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName)) + name := syscall.UTF16ToString(buf[:raw.FileNameLength/2]) + fullname := watch.path + "\\" + name + + var mask uint64 + switch raw.Action { + case syscall.FILE_ACTION_REMOVED: + mask = sys_FS_DELETE_SELF + case syscall.FILE_ACTION_MODIFIED: + mask = sys_FS_MODIFY + case syscall.FILE_ACTION_RENAMED_OLD_NAME: + watch.rename = name + case syscall.FILE_ACTION_RENAMED_NEW_NAME: + if watch.names[watch.rename] != 0 { + watch.names[name] |= watch.names[watch.rename] + delete(watch.names, watch.rename) + mask = sys_FS_MOVE_SELF + } + } + + sendNameEvent := func() { + if w.sendEvent(fullname, watch.names[name]&mask) { + if watch.names[name]&sys_FS_ONESHOT != 0 { + delete(watch.names, name) + } + } + } + if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { + sendNameEvent() + } + if raw.Action == syscall.FILE_ACTION_REMOVED { + w.sendEvent(fullname, watch.names[name]&sys_FS_IGNORED) + delete(watch.names, name) + } + if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { + if watch.mask&sys_FS_ONESHOT != 0 { + watch.mask = 0 + } + } + if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { + fullname = watch.path + "\\" + watch.rename + sendNameEvent() + } + + // Move to the next event in the buffer + if raw.NextEntryOffset == 0 { + break + } + offset += raw.NextEntryOffset + + // Error! + if offset >= n { + w.Error <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") + break + } + } + + if err := w.startRead(watch); err != nil { + w.Error <- err + } + } +} + +func (w *Watcher) sendEvent(name string, mask uint64) bool { + if mask == 0 { + return false + } + event := &FileEvent{mask: uint32(mask), Name: name} + if mask&sys_FS_MOVE != 0 { + if mask&sys_FS_MOVED_FROM != 0 { + w.cookie++ + } + event.cookie = w.cookie + } + select { + case ch := <-w.quit: + w.quit <- ch + case w.Event <- event: + } + return true +} + +func toWindowsFlags(mask uint64) uint32 { + var m uint32 + if mask&sys_FS_ACCESS != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS + } + if mask&sys_FS_MODIFY != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE + } + if mask&sys_FS_ATTRIB != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES + } + if mask&(sys_FS_MOVE|sys_FS_CREATE|sys_FS_DELETE) != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME + } + return m +} + +func toFSnotifyFlags(action uint32) uint64 { + switch action { + case syscall.FILE_ACTION_ADDED: + return sys_FS_CREATE + case syscall.FILE_ACTION_REMOVED: + return sys_FS_DELETE + case syscall.FILE_ACTION_MODIFIED: + return sys_FS_MODIFY + case syscall.FILE_ACTION_RENAMED_OLD_NAME: + return sys_FS_MOVED_FROM + case syscall.FILE_ACTION_RENAMED_NEW_NAME: + return sys_FS_MOVED_TO + } + return 0 +} diff --git a/vendor/github.com/prometheus/node_exporter/collector/collector.go b/vendor/github.com/prometheus/node_exporter/collector/collector.go index 06c8924a0..e8840cc07 100644 --- a/vendor/github.com/prometheus/node_exporter/collector/collector.go +++ b/vendor/github.com/prometheus/node_exporter/collector/collector.go @@ -15,7 +15,6 @@ package collector import ( - "fmt" "sync" "time" @@ -83,10 +82,12 @@ func NewNodeCollector(filters ...string) (*nodeCollector, error) { for _, filter := range filters { enabled, exist := collectorState[filter] if !exist { - return nil, fmt.Errorf("missing collector: %s", filter) + log.Warnf("missing collector: %s", filter) + continue } if !*enabled { - return nil, fmt.Errorf("disabled collector: %s", filter) + log.Warnf("disabled collector: %s", filter) + continue } f[filter] = true } diff --git a/vendor/gopkg.in.o/mgo.v2/bson/LICENSE b/vendor/gopkg.in.o/mgo.v2/bson/LICENSE deleted file mode 100644 index 890326017..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -BSON library for Go - -Copyright (c) 2010-2012 - Gustavo Niemeyer - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in.o/mgo.v2/bson/bson.go b/vendor/gopkg.in.o/mgo.v2/bson/bson.go deleted file mode 100644 index 7fb7f8cae..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/bson.go +++ /dev/null @@ -1,738 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Package bson is an implementation of the BSON specification for Go: -// -// http://bsonspec.org -// -// It was created as part of the mgo MongoDB driver for Go, but is standalone -// and may be used on its own without the driver. -package bson - -import ( - "bytes" - "crypto/md5" - "crypto/rand" - "encoding/binary" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "io" - "os" - "reflect" - "runtime" - "strings" - "sync" - "sync/atomic" - "time" -) - -// -------------------------------------------------------------------------- -// The public API. - -// A value implementing the bson.Getter interface will have its GetBSON -// method called when the given value has to be marshalled, and the result -// of this method will be marshaled in place of the actual object. -// -// If GetBSON returns return a non-nil error, the marshalling procedure -// will stop and error out with the provided value. -type Getter interface { - GetBSON() (interface{}, error) -} - -// A value implementing the bson.Setter interface will receive the BSON -// value via the SetBSON method during unmarshaling, and the object -// itself will not be changed as usual. -// -// If setting the value works, the method should return nil or alternatively -// bson.SetZero to set the respective field to its zero value (nil for -// pointer types). If SetBSON returns a value of type bson.TypeError, the -// BSON value will be omitted from a map or slice being decoded and the -// unmarshalling will continue. If it returns any other non-nil error, the -// unmarshalling procedure will stop and error out with the provided value. -// -// This interface is generally useful in pointer receivers, since the method -// will want to change the receiver. A type field that implements the Setter -// interface doesn't have to be a pointer, though. -// -// Unlike the usual behavior, unmarshalling onto a value that implements a -// Setter interface will NOT reset the value to its zero state. This allows -// the value to decide by itself how to be unmarshalled. -// -// For example: -// -// type MyString string -// -// func (s *MyString) SetBSON(raw bson.Raw) error { -// return raw.Unmarshal(s) -// } -// -type Setter interface { - SetBSON(raw Raw) error -} - -// SetZero may be returned from a SetBSON method to have the value set to -// its respective zero value. When used in pointer values, this will set the -// field to nil rather than to the pre-allocated value. -var SetZero = errors.New("set to zero") - -// M is a convenient alias for a map[string]interface{} map, useful for -// dealing with BSON in a native way. For instance: -// -// bson.M{"a": 1, "b": true} -// -// There's no special handling for this type in addition to what's done anyway -// for an equivalent map type. Elements in the map will be dumped in an -// undefined ordered. See also the bson.D type for an ordered alternative. -type M map[string]interface{} - -// D represents a BSON document containing ordered elements. For example: -// -// bson.D{{"a", 1}, {"b", true}} -// -// In some situations, such as when creating indexes for MongoDB, the order in -// which the elements are defined is important. If the order is not important, -// using a map is generally more comfortable. See bson.M and bson.RawD. -type D []DocElem - -// DocElem is an element of the bson.D document representation. -type DocElem struct { - Name string - Value interface{} -} - -// Map returns a map out of the ordered element name/value pairs in d. -func (d D) Map() (m M) { - m = make(M, len(d)) - for _, item := range d { - m[item.Name] = item.Value - } - return m -} - -// The Raw type represents raw unprocessed BSON documents and elements. -// Kind is the kind of element as defined per the BSON specification, and -// Data is the raw unprocessed data for the respective element. -// Using this type it is possible to unmarshal or marshal values partially. -// -// Relevant documentation: -// -// http://bsonspec.org/#/specification -// -type Raw struct { - Kind byte - Data []byte -} - -// RawD represents a BSON document containing raw unprocessed elements. -// This low-level representation may be useful when lazily processing -// documents of uncertain content, or when manipulating the raw content -// documents in general. -type RawD []RawDocElem - -// See the RawD type. -type RawDocElem struct { - Name string - Value Raw -} - -// ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes -// long. MongoDB objects by default have such a property set in their "_id" -// property. -// -// http://www.mongodb.org/display/DOCS/Object+IDs -type ObjectId string - -// ObjectIdHex returns an ObjectId from the provided hex representation. -// Calling this function with an invalid hex representation will -// cause a runtime panic. See the IsObjectIdHex function. -func ObjectIdHex(s string) ObjectId { - d, err := hex.DecodeString(s) - if err != nil || len(d) != 12 { - panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s)) - } - return ObjectId(d) -} - -// IsObjectIdHex returns whether s is a valid hex representation of -// an ObjectId. See the ObjectIdHex function. -func IsObjectIdHex(s string) bool { - if len(s) != 24 { - return false - } - _, err := hex.DecodeString(s) - return err == nil -} - -// objectIdCounter is atomically incremented when generating a new ObjectId -// using NewObjectId() function. It's used as a counter part of an id. -var objectIdCounter uint32 = readRandomUint32() - -// readRandomUint32 returns a random objectIdCounter. -func readRandomUint32() uint32 { - var b [4]byte - _, err := io.ReadFull(rand.Reader, b[:]) - if err != nil { - panic(fmt.Errorf("cannot read random object id: %v", err)) - } - return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)) -} - -// machineId stores machine id generated once and used in subsequent calls -// to NewObjectId function. -var machineId = readMachineId() -var processId = os.Getpid() - -// readMachineId generates and returns a machine id. -// If this function fails to get the hostname it will cause a runtime error. -func readMachineId() []byte { - var sum [3]byte - id := sum[:] - hostname, err1 := os.Hostname() - if err1 != nil { - _, err2 := io.ReadFull(rand.Reader, id) - if err2 != nil { - panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2)) - } - return id - } - hw := md5.New() - hw.Write([]byte(hostname)) - copy(id, hw.Sum(nil)) - return id -} - -// NewObjectId returns a new unique ObjectId. -func NewObjectId() ObjectId { - var b [12]byte - // Timestamp, 4 bytes, big endian - binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) - // Machine, first 3 bytes of md5(hostname) - b[4] = machineId[0] - b[5] = machineId[1] - b[6] = machineId[2] - // Pid, 2 bytes, specs don't specify endianness, but we use big endian. - b[7] = byte(processId >> 8) - b[8] = byte(processId) - // Increment, 3 bytes, big endian - i := atomic.AddUint32(&objectIdCounter, 1) - b[9] = byte(i >> 16) - b[10] = byte(i >> 8) - b[11] = byte(i) - return ObjectId(b[:]) -} - -// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled -// with the provided number of seconds from epoch UTC, and all other parts -// filled with zeroes. It's not safe to insert a document with an id generated -// by this method, it is useful only for queries to find documents with ids -// generated before or after the specified timestamp. -func NewObjectIdWithTime(t time.Time) ObjectId { - var b [12]byte - binary.BigEndian.PutUint32(b[:4], uint32(t.Unix())) - return ObjectId(string(b[:])) -} - -// String returns a hex string representation of the id. -// Example: ObjectIdHex("4d88e15b60f486e428412dc9"). -func (id ObjectId) String() string { - return fmt.Sprintf(`ObjectIdHex("%x")`, string(id)) -} - -// Hex returns a hex representation of the ObjectId. -func (id ObjectId) Hex() string { - return hex.EncodeToString([]byte(id)) -} - -// MarshalJSON turns a bson.ObjectId into a json.Marshaller. -func (id ObjectId) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"%x"`, string(id))), nil -} - -var nullBytes = []byte("null") - -// UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller. -func (id *ObjectId) UnmarshalJSON(data []byte) error { - if len(data) > 0 && (data[0] == '{' || data[0] == 'O') { - var v struct { - Id json.RawMessage `json:"$oid"` - Func struct { - Id json.RawMessage - } `json:"$oidFunc"` - } - err := jdec(data, &v) - if err == nil { - if len(v.Id) > 0 { - data = []byte(v.Id) - } else { - data = []byte(v.Func.Id) - } - } - } - if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) { - *id = "" - return nil - } - if len(data) != 26 || data[0] != '"' || data[25] != '"' { - return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s", string(data))) - } - var buf [12]byte - _, err := hex.Decode(buf[:], data[1:25]) - if err != nil { - return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s (%s)", string(data), err)) - } - *id = ObjectId(string(buf[:])) - return nil -} - -// MarshalText turns bson.ObjectId into an encoding.TextMarshaler. -func (id ObjectId) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("%x", string(id))), nil -} - -// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler. -func (id *ObjectId) UnmarshalText(data []byte) error { - if len(data) == 1 && data[0] == ' ' || len(data) == 0 { - *id = "" - return nil - } - if len(data) != 24 { - return fmt.Errorf("invalid ObjectId: %s", data) - } - var buf [12]byte - _, err := hex.Decode(buf[:], data[:]) - if err != nil { - return fmt.Errorf("invalid ObjectId: %s (%s)", data, err) - } - *id = ObjectId(string(buf[:])) - return nil -} - -// Valid returns true if id is valid. A valid id must contain exactly 12 bytes. -func (id ObjectId) Valid() bool { - return len(id) == 12 -} - -// byteSlice returns byte slice of id from start to end. -// Calling this function with an invalid id will cause a runtime panic. -func (id ObjectId) byteSlice(start, end int) []byte { - if len(id) != 12 { - panic(fmt.Sprintf("invalid ObjectId: %q", string(id))) - } - return []byte(string(id)[start:end]) -} - -// Time returns the timestamp part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Time() time.Time { - // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. - secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4))) - return time.Unix(secs, 0) -} - -// Machine returns the 3-byte machine id part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Machine() []byte { - return id.byteSlice(4, 7) -} - -// Pid returns the process id part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Pid() uint16 { - return binary.BigEndian.Uint16(id.byteSlice(7, 9)) -} - -// Counter returns the incrementing value part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Counter() int32 { - b := id.byteSlice(9, 12) - // Counter is stored as big-endian 3-byte value - return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) -} - -// The Symbol type is similar to a string and is used in languages with a -// distinct symbol type. -type Symbol string - -// Now returns the current time with millisecond precision. MongoDB stores -// timestamps with the same precision, so a Time returned from this method -// will not change after a roundtrip to the database. That's the only reason -// why this function exists. Using the time.Now function also works fine -// otherwise. -func Now() time.Time { - return time.Unix(0, time.Now().UnixNano()/1e6*1e6) -} - -// MongoTimestamp is a special internal type used by MongoDB that for some -// strange reason has its own datatype defined in BSON. -type MongoTimestamp int64 - -type orderKey int64 - -// MaxKey is a special value that compares higher than all other possible BSON -// values in a MongoDB database. -var MaxKey = orderKey(1<<63 - 1) - -// MinKey is a special value that compares lower than all other possible BSON -// values in a MongoDB database. -var MinKey = orderKey(-1 << 63) - -type undefined struct{} - -// Undefined represents the undefined BSON value. -var Undefined undefined - -// Binary is a representation for non-standard binary values. Any kind should -// work, but the following are known as of this writing: -// -// 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}. -// 0x01 - Function (!?) -// 0x02 - Obsolete generic. -// 0x03 - UUID -// 0x05 - MD5 -// 0x80 - User defined. -// -type Binary struct { - Kind byte - Data []byte -} - -// RegEx represents a regular expression. The Options field may contain -// individual characters defining the way in which the pattern should be -// applied, and must be sorted. Valid options as of this writing are 'i' for -// case insensitive matching, 'm' for multi-line matching, 'x' for verbose -// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all -// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match -// unicode. The value of the Options parameter is not verified before being -// marshaled into the BSON format. -type RegEx struct { - Pattern string - Options string -} - -// JavaScript is a type that holds JavaScript code. If Scope is non-nil, it -// will be marshaled as a mapping from identifiers to values that may be -// used when evaluating the provided Code. -type JavaScript struct { - Code string - Scope interface{} -} - -// DBPointer refers to a document id in a namespace. -// -// This type is deprecated in the BSON specification and should not be used -// except for backwards compatibility with ancient applications. -type DBPointer struct { - Namespace string - Id ObjectId -} - -const initialBufferSize = 64 - -func handleErr(err *error) { - if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } else if _, ok := r.(externalPanic); ok { - panic(r) - } else if s, ok := r.(string); ok { - *err = errors.New(s) - } else if e, ok := r.(error); ok { - *err = e - } else { - panic(r) - } - } -} - -// Marshal serializes the in value, which may be a map or a struct value. -// In the case of struct values, only exported fields will be serialized, -// and the order of serialized fields will match that of the struct itself. -// The lowercased field name is used as the key for each exported field, -// but this behavior may be changed using the respective field tag. -// The tag may also contain flags to tweak the marshalling behavior for -// the field. The tag formats accepted are: -// -// "[][,[,]]" -// -// `(...) bson:"[][,[,]]" (...)` -// -// The following flags are currently supported: -// -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// -// minsize Marshal an int64 value as an int32, if that's feasible -// while preserving the numeric value. -// -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the bson keys of other struct fields. -// -// Some examples: -// -// type T struct { -// A bool -// B int "myb" -// C string "myc,omitempty" -// D string `bson:",omitempty" json:"jsonkey"` -// E int64 ",minsize" -// F int64 "myf,omitempty,minsize" -// } -// -func Marshal(in interface{}) (out []byte, err error) { - defer handleErr(&err) - e := &encoder{make([]byte, 0, initialBufferSize)} - e.addDoc(reflect.ValueOf(in)) - return e.out, nil -} - -// Unmarshal deserializes data from in into the out value. The out value -// must be a map, a pointer to a struct, or a pointer to a bson.D value. -// In the case of struct values, only exported fields will be deserialized. -// The lowercased field name is used as the key for each exported field, -// but this behavior may be changed using the respective field tag. -// The tag may also contain flags to tweak the marshalling behavior for -// the field. The tag formats accepted are: -// -// "[][,[,]]" -// -// `(...) bson:"[][,[,]]" (...)` -// -// The following flags are currently supported during unmarshal (see the -// Marshal method for other flags): -// -// inline Inline the field, which must be a struct or a map. -// Inlined structs are handled as if its fields were part -// of the outer struct. An inlined map causes keys that do -// not match any other struct field to be inserted in the -// map rather than being discarded as usual. -// -// The target field or element types of out may not necessarily match -// the BSON values of the provided data. The following conversions are -// made automatically: -// -// - Numeric types are converted if at least the integer part of the -// value would be preserved correctly -// - Bools are converted to numeric types as 1 or 0 -// - Numeric types are converted to bools as true if not 0 or false otherwise -// - Binary and string BSON data is converted to a string, array or byte slice -// -// If the value would not fit the type and cannot be converted, it's -// silently skipped. -// -// Pointer values are initialized when necessary. -func Unmarshal(in []byte, out interface{}) (err error) { - if raw, ok := out.(*Raw); ok { - raw.Kind = 3 - raw.Data = in - return nil - } - defer handleErr(&err) - v := reflect.ValueOf(out) - switch v.Kind() { - case reflect.Ptr: - fallthrough - case reflect.Map: - d := newDecoder(in) - d.readDocTo(v) - case reflect.Struct: - return errors.New("Unmarshal can't deal with struct values. Use a pointer.") - default: - return errors.New("Unmarshal needs a map or a pointer to a struct.") - } - return nil -} - -// Unmarshal deserializes raw into the out value. If the out value type -// is not compatible with raw, a *bson.TypeError is returned. -// -// See the Unmarshal function documentation for more details on the -// unmarshalling process. -func (raw Raw) Unmarshal(out interface{}) (err error) { - defer handleErr(&err) - v := reflect.ValueOf(out) - switch v.Kind() { - case reflect.Ptr: - v = v.Elem() - fallthrough - case reflect.Map: - d := newDecoder(raw.Data) - good := d.readElemTo(v, raw.Kind) - if !good { - return &TypeError{v.Type(), raw.Kind} - } - case reflect.Struct: - return errors.New("Raw Unmarshal can't deal with struct values. Use a pointer.") - default: - return errors.New("Raw Unmarshal needs a map or a valid pointer.") - } - return nil -} - -type TypeError struct { - Type reflect.Type - Kind byte -} - -func (e *TypeError) Error() string { - return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String()) -} - -// -------------------------------------------------------------------------- -// Maintain a mapping of keys to structure field indexes - -type structInfo struct { - FieldsMap map[string]fieldInfo - FieldsList []fieldInfo - InlineMap int - Zero reflect.Value -} - -type fieldInfo struct { - Key string - Num int - OmitEmpty bool - MinSize bool - Inline []int -} - -var structMap = make(map[reflect.Type]*structInfo) -var structMapMutex sync.RWMutex - -type externalPanic string - -func (e externalPanic) String() string { - return string(e) -} - -func getStructInfo(st reflect.Type) (*structInfo, error) { - structMapMutex.RLock() - sinfo, found := structMap[st] - structMapMutex.RUnlock() - if found { - return sinfo, nil - } - n := st.NumField() - fieldsMap := make(map[string]fieldInfo) - fieldsList := make([]fieldInfo, 0, n) - inlineMap := -1 - for i := 0; i != n; i++ { - field := st.Field(i) - if field.PkgPath != "" && !field.Anonymous { - continue // Private field - } - - info := fieldInfo{Num: i} - - tag := field.Tag.Get("bson") - if tag == "" && strings.Index(string(field.Tag), ":") < 0 { - tag = string(field.Tag) - } - if tag == "-" { - continue - } - - inline := false - fields := strings.Split(tag, ",") - if len(fields) > 1 { - for _, flag := range fields[1:] { - switch flag { - case "omitempty": - info.OmitEmpty = true - case "minsize": - info.MinSize = true - case "inline": - inline = true - default: - msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st) - panic(externalPanic(msg)) - } - } - tag = fields[0] - } - - if inline { - switch field.Type.Kind() { - case reflect.Map: - if inlineMap >= 0 { - return nil, errors.New("Multiple ,inline maps in struct " + st.String()) - } - if field.Type.Key() != reflect.TypeOf("") { - return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) - } - inlineMap = info.Num - case reflect.Struct: - sinfo, err := getStructInfo(field.Type) - if err != nil { - return nil, err - } - for _, finfo := range sinfo.FieldsList { - if _, found := fieldsMap[finfo.Key]; found { - msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - if finfo.Inline == nil { - finfo.Inline = []int{i, finfo.Num} - } else { - finfo.Inline = append([]int{i}, finfo.Inline...) - } - fieldsMap[finfo.Key] = finfo - fieldsList = append(fieldsList, finfo) - } - default: - panic("Option ,inline needs a struct value or map field") - } - continue - } - - if tag != "" { - info.Key = tag - } else { - info.Key = strings.ToLower(field.Name) - } - - if _, found = fieldsMap[info.Key]; found { - msg := "Duplicated key '" + info.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - - fieldsList = append(fieldsList, info) - fieldsMap[info.Key] = info - } - sinfo = &structInfo{ - fieldsMap, - fieldsList, - inlineMap, - reflect.New(st).Elem(), - } - structMapMutex.Lock() - structMap[st] = sinfo - structMapMutex.Unlock() - return sinfo, nil -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/bson_test.go b/vendor/gopkg.in.o/mgo.v2/bson/bson_test.go deleted file mode 100644 index 37451f9fd..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/bson_test.go +++ /dev/null @@ -1,1832 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// gobson - BSON library for Go. - -package bson_test - -import ( - "encoding/binary" - "encoding/hex" - "encoding/json" - "encoding/xml" - "errors" - "net/url" - "reflect" - "strings" - "testing" - "time" - - . "gopkg.in/check.v1" - "gopkg.in/mgo.v2/bson" - "gopkg.in/yaml.v2" -) - -func TestAll(t *testing.T) { - TestingT(t) -} - -type S struct{} - -var _ = Suite(&S{}) - -// Wrap up the document elements contained in data, prepending the int32 -// length of the data, and appending the '\x00' value closing the document. -func wrapInDoc(data string) string { - result := make([]byte, len(data)+5) - binary.LittleEndian.PutUint32(result, uint32(len(result))) - copy(result[4:], []byte(data)) - return string(result) -} - -func makeZeroDoc(value interface{}) (zero interface{}) { - v := reflect.ValueOf(value) - t := v.Type() - switch t.Kind() { - case reflect.Map: - mv := reflect.MakeMap(t) - zero = mv.Interface() - case reflect.Ptr: - pv := reflect.New(v.Type().Elem()) - zero = pv.Interface() - case reflect.Slice, reflect.Int, reflect.Int64, reflect.Struct: - zero = reflect.New(t).Interface() - default: - panic("unsupported doc type: " + t.Name()) - } - return zero -} - -func testUnmarshal(c *C, data string, obj interface{}) { - zero := makeZeroDoc(obj) - err := bson.Unmarshal([]byte(data), zero) - c.Assert(err, IsNil) - c.Assert(zero, DeepEquals, obj) -} - -type testItemType struct { - obj interface{} - data string -} - -// -------------------------------------------------------------------------- -// Samples from bsonspec.org: - -var sampleItems = []testItemType{ - {bson.M{"hello": "world"}, - "\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00"}, - {bson.M{"BSON": []interface{}{"awesome", float64(5.05), 1986}}, - "1\x00\x00\x00\x04BSON\x00&\x00\x00\x00\x020\x00\x08\x00\x00\x00" + - "awesome\x00\x011\x00333333\x14@\x102\x00\xc2\x07\x00\x00\x00\x00"}, -} - -func (s *S) TestMarshalSampleItems(c *C) { - for i, item := range sampleItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, item.data, Commentf("Failed on item %d", i)) - } -} - -func (s *S) TestUnmarshalSampleItems(c *C) { - for i, item := range sampleItems { - value := bson.M{} - err := bson.Unmarshal([]byte(item.data), value) - c.Assert(err, IsNil) - c.Assert(value, DeepEquals, item.obj, Commentf("Failed on item %d", i)) - } -} - -// -------------------------------------------------------------------------- -// Every type, ordered by the type flag. These are not wrapped with the -// length and last \x00 from the document. wrapInDoc() computes them. -// Note that all of them should be supported as two-way conversions. - -var allItems = []testItemType{ - {bson.M{}, - ""}, - {bson.M{"_": float64(5.05)}, - "\x01_\x00333333\x14@"}, - {bson.M{"_": "yo"}, - "\x02_\x00\x03\x00\x00\x00yo\x00"}, - {bson.M{"_": bson.M{"a": true}}, - "\x03_\x00\x09\x00\x00\x00\x08a\x00\x01\x00"}, - {bson.M{"_": []interface{}{true, false}}, - "\x04_\x00\r\x00\x00\x00\x080\x00\x01\x081\x00\x00\x00"}, - {bson.M{"_": []byte("yo")}, - "\x05_\x00\x02\x00\x00\x00\x00yo"}, - {bson.M{"_": bson.Binary{0x80, []byte("udef")}}, - "\x05_\x00\x04\x00\x00\x00\x80udef"}, - {bson.M{"_": bson.Undefined}, // Obsolete, but still seen in the wild. - "\x06_\x00"}, - {bson.M{"_": bson.ObjectId("0123456789ab")}, - "\x07_\x000123456789ab"}, - {bson.M{"_": bson.DBPointer{"testnamespace", bson.ObjectId("0123456789ab")}}, - "\x0C_\x00\x0e\x00\x00\x00testnamespace\x000123456789ab"}, - {bson.M{"_": false}, - "\x08_\x00\x00"}, - {bson.M{"_": true}, - "\x08_\x00\x01"}, - {bson.M{"_": time.Unix(0, 258e6)}, // Note the NS <=> MS conversion. - "\x09_\x00\x02\x01\x00\x00\x00\x00\x00\x00"}, - {bson.M{"_": nil}, - "\x0A_\x00"}, - {bson.M{"_": bson.RegEx{"ab", "cd"}}, - "\x0B_\x00ab\x00cd\x00"}, - {bson.M{"_": bson.JavaScript{"code", nil}}, - "\x0D_\x00\x05\x00\x00\x00code\x00"}, - {bson.M{"_": bson.Symbol("sym")}, - "\x0E_\x00\x04\x00\x00\x00sym\x00"}, - {bson.M{"_": bson.JavaScript{"code", bson.M{"": nil}}}, - "\x0F_\x00\x14\x00\x00\x00\x05\x00\x00\x00code\x00" + - "\x07\x00\x00\x00\x0A\x00\x00"}, - {bson.M{"_": 258}, - "\x10_\x00\x02\x01\x00\x00"}, - {bson.M{"_": bson.MongoTimestamp(258)}, - "\x11_\x00\x02\x01\x00\x00\x00\x00\x00\x00"}, - {bson.M{"_": int64(258)}, - "\x12_\x00\x02\x01\x00\x00\x00\x00\x00\x00"}, - {bson.M{"_": int64(258 << 32)}, - "\x12_\x00\x00\x00\x00\x00\x02\x01\x00\x00"}, - {bson.M{"_": bson.MaxKey}, - "\x7F_\x00"}, - {bson.M{"_": bson.MinKey}, - "\xFF_\x00"}, -} - -func (s *S) TestMarshalAllItems(c *C) { - for i, item := range allItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, wrapInDoc(item.data), Commentf("Failed on item %d: %#v", i, item)) - } -} - -func (s *S) TestUnmarshalAllItems(c *C) { - for i, item := range allItems { - value := bson.M{} - err := bson.Unmarshal([]byte(wrapInDoc(item.data)), value) - c.Assert(err, IsNil) - c.Assert(value, DeepEquals, item.obj, Commentf("Failed on item %d: %#v", i, item)) - } -} - -func (s *S) TestUnmarshalRawAllItems(c *C) { - for i, item := range allItems { - if len(item.data) == 0 { - continue - } - value := item.obj.(bson.M)["_"] - if value == nil { - continue - } - pv := reflect.New(reflect.ValueOf(value).Type()) - raw := bson.Raw{item.data[0], []byte(item.data[3:])} - c.Logf("Unmarshal raw: %#v, %#v", raw, pv.Interface()) - err := raw.Unmarshal(pv.Interface()) - c.Assert(err, IsNil) - c.Assert(pv.Elem().Interface(), DeepEquals, value, Commentf("Failed on item %d: %#v", i, item)) - } -} - -func (s *S) TestUnmarshalRawIncompatible(c *C) { - raw := bson.Raw{0x08, []byte{0x01}} // true - err := raw.Unmarshal(&struct{}{}) - c.Assert(err, ErrorMatches, "BSON kind 0x08 isn't compatible with type struct \\{\\}") -} - -func (s *S) TestUnmarshalZeroesStruct(c *C) { - data, err := bson.Marshal(bson.M{"b": 2}) - c.Assert(err, IsNil) - type T struct{ A, B int } - v := T{A: 1} - err = bson.Unmarshal(data, &v) - c.Assert(err, IsNil) - c.Assert(v.A, Equals, 0) - c.Assert(v.B, Equals, 2) -} - -func (s *S) TestUnmarshalZeroesMap(c *C) { - data, err := bson.Marshal(bson.M{"b": 2}) - c.Assert(err, IsNil) - m := bson.M{"a": 1} - err = bson.Unmarshal(data, &m) - c.Assert(err, IsNil) - c.Assert(m, DeepEquals, bson.M{"b": 2}) -} - -func (s *S) TestUnmarshalNonNilInterface(c *C) { - data, err := bson.Marshal(bson.M{"b": 2}) - c.Assert(err, IsNil) - m := bson.M{"a": 1} - var i interface{} - i = m - err = bson.Unmarshal(data, &i) - c.Assert(err, IsNil) - c.Assert(i, DeepEquals, bson.M{"b": 2}) - c.Assert(m, DeepEquals, bson.M{"a": 1}) -} - -// -------------------------------------------------------------------------- -// Some one way marshaling operations which would unmarshal differently. - -var oneWayMarshalItems = []testItemType{ - // These are being passed as pointers, and will unmarshal as values. - {bson.M{"": &bson.Binary{0x02, []byte("old")}}, - "\x05\x00\x07\x00\x00\x00\x02\x03\x00\x00\x00old"}, - {bson.M{"": &bson.Binary{0x80, []byte("udef")}}, - "\x05\x00\x04\x00\x00\x00\x80udef"}, - {bson.M{"": &bson.RegEx{"ab", "cd"}}, - "\x0B\x00ab\x00cd\x00"}, - {bson.M{"": &bson.JavaScript{"code", nil}}, - "\x0D\x00\x05\x00\x00\x00code\x00"}, - {bson.M{"": &bson.JavaScript{"code", bson.M{"": nil}}}, - "\x0F\x00\x14\x00\x00\x00\x05\x00\x00\x00code\x00" + - "\x07\x00\x00\x00\x0A\x00\x00"}, - - // There's no float32 type in BSON. Will encode as a float64. - {bson.M{"": float32(5.05)}, - "\x01\x00\x00\x00\x00@33\x14@"}, - - // The array will be unmarshaled as a slice instead. - {bson.M{"": [2]bool{true, false}}, - "\x04\x00\r\x00\x00\x00\x080\x00\x01\x081\x00\x00\x00"}, - - // The typed slice will be unmarshaled as []interface{}. - {bson.M{"": []bool{true, false}}, - "\x04\x00\r\x00\x00\x00\x080\x00\x01\x081\x00\x00\x00"}, - - // Will unmarshal as a []byte. - {bson.M{"": bson.Binary{0x00, []byte("yo")}}, - "\x05\x00\x02\x00\x00\x00\x00yo"}, - {bson.M{"": bson.Binary{0x02, []byte("old")}}, - "\x05\x00\x07\x00\x00\x00\x02\x03\x00\x00\x00old"}, - - // No way to preserve the type information here. We might encode as a zero - // value, but this would mean that pointer values in structs wouldn't be - // able to correctly distinguish between unset and set to the zero value. - {bson.M{"": (*byte)(nil)}, - "\x0A\x00"}, - - // No int types smaller than int32 in BSON. Could encode this as a char, - // but it would still be ambiguous, take more, and be awkward in Go when - // loaded without typing information. - {bson.M{"": byte(8)}, - "\x10\x00\x08\x00\x00\x00"}, - - // There are no unsigned types in BSON. Will unmarshal as int32 or int64. - {bson.M{"": uint32(258)}, - "\x10\x00\x02\x01\x00\x00"}, - {bson.M{"": uint64(258)}, - "\x12\x00\x02\x01\x00\x00\x00\x00\x00\x00"}, - {bson.M{"": uint64(258 << 32)}, - "\x12\x00\x00\x00\x00\x00\x02\x01\x00\x00"}, - - // This will unmarshal as int. - {bson.M{"": int32(258)}, - "\x10\x00\x02\x01\x00\x00"}, - - // That's a special case. The unsigned value is too large for an int32, - // so an int64 is used instead. - {bson.M{"": uint32(1<<32 - 1)}, - "\x12\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"}, - {bson.M{"": uint(1<<32 - 1)}, - "\x12\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"}, -} - -func (s *S) TestOneWayMarshalItems(c *C) { - for i, item := range oneWayMarshalItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, wrapInDoc(item.data), - Commentf("Failed on item %d", i)) - } -} - -// -------------------------------------------------------------------------- -// Two-way tests for user-defined structures using the samples -// from bsonspec.org. - -type specSample1 struct { - Hello string -} - -type specSample2 struct { - BSON []interface{} "BSON" -} - -var structSampleItems = []testItemType{ - {&specSample1{"world"}, - "\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00"}, - {&specSample2{[]interface{}{"awesome", float64(5.05), 1986}}, - "1\x00\x00\x00\x04BSON\x00&\x00\x00\x00\x020\x00\x08\x00\x00\x00" + - "awesome\x00\x011\x00333333\x14@\x102\x00\xc2\x07\x00\x00\x00\x00"}, -} - -func (s *S) TestMarshalStructSampleItems(c *C) { - for i, item := range structSampleItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, item.data, - Commentf("Failed on item %d", i)) - } -} - -func (s *S) TestUnmarshalStructSampleItems(c *C) { - for _, item := range structSampleItems { - testUnmarshal(c, item.data, item.obj) - } -} - -func (s *S) Test64bitInt(c *C) { - var i int64 = (1 << 31) - if int(i) > 0 { - data, err := bson.Marshal(bson.M{"i": int(i)}) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, wrapInDoc("\x12i\x00\x00\x00\x00\x80\x00\x00\x00\x00")) - - var result struct{ I int } - err = bson.Unmarshal(data, &result) - c.Assert(err, IsNil) - c.Assert(int64(result.I), Equals, i) - } -} - -// -------------------------------------------------------------------------- -// Generic two-way struct marshaling tests. - -var bytevar = byte(8) -var byteptr = &bytevar - -var structItems = []testItemType{ - {&struct{ Ptr *byte }{nil}, - "\x0Aptr\x00"}, - {&struct{ Ptr *byte }{&bytevar}, - "\x10ptr\x00\x08\x00\x00\x00"}, - {&struct{ Ptr **byte }{&byteptr}, - "\x10ptr\x00\x08\x00\x00\x00"}, - {&struct{ Byte byte }{8}, - "\x10byte\x00\x08\x00\x00\x00"}, - {&struct{ Byte byte }{0}, - "\x10byte\x00\x00\x00\x00\x00"}, - {&struct { - V byte "Tag" - }{8}, - "\x10Tag\x00\x08\x00\x00\x00"}, - {&struct { - V *struct { - Byte byte - } - }{&struct{ Byte byte }{8}}, - "\x03v\x00" + "\x0f\x00\x00\x00\x10byte\x00\b\x00\x00\x00\x00"}, - {&struct{ priv byte }{}, ""}, - - // The order of the dumped fields should be the same in the struct. - {&struct{ A, C, B, D, F, E *byte }{}, - "\x0Aa\x00\x0Ac\x00\x0Ab\x00\x0Ad\x00\x0Af\x00\x0Ae\x00"}, - - {&struct{ V bson.Raw }{bson.Raw{0x03, []byte("\x0f\x00\x00\x00\x10byte\x00\b\x00\x00\x00\x00")}}, - "\x03v\x00" + "\x0f\x00\x00\x00\x10byte\x00\b\x00\x00\x00\x00"}, - {&struct{ V bson.Raw }{bson.Raw{0x10, []byte("\x00\x00\x00\x00")}}, - "\x10v\x00" + "\x00\x00\x00\x00"}, - - // Byte arrays. - {&struct{ V [2]byte }{[2]byte{'y', 'o'}}, - "\x05v\x00\x02\x00\x00\x00\x00yo"}, -} - -func (s *S) TestMarshalStructItems(c *C) { - for i, item := range structItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, wrapInDoc(item.data), - Commentf("Failed on item %d", i)) - } -} - -func (s *S) TestUnmarshalStructItems(c *C) { - for _, item := range structItems { - testUnmarshal(c, wrapInDoc(item.data), item.obj) - } -} - -func (s *S) TestUnmarshalRawStructItems(c *C) { - for i, item := range structItems { - raw := bson.Raw{0x03, []byte(wrapInDoc(item.data))} - zero := makeZeroDoc(item.obj) - err := raw.Unmarshal(zero) - c.Assert(err, IsNil) - c.Assert(zero, DeepEquals, item.obj, Commentf("Failed on item %d: %#v", i, item)) - } -} - -func (s *S) TestUnmarshalRawNil(c *C) { - // Regression test: shouldn't try to nil out the pointer itself, - // as it's not settable. - raw := bson.Raw{0x0A, []byte{}} - err := raw.Unmarshal(&struct{}{}) - c.Assert(err, IsNil) -} - -// -------------------------------------------------------------------------- -// One-way marshaling tests. - -type dOnIface struct { - D interface{} -} - -type ignoreField struct { - Before string - Ignore string `bson:"-"` - After string -} - -var marshalItems = []testItemType{ - // Ordered document dump. Will unmarshal as a dictionary by default. - {bson.D{{"a", nil}, {"c", nil}, {"b", nil}, {"d", nil}, {"f", nil}, {"e", true}}, - "\x0Aa\x00\x0Ac\x00\x0Ab\x00\x0Ad\x00\x0Af\x00\x08e\x00\x01"}, - {MyD{{"a", nil}, {"c", nil}, {"b", nil}, {"d", nil}, {"f", nil}, {"e", true}}, - "\x0Aa\x00\x0Ac\x00\x0Ab\x00\x0Ad\x00\x0Af\x00\x08e\x00\x01"}, - {&dOnIface{bson.D{{"a", nil}, {"c", nil}, {"b", nil}, {"d", true}}}, - "\x03d\x00" + wrapInDoc("\x0Aa\x00\x0Ac\x00\x0Ab\x00\x08d\x00\x01")}, - - {bson.RawD{{"a", bson.Raw{0x0A, nil}}, {"c", bson.Raw{0x0A, nil}}, {"b", bson.Raw{0x08, []byte{0x01}}}}, - "\x0Aa\x00" + "\x0Ac\x00" + "\x08b\x00\x01"}, - {MyRawD{{"a", bson.Raw{0x0A, nil}}, {"c", bson.Raw{0x0A, nil}}, {"b", bson.Raw{0x08, []byte{0x01}}}}, - "\x0Aa\x00" + "\x0Ac\x00" + "\x08b\x00\x01"}, - {&dOnIface{bson.RawD{{"a", bson.Raw{0x0A, nil}}, {"c", bson.Raw{0x0A, nil}}, {"b", bson.Raw{0x08, []byte{0x01}}}}}, - "\x03d\x00" + wrapInDoc("\x0Aa\x00"+"\x0Ac\x00"+"\x08b\x00\x01")}, - - {&ignoreField{"before", "ignore", "after"}, - "\x02before\x00\a\x00\x00\x00before\x00\x02after\x00\x06\x00\x00\x00after\x00"}, - - // Marshalling a Raw document does nothing. - {bson.Raw{0x03, []byte(wrapInDoc("anything"))}, - "anything"}, - {bson.Raw{Data: []byte(wrapInDoc("anything"))}, - "anything"}, -} - -func (s *S) TestMarshalOneWayItems(c *C) { - for _, item := range marshalItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, wrapInDoc(item.data)) - } -} - -// -------------------------------------------------------------------------- -// One-way unmarshaling tests. - -var unmarshalItems = []testItemType{ - // Field is private. Should not attempt to unmarshal it. - {&struct{ priv byte }{}, - "\x10priv\x00\x08\x00\x00\x00"}, - - // Wrong casing. Field names are lowercased. - {&struct{ Byte byte }{}, - "\x10Byte\x00\x08\x00\x00\x00"}, - - // Ignore non-existing field. - {&struct{ Byte byte }{9}, - "\x10boot\x00\x08\x00\x00\x00" + "\x10byte\x00\x09\x00\x00\x00"}, - - // Do not unmarshal on ignored field. - {&ignoreField{"before", "", "after"}, - "\x02before\x00\a\x00\x00\x00before\x00" + - "\x02-\x00\a\x00\x00\x00ignore\x00" + - "\x02after\x00\x06\x00\x00\x00after\x00"}, - - // Ignore unsuitable types silently. - {map[string]string{"str": "s"}, - "\x02str\x00\x02\x00\x00\x00s\x00" + "\x10int\x00\x01\x00\x00\x00"}, - {map[string][]int{"array": []int{5, 9}}, - "\x04array\x00" + wrapInDoc("\x100\x00\x05\x00\x00\x00"+"\x021\x00\x02\x00\x00\x00s\x00"+"\x102\x00\x09\x00\x00\x00")}, - - // Wrong type. Shouldn't init pointer. - {&struct{ Str *byte }{}, - "\x02str\x00\x02\x00\x00\x00s\x00"}, - {&struct{ Str *struct{ Str string } }{}, - "\x02str\x00\x02\x00\x00\x00s\x00"}, - - // Ordered document. - {&struct{ bson.D }{bson.D{{"a", nil}, {"c", nil}, {"b", nil}, {"d", true}}}, - "\x03d\x00" + wrapInDoc("\x0Aa\x00\x0Ac\x00\x0Ab\x00\x08d\x00\x01")}, - - // Raw document. - {&bson.Raw{0x03, []byte(wrapInDoc("\x10byte\x00\x08\x00\x00\x00"))}, - "\x10byte\x00\x08\x00\x00\x00"}, - - // RawD document. - {&struct{ bson.RawD }{bson.RawD{{"a", bson.Raw{0x0A, []byte{}}}, {"c", bson.Raw{0x0A, []byte{}}}, {"b", bson.Raw{0x08, []byte{0x01}}}}}, - "\x03rawd\x00" + wrapInDoc("\x0Aa\x00\x0Ac\x00\x08b\x00\x01")}, - - // Decode old binary. - {bson.M{"_": []byte("old")}, - "\x05_\x00\x07\x00\x00\x00\x02\x03\x00\x00\x00old"}, - - // Decode old binary without length. According to the spec, this shouldn't happen. - {bson.M{"_": []byte("old")}, - "\x05_\x00\x03\x00\x00\x00\x02old"}, - - // Decode a doc within a doc in to a slice within a doc; shouldn't error - {&struct{ Foo []string }{}, - "\x03\x66\x6f\x6f\x00\x05\x00\x00\x00\x00"}, -} - -func (s *S) TestUnmarshalOneWayItems(c *C) { - for _, item := range unmarshalItems { - testUnmarshal(c, wrapInDoc(item.data), item.obj) - } -} - -func (s *S) TestUnmarshalNilInStruct(c *C) { - // Nil is the default value, so we need to ensure it's indeed being set. - b := byte(1) - v := &struct{ Ptr *byte }{&b} - err := bson.Unmarshal([]byte(wrapInDoc("\x0Aptr\x00")), v) - c.Assert(err, IsNil) - c.Assert(v, DeepEquals, &struct{ Ptr *byte }{nil}) -} - -// -------------------------------------------------------------------------- -// Marshalling error cases. - -type structWithDupKeys struct { - Name byte - Other byte "name" // Tag should precede. -} - -var marshalErrorItems = []testItemType{ - {bson.M{"": uint64(1 << 63)}, - "BSON has no uint64 type, and value is too large to fit correctly in an int64"}, - {bson.M{"": bson.ObjectId("tooshort")}, - "ObjectIDs must be exactly 12 bytes long \\(got 8\\)"}, - {int64(123), - "Can't marshal int64 as a BSON document"}, - {bson.M{"": 1i}, - "Can't marshal complex128 in a BSON document"}, - {&structWithDupKeys{}, - "Duplicated key 'name' in struct bson_test.structWithDupKeys"}, - {bson.Raw{0xA, []byte{}}, - "Attempted to marshal Raw kind 10 as a document"}, - {bson.Raw{0x3, []byte{}}, - "Attempted to marshal empty Raw document"}, - {bson.M{"w": bson.Raw{0x3, []byte{}}}, - "Attempted to marshal empty Raw document"}, - {&inlineCantPtr{&struct{ A, B int }{1, 2}}, - "Option ,inline needs a struct value or map field"}, - {&inlineDupName{1, struct{ A, B int }{2, 3}}, - "Duplicated key 'a' in struct bson_test.inlineDupName"}, - {&inlineDupMap{}, - "Multiple ,inline maps in struct bson_test.inlineDupMap"}, - {&inlineBadKeyMap{}, - "Option ,inline needs a map with string keys in struct bson_test.inlineBadKeyMap"}, - {&inlineMap{A: 1, M: map[string]interface{}{"a": 1}}, - `Can't have key "a" in inlined map; conflicts with struct field`}, -} - -func (s *S) TestMarshalErrorItems(c *C) { - for _, item := range marshalErrorItems { - data, err := bson.Marshal(item.obj) - c.Assert(err, ErrorMatches, item.data) - c.Assert(data, IsNil) - } -} - -// -------------------------------------------------------------------------- -// Unmarshalling error cases. - -type unmarshalErrorType struct { - obj interface{} - data string - error string -} - -var unmarshalErrorItems = []unmarshalErrorType{ - // Tag name conflicts with existing parameter. - {&structWithDupKeys{}, - "\x10name\x00\x08\x00\x00\x00", - "Duplicated key 'name' in struct bson_test.structWithDupKeys"}, - - // Non-string map key. - {map[int]interface{}{}, - "\x10name\x00\x08\x00\x00\x00", - "BSON map must have string keys. Got: map\\[int\\]interface \\{\\}"}, - - {nil, - "\xEEname\x00", - "Unknown element kind \\(0xEE\\)"}, - - {struct{ Name bool }{}, - "\x10name\x00\x08\x00\x00\x00", - "Unmarshal can't deal with struct values. Use a pointer."}, - - {123, - "\x10name\x00\x08\x00\x00\x00", - "Unmarshal needs a map or a pointer to a struct."}, - - {nil, - "\x08\x62\x00\x02", - "encoded boolean must be 1 or 0, found 2"}, -} - -func (s *S) TestUnmarshalErrorItems(c *C) { - for _, item := range unmarshalErrorItems { - data := []byte(wrapInDoc(item.data)) - var value interface{} - switch reflect.ValueOf(item.obj).Kind() { - case reflect.Map, reflect.Ptr: - value = makeZeroDoc(item.obj) - case reflect.Invalid: - value = bson.M{} - default: - value = item.obj - } - err := bson.Unmarshal(data, value) - c.Assert(err, ErrorMatches, item.error) - } -} - -type unmarshalRawErrorType struct { - obj interface{} - raw bson.Raw - error string -} - -var unmarshalRawErrorItems = []unmarshalRawErrorType{ - // Tag name conflicts with existing parameter. - {&structWithDupKeys{}, - bson.Raw{0x03, []byte("\x10byte\x00\x08\x00\x00\x00")}, - "Duplicated key 'name' in struct bson_test.structWithDupKeys"}, - - {&struct{}{}, - bson.Raw{0xEE, []byte{}}, - "Unknown element kind \\(0xEE\\)"}, - - {struct{ Name bool }{}, - bson.Raw{0x10, []byte("\x08\x00\x00\x00")}, - "Raw Unmarshal can't deal with struct values. Use a pointer."}, - - {123, - bson.Raw{0x10, []byte("\x08\x00\x00\x00")}, - "Raw Unmarshal needs a map or a valid pointer."}, -} - -func (s *S) TestUnmarshalRawErrorItems(c *C) { - for i, item := range unmarshalRawErrorItems { - err := item.raw.Unmarshal(item.obj) - c.Assert(err, ErrorMatches, item.error, Commentf("Failed on item %d: %#v\n", i, item)) - } -} - -var corruptedData = []string{ - "\x04\x00\x00\x00\x00", // Document shorter than minimum - "\x06\x00\x00\x00\x00", // Not enough data - "\x05\x00\x00", // Broken length - "\x05\x00\x00\x00\xff", // Corrupted termination - "\x0A\x00\x00\x00\x0Aooop\x00", // Unfinished C string - - // Array end past end of string (s[2]=0x07 is correct) - wrapInDoc("\x04\x00\x09\x00\x00\x00\x0A\x00\x00"), - - // Array end within string, but past acceptable. - wrapInDoc("\x04\x00\x08\x00\x00\x00\x0A\x00\x00"), - - // Document end within string, but past acceptable. - wrapInDoc("\x03\x00\x08\x00\x00\x00\x0A\x00\x00"), - - // String with corrupted end. - wrapInDoc("\x02\x00\x03\x00\x00\x00yo\xFF"), - - // String with negative length (issue #116). - "\x0c\x00\x00\x00\x02x\x00\xff\xff\xff\xff\x00", - - // String with zero length (must include trailing '\x00') - "\x0c\x00\x00\x00\x02x\x00\x00\x00\x00\x00\x00", - - // Binary with negative length. - "\r\x00\x00\x00\x05x\x00\xff\xff\xff\xff\x00\x00", -} - -func (s *S) TestUnmarshalMapDocumentTooShort(c *C) { - for _, data := range corruptedData { - err := bson.Unmarshal([]byte(data), bson.M{}) - c.Assert(err, ErrorMatches, "Document is corrupted") - - err = bson.Unmarshal([]byte(data), &struct{}{}) - c.Assert(err, ErrorMatches, "Document is corrupted") - } -} - -// -------------------------------------------------------------------------- -// Setter test cases. - -var setterResult = map[string]error{} - -type setterType struct { - received interface{} -} - -func (o *setterType) SetBSON(raw bson.Raw) error { - err := raw.Unmarshal(&o.received) - if err != nil { - panic("The panic:" + err.Error()) - } - if s, ok := o.received.(string); ok { - if result, ok := setterResult[s]; ok { - return result - } - } - return nil -} - -type ptrSetterDoc struct { - Field *setterType "_" -} - -type valSetterDoc struct { - Field setterType "_" -} - -func (s *S) TestUnmarshalAllItemsWithPtrSetter(c *C) { - for _, item := range allItems { - for i := 0; i != 2; i++ { - var field *setterType - if i == 0 { - obj := &ptrSetterDoc{} - err := bson.Unmarshal([]byte(wrapInDoc(item.data)), obj) - c.Assert(err, IsNil) - field = obj.Field - } else { - obj := &valSetterDoc{} - err := bson.Unmarshal([]byte(wrapInDoc(item.data)), obj) - c.Assert(err, IsNil) - field = &obj.Field - } - if item.data == "" { - // Nothing to unmarshal. Should be untouched. - if i == 0 { - c.Assert(field, IsNil) - } else { - c.Assert(field.received, IsNil) - } - } else { - expected := item.obj.(bson.M)["_"] - c.Assert(field, NotNil, Commentf("Pointer not initialized (%#v)", expected)) - c.Assert(field.received, DeepEquals, expected) - } - } - } -} - -func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) { - obj := &setterType{} - err := bson.Unmarshal([]byte(sampleItems[0].data), obj) - c.Assert(err, IsNil) - c.Assert(obj.received, DeepEquals, bson.M{"hello": "world"}) -} - -func (s *S) TestUnmarshalSetterOmits(c *C) { - setterResult["2"] = &bson.TypeError{} - setterResult["4"] = &bson.TypeError{} - defer func() { - delete(setterResult, "2") - delete(setterResult, "4") - }() - - m := map[string]*setterType{} - data := wrapInDoc("\x02abc\x00\x02\x00\x00\x001\x00" + - "\x02def\x00\x02\x00\x00\x002\x00" + - "\x02ghi\x00\x02\x00\x00\x003\x00" + - "\x02jkl\x00\x02\x00\x00\x004\x00") - err := bson.Unmarshal([]byte(data), m) - c.Assert(err, IsNil) - c.Assert(m["abc"], NotNil) - c.Assert(m["def"], IsNil) - c.Assert(m["ghi"], NotNil) - c.Assert(m["jkl"], IsNil) - - c.Assert(m["abc"].received, Equals, "1") - c.Assert(m["ghi"].received, Equals, "3") -} - -func (s *S) TestUnmarshalSetterErrors(c *C) { - boom := errors.New("BOOM") - setterResult["2"] = boom - defer delete(setterResult, "2") - - m := map[string]*setterType{} - data := wrapInDoc("\x02abc\x00\x02\x00\x00\x001\x00" + - "\x02def\x00\x02\x00\x00\x002\x00" + - "\x02ghi\x00\x02\x00\x00\x003\x00") - err := bson.Unmarshal([]byte(data), m) - c.Assert(err, Equals, boom) - c.Assert(m["abc"], NotNil) - c.Assert(m["def"], IsNil) - c.Assert(m["ghi"], IsNil) - - c.Assert(m["abc"].received, Equals, "1") -} - -func (s *S) TestDMap(c *C) { - d := bson.D{{"a", 1}, {"b", 2}} - c.Assert(d.Map(), DeepEquals, bson.M{"a": 1, "b": 2}) -} - -func (s *S) TestUnmarshalSetterSetZero(c *C) { - setterResult["foo"] = bson.SetZero - defer delete(setterResult, "field") - - data, err := bson.Marshal(bson.M{"field": "foo"}) - c.Assert(err, IsNil) - - m := map[string]*setterType{} - err = bson.Unmarshal([]byte(data), m) - c.Assert(err, IsNil) - - value, ok := m["field"] - c.Assert(ok, Equals, true) - c.Assert(value, IsNil) -} - -// -------------------------------------------------------------------------- -// Getter test cases. - -type typeWithGetter struct { - result interface{} - err error -} - -func (t *typeWithGetter) GetBSON() (interface{}, error) { - if t == nil { - return "", nil - } - return t.result, t.err -} - -type docWithGetterField struct { - Field *typeWithGetter "_" -} - -func (s *S) TestMarshalAllItemsWithGetter(c *C) { - for i, item := range allItems { - if item.data == "" { - continue - } - obj := &docWithGetterField{} - obj.Field = &typeWithGetter{result: item.obj.(bson.M)["_"]} - data, err := bson.Marshal(obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, wrapInDoc(item.data), - Commentf("Failed on item #%d", i)) - } -} - -func (s *S) TestMarshalWholeDocumentWithGetter(c *C) { - obj := &typeWithGetter{result: sampleItems[0].obj} - data, err := bson.Marshal(obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, sampleItems[0].data) -} - -func (s *S) TestGetterErrors(c *C) { - e := errors.New("oops") - - obj1 := &docWithGetterField{} - obj1.Field = &typeWithGetter{sampleItems[0].obj, e} - data, err := bson.Marshal(obj1) - c.Assert(err, ErrorMatches, "oops") - c.Assert(data, IsNil) - - obj2 := &typeWithGetter{sampleItems[0].obj, e} - data, err = bson.Marshal(obj2) - c.Assert(err, ErrorMatches, "oops") - c.Assert(data, IsNil) -} - -type intGetter int64 - -func (t intGetter) GetBSON() (interface{}, error) { - return int64(t), nil -} - -type typeWithIntGetter struct { - V intGetter ",minsize" -} - -func (s *S) TestMarshalShortWithGetter(c *C) { - obj := typeWithIntGetter{42} - data, err := bson.Marshal(obj) - c.Assert(err, IsNil) - m := bson.M{} - err = bson.Unmarshal(data, m) - c.Assert(err, IsNil) - c.Assert(m["v"], Equals, 42) -} - -func (s *S) TestMarshalWithGetterNil(c *C) { - obj := docWithGetterField{} - data, err := bson.Marshal(obj) - c.Assert(err, IsNil) - m := bson.M{} - err = bson.Unmarshal(data, m) - c.Assert(err, IsNil) - c.Assert(m, DeepEquals, bson.M{"_": ""}) -} - -// -------------------------------------------------------------------------- -// Cross-type conversion tests. - -type crossTypeItem struct { - obj1 interface{} - obj2 interface{} -} - -type condStr struct { - V string ",omitempty" -} -type condStrNS struct { - V string `a:"A" bson:",omitempty" b:"B"` -} -type condBool struct { - V bool ",omitempty" -} -type condInt struct { - V int ",omitempty" -} -type condUInt struct { - V uint ",omitempty" -} -type condFloat struct { - V float64 ",omitempty" -} -type condIface struct { - V interface{} ",omitempty" -} -type condPtr struct { - V *bool ",omitempty" -} -type condSlice struct { - V []string ",omitempty" -} -type condMap struct { - V map[string]int ",omitempty" -} -type namedCondStr struct { - V string "myv,omitempty" -} -type condTime struct { - V time.Time ",omitempty" -} -type condStruct struct { - V struct{ A []int } ",omitempty" -} -type condRaw struct { - V bson.Raw ",omitempty" -} - -type shortInt struct { - V int64 ",minsize" -} -type shortUint struct { - V uint64 ",minsize" -} -type shortIface struct { - V interface{} ",minsize" -} -type shortPtr struct { - V *int64 ",minsize" -} -type shortNonEmptyInt struct { - V int64 ",minsize,omitempty" -} - -type inlineInt struct { - V struct{ A, B int } ",inline" -} -type inlineCantPtr struct { - V *struct{ A, B int } ",inline" -} -type inlineDupName struct { - A int - V struct{ A, B int } ",inline" -} -type inlineMap struct { - A int - M map[string]interface{} ",inline" -} -type inlineMapInt struct { - A int - M map[string]int ",inline" -} -type inlineMapMyM struct { - A int - M MyM ",inline" -} -type inlineDupMap struct { - M1 map[string]interface{} ",inline" - M2 map[string]interface{} ",inline" -} -type inlineBadKeyMap struct { - M map[int]int ",inline" -} -type inlineUnexported struct { - M map[string]interface{} ",inline" - unexported ",inline" -} -type unexported struct { - A int -} - -type getterSetterD bson.D - -func (s getterSetterD) GetBSON() (interface{}, error) { - if len(s) == 0 { - return bson.D{}, nil - } - return bson.D(s[:len(s)-1]), nil -} - -func (s *getterSetterD) SetBSON(raw bson.Raw) error { - var doc bson.D - err := raw.Unmarshal(&doc) - doc = append(doc, bson.DocElem{"suffix", true}) - *s = getterSetterD(doc) - return err -} - -type getterSetterInt int - -func (i getterSetterInt) GetBSON() (interface{}, error) { - return bson.D{{"a", int(i)}}, nil -} - -func (i *getterSetterInt) SetBSON(raw bson.Raw) error { - var doc struct{ A int } - err := raw.Unmarshal(&doc) - *i = getterSetterInt(doc.A) - return err -} - -type ifaceType interface { - Hello() -} - -type ifaceSlice []ifaceType - -func (s *ifaceSlice) SetBSON(raw bson.Raw) error { - var ns []int - if err := raw.Unmarshal(&ns); err != nil { - return err - } - *s = make(ifaceSlice, ns[0]) - return nil -} - -func (s ifaceSlice) GetBSON() (interface{}, error) { - return []int{len(s)}, nil -} - -type ( - MyString string - MyBytes []byte - MyBool bool - MyD []bson.DocElem - MyRawD []bson.RawDocElem - MyM map[string]interface{} -) - -var ( - truevar = true - falsevar = false - - int64var = int64(42) - int64ptr = &int64var - intvar = int(42) - intptr = &intvar - - gsintvar = getterSetterInt(42) -) - -func parseURL(s string) *url.URL { - u, err := url.Parse(s) - if err != nil { - panic(err) - } - return u -} - -// That's a pretty fun test. It will dump the first item, generate a zero -// value equivalent to the second one, load the dumped data onto it, and then -// verify that the resulting value is deep-equal to the untouched second value. -// Then, it will do the same in the *opposite* direction! -var twoWayCrossItems = []crossTypeItem{ - // int<=>int - {&struct{ I int }{42}, &struct{ I int8 }{42}}, - {&struct{ I int }{42}, &struct{ I int32 }{42}}, - {&struct{ I int }{42}, &struct{ I int64 }{42}}, - {&struct{ I int8 }{42}, &struct{ I int32 }{42}}, - {&struct{ I int8 }{42}, &struct{ I int64 }{42}}, - {&struct{ I int32 }{42}, &struct{ I int64 }{42}}, - - // uint<=>uint - {&struct{ I uint }{42}, &struct{ I uint8 }{42}}, - {&struct{ I uint }{42}, &struct{ I uint32 }{42}}, - {&struct{ I uint }{42}, &struct{ I uint64 }{42}}, - {&struct{ I uint8 }{42}, &struct{ I uint32 }{42}}, - {&struct{ I uint8 }{42}, &struct{ I uint64 }{42}}, - {&struct{ I uint32 }{42}, &struct{ I uint64 }{42}}, - - // float32<=>float64 - {&struct{ I float32 }{42}, &struct{ I float64 }{42}}, - - // int<=>uint - {&struct{ I uint }{42}, &struct{ I int }{42}}, - {&struct{ I uint }{42}, &struct{ I int8 }{42}}, - {&struct{ I uint }{42}, &struct{ I int32 }{42}}, - {&struct{ I uint }{42}, &struct{ I int64 }{42}}, - {&struct{ I uint8 }{42}, &struct{ I int }{42}}, - {&struct{ I uint8 }{42}, &struct{ I int8 }{42}}, - {&struct{ I uint8 }{42}, &struct{ I int32 }{42}}, - {&struct{ I uint8 }{42}, &struct{ I int64 }{42}}, - {&struct{ I uint32 }{42}, &struct{ I int }{42}}, - {&struct{ I uint32 }{42}, &struct{ I int8 }{42}}, - {&struct{ I uint32 }{42}, &struct{ I int32 }{42}}, - {&struct{ I uint32 }{42}, &struct{ I int64 }{42}}, - {&struct{ I uint64 }{42}, &struct{ I int }{42}}, - {&struct{ I uint64 }{42}, &struct{ I int8 }{42}}, - {&struct{ I uint64 }{42}, &struct{ I int32 }{42}}, - {&struct{ I uint64 }{42}, &struct{ I int64 }{42}}, - - // int <=> float - {&struct{ I int }{42}, &struct{ I float64 }{42}}, - - // int <=> bool - {&struct{ I int }{1}, &struct{ I bool }{true}}, - {&struct{ I int }{0}, &struct{ I bool }{false}}, - - // uint <=> float64 - {&struct{ I uint }{42}, &struct{ I float64 }{42}}, - - // uint <=> bool - {&struct{ I uint }{1}, &struct{ I bool }{true}}, - {&struct{ I uint }{0}, &struct{ I bool }{false}}, - - // float64 <=> bool - {&struct{ I float64 }{1}, &struct{ I bool }{true}}, - {&struct{ I float64 }{0}, &struct{ I bool }{false}}, - - // string <=> string and string <=> []byte - {&struct{ S []byte }{[]byte("abc")}, &struct{ S string }{"abc"}}, - {&struct{ S []byte }{[]byte("def")}, &struct{ S bson.Symbol }{"def"}}, - {&struct{ S string }{"ghi"}, &struct{ S bson.Symbol }{"ghi"}}, - - // map <=> struct - {&struct { - A struct { - B, C int - } - }{struct{ B, C int }{1, 2}}, - map[string]map[string]int{"a": map[string]int{"b": 1, "c": 2}}}, - - {&struct{ A bson.Symbol }{"abc"}, map[string]string{"a": "abc"}}, - {&struct{ A bson.Symbol }{"abc"}, map[string][]byte{"a": []byte("abc")}}, - {&struct{ A []byte }{[]byte("abc")}, map[string]string{"a": "abc"}}, - {&struct{ A uint }{42}, map[string]int{"a": 42}}, - {&struct{ A uint }{42}, map[string]float64{"a": 42}}, - {&struct{ A uint }{1}, map[string]bool{"a": true}}, - {&struct{ A int }{42}, map[string]uint{"a": 42}}, - {&struct{ A int }{42}, map[string]float64{"a": 42}}, - {&struct{ A int }{1}, map[string]bool{"a": true}}, - {&struct{ A float64 }{42}, map[string]float32{"a": 42}}, - {&struct{ A float64 }{42}, map[string]int{"a": 42}}, - {&struct{ A float64 }{42}, map[string]uint{"a": 42}}, - {&struct{ A float64 }{1}, map[string]bool{"a": true}}, - {&struct{ A bool }{true}, map[string]int{"a": 1}}, - {&struct{ A bool }{true}, map[string]uint{"a": 1}}, - {&struct{ A bool }{true}, map[string]float64{"a": 1}}, - {&struct{ A **byte }{&byteptr}, map[string]byte{"a": 8}}, - - // url.URL <=> string - {&struct{ URL *url.URL }{parseURL("h://e.c/p")}, map[string]string{"url": "h://e.c/p"}}, - {&struct{ URL url.URL }{*parseURL("h://e.c/p")}, map[string]string{"url": "h://e.c/p"}}, - - // Slices - {&struct{ S []int }{[]int{1, 2, 3}}, map[string][]int{"s": []int{1, 2, 3}}}, - {&struct{ S *[]int }{&[]int{1, 2, 3}}, map[string][]int{"s": []int{1, 2, 3}}}, - - // Conditionals - {&condBool{true}, map[string]bool{"v": true}}, - {&condBool{}, map[string]bool{}}, - {&condInt{1}, map[string]int{"v": 1}}, - {&condInt{}, map[string]int{}}, - {&condUInt{1}, map[string]uint{"v": 1}}, - {&condUInt{}, map[string]uint{}}, - {&condFloat{}, map[string]int{}}, - {&condStr{"yo"}, map[string]string{"v": "yo"}}, - {&condStr{}, map[string]string{}}, - {&condStrNS{"yo"}, map[string]string{"v": "yo"}}, - {&condStrNS{}, map[string]string{}}, - {&condSlice{[]string{"yo"}}, map[string][]string{"v": []string{"yo"}}}, - {&condSlice{}, map[string][]string{}}, - {&condMap{map[string]int{"k": 1}}, bson.M{"v": bson.M{"k": 1}}}, - {&condMap{}, map[string][]string{}}, - {&condIface{"yo"}, map[string]string{"v": "yo"}}, - {&condIface{""}, map[string]string{"v": ""}}, - {&condIface{}, map[string]string{}}, - {&condPtr{&truevar}, map[string]bool{"v": true}}, - {&condPtr{&falsevar}, map[string]bool{"v": false}}, - {&condPtr{}, map[string]string{}}, - - {&condTime{time.Unix(123456789, 123e6)}, map[string]time.Time{"v": time.Unix(123456789, 123e6)}}, - {&condTime{}, map[string]string{}}, - - {&condStruct{struct{ A []int }{[]int{1}}}, bson.M{"v": bson.M{"a": []interface{}{1}}}}, - {&condStruct{struct{ A []int }{}}, bson.M{}}, - - {&condRaw{bson.Raw{Kind: 0x0A, Data: []byte{}}}, bson.M{"v": nil}}, - {&condRaw{bson.Raw{Kind: 0x00}}, bson.M{}}, - - {&namedCondStr{"yo"}, map[string]string{"myv": "yo"}}, - {&namedCondStr{}, map[string]string{}}, - - {&shortInt{1}, map[string]interface{}{"v": 1}}, - {&shortInt{1 << 30}, map[string]interface{}{"v": 1 << 30}}, - {&shortInt{1 << 31}, map[string]interface{}{"v": int64(1 << 31)}}, - {&shortUint{1 << 30}, map[string]interface{}{"v": 1 << 30}}, - {&shortUint{1 << 31}, map[string]interface{}{"v": int64(1 << 31)}}, - {&shortIface{int64(1) << 31}, map[string]interface{}{"v": int64(1 << 31)}}, - {&shortPtr{int64ptr}, map[string]interface{}{"v": intvar}}, - - {&shortNonEmptyInt{1}, map[string]interface{}{"v": 1}}, - {&shortNonEmptyInt{1 << 31}, map[string]interface{}{"v": int64(1 << 31)}}, - {&shortNonEmptyInt{}, map[string]interface{}{}}, - - {&inlineInt{struct{ A, B int }{1, 2}}, map[string]interface{}{"a": 1, "b": 2}}, - {&inlineMap{A: 1, M: map[string]interface{}{"b": 2}}, map[string]interface{}{"a": 1, "b": 2}}, - {&inlineMap{A: 1, M: nil}, map[string]interface{}{"a": 1}}, - {&inlineMapInt{A: 1, M: map[string]int{"b": 2}}, map[string]int{"a": 1, "b": 2}}, - {&inlineMapInt{A: 1, M: nil}, map[string]int{"a": 1}}, - {&inlineMapMyM{A: 1, M: MyM{"b": MyM{"c": 3}}}, map[string]interface{}{"a": 1, "b": map[string]interface{}{"c": 3}}}, - {&inlineUnexported{M: map[string]interface{}{"b": 1}, unexported: unexported{A: 2}}, map[string]interface{}{"b": 1, "a": 2}}, - - // []byte <=> Binary - {&struct{ B []byte }{[]byte("abc")}, map[string]bson.Binary{"b": bson.Binary{Data: []byte("abc")}}}, - - // []byte <=> MyBytes - {&struct{ B MyBytes }{[]byte("abc")}, map[string]string{"b": "abc"}}, - {&struct{ B MyBytes }{[]byte{}}, map[string]string{"b": ""}}, - {&struct{ B MyBytes }{}, map[string]bool{}}, - {&struct{ B []byte }{[]byte("abc")}, map[string]MyBytes{"b": []byte("abc")}}, - - // bool <=> MyBool - {&struct{ B MyBool }{true}, map[string]bool{"b": true}}, - {&struct{ B MyBool }{}, map[string]bool{"b": false}}, - {&struct{ B MyBool }{}, map[string]string{}}, - {&struct{ B bool }{}, map[string]MyBool{"b": false}}, - - // arrays - {&struct{ V [2]int }{[...]int{1, 2}}, map[string][2]int{"v": [2]int{1, 2}}}, - {&struct{ V [2]byte }{[...]byte{1, 2}}, map[string][2]byte{"v": [2]byte{1, 2}}}, - - // zero time - {&struct{ V time.Time }{}, map[string]interface{}{"v": time.Time{}}}, - - // zero time + 1 second + 1 millisecond; overflows int64 as nanoseconds - {&struct{ V time.Time }{time.Unix(-62135596799, 1e6).Local()}, - map[string]interface{}{"v": time.Unix(-62135596799, 1e6).Local()}}, - - // bson.D <=> []DocElem - {&bson.D{{"a", bson.D{{"b", 1}, {"c", 2}}}}, &bson.D{{"a", bson.D{{"b", 1}, {"c", 2}}}}}, - {&bson.D{{"a", bson.D{{"b", 1}, {"c", 2}}}}, &MyD{{"a", MyD{{"b", 1}, {"c", 2}}}}}, - {&struct{ V MyD }{MyD{{"a", 1}}}, &bson.D{{"v", bson.D{{"a", 1}}}}}, - - // bson.RawD <=> []RawDocElem - {&bson.RawD{{"a", bson.Raw{0x08, []byte{0x01}}}}, &bson.RawD{{"a", bson.Raw{0x08, []byte{0x01}}}}}, - {&bson.RawD{{"a", bson.Raw{0x08, []byte{0x01}}}}, &MyRawD{{"a", bson.Raw{0x08, []byte{0x01}}}}}, - - // bson.M <=> map - {bson.M{"a": bson.M{"b": 1, "c": 2}}, MyM{"a": MyM{"b": 1, "c": 2}}}, - {bson.M{"a": bson.M{"b": 1, "c": 2}}, map[string]interface{}{"a": map[string]interface{}{"b": 1, "c": 2}}}, - - // bson.M <=> map[MyString] - {bson.M{"a": bson.M{"b": 1, "c": 2}}, map[MyString]interface{}{"a": map[MyString]interface{}{"b": 1, "c": 2}}}, - - // json.Number <=> int64, float64 - {&struct{ N json.Number }{"5"}, map[string]interface{}{"n": int64(5)}}, - {&struct{ N json.Number }{"5.05"}, map[string]interface{}{"n": 5.05}}, - {&struct{ N json.Number }{"9223372036854776000"}, map[string]interface{}{"n": float64(1 << 63)}}, - - // bson.D <=> non-struct getter/setter - {&bson.D{{"a", 1}}, &getterSetterD{{"a", 1}, {"suffix", true}}}, - {&bson.D{{"a", 42}}, &gsintvar}, - - // Interface slice setter. - {&struct{ V ifaceSlice }{ifaceSlice{nil, nil, nil}}, bson.M{"v": []interface{}{3}}}, -} - -// Same thing, but only one way (obj1 => obj2). -var oneWayCrossItems = []crossTypeItem{ - // map <=> struct - {map[string]interface{}{"a": 1, "b": "2", "c": 3}, map[string]int{"a": 1, "c": 3}}, - - // inline map elides badly typed values - {map[string]interface{}{"a": 1, "b": "2", "c": 3}, &inlineMapInt{A: 1, M: map[string]int{"c": 3}}}, - - // Can't decode int into struct. - {bson.M{"a": bson.M{"b": 2}}, &struct{ A bool }{}}, - - // Would get decoded into a int32 too in the opposite direction. - {&shortIface{int64(1) << 30}, map[string]interface{}{"v": 1 << 30}}, - - // Ensure omitempty on struct with private fields works properly. - {&struct { - V struct{ v time.Time } ",omitempty" - }{}, map[string]interface{}{}}, - - // Attempt to marshal slice into RawD (issue #120). - {bson.M{"x": []int{1, 2, 3}}, &struct{ X bson.RawD }{}}, -} - -func testCrossPair(c *C, dump interface{}, load interface{}) { - c.Logf("Dump: %#v", dump) - c.Logf("Load: %#v", load) - zero := makeZeroDoc(load) - data, err := bson.Marshal(dump) - c.Assert(err, IsNil) - c.Logf("Dumped: %#v", string(data)) - err = bson.Unmarshal(data, zero) - c.Assert(err, IsNil) - c.Logf("Loaded: %#v", zero) - c.Assert(zero, DeepEquals, load) -} - -func (s *S) TestTwoWayCrossPairs(c *C) { - for _, item := range twoWayCrossItems { - testCrossPair(c, item.obj1, item.obj2) - testCrossPair(c, item.obj2, item.obj1) - } -} - -func (s *S) TestOneWayCrossPairs(c *C) { - for _, item := range oneWayCrossItems { - testCrossPair(c, item.obj1, item.obj2) - } -} - -// -------------------------------------------------------------------------- -// ObjectId hex representation test. - -func (s *S) TestObjectIdHex(c *C) { - id := bson.ObjectIdHex("4d88e15b60f486e428412dc9") - c.Assert(id.String(), Equals, `ObjectIdHex("4d88e15b60f486e428412dc9")`) - c.Assert(id.Hex(), Equals, "4d88e15b60f486e428412dc9") -} - -func (s *S) TestIsObjectIdHex(c *C) { - test := []struct { - id string - valid bool - }{ - {"4d88e15b60f486e428412dc9", true}, - {"4d88e15b60f486e428412dc", false}, - {"4d88e15b60f486e428412dc9e", false}, - {"4d88e15b60f486e428412dcx", false}, - } - for _, t := range test { - c.Assert(bson.IsObjectIdHex(t.id), Equals, t.valid) - } -} - -// -------------------------------------------------------------------------- -// ObjectId parts extraction tests. - -type objectIdParts struct { - id bson.ObjectId - timestamp int64 - machine []byte - pid uint16 - counter int32 -} - -var objectIds = []objectIdParts{ - objectIdParts{ - bson.ObjectIdHex("4d88e15b60f486e428412dc9"), - 1300816219, - []byte{0x60, 0xf4, 0x86}, - 0xe428, - 4271561, - }, - objectIdParts{ - bson.ObjectIdHex("000000000000000000000000"), - 0, - []byte{0x00, 0x00, 0x00}, - 0x0000, - 0, - }, - objectIdParts{ - bson.ObjectIdHex("00000000aabbccddee000001"), - 0, - []byte{0xaa, 0xbb, 0xcc}, - 0xddee, - 1, - }, -} - -func (s *S) TestObjectIdPartsExtraction(c *C) { - for i, v := range objectIds { - t := time.Unix(v.timestamp, 0) - c.Assert(v.id.Time(), Equals, t, Commentf("#%d Wrong timestamp value", i)) - c.Assert(v.id.Machine(), DeepEquals, v.machine, Commentf("#%d Wrong machine id value", i)) - c.Assert(v.id.Pid(), Equals, v.pid, Commentf("#%d Wrong pid value", i)) - c.Assert(v.id.Counter(), Equals, v.counter, Commentf("#%d Wrong counter value", i)) - } -} - -func (s *S) TestNow(c *C) { - before := time.Now() - time.Sleep(1e6) - now := bson.Now() - time.Sleep(1e6) - after := time.Now() - c.Assert(now.After(before) && now.Before(after), Equals, true, Commentf("now=%s, before=%s, after=%s", now, before, after)) -} - -// -------------------------------------------------------------------------- -// ObjectId generation tests. - -func (s *S) TestNewObjectId(c *C) { - // Generate 10 ids - ids := make([]bson.ObjectId, 10) - for i := 0; i < 10; i++ { - ids[i] = bson.NewObjectId() - } - for i := 1; i < 10; i++ { - prevId := ids[i-1] - id := ids[i] - // Test for uniqueness among all other 9 generated ids - for j, tid := range ids { - if j != i { - c.Assert(id, Not(Equals), tid, Commentf("Generated ObjectId is not unique")) - } - } - // Check that timestamp was incremented and is within 30 seconds of the previous one - secs := id.Time().Sub(prevId.Time()).Seconds() - c.Assert((secs >= 0 && secs <= 30), Equals, true, Commentf("Wrong timestamp in generated ObjectId")) - // Check that machine ids are the same - c.Assert(id.Machine(), DeepEquals, prevId.Machine()) - // Check that pids are the same - c.Assert(id.Pid(), Equals, prevId.Pid()) - // Test for proper increment - delta := int(id.Counter() - prevId.Counter()) - c.Assert(delta, Equals, 1, Commentf("Wrong increment in generated ObjectId")) - } -} - -func (s *S) TestNewObjectIdWithTime(c *C) { - t := time.Unix(12345678, 0) - id := bson.NewObjectIdWithTime(t) - c.Assert(id.Time(), Equals, t) - c.Assert(id.Machine(), DeepEquals, []byte{0x00, 0x00, 0x00}) - c.Assert(int(id.Pid()), Equals, 0) - c.Assert(int(id.Counter()), Equals, 0) -} - -// -------------------------------------------------------------------------- -// ObjectId JSON marshalling. - -type jsonType struct { - Id bson.ObjectId -} - -var jsonIdTests = []struct { - value jsonType - json string - marshal bool - unmarshal bool - error string -}{{ - value: jsonType{Id: bson.ObjectIdHex("4d88e15b60f486e428412dc9")}, - json: `{"Id":"4d88e15b60f486e428412dc9"}`, - marshal: true, - unmarshal: true, -}, { - value: jsonType{}, - json: `{"Id":""}`, - marshal: true, - unmarshal: true, -}, { - value: jsonType{}, - json: `{"Id":null}`, - marshal: false, - unmarshal: true, -}, { - json: `{"Id":"4d88e15b60f486e428412dc9A"}`, - error: `invalid ObjectId in JSON: "4d88e15b60f486e428412dc9A"`, - marshal: false, - unmarshal: true, -}, { - json: `{"Id":"4d88e15b60f486e428412dcZ"}`, - error: `invalid ObjectId in JSON: "4d88e15b60f486e428412dcZ" .*`, - marshal: false, - unmarshal: true, -}} - -func (s *S) TestObjectIdJSONMarshaling(c *C) { - for _, test := range jsonIdTests { - if test.marshal { - data, err := json.Marshal(&test.value) - if test.error == "" { - c.Assert(err, IsNil) - c.Assert(string(data), Equals, test.json) - } else { - c.Assert(err, ErrorMatches, test.error) - } - } - - if test.unmarshal { - var value jsonType - err := json.Unmarshal([]byte(test.json), &value) - if test.error == "" { - c.Assert(err, IsNil) - c.Assert(value, DeepEquals, test.value) - } else { - c.Assert(err, ErrorMatches, test.error) - } - } - } -} - -// -------------------------------------------------------------------------- -// Spec tests - -type specTest struct { - Description string - Documents []struct { - Decoded map[string]interface{} - Encoded string - DecodeOnly bool `yaml:"decodeOnly"` - Error interface{} - } -} - -func (s *S) TestSpecTests(c *C) { - for _, data := range specTests { - var test specTest - err := yaml.Unmarshal([]byte(data), &test) - c.Assert(err, IsNil) - - c.Logf("Running spec test set %q", test.Description) - - for _, doc := range test.Documents { - if doc.Error != nil { - continue - } - c.Logf("Ensuring %q decodes as %v", doc.Encoded, doc.Decoded) - var decoded map[string]interface{} - encoded, err := hex.DecodeString(doc.Encoded) - c.Assert(err, IsNil) - err = bson.Unmarshal(encoded, &decoded) - c.Assert(err, IsNil) - c.Assert(decoded, DeepEquals, doc.Decoded) - } - - for _, doc := range test.Documents { - if doc.DecodeOnly || doc.Error != nil { - continue - } - c.Logf("Ensuring %v encodes as %q", doc.Decoded, doc.Encoded) - encoded, err := bson.Marshal(doc.Decoded) - c.Assert(err, IsNil) - c.Assert(strings.ToUpper(hex.EncodeToString(encoded)), Equals, doc.Encoded) - } - - for _, doc := range test.Documents { - if doc.Error == nil { - continue - } - c.Logf("Ensuring %q errors when decoded: %s", doc.Encoded, doc.Error) - var decoded map[string]interface{} - encoded, err := hex.DecodeString(doc.Encoded) - c.Assert(err, IsNil) - err = bson.Unmarshal(encoded, &decoded) - c.Assert(err, NotNil) - c.Logf("Failed with: %v", err) - } - } -} - -// -------------------------------------------------------------------------- -// ObjectId Text encoding.TextUnmarshaler. - -var textIdTests = []struct { - value bson.ObjectId - text string - marshal bool - unmarshal bool - error string -}{{ - value: bson.ObjectIdHex("4d88e15b60f486e428412dc9"), - text: "4d88e15b60f486e428412dc9", - marshal: true, - unmarshal: true, -}, { - text: "", - marshal: true, - unmarshal: true, -}, { - text: "4d88e15b60f486e428412dc9A", - marshal: false, - unmarshal: true, - error: `invalid ObjectId: 4d88e15b60f486e428412dc9A`, -}, { - text: "4d88e15b60f486e428412dcZ", - marshal: false, - unmarshal: true, - error: `invalid ObjectId: 4d88e15b60f486e428412dcZ .*`, -}} - -func (s *S) TestObjectIdTextMarshaling(c *C) { - for _, test := range textIdTests { - if test.marshal { - data, err := test.value.MarshalText() - if test.error == "" { - c.Assert(err, IsNil) - c.Assert(string(data), Equals, test.text) - } else { - c.Assert(err, ErrorMatches, test.error) - } - } - - if test.unmarshal { - err := test.value.UnmarshalText([]byte(test.text)) - if test.error == "" { - c.Assert(err, IsNil) - if test.value != "" { - value := bson.ObjectIdHex(test.text) - c.Assert(value, DeepEquals, test.value) - } - } else { - c.Assert(err, ErrorMatches, test.error) - } - } - } -} - -// -------------------------------------------------------------------------- -// ObjectId XML marshalling. - -type xmlType struct { - Id bson.ObjectId -} - -var xmlIdTests = []struct { - value xmlType - xml string - marshal bool - unmarshal bool - error string -}{{ - value: xmlType{Id: bson.ObjectIdHex("4d88e15b60f486e428412dc9")}, - xml: "4d88e15b60f486e428412dc9", - marshal: true, - unmarshal: true, -}, { - value: xmlType{}, - xml: "", - marshal: true, - unmarshal: true, -}, { - xml: "4d88e15b60f486e428412dc9A", - marshal: false, - unmarshal: true, - error: `invalid ObjectId: 4d88e15b60f486e428412dc9A`, -}, { - xml: "4d88e15b60f486e428412dcZ", - marshal: false, - unmarshal: true, - error: `invalid ObjectId: 4d88e15b60f486e428412dcZ .*`, -}} - -func (s *S) TestObjectIdXMLMarshaling(c *C) { - for _, test := range xmlIdTests { - if test.marshal { - data, err := xml.Marshal(&test.value) - if test.error == "" { - c.Assert(err, IsNil) - c.Assert(string(data), Equals, test.xml) - } else { - c.Assert(err, ErrorMatches, test.error) - } - } - - if test.unmarshal { - var value xmlType - err := xml.Unmarshal([]byte(test.xml), &value) - if test.error == "" { - c.Assert(err, IsNil) - c.Assert(value, DeepEquals, test.value) - } else { - c.Assert(err, ErrorMatches, test.error) - } - } - } -} - -// -------------------------------------------------------------------------- -// Some simple benchmarks. - -type BenchT struct { - A, B, C, D, E, F string -} - -type BenchRawT struct { - A string - B int - C bson.M - D []float64 -} - -func (s *S) BenchmarkUnmarhsalStruct(c *C) { - v := BenchT{A: "A", D: "D", E: "E"} - data, err := bson.Marshal(&v) - if err != nil { - panic(err) - } - c.ResetTimer() - for i := 0; i < c.N; i++ { - err = bson.Unmarshal(data, &v) - } - if err != nil { - panic(err) - } -} - -func (s *S) BenchmarkUnmarhsalMap(c *C) { - m := bson.M{"a": "a", "d": "d", "e": "e"} - data, err := bson.Marshal(&m) - if err != nil { - panic(err) - } - c.ResetTimer() - for i := 0; i < c.N; i++ { - err = bson.Unmarshal(data, &m) - } - if err != nil { - panic(err) - } -} - -func (s *S) BenchmarkUnmarshalRaw(c *C) { - var err error - m := BenchRawT{ - A: "test_string", - B: 123, - C: bson.M{ - "subdoc_int": 12312, - "subdoc_doc": bson.M{"1": 1}, - }, - D: []float64{0.0, 1.3333, -99.9997, 3.1415}, - } - data, err := bson.Marshal(&m) - if err != nil { - panic(err) - } - raw := bson.Raw{} - c.ResetTimer() - for i := 0; i < c.N; i++ { - err = bson.Unmarshal(data, &raw) - } - if err != nil { - panic(err) - } -} - -func (s *S) BenchmarkNewObjectId(c *C) { - for i := 0; i < c.N; i++ { - bson.NewObjectId() - } -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/decimal.go b/vendor/gopkg.in.o/mgo.v2/bson/decimal.go deleted file mode 100644 index 3d2f70020..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/decimal.go +++ /dev/null @@ -1,310 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bson - -import ( - "fmt" - "strconv" - "strings" -) - -// Decimal128 holds decimal128 BSON values. -type Decimal128 struct { - h, l uint64 -} - -func (d Decimal128) String() string { - var pos int // positive sign - var e int // exponent - var h, l uint64 // significand high/low - - if d.h>>63&1 == 0 { - pos = 1 - } - - switch d.h >> 58 & (1<<5 - 1) { - case 0x1F: - return "NaN" - case 0x1E: - return "-Inf"[pos:] - } - - l = d.l - if d.h>>61&3 == 3 { - // Bits: 1*sign 2*ignored 14*exponent 111*significand. - // Implicit 0b100 prefix in significand. - e = int(d.h>>47&(1<<14-1)) - 6176 - //h = 4<<47 | d.h&(1<<47-1) - // Spec says all of these values are out of range. - h, l = 0, 0 - } else { - // Bits: 1*sign 14*exponent 113*significand - e = int(d.h>>49&(1<<14-1)) - 6176 - h = d.h & (1<<49 - 1) - } - - // Would be handled by the logic below, but that's trivial and common. - if h == 0 && l == 0 && e == 0 { - return "-0"[pos:] - } - - var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero. - var last = len(repr) - var i = len(repr) - var dot = len(repr) + e - var rem uint32 -Loop: - for d9 := 0; d9 < 5; d9++ { - h, l, rem = divmod(h, l, 1e9) - for d1 := 0; d1 < 9; d1++ { - // Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc. - if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) { - e += len(repr) - i - i-- - repr[i] = '.' - last = i - 1 - dot = len(repr) // Unmark. - } - c := '0' + byte(rem%10) - rem /= 10 - i-- - repr[i] = c - // Handle "0E+3", "1E+3", etc. - if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) { - last = i - break Loop - } - if c != '0' { - last = i - } - // Break early. Works without it, but why. - if dot > i && l == 0 && h == 0 && rem == 0 { - break Loop - } - } - } - repr[last-1] = '-' - last-- - - if e > 0 { - return string(repr[last+pos:]) + "E+" + strconv.Itoa(e) - } - if e < 0 { - return string(repr[last+pos:]) + "E" + strconv.Itoa(e) - } - return string(repr[last+pos:]) -} - -func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) { - div64 := uint64(div) - a := h >> 32 - aq := a / div64 - ar := a % div64 - b := ar<<32 + h&(1<<32-1) - bq := b / div64 - br := b % div64 - c := br<<32 + l>>32 - cq := c / div64 - cr := c % div64 - d := cr<<32 + l&(1<<32-1) - dq := d / div64 - dr := d % div64 - return (aq<<32 | bq), (cq<<32 | dq), uint32(dr) -} - -var dNaN = Decimal128{0x1F << 58, 0} -var dPosInf = Decimal128{0x1E << 58, 0} -var dNegInf = Decimal128{0x3E << 58, 0} - -func dErr(s string) (Decimal128, error) { - return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s) -} - -func ParseDecimal128(s string) (Decimal128, error) { - orig := s - if s == "" { - return dErr(orig) - } - neg := s[0] == '-' - if neg || s[0] == '+' { - s = s[1:] - } - - if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') { - if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") { - return dNaN, nil - } - if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { - if neg { - return dNegInf, nil - } - return dPosInf, nil - } - return dErr(orig) - } - - var h, l uint64 - var e int - - var add, ovr uint32 - var mul uint32 = 1 - var dot = -1 - var digits = 0 - var i = 0 - for i < len(s) { - c := s[i] - if mul == 1e9 { - h, l, ovr = muladd(h, l, mul, add) - mul, add = 1, 0 - if ovr > 0 || h&((1<<15-1)<<49) > 0 { - return dErr(orig) - } - } - if c >= '0' && c <= '9' { - i++ - if c > '0' || digits > 0 { - digits++ - } - if digits > 34 { - if c == '0' { - // Exact rounding. - e++ - continue - } - return dErr(orig) - } - mul *= 10 - add *= 10 - add += uint32(c - '0') - continue - } - if c == '.' { - i++ - if dot >= 0 || i == 1 && len(s) == 1 { - return dErr(orig) - } - if i == len(s) { - break - } - if s[i] < '0' || s[i] > '9' || e > 0 { - return dErr(orig) - } - dot = i - continue - } - break - } - if i == 0 { - return dErr(orig) - } - if mul > 1 { - h, l, ovr = muladd(h, l, mul, add) - if ovr > 0 || h&((1<<15-1)<<49) > 0 { - return dErr(orig) - } - } - if dot >= 0 { - e += dot - i - } - if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') { - i++ - eneg := s[i] == '-' - if eneg || s[i] == '+' { - i++ - if i == len(s) { - return dErr(orig) - } - } - n := 0 - for i < len(s) && n < 1e4 { - c := s[i] - i++ - if c < '0' || c > '9' { - return dErr(orig) - } - n *= 10 - n += int(c - '0') - } - if eneg { - n = -n - } - e += n - for e < -6176 { - // Subnormal. - var div uint32 = 1 - for div < 1e9 && e < -6176 { - div *= 10 - e++ - } - var rem uint32 - h, l, rem = divmod(h, l, div) - if rem > 0 { - return dErr(orig) - } - } - for e > 6111 { - // Clamped. - var mul uint32 = 1 - for mul < 1e9 && e > 6111 { - mul *= 10 - e-- - } - h, l, ovr = muladd(h, l, mul, 0) - if ovr > 0 || h&((1<<15-1)<<49) > 0 { - return dErr(orig) - } - } - if e < -6176 || e > 6111 { - return dErr(orig) - } - } - - if i < len(s) { - return dErr(orig) - } - - h |= uint64(e+6176) & uint64(1<<14-1) << 49 - if neg { - h |= 1 << 63 - } - return Decimal128{h, l}, nil -} - -func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) { - mul64 := uint64(mul) - a := mul64 * (l & (1<<32 - 1)) - b := a>>32 + mul64*(l>>32) - c := b>>32 + mul64*(h&(1<<32-1)) - d := c>>32 + mul64*(h>>32) - - a = a&(1<<32-1) + uint64(add) - b = b&(1<<32-1) + a>>32 - c = c&(1<<32-1) + b>>32 - d = d&(1<<32-1) + c>>32 - - return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32) -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/decimal_test.go b/vendor/gopkg.in.o/mgo.v2/bson/decimal_test.go deleted file mode 100644 index a29728094..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/decimal_test.go +++ /dev/null @@ -1,4109 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bson_test - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "regexp" - "strings" - - "gopkg.in/mgo.v2/bson" - - . "gopkg.in/check.v1" -) - -// -------------------------------------------------------------------------- -// Decimal tests - -type decimalTests struct { - Valid []struct { - Description string `json:"description"` - BSON string `json:"bson"` - CanonicalBSON string `json:"canonical_bson"` - ExtJSON string `json:"extjson"` - CanonicalExtJSON string `json:"canonical_extjson"` - Lossy bool `json:"lossy"` - } `json:"valid"` - - ParseErrors []struct { - Description string `json:"description"` - String string `json:"string"` - } `json:"parseErrors"` -} - -func extJSONRepr(s string) string { - var value struct { - D struct { - Repr string `json:"$numberDecimal"` - } `json:"d"` - } - err := json.Unmarshal([]byte(s), &value) - if err != nil { - panic(err) - } - return value.D.Repr -} - -func (s *S) TestDecimalTests(c *C) { - // These also conform to the spec and are used by Go elsewhere. - // (e.g. math/big won't parse "Infinity"). - goStr := func(s string) string { - switch s { - case "Infinity": - return "Inf" - case "-Infinity": - return "-Inf" - } - return s - } - - for _, testEntry := range decimalTestsJSON { - testFile := testEntry.file - - var tests decimalTests - err := json.Unmarshal([]byte(testEntry.json), &tests) - c.Assert(err, IsNil) - - for _, test := range tests.Valid { - c.Logf("Running %s test: %s", testFile, test.Description) - - test.BSON = strings.ToLower(test.BSON) - - // Unmarshal value from BSON data. - bsonData, err := hex.DecodeString(test.BSON) - var bsonValue struct{ D interface{} } - err = bson.Unmarshal(bsonData, &bsonValue) - c.Assert(err, IsNil) - dec128, ok := bsonValue.D.(bson.Decimal128) - c.Assert(ok, Equals, true) - - // Extract ExtJSON representations (canonical and not). - extjRepr := extJSONRepr(test.ExtJSON) - cextjRepr := extjRepr - if test.CanonicalExtJSON != "" { - cextjRepr = extJSONRepr(test.CanonicalExtJSON) - } - - wantRepr := goStr(cextjRepr) - - // Generate canonical representation. - c.Assert(dec128.String(), Equals, wantRepr) - - // Parse original canonical representation. - parsed, err := bson.ParseDecimal128(cextjRepr) - c.Assert(err, IsNil) - c.Assert(parsed.String(), Equals, wantRepr) - - // Parse non-canonical representation. - parsed, err = bson.ParseDecimal128(extjRepr) - c.Assert(err, IsNil) - c.Assert(parsed.String(), Equals, wantRepr) - - // Parse Go canonical representation (Inf vs. Infinity). - parsed, err = bson.ParseDecimal128(wantRepr) - c.Assert(err, IsNil) - c.Assert(parsed.String(), Equals, wantRepr) - - // Marshal original value back into BSON data. - data, err := bson.Marshal(bsonValue) - c.Assert(err, IsNil) - c.Assert(hex.EncodeToString(data), Equals, test.BSON) - - if test.Lossy { - continue - } - - // Marshal the parsed canonical representation. - var parsedValue struct{ D interface{} } - parsedValue.D = parsed - data, err = bson.Marshal(parsedValue) - c.Assert(err, IsNil) - c.Assert(hex.EncodeToString(data), Equals, test.BSON) - } - - for _, test := range tests.ParseErrors { - c.Logf("Running %s parse error test: %s (string %q)", testFile, test.Description, test.String) - - _, err := bson.ParseDecimal128(test.String) - quoted := regexp.QuoteMeta(fmt.Sprintf("%q", test.String)) - c.Assert(err, ErrorMatches, `cannot parse `+quoted+` as a decimal128`) - } - } -} - -const decBenchNum = "9.999999999999999999999999999999999E+6144" - -func (s *S) BenchmarkDecimal128String(c *C) { - d, err := bson.ParseDecimal128(decBenchNum) - c.Assert(err, IsNil) - c.Assert(d.String(), Equals, decBenchNum) - - c.ResetTimer() - for i := 0; i < c.N; i++ { - d.String() - } -} - -func (s *S) BenchmarkDecimal128Parse(c *C) { - var err error - c.ResetTimer() - for i := 0; i < c.N; i++ { - _, err = bson.ParseDecimal128(decBenchNum) - } - if err != nil { - panic(err) - } -} - -var decimalTestsJSON = []struct{ file, json string }{ - {"decimal128-1.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "valid": [ - { - "description": "Special - Canonical NaN", - "bson": "180000001364000000000000000000000000000000007C00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" - }, - { - "description": "Special - Negative NaN", - "bson": "18000000136400000000000000000000000000000000FC00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", - "lossy": true - }, - { - "description": "Special - Negative NaN", - "bson": "18000000136400000000000000000000000000000000FC00", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-NaN\"}}", - "lossy": true - }, - { - "description": "Special - Canonical SNaN", - "bson": "180000001364000000000000000000000000000000007E00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", - "lossy": true - }, - { - "description": "Special - Negative SNaN", - "bson": "18000000136400000000000000000000000000000000FE00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", - "lossy": true - }, - { - "description": "Special - NaN with a payload", - "bson": "180000001364001200000000000000000000000000007E00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}", - "lossy": true - }, - { - "description": "Special - Canonical Positive Infinity", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "Special - Canonical Negative Infinity", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "Special - Invalid representation treated as 0", - "bson": "180000001364000000000000000000000000000000106C00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}", - "lossy": true - }, - { - "description": "Special - Invalid representation treated as -0", - "bson": "18000000136400DCBA9876543210DEADBEEF00000010EC00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}", - "lossy": true - }, - { - "description": "Special - Invalid representation treated as 0E3", - "bson": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF116C00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}", - "lossy": true - }, - { - "description": "Regular - Adjusted Exponent Limit", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF22F00", - "extjson": "{\"d\": { \"$numberDecimal\": \"0.000001234567890123456789012345678901234\" }}" - }, - { - "description": "Regular - Smallest", - "bson": "18000000136400D204000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001234\"}}" - }, - { - "description": "Regular - Smallest with Trailing Zeros", - "bson": "1800000013640040EF5A07000000000000000000002A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00123400000\"}}" - }, - { - "description": "Regular - 0.1", - "bson": "1800000013640001000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1\"}}" - }, - { - "description": "Regular - 0.1234567890123456789012345678901234", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFC2F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1234567890123456789012345678901234\"}}" - }, - { - "description": "Regular - 0", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "Regular - -0", - "bson": "18000000136400000000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" - }, - { - "description": "Regular - -0.0", - "bson": "1800000013640000000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" - }, - { - "description": "Regular - 2", - "bson": "180000001364000200000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2\"}}" - }, - { - "description": "Regular - 2.000", - "bson": "18000000136400D0070000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2.000\"}}" - }, - { - "description": "Regular - Largest", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" - }, - { - "description": "Scientific - Tiniest", - "bson": "18000000136400FFFFFFFF638E8D37C087ADBE09ED010000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E-6143\"}}" - }, - { - "description": "Scientific - Tiny", - "bson": "180000001364000100000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" - }, - { - "description": "Scientific - Negative Tiny", - "bson": "180000001364000100000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" - }, - { - "description": "Scientific - Adjusted Exponent Limit", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF02F00", - "extjson": "{\"d\": { \"$numberDecimal\": \"1.234567890123456789012345678901234E-7\" }}" - }, - { - "description": "Scientific - Fractional", - "bson": "1800000013640064000000000000000000000000002CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}" - }, - { - "description": "Scientific - 0 with Exponent", - "bson": "180000001364000000000000000000000000000000205F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6000\"}}" - }, - { - "description": "Scientific - 0 with Negative Exponent", - "bson": "1800000013640000000000000000000000000000007A2B00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-611\"}}" - }, - { - "description": "Scientific - No Decimal with Signed Exponent", - "bson": "180000001364000100000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" - }, - { - "description": "Scientific - Trailing Zero", - "bson": "180000001364001A04000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.050E+4\"}}" - }, - { - "description": "Scientific - With Decimal", - "bson": "180000001364006900000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.05E+3\"}}" - }, - { - "description": "Scientific - Full", - "bson": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"5192296858534827628530496329220095\"}}" - }, - { - "description": "Scientific - Large", - "bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" - }, - { - "description": "Scientific - Largest", - "bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}" - }, - { - "description": "Non-Canonical Parsing - Exponent Normalization", - "bson": "1800000013640064000000000000000000000000002CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-100E-10\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}" - }, - { - "description": "Non-Canonical Parsing - Unsigned Positive Exponent", - "bson": "180000001364000100000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" - }, - { - "description": "Non-Canonical Parsing - Lowercase Exponent Identifier", - "bson": "180000001364000100000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}" - }, - { - "description": "Non-Canonical Parsing - Long Significand with Exponent", - "bson": "1800000013640079D9E0F9763ADA429D0200000000583000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12345689012345789012345E+12\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.2345689012345789012345E+34\"}}" - }, - { - "description": "Non-Canonical Parsing - Positive Sign", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+1234567890123456789012345678901234\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" - }, - { - "description": "Non-Canonical Parsing - Long Decimal String", - "bson": "180000001364000100000000000000000000000000722800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \".000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-999\"}}" - }, - { - "description": "Non-Canonical Parsing - nan", - "bson": "180000001364000000000000000000000000000000007C00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"nan\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" - }, - { - "description": "Non-Canonical Parsing - nAn", - "bson": "180000001364000000000000000000000000000000007C00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"nAn\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" - }, - { - "description": "Non-Canonical Parsing - +infinity", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+infinity\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - infinity", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"infinity\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - infiniTY", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"infiniTY\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - inf", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"inf\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - inF", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"inF\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - -infinity", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-infinity\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - -infiniTy", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-infiniTy\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - -Inf", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - -inf", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-inf\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "Non-Canonical Parsing - -inF", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-inF\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "Rounded Subnormal number", - "bson": "180000001364000100000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10E-6177\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" - }, - { - "description": "Clamped", - "bson": "180000001364000a00000000000000000000000000fe5f00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E6112\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}" - }, - { - "description": "Exact rounding", - "bson": "18000000136400000000000a5bc138938d44c64d31cc3700", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+999\"}}" - } - ] -} -`}, - - {"decimal128-2.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "valid": [ - { - "description": "[decq021] Normality", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C40B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1234567890123456789012345678901234\"}}" - }, - { - "description": "[decq823] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400010000800000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483649\"}}" - }, - { - "description": "[decq822] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400000000800000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483648\"}}" - }, - { - "description": "[decq821] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400FFFFFF7F0000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483647\"}}" - }, - { - "description": "[decq820] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400FEFFFF7F0000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483646\"}}" - }, - { - "description": "[decq152] fold-downs (more below)", - "bson": "18000000136400393000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-12345\"}}" - }, - { - "description": "[decq154] fold-downs (more below)", - "bson": "18000000136400D20400000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1234\"}}" - }, - { - "description": "[decq006] derivative canonical plain strings", - "bson": "18000000136400EE0200000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-750\"}}" - }, - { - "description": "[decq164] fold-downs (more below)", - "bson": "1800000013640039300000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-123.45\"}}" - }, - { - "description": "[decq156] fold-downs (more below)", - "bson": "180000001364007B0000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-123\"}}" - }, - { - "description": "[decq008] derivative canonical plain strings", - "bson": "18000000136400EE020000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-75.0\"}}" - }, - { - "description": "[decq158] fold-downs (more below)", - "bson": "180000001364000C0000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-12\"}}" - }, - { - "description": "[decq122] Nmax and similar", - "bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFFDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.999999999999999999999999999999999E+6144\"}}" - }, - { - "description": "[decq002] (mostly derived from the Strawman 4 document and examples)", - "bson": "18000000136400EE020000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50\"}}" - }, - { - "description": "[decq004] derivative canonical plain strings", - "bson": "18000000136400EE0200000000000000000000000042B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50E+3\"}}" - }, - { - "description": "[decq018] derivative canonical plain strings", - "bson": "18000000136400EE020000000000000000000000002EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50E-7\"}}" - }, - { - "description": "[decq125] Nmax and similar", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.234567890123456789012345678901234E+6144\"}}" - }, - { - "description": "[decq131] fold-downs (more below)", - "bson": "18000000136400000000807F1BCF85B27059C8A43CFEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.230000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq162] fold-downs (more below)", - "bson": "180000001364007B000000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.23\"}}" - }, - { - "description": "[decq176] Nmin and below", - "bson": "18000000136400010000000A5BC138938D44C64D31008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000001E-6143\"}}" - }, - { - "description": "[decq174] Nmin and below", - "bson": "18000000136400000000000A5BC138938D44C64D31008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E-6143\"}}" - }, - { - "description": "[decq133] fold-downs (more below)", - "bson": "18000000136400000000000A5BC138938D44C64D31FEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq160] fold-downs (more below)", - "bson": "18000000136400010000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1\"}}" - }, - { - "description": "[decq172] Nmin and below", - "bson": "180000001364000100000000000000000000000000428000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6143\"}}" - }, - { - "description": "[decq010] derivative canonical plain strings", - "bson": "18000000136400EE020000000000000000000000003AB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.750\"}}" - }, - { - "description": "[decq012] derivative canonical plain strings", - "bson": "18000000136400EE0200000000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0750\"}}" - }, - { - "description": "[decq014] derivative canonical plain strings", - "bson": "18000000136400EE0200000000000000000000000034B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000750\"}}" - }, - { - "description": "[decq016] derivative canonical plain strings", - "bson": "18000000136400EE0200000000000000000000000030B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000750\"}}" - }, - { - "description": "[decq404] zeros", - "bson": "180000001364000000000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" - }, - { - "description": "[decq424] negative zeros", - "bson": "180000001364000000000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" - }, - { - "description": "[decq407] zeros", - "bson": "1800000013640000000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" - }, - { - "description": "[decq427] negative zeros", - "bson": "1800000013640000000000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" - }, - { - "description": "[decq409] zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[decq428] negative zeros", - "bson": "18000000136400000000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" - }, - { - "description": "[decq700] Selected DPD codes", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[decq406] zeros", - "bson": "1800000013640000000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" - }, - { - "description": "[decq426] negative zeros", - "bson": "1800000013640000000000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" - }, - { - "description": "[decq410] zeros", - "bson": "180000001364000000000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" - }, - { - "description": "[decq431] negative zeros", - "bson": "18000000136400000000000000000000000000000046B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+3\"}}" - }, - { - "description": "[decq419] clamped zeros...", - "bson": "180000001364000000000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" - }, - { - "description": "[decq432] negative zeros", - "bson": "180000001364000000000000000000000000000000FEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" - }, - { - "description": "[decq405] zeros", - "bson": "180000001364000000000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" - }, - { - "description": "[decq425] negative zeros", - "bson": "180000001364000000000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" - }, - { - "description": "[decq508] Specials", - "bson": "180000001364000000000000000000000000000000007800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}" - }, - { - "description": "[decq528] Specials", - "bson": "18000000136400000000000000000000000000000000F800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}" - }, - { - "description": "[decq541] Specials", - "bson": "180000001364000000000000000000000000000000007C00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}" - }, - { - "description": "[decq074] Nmin and below", - "bson": "18000000136400000000000A5BC138938D44C64D31000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E-6143\"}}" - }, - { - "description": "[decq602] fold-down full sequence", - "bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq604] fold-down full sequence", - "bson": "180000001364000000000081EFAC855B416D2DEE04FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E+6143\"}}" - }, - { - "description": "[decq606] fold-down full sequence", - "bson": "1800000013640000000080264B91C02220BE377E00FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000000E+6142\"}}" - }, - { - "description": "[decq608] fold-down full sequence", - "bson": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000E+6141\"}}" - }, - { - "description": "[decq610] fold-down full sequence", - "bson": "18000000136400000000A0CA17726DAE0F1E430100FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000E+6140\"}}" - }, - { - "description": "[decq612] fold-down full sequence", - "bson": "18000000136400000000106102253E5ECE4F200000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000E+6139\"}}" - }, - { - "description": "[decq614] fold-down full sequence", - "bson": "18000000136400000000E83C80D09F3C2E3B030000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000E+6138\"}}" - }, - { - "description": "[decq616] fold-down full sequence", - "bson": "18000000136400000000E4D20CC8DCD2B752000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000E+6137\"}}" - }, - { - "description": "[decq618] fold-down full sequence", - "bson": "180000001364000000004A48011416954508000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000E+6136\"}}" - }, - { - "description": "[decq620] fold-down full sequence", - "bson": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000E+6135\"}}" - }, - { - "description": "[decq622] fold-down full sequence", - "bson": "18000000136400000080F64AE1C7022D1500000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000E+6134\"}}" - }, - { - "description": "[decq624] fold-down full sequence", - "bson": "18000000136400000040B2BAC9E0191E0200000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000E+6133\"}}" - }, - { - "description": "[decq626] fold-down full sequence", - "bson": "180000001364000000A0DEC5ADC935360000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000E+6132\"}}" - }, - { - "description": "[decq628] fold-down full sequence", - "bson": "18000000136400000010632D5EC76B050000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000E+6131\"}}" - }, - { - "description": "[decq630] fold-down full sequence", - "bson": "180000001364000000E8890423C78A000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000E+6130\"}}" - }, - { - "description": "[decq632] fold-down full sequence", - "bson": "18000000136400000064A7B3B6E00D000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000E+6129\"}}" - }, - { - "description": "[decq634] fold-down full sequence", - "bson": "1800000013640000008A5D78456301000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000E+6128\"}}" - }, - { - "description": "[decq636] fold-down full sequence", - "bson": "180000001364000000C16FF2862300000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000E+6127\"}}" - }, - { - "description": "[decq638] fold-down full sequence", - "bson": "180000001364000080C6A47E8D0300000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000E+6126\"}}" - }, - { - "description": "[decq640] fold-down full sequence", - "bson": "1800000013640000407A10F35A0000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000E+6125\"}}" - }, - { - "description": "[decq642] fold-down full sequence", - "bson": "1800000013640000A0724E18090000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000E+6124\"}}" - }, - { - "description": "[decq644] fold-down full sequence", - "bson": "180000001364000010A5D4E8000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000E+6123\"}}" - }, - { - "description": "[decq646] fold-down full sequence", - "bson": "1800000013640000E8764817000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000E+6122\"}}" - }, - { - "description": "[decq648] fold-down full sequence", - "bson": "1800000013640000E40B5402000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000E+6121\"}}" - }, - { - "description": "[decq650] fold-down full sequence", - "bson": "1800000013640000CA9A3B00000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000E+6120\"}}" - }, - { - "description": "[decq652] fold-down full sequence", - "bson": "1800000013640000E1F50500000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000E+6119\"}}" - }, - { - "description": "[decq654] fold-down full sequence", - "bson": "180000001364008096980000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000E+6118\"}}" - }, - { - "description": "[decq656] fold-down full sequence", - "bson": "1800000013640040420F0000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000E+6117\"}}" - }, - { - "description": "[decq658] fold-down full sequence", - "bson": "18000000136400A086010000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000E+6116\"}}" - }, - { - "description": "[decq660] fold-down full sequence", - "bson": "180000001364001027000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000E+6115\"}}" - }, - { - "description": "[decq662] fold-down full sequence", - "bson": "18000000136400E803000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000E+6114\"}}" - }, - { - "description": "[decq664] fold-down full sequence", - "bson": "180000001364006400000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+6113\"}}" - }, - { - "description": "[decq666] fold-down full sequence", - "bson": "180000001364000A00000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}" - }, - { - "description": "[decq060] fold-downs (more below)", - "bson": "180000001364000100000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1\"}}" - }, - { - "description": "[decq670] fold-down full sequence", - "bson": "180000001364000100000000000000000000000000FC5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6110\"}}" - }, - { - "description": "[decq668] fold-down full sequence", - "bson": "180000001364000100000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6111\"}}" - }, - { - "description": "[decq072] Nmin and below", - "bson": "180000001364000100000000000000000000000000420000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6143\"}}" - }, - { - "description": "[decq076] Nmin and below", - "bson": "18000000136400010000000A5BC138938D44C64D31000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000001E-6143\"}}" - }, - { - "description": "[decq036] fold-downs (more below)", - "bson": "18000000136400000000807F1BCF85B27059C8A43CFE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.230000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq062] fold-downs (more below)", - "bson": "180000001364007B000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23\"}}" - }, - { - "description": "[decq034] Nmax and similar", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.234567890123456789012345678901234E+6144\"}}" - }, - { - "description": "[decq441] exponent lengths", - "bson": "180000001364000700000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7\"}}" - }, - { - "description": "[decq449] exponent lengths", - "bson": "1800000013640007000000000000000000000000001E5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+5999\"}}" - }, - { - "description": "[decq447] exponent lengths", - "bson": "1800000013640007000000000000000000000000000E3800", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+999\"}}" - }, - { - "description": "[decq445] exponent lengths", - "bson": "180000001364000700000000000000000000000000063100", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+99\"}}" - }, - { - "description": "[decq443] exponent lengths", - "bson": "180000001364000700000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+9\"}}" - }, - { - "description": "[decq842] VG testcase", - "bson": "180000001364000000FED83F4E7C9FE4E269E38A5BCD1700", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7.049000000000010795488000000000000E-3097\"}}" - }, - { - "description": "[decq841] VG testcase", - "bson": "180000001364000000203B9DB5056F000000000000002400", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"8.000000000000000000E-1550\"}}" - }, - { - "description": "[decq840] VG testcase", - "bson": "180000001364003C17258419D710C42F0000000000002400", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"8.81125000000001349436E-1548\"}}" - }, - { - "description": "[decq701] Selected DPD codes", - "bson": "180000001364000900000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"9\"}}" - }, - { - "description": "[decq032] Nmax and similar", - "bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}" - }, - { - "description": "[decq702] Selected DPD codes", - "bson": "180000001364000A00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}" - }, - { - "description": "[decq057] fold-downs (more below)", - "bson": "180000001364000C00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12\"}}" - }, - { - "description": "[decq703] Selected DPD codes", - "bson": "180000001364001300000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"19\"}}" - }, - { - "description": "[decq704] Selected DPD codes", - "bson": "180000001364001400000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"20\"}}" - }, - { - "description": "[decq705] Selected DPD codes", - "bson": "180000001364001D00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"29\"}}" - }, - { - "description": "[decq706] Selected DPD codes", - "bson": "180000001364001E00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"30\"}}" - }, - { - "description": "[decq707] Selected DPD codes", - "bson": "180000001364002700000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"39\"}}" - }, - { - "description": "[decq708] Selected DPD codes", - "bson": "180000001364002800000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"40\"}}" - }, - { - "description": "[decq709] Selected DPD codes", - "bson": "180000001364003100000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"49\"}}" - }, - { - "description": "[decq710] Selected DPD codes", - "bson": "180000001364003200000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"50\"}}" - }, - { - "description": "[decq711] Selected DPD codes", - "bson": "180000001364003B00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"59\"}}" - }, - { - "description": "[decq712] Selected DPD codes", - "bson": "180000001364003C00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"60\"}}" - }, - { - "description": "[decq713] Selected DPD codes", - "bson": "180000001364004500000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"69\"}}" - }, - { - "description": "[decq714] Selected DPD codes", - "bson": "180000001364004600000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"70\"}}" - }, - { - "description": "[decq715] Selected DPD codes", - "bson": "180000001364004700000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"71\"}}" - }, - { - "description": "[decq716] Selected DPD codes", - "bson": "180000001364004800000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"72\"}}" - }, - { - "description": "[decq717] Selected DPD codes", - "bson": "180000001364004900000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"73\"}}" - }, - { - "description": "[decq718] Selected DPD codes", - "bson": "180000001364004A00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"74\"}}" - }, - { - "description": "[decq719] Selected DPD codes", - "bson": "180000001364004B00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"75\"}}" - }, - { - "description": "[decq720] Selected DPD codes", - "bson": "180000001364004C00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"76\"}}" - }, - { - "description": "[decq721] Selected DPD codes", - "bson": "180000001364004D00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"77\"}}" - }, - { - "description": "[decq722] Selected DPD codes", - "bson": "180000001364004E00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"78\"}}" - }, - { - "description": "[decq723] Selected DPD codes", - "bson": "180000001364004F00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"79\"}}" - }, - { - "description": "[decq056] fold-downs (more below)", - "bson": "180000001364007B00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"123\"}}" - }, - { - "description": "[decq064] fold-downs (more below)", - "bson": "1800000013640039300000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"123.45\"}}" - }, - { - "description": "[decq732] Selected DPD codes", - "bson": "180000001364000802000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"520\"}}" - }, - { - "description": "[decq733] Selected DPD codes", - "bson": "180000001364000902000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"521\"}}" - }, - { - "description": "[decq740] DPD: one of each of the huffman groups", - "bson": "180000001364000903000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"777\"}}" - }, - { - "description": "[decq741] DPD: one of each of the huffman groups", - "bson": "180000001364000A03000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"778\"}}" - }, - { - "description": "[decq742] DPD: one of each of the huffman groups", - "bson": "180000001364001303000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"787\"}}" - }, - { - "description": "[decq746] DPD: one of each of the huffman groups", - "bson": "180000001364001F03000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"799\"}}" - }, - { - "description": "[decq743] DPD: one of each of the huffman groups", - "bson": "180000001364006D03000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"877\"}}" - }, - { - "description": "[decq753] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "180000001364007803000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"888\"}}" - }, - { - "description": "[decq754] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "180000001364007903000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"889\"}}" - }, - { - "description": "[decq760] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "180000001364008203000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"898\"}}" - }, - { - "description": "[decq764] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "180000001364008303000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"899\"}}" - }, - { - "description": "[decq745] DPD: one of each of the huffman groups", - "bson": "18000000136400D303000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"979\"}}" - }, - { - "description": "[decq770] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "18000000136400DC03000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"988\"}}" - }, - { - "description": "[decq774] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "18000000136400DD03000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"989\"}}" - }, - { - "description": "[decq730] Selected DPD codes", - "bson": "18000000136400E203000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"994\"}}" - }, - { - "description": "[decq731] Selected DPD codes", - "bson": "18000000136400E303000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"995\"}}" - }, - { - "description": "[decq744] DPD: one of each of the huffman groups", - "bson": "18000000136400E503000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"997\"}}" - }, - { - "description": "[decq780] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "18000000136400E603000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"998\"}}" - }, - { - "description": "[decq787] DPD all-highs cases (includes the 24 redundant codes)", - "bson": "18000000136400E703000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"999\"}}" - }, - { - "description": "[decq053] fold-downs (more below)", - "bson": "18000000136400D204000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1234\"}}" - }, - { - "description": "[decq052] fold-downs (more below)", - "bson": "180000001364003930000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12345\"}}" - }, - { - "description": "[decq792] Miscellaneous (testers' queries, etc.)", - "bson": "180000001364003075000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"30000\"}}" - }, - { - "description": "[decq793] Miscellaneous (testers' queries, etc.)", - "bson": "1800000013640090940D0000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"890000\"}}" - }, - { - "description": "[decq824] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400FEFFFF7F00000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483646\"}}" - }, - { - "description": "[decq825] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400FFFFFF7F00000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483647\"}}" - }, - { - "description": "[decq826] values around [u]int32 edges (zeros done earlier)", - "bson": "180000001364000000008000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483648\"}}" - }, - { - "description": "[decq827] values around [u]int32 edges (zeros done earlier)", - "bson": "180000001364000100008000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483649\"}}" - }, - { - "description": "[decq828] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400FEFFFFFF00000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967294\"}}" - }, - { - "description": "[decq829] values around [u]int32 edges (zeros done earlier)", - "bson": "18000000136400FFFFFFFF00000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967295\"}}" - }, - { - "description": "[decq830] values around [u]int32 edges (zeros done earlier)", - "bson": "180000001364000000000001000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967296\"}}" - }, - { - "description": "[decq831] values around [u]int32 edges (zeros done earlier)", - "bson": "180000001364000100000001000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967297\"}}" - }, - { - "description": "[decq022] Normality", - "bson": "18000000136400C7711CC7B548F377DC80A131C836403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1111111111111111111111111111111111\"}}" - }, - { - "description": "[decq020] Normality", - "bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}" - }, - { - "description": "[decq550] Specials", - "bson": "18000000136400FFFFFFFF638E8D37C087ADBE09ED413000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"9999999999999999999999999999999999\"}}" - } - ] -} -`}, - - {"decimal128-3.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "valid": [ - { - "description": "[basx066] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE0000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-00345678.5432\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}" - }, - { - "description": "[basx065] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE0000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0345678.5432\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}" - }, - { - "description": "[basx064] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE0000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}" - }, - { - "description": "[basx041] strings without E cannot generate E in result", - "bson": "180000001364004C0000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-76\"}}" - }, - { - "description": "[basx027] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000F270000000000000000000000003AB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.999\"}}" - }, - { - "description": "[basx026] conform to rules and exponent will be in permitted range).", - "bson": "180000001364009F230000000000000000000000003AB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.119\"}}" - }, - { - "description": "[basx025] conform to rules and exponent will be in permitted range).", - "bson": "180000001364008F030000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.11\"}}" - }, - { - "description": "[basx024] conform to rules and exponent will be in permitted range).", - "bson": "180000001364005B000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.1\"}}" - }, - { - "description": "[dqbsr531] negatives (Rounded)", - "bson": "1800000013640099761CC7B548F377DC80A131C836FEAF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.1111111111111111111111111111123450\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.111111111111111111111111111112345\"}}" - }, - { - "description": "[basx022] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000A000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0\"}}" - }, - { - "description": "[basx021] conform to rules and exponent will be in permitted range).", - "bson": "18000000136400010000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1\"}}" - }, - { - "description": "[basx601] Zeros", - "bson": "1800000013640000000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" - }, - { - "description": "[basx622] Zeros", - "bson": "1800000013640000000000000000000000000000002EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-9\"}}" - }, - { - "description": "[basx602] Zeros", - "bson": "180000001364000000000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}" - }, - { - "description": "[basx621] Zeros", - "bson": "18000000136400000000000000000000000000000030B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-8\"}}" - }, - { - "description": "[basx603] Zeros", - "bson": "180000001364000000000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" - }, - { - "description": "[basx620] Zeros", - "bson": "18000000136400000000000000000000000000000032B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-7\"}}" - }, - { - "description": "[basx604] Zeros", - "bson": "180000001364000000000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" - }, - { - "description": "[basx619] Zeros", - "bson": "18000000136400000000000000000000000000000034B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000\"}}" - }, - { - "description": "[basx605] Zeros", - "bson": "180000001364000000000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" - }, - { - "description": "[basx618] Zeros", - "bson": "18000000136400000000000000000000000000000036B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}" - }, - { - "description": "[basx680] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"000000.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx606] Zeros", - "bson": "180000001364000000000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" - }, - { - "description": "[basx617] Zeros", - "bson": "18000000136400000000000000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" - }, - { - "description": "[basx681] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"00000.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx686] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+00000.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx687] Zeros", - "bson": "18000000136400000000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-00000.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" - }, - { - "description": "[basx019] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640000000000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-00.00\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" - }, - { - "description": "[basx607] Zeros", - "bson": "1800000013640000000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" - }, - { - "description": "[basx616] Zeros", - "bson": "1800000013640000000000000000000000000000003AB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}" - }, - { - "description": "[basx682] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0000.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx155] Numbers with E", - "bson": "1800000013640000000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000e+0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" - }, - { - "description": "[basx130] Numbers with E", - "bson": "180000001364000000000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" - }, - { - "description": "[basx290] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" - }, - { - "description": "[basx131] Numbers with E", - "bson": "180000001364000000000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" - }, - { - "description": "[basx291] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000036B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}" - }, - { - "description": "[basx132] Numbers with E", - "bson": "180000001364000000000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" - }, - { - "description": "[basx292] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000034B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000\"}}" - }, - { - "description": "[basx133] Numbers with E", - "bson": "180000001364000000000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" - }, - { - "description": "[basx293] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000032B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-7\"}}" - }, - { - "description": "[basx608] Zeros", - "bson": "1800000013640000000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" - }, - { - "description": "[basx615] Zeros", - "bson": "1800000013640000000000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" - }, - { - "description": "[basx683] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"000.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx630] Zeros", - "bson": "1800000013640000000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" - }, - { - "description": "[basx670] Zeros", - "bson": "1800000013640000000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" - }, - { - "description": "[basx631] Zeros", - "bson": "1800000013640000000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" - }, - { - "description": "[basx671] Zeros", - "bson": "1800000013640000000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" - }, - { - "description": "[basx134] Numbers with E", - "bson": "180000001364000000000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" - }, - { - "description": "[basx294] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" - }, - { - "description": "[basx632] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx672] Zeros", - "bson": "180000001364000000000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" - }, - { - "description": "[basx135] Numbers with E", - "bson": "180000001364000000000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" - }, - { - "description": "[basx295] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000036B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}" - }, - { - "description": "[basx633] Zeros", - "bson": "180000001364000000000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}" - }, - { - "description": "[basx673] Zeros", - "bson": "180000001364000000000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" - }, - { - "description": "[basx136] Numbers with E", - "bson": "180000001364000000000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" - }, - { - "description": "[basx674] Zeros", - "bson": "180000001364000000000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" - }, - { - "description": "[basx634] Zeros", - "bson": "180000001364000000000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}" - }, - { - "description": "[basx137] Numbers with E", - "bson": "180000001364000000000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" - }, - { - "description": "[basx635] Zeros", - "bson": "180000001364000000000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" - }, - { - "description": "[basx675] Zeros", - "bson": "180000001364000000000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" - }, - { - "description": "[basx636] Zeros", - "bson": "180000001364000000000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}" - }, - { - "description": "[basx676] Zeros", - "bson": "180000001364000000000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}" - }, - { - "description": "[basx637] Zeros", - "bson": "1800000013640000000000000000000000000000004A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}" - }, - { - "description": "[basx677] Zeros", - "bson": "1800000013640000000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" - }, - { - "description": "[basx638] Zeros", - "bson": "1800000013640000000000000000000000000000004C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}" - }, - { - "description": "[basx678] Zeros", - "bson": "1800000013640000000000000000000000000000002C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-10\"}}" - }, - { - "description": "[basx149] Numbers with E", - "bson": "180000001364000000000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"000E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" - }, - { - "description": "[basx639] Zeros", - "bson": "1800000013640000000000000000000000000000004E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}" - }, - { - "description": "[basx679] Zeros", - "bson": "1800000013640000000000000000000000000000002A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-11\"}}" - }, - { - "description": "[basx063] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE00000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+00345678.5432\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" - }, - { - "description": "[basx018] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640000000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" - }, - { - "description": "[basx609] Zeros", - "bson": "1800000013640000000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" - }, - { - "description": "[basx614] Zeros", - "bson": "1800000013640000000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" - }, - { - "description": "[basx684] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"00.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx640] Zeros", - "bson": "1800000013640000000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" - }, - { - "description": "[basx660] Zeros", - "bson": "1800000013640000000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" - }, - { - "description": "[basx641] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx661] Zeros", - "bson": "1800000013640000000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}" - }, - { - "description": "[basx296] some more negative zeros [systematic tests below]", - "bson": "1800000013640000000000000000000000000000003AB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}" - }, - { - "description": "[basx642] Zeros", - "bson": "180000001364000000000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}" - }, - { - "description": "[basx662] Zeros", - "bson": "1800000013640000000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}" - }, - { - "description": "[basx297] some more negative zeros [systematic tests below]", - "bson": "18000000136400000000000000000000000000000038B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}" - }, - { - "description": "[basx643] Zeros", - "bson": "180000001364000000000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}" - }, - { - "description": "[basx663] Zeros", - "bson": "180000001364000000000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}" - }, - { - "description": "[basx644] Zeros", - "bson": "180000001364000000000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" - }, - { - "description": "[basx664] Zeros", - "bson": "180000001364000000000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}" - }, - { - "description": "[basx645] Zeros", - "bson": "180000001364000000000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}" - }, - { - "description": "[basx665] Zeros", - "bson": "180000001364000000000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}" - }, - { - "description": "[basx646] Zeros", - "bson": "1800000013640000000000000000000000000000004A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}" - }, - { - "description": "[basx666] Zeros", - "bson": "180000001364000000000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}" - }, - { - "description": "[basx647] Zeros", - "bson": "1800000013640000000000000000000000000000004C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}" - }, - { - "description": "[basx667] Zeros", - "bson": "180000001364000000000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}" - }, - { - "description": "[basx648] Zeros", - "bson": "1800000013640000000000000000000000000000004E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}" - }, - { - "description": "[basx668] Zeros", - "bson": "1800000013640000000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" - }, - { - "description": "[basx160] Numbers with E", - "bson": "180000001364000000000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"00E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" - }, - { - "description": "[basx161] Numbers with E", - "bson": "1800000013640000000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"00E-9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}" - }, - { - "description": "[basx649] Zeros", - "bson": "180000001364000000000000000000000000000000503000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8\"}}" - }, - { - "description": "[basx669] Zeros", - "bson": "1800000013640000000000000000000000000000002C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-10\"}}" - }, - { - "description": "[basx062] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE00000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+0345678.5432\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" - }, - { - "description": "[basx001] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx017] conform to rules and exponent will be in permitted range).", - "bson": "18000000136400000000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" - }, - { - "description": "[basx611] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx613] Zeros", - "bson": "18000000136400000000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" - }, - { - "description": "[basx685] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx688] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+0.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx689] Zeros", - "bson": "18000000136400000000000000000000000000000040B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}" - }, - { - "description": "[basx650] Zeros", - "bson": "180000001364000000000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}" - }, - { - "description": "[basx651] Zeros", - "bson": "180000001364000000000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}" - }, - { - "description": "[basx298] some more negative zeros [systematic tests below]", - "bson": "1800000013640000000000000000000000000000003CB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}" - }, - { - "description": "[basx652] Zeros", - "bson": "180000001364000000000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}" - }, - { - "description": "[basx299] some more negative zeros [systematic tests below]", - "bson": "1800000013640000000000000000000000000000003AB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}" - }, - { - "description": "[basx653] Zeros", - "bson": "180000001364000000000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}" - }, - { - "description": "[basx654] Zeros", - "bson": "180000001364000000000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}" - }, - { - "description": "[basx655] Zeros", - "bson": "1800000013640000000000000000000000000000004A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}" - }, - { - "description": "[basx656] Zeros", - "bson": "1800000013640000000000000000000000000000004C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}" - }, - { - "description": "[basx657] Zeros", - "bson": "1800000013640000000000000000000000000000004E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}" - }, - { - "description": "[basx658] Zeros", - "bson": "180000001364000000000000000000000000000000503000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8\"}}" - }, - { - "description": "[basx138] Numbers with E", - "bson": "180000001364000000000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+0E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" - }, - { - "description": "[basx139] Numbers with E", - "bson": "18000000136400000000000000000000000000000052B000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+9\"}}" - }, - { - "description": "[basx144] Numbers with E", - "bson": "180000001364000000000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" - }, - { - "description": "[basx154] Numbers with E", - "bson": "180000001364000000000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" - }, - { - "description": "[basx659] Zeros", - "bson": "180000001364000000000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}" - }, - { - "description": "[basx042] strings without E cannot generate E in result", - "bson": "18000000136400FC040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+12.76\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" - }, - { - "description": "[basx143] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+1E+009\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx061] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE00000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+345678.5432\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" - }, - { - "description": "[basx036] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640015CD5B0700000000000000000000203000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000000123456789\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23456789E-8\"}}" - }, - { - "description": "[basx035] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640015CD5B0700000000000000000000223000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000123456789\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23456789E-7\"}}" - }, - { - "description": "[basx034] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640015CD5B0700000000000000000000243000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000123456789\"}}" - }, - { - "description": "[basx053] strings without E cannot generate E in result", - "bson": "180000001364003200000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000050\"}}" - }, - { - "description": "[basx033] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640015CD5B0700000000000000000000263000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000123456789\"}}" - }, - { - "description": "[basx016] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000C000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.012\"}}" - }, - { - "description": "[basx015] conform to rules and exponent will be in permitted range).", - "bson": "180000001364007B000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123\"}}" - }, - { - "description": "[basx037] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640078DF0D8648700000000000000000223000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123456789012344\"}}" - }, - { - "description": "[basx038] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640079DF0D8648700000000000000000223000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123456789012345\"}}" - }, - { - "description": "[basx250] Numbers with E", - "bson": "18000000136400F104000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" - }, - { - "description": "[basx257] Numbers with E", - "bson": "18000000136400F104000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" - }, - { - "description": "[basx256] Numbers with E", - "bson": "18000000136400F104000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" - }, - { - "description": "[basx258] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" - }, - { - "description": "[basx251] Numbers with E", - "bson": "18000000136400F104000000000000000000000000103000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-21\"}}" - }, - { - "description": "[basx263] Numbers with E", - "bson": "18000000136400F104000000000000000000000000603000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+19\"}}" - }, - { - "description": "[basx255] Numbers with E", - "bson": "18000000136400F104000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}" - }, - { - "description": "[basx259] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" - }, - { - "description": "[basx254] Numbers with E", - "bson": "18000000136400F104000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0001265\"}}" - }, - { - "description": "[basx260] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" - }, - { - "description": "[basx253] Numbers with E", - "bson": "18000000136400F104000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00001265\"}}" - }, - { - "description": "[basx261] Numbers with E", - "bson": "18000000136400F104000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" - }, - { - "description": "[basx252] Numbers with E", - "bson": "18000000136400F104000000000000000000000000283000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-9\"}}" - }, - { - "description": "[basx262] Numbers with E", - "bson": "18000000136400F104000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+7\"}}" - }, - { - "description": "[basx159] Numbers with E", - "bson": "1800000013640049000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.73e-7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7.3E-8\"}}" - }, - { - "description": "[basx004] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640064000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00\"}}" - }, - { - "description": "[basx003] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000A000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0\"}}" - }, - { - "description": "[basx002] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000100000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1\"}}" - }, - { - "description": "[basx148] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+009\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx153] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E009\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx141] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+09\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx146] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+09\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx151] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1e09\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx142] Numbers with E", - "bson": "180000001364000100000000000000000000000000F43000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}" - }, - { - "description": "[basx147] Numbers with E", - "bson": "180000001364000100000000000000000000000000F43000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+90\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}" - }, - { - "description": "[basx152] Numbers with E", - "bson": "180000001364000100000000000000000000000000F43000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E90\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}" - }, - { - "description": "[basx140] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx150] Numbers with E", - "bson": "180000001364000100000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}" - }, - { - "description": "[basx014] conform to rules and exponent will be in permitted range).", - "bson": "18000000136400D2040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.234\"}}" - }, - { - "description": "[basx170] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" - }, - { - "description": "[basx177] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" - }, - { - "description": "[basx176] Numbers with E", - "bson": "18000000136400F104000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" - }, - { - "description": "[basx178] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" - }, - { - "description": "[basx171] Numbers with E", - "bson": "18000000136400F104000000000000000000000000123000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-20\"}}" - }, - { - "description": "[basx183] Numbers with E", - "bson": "18000000136400F104000000000000000000000000623000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+20\"}}" - }, - { - "description": "[basx175] Numbers with E", - "bson": "18000000136400F104000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" - }, - { - "description": "[basx179] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" - }, - { - "description": "[basx174] Numbers with E", - "bson": "18000000136400F104000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}" - }, - { - "description": "[basx180] Numbers with E", - "bson": "18000000136400F104000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" - }, - { - "description": "[basx173] Numbers with E", - "bson": "18000000136400F104000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0001265\"}}" - }, - { - "description": "[basx181] Numbers with E", - "bson": "18000000136400F104000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" - }, - { - "description": "[basx172] Numbers with E", - "bson": "18000000136400F1040000000000000000000000002A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-8\"}}" - }, - { - "description": "[basx182] Numbers with E", - "bson": "18000000136400F1040000000000000000000000004A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+8\"}}" - }, - { - "description": "[basx157] Numbers with E", - "bson": "180000001364000400000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"4E+9\"}}" - }, - { - "description": "[basx067] examples", - "bson": "180000001364000500000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000005\"}}" - }, - { - "description": "[basx069] examples", - "bson": "180000001364000500000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-7\"}}" - }, - { - "description": "[basx385] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7\"}}" - }, - { - "description": "[basx365] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000543000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E10\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+10\"}}" - }, - { - "description": "[basx405] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000002C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-10\"}}" - }, - { - "description": "[basx363] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000563000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E11\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+11\"}}" - }, - { - "description": "[basx407] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000002A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-11\"}}" - }, - { - "description": "[basx361] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000583000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E12\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+12\"}}" - }, - { - "description": "[basx409] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000283000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-12\"}}" - }, - { - "description": "[basx411] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000263000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-13\"}}" - }, - { - "description": "[basx383] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+1\"}}" - }, - { - "description": "[basx387] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.7\"}}" - }, - { - "description": "[basx381] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+2\"}}" - }, - { - "description": "[basx389] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.07\"}}" - }, - { - "description": "[basx379] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+3\"}}" - }, - { - "description": "[basx391] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.007\"}}" - }, - { - "description": "[basx377] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+4\"}}" - }, - { - "description": "[basx393] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0007\"}}" - }, - { - "description": "[basx375] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000004A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+5\"}}" - }, - { - "description": "[basx395] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00007\"}}" - }, - { - "description": "[basx373] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000004C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+6\"}}" - }, - { - "description": "[basx397] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000007\"}}" - }, - { - "description": "[basx371] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000004E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+7\"}}" - }, - { - "description": "[basx399] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-7\"}}" - }, - { - "description": "[basx369] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000503000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+8\"}}" - }, - { - "description": "[basx401] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-8\"}}" - }, - { - "description": "[basx367] Engineering notation tests", - "bson": "180000001364000700000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+9\"}}" - }, - { - "description": "[basx403] Engineering notation tests", - "bson": "1800000013640007000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-9\"}}" - }, - { - "description": "[basx007] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640064000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10.0\"}}" - }, - { - "description": "[basx005] conform to rules and exponent will be in permitted range).", - "bson": "180000001364000A00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}" - }, - { - "description": "[basx165] Numbers with E", - "bson": "180000001364000A00000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+009\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" - }, - { - "description": "[basx163] Numbers with E", - "bson": "180000001364000A00000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+09\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" - }, - { - "description": "[basx325] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}" - }, - { - "description": "[basx305] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000543000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e10\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+11\"}}" - }, - { - "description": "[basx345] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000002C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-10\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-9\"}}" - }, - { - "description": "[basx303] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000563000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e11\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+12\"}}" - }, - { - "description": "[basx347] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000002A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-11\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-10\"}}" - }, - { - "description": "[basx301] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000583000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e12\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+13\"}}" - }, - { - "description": "[basx349] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000283000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-12\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-11\"}}" - }, - { - "description": "[basx351] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000263000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-13\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-12\"}}" - }, - { - "description": "[basx323] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+2\"}}" - }, - { - "description": "[basx327] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0\"}}" - }, - { - "description": "[basx321] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+3\"}}" - }, - { - "description": "[basx329] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.10\"}}" - }, - { - "description": "[basx319] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+4\"}}" - }, - { - "description": "[basx331] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.010\"}}" - }, - { - "description": "[basx317] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+5\"}}" - }, - { - "description": "[basx333] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0010\"}}" - }, - { - "description": "[basx315] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000004A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6\"}}" - }, - { - "description": "[basx335] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00010\"}}" - }, - { - "description": "[basx313] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000004C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+7\"}}" - }, - { - "description": "[basx337] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-6\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000010\"}}" - }, - { - "description": "[basx311] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000004E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+8\"}}" - }, - { - "description": "[basx339] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000010\"}}" - }, - { - "description": "[basx309] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000503000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+9\"}}" - }, - { - "description": "[basx341] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-7\"}}" - }, - { - "description": "[basx164] Numbers with E", - "bson": "180000001364000A00000000000000000000000000F43000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e+90\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+91\"}}" - }, - { - "description": "[basx162] Numbers with E", - "bson": "180000001364000A00000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" - }, - { - "description": "[basx307] Engineering notation tests", - "bson": "180000001364000A00000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}" - }, - { - "description": "[basx343] Engineering notation tests", - "bson": "180000001364000A000000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-8\"}}" - }, - { - "description": "[basx008] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640065000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10.1\"}}" - }, - { - "description": "[basx009] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640068000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10.4\"}}" - }, - { - "description": "[basx010] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640069000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10.5\"}}" - }, - { - "description": "[basx011] conform to rules and exponent will be in permitted range).", - "bson": "180000001364006A000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10.6\"}}" - }, - { - "description": "[basx012] conform to rules and exponent will be in permitted range).", - "bson": "180000001364006D000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"10.9\"}}" - }, - { - "description": "[basx013] conform to rules and exponent will be in permitted range).", - "bson": "180000001364006E000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"11.0\"}}" - }, - { - "description": "[basx040] strings without E cannot generate E in result", - "bson": "180000001364000C00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12\"}}" - }, - { - "description": "[basx190] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" - }, - { - "description": "[basx197] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" - }, - { - "description": "[basx196] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" - }, - { - "description": "[basx198] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" - }, - { - "description": "[basx191] Numbers with E", - "bson": "18000000136400F104000000000000000000000000143000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-19\"}}" - }, - { - "description": "[basx203] Numbers with E", - "bson": "18000000136400F104000000000000000000000000643000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+21\"}}" - }, - { - "description": "[basx195] Numbers with E", - "bson": "18000000136400F104000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" - }, - { - "description": "[basx199] Numbers with E", - "bson": "18000000136400F104000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" - }, - { - "description": "[basx194] Numbers with E", - "bson": "18000000136400F104000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" - }, - { - "description": "[basx200] Numbers with E", - "bson": "18000000136400F104000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" - }, - { - "description": "[basx193] Numbers with E", - "bson": "18000000136400F104000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}" - }, - { - "description": "[basx201] Numbers with E", - "bson": "18000000136400F104000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}" - }, - { - "description": "[basx192] Numbers with E", - "bson": "18000000136400F1040000000000000000000000002C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-7\"}}" - }, - { - "description": "[basx202] Numbers with E", - "bson": "18000000136400F1040000000000000000000000004C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+9\"}}" - }, - { - "description": "[basx044] strings without E cannot generate E in result", - "bson": "18000000136400FC040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"012.76\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" - }, - { - "description": "[basx042] strings without E cannot generate E in result", - "bson": "18000000136400FC040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" - }, - { - "description": "[basx046] strings without E cannot generate E in result", - "bson": "180000001364001100000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"17.\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"17\"}}" - }, - { - "description": "[basx049] strings without E cannot generate E in result", - "bson": "180000001364002C00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0044\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"44\"}}" - }, - { - "description": "[basx048] strings without E cannot generate E in result", - "bson": "180000001364002C00000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"044\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"44\"}}" - }, - { - "description": "[basx158] Numbers with E", - "bson": "180000001364002C00000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"44E+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4.4E+10\"}}" - }, - { - "description": "[basx068] examples", - "bson": "180000001364003200000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"50E-7\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000050\"}}" - }, - { - "description": "[basx169] Numbers with E", - "bson": "180000001364006400000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+009\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}" - }, - { - "description": "[basx167] Numbers with E", - "bson": "180000001364006400000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+09\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}" - }, - { - "description": "[basx168] Numbers with E", - "bson": "180000001364006400000000000000000000000000F43000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"100E+90\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+92\"}}" - }, - { - "description": "[basx166] Numbers with E", - "bson": "180000001364006400000000000000000000000000523000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+9\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}" - }, - { - "description": "[basx210] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" - }, - { - "description": "[basx217] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" - }, - { - "description": "[basx216] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" - }, - { - "description": "[basx218] Numbers with E", - "bson": "18000000136400F104000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" - }, - { - "description": "[basx211] Numbers with E", - "bson": "18000000136400F104000000000000000000000000163000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-18\"}}" - }, - { - "description": "[basx223] Numbers with E", - "bson": "18000000136400F104000000000000000000000000663000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+22\"}}" - }, - { - "description": "[basx215] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" - }, - { - "description": "[basx219] Numbers with E", - "bson": "18000000136400F104000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" - }, - { - "description": "[basx214] Numbers with E", - "bson": "18000000136400F104000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" - }, - { - "description": "[basx220] Numbers with E", - "bson": "18000000136400F104000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}" - }, - { - "description": "[basx213] Numbers with E", - "bson": "18000000136400F104000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}" - }, - { - "description": "[basx221] Numbers with E", - "bson": "18000000136400F104000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+6\"}}" - }, - { - "description": "[basx212] Numbers with E", - "bson": "18000000136400F1040000000000000000000000002E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000001265\"}}" - }, - { - "description": "[basx222] Numbers with E", - "bson": "18000000136400F1040000000000000000000000004E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+10\"}}" - }, - { - "description": "[basx006] conform to rules and exponent will be in permitted range).", - "bson": "18000000136400E803000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1000\"}}" - }, - { - "description": "[basx230] Numbers with E", - "bson": "18000000136400F104000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" - }, - { - "description": "[basx237] Numbers with E", - "bson": "18000000136400F104000000000000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}" - }, - { - "description": "[basx236] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}" - }, - { - "description": "[basx238] Numbers with E", - "bson": "18000000136400F104000000000000000000000000423000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+1\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}" - }, - { - "description": "[basx231] Numbers with E", - "bson": "18000000136400F104000000000000000000000000183000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-17\"}}" - }, - { - "description": "[basx243] Numbers with E", - "bson": "18000000136400F104000000000000000000000000683000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+20\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+23\"}}" - }, - { - "description": "[basx235] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}" - }, - { - "description": "[basx239] Numbers with E", - "bson": "18000000136400F104000000000000000000000000443000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+2\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}" - }, - { - "description": "[basx234] Numbers with E", - "bson": "18000000136400F1040000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}" - }, - { - "description": "[basx240] Numbers with E", - "bson": "18000000136400F104000000000000000000000000463000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+3\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+6\"}}" - }, - { - "description": "[basx233] Numbers with E", - "bson": "18000000136400F104000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}" - }, - { - "description": "[basx241] Numbers with E", - "bson": "18000000136400F104000000000000000000000000483000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+4\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+7\"}}" - }, - { - "description": "[basx232] Numbers with E", - "bson": "18000000136400F104000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00001265\"}}" - }, - { - "description": "[basx242] Numbers with E", - "bson": "18000000136400F104000000000000000000000000503000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+8\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+11\"}}" - }, - { - "description": "[basx060] strings without E cannot generate E in result", - "bson": "18000000136400185C0ACE00000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}" - }, - { - "description": "[basx059] strings without E cannot generate E in result", - "bson": "18000000136400F198670C08000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0345678.54321\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.54321\"}}" - }, - { - "description": "[basx058] strings without E cannot generate E in result", - "bson": "180000001364006AF90B7C50000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.543210\"}}" - }, - { - "description": "[basx057] strings without E cannot generate E in result", - "bson": "180000001364006A19562522020000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"2345678.543210\"}}" - }, - { - "description": "[basx056] strings without E cannot generate E in result", - "bson": "180000001364006AB9C8733A0B0000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"12345678.543210\"}}" - }, - { - "description": "[basx031] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640040AF0D8648700000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789.000000\"}}" - }, - { - "description": "[basx030] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640080910F8648700000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789.123456\"}}" - }, - { - "description": "[basx032] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640080910F8648700000000000000000403000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789123456\"}}" - } - ] -} -`}, - - {"decimal128-4.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "valid": [ - { - "description": "[basx023] conform to rules and exponent will be in permitted range).", - "bson": "1800000013640001000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.1\"}}" - }, - - { - "description": "[basx045] strings without E cannot generate E in result", - "bson": "1800000013640003000000000000000000000000003A3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+0.003\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.003\"}}" - }, - { - "description": "[basx610] Zeros", - "bson": "1800000013640000000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \".0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}" - }, - { - "description": "[basx612] Zeros", - "bson": "1800000013640000000000000000000000000000003EB000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-.0\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}" - }, - { - "description": "[basx043] strings without E cannot generate E in result", - "bson": "18000000136400FC040000000000000000000000003C3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"+12.76\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}" - }, - { - "description": "[basx055] strings without E cannot generate E in result", - "bson": "180000001364000500000000000000000000000000303000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000005\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-8\"}}" - }, - { - "description": "[basx054] strings without E cannot generate E in result", - "bson": "180000001364000500000000000000000000000000323000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000005\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-7\"}}" - }, - { - "description": "[basx052] strings without E cannot generate E in result", - "bson": "180000001364000500000000000000000000000000343000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000005\"}}" - }, - { - "description": "[basx051] strings without E cannot generate E in result", - "bson": "180000001364000500000000000000000000000000363000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"00.00005\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00005\"}}" - }, - { - "description": "[basx050] strings without E cannot generate E in result", - "bson": "180000001364000500000000000000000000000000383000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0005\"}}" - }, - { - "description": "[basx047] strings without E cannot generate E in result", - "bson": "1800000013640005000000000000000000000000003E3000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \".5\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.5\"}}" - }, - { - "description": "[dqbsr431] check rounding modes heeded (Rounded)", - "bson": "1800000013640099761CC7B548F377DC80A131C836FE2F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.1111111111111111111111111111123450\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.111111111111111111111111111112345\"}}" - }, - { - "description": "OK2", - "bson": "18000000136400000000000A5BC138938D44C64D31FC2F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \".100000000000000000000000000000000000000000000000000000000000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1000000000000000000000000000000000\"}}" - } - ], - "parseErrors": [ - { - "description": "[basx564] Near-specials (Conversion_syntax)", - "string": "Infi" - }, - { - "description": "[basx565] Near-specials (Conversion_syntax)", - "string": "Infin" - }, - { - "description": "[basx566] Near-specials (Conversion_syntax)", - "string": "Infini" - }, - { - "description": "[basx567] Near-specials (Conversion_syntax)", - "string": "Infinit" - }, - { - "description": "[basx568] Near-specials (Conversion_syntax)", - "string": "-Infinit" - }, - { - "description": "[basx590] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": ".Infinity" - }, - { - "description": "[basx562] Near-specials (Conversion_syntax)", - "string": "NaNq" - }, - { - "description": "[basx563] Near-specials (Conversion_syntax)", - "string": "NaNs" - }, - { - "description": "[dqbas939] overflow results at different rounding modes (Overflow & Inexact & Rounded)", - "string": "-7e10000" - }, - { - "description": "[dqbsr534] negatives (Rounded & Inexact)", - "string": "-1.11111111111111111111111111111234650" - }, - { - "description": "[dqbsr535] negatives (Rounded & Inexact)", - "string": "-1.11111111111111111111111111111234551" - }, - { - "description": "[dqbsr533] negatives (Rounded & Inexact)", - "string": "-1.11111111111111111111111111111234550" - }, - { - "description": "[dqbsr532] negatives (Rounded & Inexact)", - "string": "-1.11111111111111111111111111111234549" - }, - { - "description": "[dqbsr432] check rounding modes heeded (Rounded & Inexact)", - "string": "1.11111111111111111111111111111234549" - }, - { - "description": "[dqbsr433] check rounding modes heeded (Rounded & Inexact)", - "string": "1.11111111111111111111111111111234550" - }, - { - "description": "[dqbsr435] check rounding modes heeded (Rounded & Inexact)", - "string": "1.11111111111111111111111111111234551" - }, - { - "description": "[dqbsr434] check rounding modes heeded (Rounded & Inexact)", - "string": "1.11111111111111111111111111111234650" - }, - { - "description": "[dqbas938] overflow results at different rounding modes (Overflow & Inexact & Rounded)", - "string": "7e10000" - }, - { - "description": "Inexact rounding#1", - "string": "100000000000000000000000000000000000000000000000000000000001" - }, - { - "description": "Inexact rounding#2", - "string": "1E-6177" - } - ] -} -`}, - - {"decimal128-5.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "valid": [ - { - "description": "[decq035] fold-downs (more below) (Clamped)", - "bson": "18000000136400000000807F1BCF85B27059C8A43CFE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.230000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq037] fold-downs (more below) (Clamped)", - "bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq077] Nmin and below (Subnormal)", - "bson": "180000001364000000000081EFAC855B416D2DEE04000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.100000000000000000000000000000000E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E-6144\"}}" - }, - { - "description": "[decq078] Nmin and below (Subnormal)", - "bson": "180000001364000000000081EFAC855B416D2DEE04000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E-6144\"}}" - }, - { - "description": "[decq079] Nmin and below (Subnormal)", - "bson": "180000001364000A00000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000000000000000000000000010E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-6175\"}}" - }, - { - "description": "[decq080] Nmin and below (Subnormal)", - "bson": "180000001364000A00000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-6175\"}}" - }, - { - "description": "[decq081] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000020000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000000000000000000000000000001E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6175\"}}" - }, - { - "description": "[decq082] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000020000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6175\"}}" - }, - { - "description": "[decq083] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000000000000000000000000001E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" - }, - { - "description": "[decq084] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" - }, - { - "description": "[decq090] underflows cannot be tested for simple copies, check edge cases (Subnormal)", - "bson": "180000001364000100000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1e-6176\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}" - }, - { - "description": "[decq100] underflows cannot be tested for simple copies, check edge cases (Subnormal)", - "bson": "18000000136400FFFFFFFF095BC138938D44C64D31000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"999999999999999999999999999999999e-6176\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.99999999999999999999999999999999E-6144\"}}" - }, - { - "description": "[decq130] fold-downs (more below) (Clamped)", - "bson": "18000000136400000000807F1BCF85B27059C8A43CFEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.23E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.230000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq132] fold-downs (more below) (Clamped)", - "bson": "18000000136400000000000A5BC138938D44C64D31FEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq177] Nmin and below (Subnormal)", - "bson": "180000001364000000000081EFAC855B416D2DEE04008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.100000000000000000000000000000000E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00000000000000000000000000000000E-6144\"}}" - }, - { - "description": "[decq178] Nmin and below (Subnormal)", - "bson": "180000001364000000000081EFAC855B416D2DEE04008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00000000000000000000000000000000E-6144\"}}" - }, - { - "description": "[decq179] Nmin and below (Subnormal)", - "bson": "180000001364000A00000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000000000000000000000000010E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0E-6175\"}}" - }, - { - "description": "[decq180] Nmin and below (Subnormal)", - "bson": "180000001364000A00000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0E-6175\"}}" - }, - { - "description": "[decq181] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000028000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000000000000000000000000000001E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6175\"}}" - }, - { - "description": "[decq182] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000028000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6175\"}}" - }, - { - "description": "[decq183] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000000000000000000000000001E-6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" - }, - { - "description": "[decq184] Nmin and below (Subnormal)", - "bson": "180000001364000100000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" - }, - { - "description": "[decq190] underflow edge cases (Subnormal)", - "bson": "180000001364000100000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-1e-6176\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}" - }, - { - "description": "[decq200] underflow edge cases (Subnormal)", - "bson": "18000000136400FFFFFFFF095BC138938D44C64D31008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-999999999999999999999999999999999e-6176\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.99999999999999999999999999999999E-6144\"}}" - }, - { - "description": "[decq400] zeros (Clamped)", - "bson": "180000001364000000000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" - }, - { - "description": "[decq401] zeros (Clamped)", - "bson": "180000001364000000000000000000000000000000000000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6177\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}" - }, - { - "description": "[decq414] clamped zeros... (Clamped)", - "bson": "180000001364000000000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6112\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" - }, - { - "description": "[decq416] clamped zeros... (Clamped)", - "bson": "180000001364000000000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" - }, - { - "description": "[decq418] clamped zeros... (Clamped)", - "bson": "180000001364000000000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}" - }, - { - "description": "[decq420] negative zeros (Clamped)", - "bson": "180000001364000000000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-8000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" - }, - { - "description": "[decq421] negative zeros (Clamped)", - "bson": "180000001364000000000000000000000000000000008000", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6177\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}" - }, - { - "description": "[decq434] clamped zeros... (Clamped)", - "bson": "180000001364000000000000000000000000000000FEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6112\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" - }, - { - "description": "[decq436] clamped zeros... (Clamped)", - "bson": "180000001364000000000000000000000000000000FEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" - }, - { - "description": "[decq438] clamped zeros... (Clamped)", - "bson": "180000001364000000000000000000000000000000FEDF00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+8000\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}" - }, - { - "description": "[decq601] fold-down full sequence (Clamped)", - "bson": "18000000136400000000000A5BC138938D44C64D31FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6144\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}" - }, - { - "description": "[decq603] fold-down full sequence (Clamped)", - "bson": "180000001364000000000081EFAC855B416D2DEE04FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6143\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E+6143\"}}" - }, - { - "description": "[decq605] fold-down full sequence (Clamped)", - "bson": "1800000013640000000080264B91C02220BE377E00FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6142\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000000E+6142\"}}" - }, - { - "description": "[decq607] fold-down full sequence (Clamped)", - "bson": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6141\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000E+6141\"}}" - }, - { - "description": "[decq609] fold-down full sequence (Clamped)", - "bson": "18000000136400000000A0CA17726DAE0F1E430100FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6140\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000E+6140\"}}" - }, - { - "description": "[decq611] fold-down full sequence (Clamped)", - "bson": "18000000136400000000106102253E5ECE4F200000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6139\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000E+6139\"}}" - }, - { - "description": "[decq613] fold-down full sequence (Clamped)", - "bson": "18000000136400000000E83C80D09F3C2E3B030000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6138\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000E+6138\"}}" - }, - { - "description": "[decq615] fold-down full sequence (Clamped)", - "bson": "18000000136400000000E4D20CC8DCD2B752000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6137\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000E+6137\"}}" - }, - { - "description": "[decq617] fold-down full sequence (Clamped)", - "bson": "180000001364000000004A48011416954508000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6136\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000E+6136\"}}" - }, - { - "description": "[decq619] fold-down full sequence (Clamped)", - "bson": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6135\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000E+6135\"}}" - }, - { - "description": "[decq621] fold-down full sequence (Clamped)", - "bson": "18000000136400000080F64AE1C7022D1500000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6134\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000E+6134\"}}" - }, - { - "description": "[decq623] fold-down full sequence (Clamped)", - "bson": "18000000136400000040B2BAC9E0191E0200000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6133\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000E+6133\"}}" - }, - { - "description": "[decq625] fold-down full sequence (Clamped)", - "bson": "180000001364000000A0DEC5ADC935360000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6132\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000E+6132\"}}" - }, - { - "description": "[decq627] fold-down full sequence (Clamped)", - "bson": "18000000136400000010632D5EC76B050000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6131\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000E+6131\"}}" - }, - { - "description": "[decq629] fold-down full sequence (Clamped)", - "bson": "180000001364000000E8890423C78A000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6130\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000E+6130\"}}" - }, - { - "description": "[decq631] fold-down full sequence (Clamped)", - "bson": "18000000136400000064A7B3B6E00D000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6129\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000E+6129\"}}" - }, - { - "description": "[decq633] fold-down full sequence (Clamped)", - "bson": "1800000013640000008A5D78456301000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6128\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000E+6128\"}}" - }, - { - "description": "[decq635] fold-down full sequence (Clamped)", - "bson": "180000001364000000C16FF2862300000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6127\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000E+6127\"}}" - }, - { - "description": "[decq637] fold-down full sequence (Clamped)", - "bson": "180000001364000080C6A47E8D0300000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6126\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000E+6126\"}}" - }, - { - "description": "[decq639] fold-down full sequence (Clamped)", - "bson": "1800000013640000407A10F35A0000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6125\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000E+6125\"}}" - }, - { - "description": "[decq641] fold-down full sequence (Clamped)", - "bson": "1800000013640000A0724E18090000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6124\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000E+6124\"}}" - }, - { - "description": "[decq643] fold-down full sequence (Clamped)", - "bson": "180000001364000010A5D4E8000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6123\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000E+6123\"}}" - }, - { - "description": "[decq645] fold-down full sequence (Clamped)", - "bson": "1800000013640000E8764817000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6122\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000E+6122\"}}" - }, - { - "description": "[decq647] fold-down full sequence (Clamped)", - "bson": "1800000013640000E40B5402000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6121\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000E+6121\"}}" - }, - { - "description": "[decq649] fold-down full sequence (Clamped)", - "bson": "1800000013640000CA9A3B00000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6120\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000E+6120\"}}" - }, - { - "description": "[decq651] fold-down full sequence (Clamped)", - "bson": "1800000013640000E1F50500000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6119\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000E+6119\"}}" - }, - { - "description": "[decq653] fold-down full sequence (Clamped)", - "bson": "180000001364008096980000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6118\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000E+6118\"}}" - }, - { - "description": "[decq655] fold-down full sequence (Clamped)", - "bson": "1800000013640040420F0000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6117\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000E+6117\"}}" - }, - { - "description": "[decq657] fold-down full sequence (Clamped)", - "bson": "18000000136400A086010000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6116\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000E+6116\"}}" - }, - { - "description": "[decq659] fold-down full sequence (Clamped)", - "bson": "180000001364001027000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6115\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000E+6115\"}}" - }, - { - "description": "[decq661] fold-down full sequence (Clamped)", - "bson": "18000000136400E803000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6114\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000E+6114\"}}" - }, - { - "description": "[decq663] fold-down full sequence (Clamped)", - "bson": "180000001364006400000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6113\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+6113\"}}" - }, - { - "description": "[decq665] fold-down full sequence (Clamped)", - "bson": "180000001364000A00000000000000000000000000FE5F00", - "extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6112\"}}", - "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}" - } - ] -} -`}, - - {"decimal128-6.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "parseErrors": [ - { - "description": "Incomplete Exponent", - "string": "1e" - }, - { - "description": "Exponent at the beginning", - "string": "E01" - }, - { - "description": "Just a decimal place", - "string": "." - }, - { - "description": "2 decimal places", - "string": "..3" - }, - { - "description": "2 decimal places", - "string": ".13.3" - }, - { - "description": "2 decimal places", - "string": "1..3" - }, - { - "description": "2 decimal places", - "string": "1.3.4" - }, - { - "description": "2 decimal places", - "string": "1.34." - }, - { - "description": "Decimal with no digits", - "string": ".e" - }, - { - "description": "2 signs", - "string": "+-32.4" - }, - { - "description": "2 signs", - "string": "-+32.4" - }, - { - "description": "2 negative signs", - "string": "--32.4" - }, - { - "description": "2 negative signs", - "string": "-32.-4" - }, - { - "description": "End in negative sign", - "string": "32.0-" - }, - { - "description": "2 negative signs", - "string": "32.4E--21" - }, - { - "description": "2 negative signs", - "string": "32.4E-2-1" - }, - { - "description": "2 signs", - "string": "32.4E+-21" - }, - { - "description": "Empty string", - "string": "" - }, - { - "description": "leading white space positive number", - "string": " 1" - }, - { - "description": "leading white space negative number", - "string": " -1" - }, - { - "description": "trailing white space", - "string": "1 " - }, - { - "description": "Invalid", - "string": "E" - }, - { - "description": "Invalid", - "string": "invalid" - }, - { - "description": "Invalid", - "string": "i" - }, - { - "description": "Invalid", - "string": "in" - }, - { - "description": "Invalid", - "string": "-in" - }, - { - "description": "Invalid", - "string": "Na" - }, - { - "description": "Invalid", - "string": "-Na" - }, - { - "description": "Invalid", - "string": "1.23abc" - }, - { - "description": "Invalid", - "string": "1.23abcE+02" - }, - { - "description": "Invalid", - "string": "1.23E+0aabs2" - } - ] -} -`}, - - {"decimal128-7.json", ` -{ - "description": "Decimal128", - "bson_type": "0x13", - "test_key": "d", - "parseErrors": [ - { - "description": "[basx572] Near-specials (Conversion_syntax)", - "string": "-9Inf" - }, - { - "description": "[basx516] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "-1-" - }, - { - "description": "[basx533] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "0000.." - }, - { - "description": "[basx534] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": ".0000." - }, - { - "description": "[basx535] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "00..00" - }, - { - "description": "[basx569] Near-specials (Conversion_syntax)", - "string": "0Inf" - }, - { - "description": "[basx571] Near-specials (Conversion_syntax)", - "string": "-0Inf" - }, - { - "description": "[basx575] Near-specials (Conversion_syntax)", - "string": "0sNaN" - }, - { - "description": "[basx503] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "++1" - }, - { - "description": "[basx504] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "--1" - }, - { - "description": "[basx505] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "-+1" - }, - { - "description": "[basx506] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "+-1" - }, - { - "description": "[basx510] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": " +1" - }, - { - "description": "[basx513] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": " + 1" - }, - { - "description": "[basx514] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": " - 1" - }, - { - "description": "[basx501] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "." - }, - { - "description": "[basx502] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": ".." - }, - { - "description": "[basx519] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "" - }, - { - "description": "[basx525] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "e100" - }, - { - "description": "[basx549] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "e+1" - }, - { - "description": "[basx577] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": ".e+1" - }, - { - "description": "[basx578] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "+.e+1" - }, - { - "description": "[basx581] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "E+1" - }, - { - "description": "[basx582] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": ".E+1" - }, - { - "description": "[basx583] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "+.E+1" - }, - { - "description": "[basx579] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "-.e+" - }, - { - "description": "[basx580] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "-.e" - }, - { - "description": "[basx584] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "-.E+" - }, - { - "description": "[basx585] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "-.E" - }, - { - "description": "[basx589] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "+.Inf" - }, - { - "description": "[basx586] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": ".NaN" - }, - { - "description": "[basx587] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "-.NaN" - }, - { - "description": "[basx545] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "ONE" - }, - { - "description": "[basx561] Near-specials (Conversion_syntax)", - "string": "qNaN" - }, - { - "description": "[basx573] Near-specials (Conversion_syntax)", - "string": "-sNa" - }, - { - "description": "[basx588] some baddies with dots and Es and dots and specials (Conversion_syntax)", - "string": "+.sNaN" - }, - { - "description": "[basx544] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "ten" - }, - { - "description": "[basx527] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "u0b65" - }, - { - "description": "[basx526] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "u0e5a" - }, - { - "description": "[basx515] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "x" - }, - { - "description": "[basx574] Near-specials (Conversion_syntax)", - "string": "xNaN" - }, - { - "description": "[basx530] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": ".123.5" - }, - { - "description": "[basx500] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1..2" - }, - { - "description": "[basx542] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1e1.0" - }, - { - "description": "[basx553] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E+1.2.3" - }, - { - "description": "[basx543] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1e123e" - }, - { - "description": "[basx552] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E+1.2" - }, - { - "description": "[basx546] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1e.1" - }, - { - "description": "[basx547] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1e1." - }, - { - "description": "[basx554] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E++1" - }, - { - "description": "[basx555] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E--1" - }, - { - "description": "[basx556] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E+-1" - }, - { - "description": "[basx557] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E-+1" - }, - { - "description": "[basx558] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E'1" - }, - { - "description": "[basx559] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E\"1" - }, - { - "description": "[basx520] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1e-" - }, - { - "description": "[basx560] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1E" - }, - { - "description": "[basx548] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1ee" - }, - { - "description": "[basx551] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1.2.1" - }, - { - "description": "[basx550] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1.23.4" - }, - { - "description": "[basx529] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "1.34.5" - }, - { - "description": "[basx531] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "01.35." - }, - { - "description": "[basx532] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "01.35-" - }, - { - "description": "[basx518] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "3+" - }, - { - "description": "[basx521] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "7e99999a" - }, - { - "description": "[basx570] Near-specials (Conversion_syntax)", - "string": "9Inf" - }, - { - "description": "[basx512] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "12 " - }, - { - "description": "[basx517] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "12-" - }, - { - "description": "[basx507] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "12e" - }, - { - "description": "[basx508] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "12e++" - }, - { - "description": "[basx509] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "12f4" - }, - { - "description": "[basx536] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "111e*123" - }, - { - "description": "[basx537] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "111e123-" - }, - { - "description": "[basx540] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "111e1*23" - }, - { - "description": "[basx538] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "111e+12+" - }, - { - "description": "[basx539] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "111e1-3-" - }, - { - "description": "[basx541] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "111E1e+3" - }, - { - "description": "[basx528] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "123,65" - }, - { - "description": "[basx523] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "7e12356789012x" - }, - { - "description": "[basx522] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)", - "string": "7e123567890x" - } - ] -} -`}, -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/decode.go b/vendor/gopkg.in.o/mgo.v2/bson/decode.go deleted file mode 100644 index 7c2d8416a..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/decode.go +++ /dev/null @@ -1,849 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// gobson - BSON library for Go. - -package bson - -import ( - "fmt" - "math" - "net/url" - "reflect" - "strconv" - "sync" - "time" -) - -type decoder struct { - in []byte - i int - docType reflect.Type -} - -var typeM = reflect.TypeOf(M{}) - -func newDecoder(in []byte) *decoder { - return &decoder{in, 0, typeM} -} - -// -------------------------------------------------------------------------- -// Some helper functions. - -func corrupted() { - panic("Document is corrupted") -} - -func settableValueOf(i interface{}) reflect.Value { - v := reflect.ValueOf(i) - sv := reflect.New(v.Type()).Elem() - sv.Set(v) - return sv -} - -// -------------------------------------------------------------------------- -// Unmarshaling of documents. - -const ( - setterUnknown = iota - setterNone - setterType - setterAddr -) - -var setterStyles map[reflect.Type]int -var setterIface reflect.Type -var setterMutex sync.RWMutex - -func init() { - var iface Setter - setterIface = reflect.TypeOf(&iface).Elem() - setterStyles = make(map[reflect.Type]int) -} - -func setterStyle(outt reflect.Type) int { - setterMutex.RLock() - style := setterStyles[outt] - setterMutex.RUnlock() - if style == setterUnknown { - setterMutex.Lock() - defer setterMutex.Unlock() - if outt.Implements(setterIface) { - setterStyles[outt] = setterType - } else if reflect.PtrTo(outt).Implements(setterIface) { - setterStyles[outt] = setterAddr - } else { - setterStyles[outt] = setterNone - } - style = setterStyles[outt] - } - return style -} - -func getSetter(outt reflect.Type, out reflect.Value) Setter { - style := setterStyle(outt) - if style == setterNone { - return nil - } - if style == setterAddr { - if !out.CanAddr() { - return nil - } - out = out.Addr() - } else if outt.Kind() == reflect.Ptr && out.IsNil() { - out.Set(reflect.New(outt.Elem())) - } - return out.Interface().(Setter) -} - -func clearMap(m reflect.Value) { - var none reflect.Value - for _, k := range m.MapKeys() { - m.SetMapIndex(k, none) - } -} - -func (d *decoder) readDocTo(out reflect.Value) { - var elemType reflect.Type - outt := out.Type() - outk := outt.Kind() - - for { - if outk == reflect.Ptr && out.IsNil() { - out.Set(reflect.New(outt.Elem())) - } - if setter := getSetter(outt, out); setter != nil { - var raw Raw - d.readDocTo(reflect.ValueOf(&raw)) - err := setter.SetBSON(raw) - if _, ok := err.(*TypeError); err != nil && !ok { - panic(err) - } - return - } - if outk == reflect.Ptr { - out = out.Elem() - outt = out.Type() - outk = out.Kind() - continue - } - break - } - - var fieldsMap map[string]fieldInfo - var inlineMap reflect.Value - start := d.i - - origout := out - if outk == reflect.Interface { - if d.docType.Kind() == reflect.Map { - mv := reflect.MakeMap(d.docType) - out.Set(mv) - out = mv - } else { - dv := reflect.New(d.docType).Elem() - out.Set(dv) - out = dv - } - outt = out.Type() - outk = outt.Kind() - } - - docType := d.docType - keyType := typeString - convertKey := false - switch outk { - case reflect.Map: - keyType = outt.Key() - if keyType.Kind() != reflect.String { - panic("BSON map must have string keys. Got: " + outt.String()) - } - if keyType != typeString { - convertKey = true - } - elemType = outt.Elem() - if elemType == typeIface { - d.docType = outt - } - if out.IsNil() { - out.Set(reflect.MakeMap(out.Type())) - } else if out.Len() > 0 { - clearMap(out) - } - case reflect.Struct: - if outt != typeRaw { - sinfo, err := getStructInfo(out.Type()) - if err != nil { - panic(err) - } - fieldsMap = sinfo.FieldsMap - out.Set(sinfo.Zero) - if sinfo.InlineMap != -1 { - inlineMap = out.Field(sinfo.InlineMap) - if !inlineMap.IsNil() && inlineMap.Len() > 0 { - clearMap(inlineMap) - } - elemType = inlineMap.Type().Elem() - if elemType == typeIface { - d.docType = inlineMap.Type() - } - } - } - case reflect.Slice: - switch outt.Elem() { - case typeDocElem: - origout.Set(d.readDocElems(outt)) - return - case typeRawDocElem: - origout.Set(d.readRawDocElems(outt)) - return - } - fallthrough - default: - panic("Unsupported document type for unmarshalling: " + out.Type().String()) - } - - end := int(d.readInt32()) - end += d.i - 4 - if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { - corrupted() - } - for d.in[d.i] != '\x00' { - kind := d.readByte() - name := d.readCStr() - if d.i >= end { - corrupted() - } - - switch outk { - case reflect.Map: - e := reflect.New(elemType).Elem() - if d.readElemTo(e, kind) { - k := reflect.ValueOf(name) - if convertKey { - k = k.Convert(keyType) - } - out.SetMapIndex(k, e) - } - case reflect.Struct: - if outt == typeRaw { - d.dropElem(kind) - } else { - if info, ok := fieldsMap[name]; ok { - if info.Inline == nil { - d.readElemTo(out.Field(info.Num), kind) - } else { - d.readElemTo(out.FieldByIndex(info.Inline), kind) - } - } else if inlineMap.IsValid() { - if inlineMap.IsNil() { - inlineMap.Set(reflect.MakeMap(inlineMap.Type())) - } - e := reflect.New(elemType).Elem() - if d.readElemTo(e, kind) { - inlineMap.SetMapIndex(reflect.ValueOf(name), e) - } - } else { - d.dropElem(kind) - } - } - case reflect.Slice: - } - - if d.i >= end { - corrupted() - } - } - d.i++ // '\x00' - if d.i != end { - corrupted() - } - d.docType = docType - - if outt == typeRaw { - out.Set(reflect.ValueOf(Raw{0x03, d.in[start:d.i]})) - } -} - -func (d *decoder) readArrayDocTo(out reflect.Value) { - end := int(d.readInt32()) - end += d.i - 4 - if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { - corrupted() - } - i := 0 - l := out.Len() - for d.in[d.i] != '\x00' { - if i >= l { - panic("Length mismatch on array field") - } - kind := d.readByte() - for d.i < end && d.in[d.i] != '\x00' { - d.i++ - } - if d.i >= end { - corrupted() - } - d.i++ - d.readElemTo(out.Index(i), kind) - if d.i >= end { - corrupted() - } - i++ - } - if i != l { - panic("Length mismatch on array field") - } - d.i++ // '\x00' - if d.i != end { - corrupted() - } -} - -func (d *decoder) readSliceDoc(t reflect.Type) interface{} { - tmp := make([]reflect.Value, 0, 8) - elemType := t.Elem() - if elemType == typeRawDocElem { - d.dropElem(0x04) - return reflect.Zero(t).Interface() - } - - end := int(d.readInt32()) - end += d.i - 4 - if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { - corrupted() - } - for d.in[d.i] != '\x00' { - kind := d.readByte() - for d.i < end && d.in[d.i] != '\x00' { - d.i++ - } - if d.i >= end { - corrupted() - } - d.i++ - e := reflect.New(elemType).Elem() - if d.readElemTo(e, kind) { - tmp = append(tmp, e) - } - if d.i >= end { - corrupted() - } - } - d.i++ // '\x00' - if d.i != end { - corrupted() - } - - n := len(tmp) - slice := reflect.MakeSlice(t, n, n) - for i := 0; i != n; i++ { - slice.Index(i).Set(tmp[i]) - } - return slice.Interface() -} - -var typeSlice = reflect.TypeOf([]interface{}{}) -var typeIface = typeSlice.Elem() - -func (d *decoder) readDocElems(typ reflect.Type) reflect.Value { - docType := d.docType - d.docType = typ - slice := make([]DocElem, 0, 8) - d.readDocWith(func(kind byte, name string) { - e := DocElem{Name: name} - v := reflect.ValueOf(&e.Value) - if d.readElemTo(v.Elem(), kind) { - slice = append(slice, e) - } - }) - slicev := reflect.New(typ).Elem() - slicev.Set(reflect.ValueOf(slice)) - d.docType = docType - return slicev -} - -func (d *decoder) readRawDocElems(typ reflect.Type) reflect.Value { - docType := d.docType - d.docType = typ - slice := make([]RawDocElem, 0, 8) - d.readDocWith(func(kind byte, name string) { - e := RawDocElem{Name: name} - v := reflect.ValueOf(&e.Value) - if d.readElemTo(v.Elem(), kind) { - slice = append(slice, e) - } - }) - slicev := reflect.New(typ).Elem() - slicev.Set(reflect.ValueOf(slice)) - d.docType = docType - return slicev -} - -func (d *decoder) readDocWith(f func(kind byte, name string)) { - end := int(d.readInt32()) - end += d.i - 4 - if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { - corrupted() - } - for d.in[d.i] != '\x00' { - kind := d.readByte() - name := d.readCStr() - if d.i >= end { - corrupted() - } - f(kind, name) - if d.i >= end { - corrupted() - } - } - d.i++ // '\x00' - if d.i != end { - corrupted() - } -} - -// -------------------------------------------------------------------------- -// Unmarshaling of individual elements within a document. - -var blackHole = settableValueOf(struct{}{}) - -func (d *decoder) dropElem(kind byte) { - d.readElemTo(blackHole, kind) -} - -// Attempt to decode an element from the document and put it into out. -// If the types are not compatible, the returned ok value will be -// false and out will be unchanged. -func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) { - - start := d.i - - if kind == 0x03 { - // Delegate unmarshaling of documents. - outt := out.Type() - outk := out.Kind() - switch outk { - case reflect.Interface, reflect.Ptr, reflect.Struct, reflect.Map: - d.readDocTo(out) - return true - } - if setterStyle(outt) != setterNone { - d.readDocTo(out) - return true - } - if outk == reflect.Slice { - switch outt.Elem() { - case typeDocElem: - out.Set(d.readDocElems(outt)) - case typeRawDocElem: - out.Set(d.readRawDocElems(outt)) - default: - d.readDocTo(blackHole) - } - return true - } - d.readDocTo(blackHole) - return true - } - - var in interface{} - - switch kind { - case 0x01: // Float64 - in = d.readFloat64() - case 0x02: // UTF-8 string - in = d.readStr() - case 0x03: // Document - panic("Can't happen. Handled above.") - case 0x04: // Array - outt := out.Type() - if setterStyle(outt) != setterNone { - // Skip the value so its data is handed to the setter below. - d.dropElem(kind) - break - } - for outt.Kind() == reflect.Ptr { - outt = outt.Elem() - } - switch outt.Kind() { - case reflect.Array: - d.readArrayDocTo(out) - return true - case reflect.Slice: - in = d.readSliceDoc(outt) - default: - in = d.readSliceDoc(typeSlice) - } - case 0x05: // Binary - b := d.readBinary() - if b.Kind == 0x00 || b.Kind == 0x02 { - in = b.Data - } else { - in = b - } - case 0x06: // Undefined (obsolete, but still seen in the wild) - in = Undefined - case 0x07: // ObjectId - in = ObjectId(d.readBytes(12)) - case 0x08: // Bool - in = d.readBool() - case 0x09: // Timestamp - // MongoDB handles timestamps as milliseconds. - i := d.readInt64() - if i == -62135596800000 { - in = time.Time{} // In UTC for convenience. - } else { - in = time.Unix(i/1e3, i%1e3*1e6) - } - case 0x0A: // Nil - in = nil - case 0x0B: // RegEx - in = d.readRegEx() - case 0x0C: - in = DBPointer{Namespace: d.readStr(), Id: ObjectId(d.readBytes(12))} - case 0x0D: // JavaScript without scope - in = JavaScript{Code: d.readStr()} - case 0x0E: // Symbol - in = Symbol(d.readStr()) - case 0x0F: // JavaScript with scope - d.i += 4 // Skip length - js := JavaScript{d.readStr(), make(M)} - d.readDocTo(reflect.ValueOf(js.Scope)) - in = js - case 0x10: // Int32 - in = int(d.readInt32()) - case 0x11: // Mongo-specific timestamp - in = MongoTimestamp(d.readInt64()) - case 0x12: // Int64 - in = d.readInt64() - case 0x13: // Decimal128 - in = Decimal128{ - l: uint64(d.readInt64()), - h: uint64(d.readInt64()), - } - case 0x7F: // Max key - in = MaxKey - case 0xFF: // Min key - in = MinKey - default: - panic(fmt.Sprintf("Unknown element kind (0x%02X)", kind)) - } - - outt := out.Type() - - if outt == typeRaw { - out.Set(reflect.ValueOf(Raw{kind, d.in[start:d.i]})) - return true - } - - if setter := getSetter(outt, out); setter != nil { - err := setter.SetBSON(Raw{kind, d.in[start:d.i]}) - if err == SetZero { - out.Set(reflect.Zero(outt)) - return true - } - if err == nil { - return true - } - if _, ok := err.(*TypeError); !ok { - panic(err) - } - return false - } - - if in == nil { - out.Set(reflect.Zero(outt)) - return true - } - - outk := outt.Kind() - - // Dereference and initialize pointer if necessary. - first := true - for outk == reflect.Ptr { - if !out.IsNil() { - out = out.Elem() - } else { - elem := reflect.New(outt.Elem()) - if first { - // Only set if value is compatible. - first = false - defer func(out, elem reflect.Value) { - if good { - out.Set(elem) - } - }(out, elem) - } else { - out.Set(elem) - } - out = elem - } - outt = out.Type() - outk = outt.Kind() - } - - inv := reflect.ValueOf(in) - if outt == inv.Type() { - out.Set(inv) - return true - } - - switch outk { - case reflect.Interface: - out.Set(inv) - return true - case reflect.String: - switch inv.Kind() { - case reflect.String: - out.SetString(inv.String()) - return true - case reflect.Slice: - if b, ok := in.([]byte); ok { - out.SetString(string(b)) - return true - } - case reflect.Int, reflect.Int64: - if outt == typeJSONNumber { - out.SetString(strconv.FormatInt(inv.Int(), 10)) - return true - } - case reflect.Float64: - if outt == typeJSONNumber { - out.SetString(strconv.FormatFloat(inv.Float(), 'f', -1, 64)) - return true - } - } - case reflect.Slice, reflect.Array: - // Remember, array (0x04) slices are built with the correct - // element type. If we are here, must be a cross BSON kind - // conversion (e.g. 0x05 unmarshalling on string). - if outt.Elem().Kind() != reflect.Uint8 { - break - } - switch inv.Kind() { - case reflect.String: - slice := []byte(inv.String()) - out.Set(reflect.ValueOf(slice)) - return true - case reflect.Slice: - switch outt.Kind() { - case reflect.Array: - reflect.Copy(out, inv) - case reflect.Slice: - out.SetBytes(inv.Bytes()) - } - return true - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch inv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - out.SetInt(inv.Int()) - return true - case reflect.Float32, reflect.Float64: - out.SetInt(int64(inv.Float())) - return true - case reflect.Bool: - if inv.Bool() { - out.SetInt(1) - } else { - out.SetInt(0) - } - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - panic("can't happen: no uint types in BSON (!?)") - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - switch inv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - out.SetUint(uint64(inv.Int())) - return true - case reflect.Float32, reflect.Float64: - out.SetUint(uint64(inv.Float())) - return true - case reflect.Bool: - if inv.Bool() { - out.SetUint(1) - } else { - out.SetUint(0) - } - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - panic("Can't happen. No uint types in BSON.") - } - case reflect.Float32, reflect.Float64: - switch inv.Kind() { - case reflect.Float32, reflect.Float64: - out.SetFloat(inv.Float()) - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - out.SetFloat(float64(inv.Int())) - return true - case reflect.Bool: - if inv.Bool() { - out.SetFloat(1) - } else { - out.SetFloat(0) - } - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - panic("Can't happen. No uint types in BSON?") - } - case reflect.Bool: - switch inv.Kind() { - case reflect.Bool: - out.SetBool(inv.Bool()) - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - out.SetBool(inv.Int() != 0) - return true - case reflect.Float32, reflect.Float64: - out.SetBool(inv.Float() != 0) - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - panic("Can't happen. No uint types in BSON?") - } - case reflect.Struct: - if outt == typeURL && inv.Kind() == reflect.String { - u, err := url.Parse(inv.String()) - if err != nil { - panic(err) - } - out.Set(reflect.ValueOf(u).Elem()) - return true - } - if outt == typeBinary { - if b, ok := in.([]byte); ok { - out.Set(reflect.ValueOf(Binary{Data: b})) - return true - } - } - } - - return false -} - -// -------------------------------------------------------------------------- -// Parsers of basic types. - -func (d *decoder) readRegEx() RegEx { - re := RegEx{} - re.Pattern = d.readCStr() - re.Options = d.readCStr() - return re -} - -func (d *decoder) readBinary() Binary { - l := d.readInt32() - b := Binary{} - b.Kind = d.readByte() - b.Data = d.readBytes(l) - if b.Kind == 0x02 && len(b.Data) >= 4 { - // Weird obsolete format with redundant length. - b.Data = b.Data[4:] - } - return b -} - -func (d *decoder) readStr() string { - l := d.readInt32() - b := d.readBytes(l - 1) - if d.readByte() != '\x00' { - corrupted() - } - return string(b) -} - -func (d *decoder) readCStr() string { - start := d.i - end := start - l := len(d.in) - for ; end != l; end++ { - if d.in[end] == '\x00' { - break - } - } - d.i = end + 1 - if d.i > l { - corrupted() - } - return string(d.in[start:end]) -} - -func (d *decoder) readBool() bool { - b := d.readByte() - if b == 0 { - return false - } - if b == 1 { - return true - } - panic(fmt.Sprintf("encoded boolean must be 1 or 0, found %d", b)) -} - -func (d *decoder) readFloat64() float64 { - return math.Float64frombits(uint64(d.readInt64())) -} - -func (d *decoder) readInt32() int32 { - b := d.readBytes(4) - return int32((uint32(b[0]) << 0) | - (uint32(b[1]) << 8) | - (uint32(b[2]) << 16) | - (uint32(b[3]) << 24)) -} - -func (d *decoder) readInt64() int64 { - b := d.readBytes(8) - return int64((uint64(b[0]) << 0) | - (uint64(b[1]) << 8) | - (uint64(b[2]) << 16) | - (uint64(b[3]) << 24) | - (uint64(b[4]) << 32) | - (uint64(b[5]) << 40) | - (uint64(b[6]) << 48) | - (uint64(b[7]) << 56)) -} - -func (d *decoder) readByte() byte { - i := d.i - d.i++ - if d.i > len(d.in) { - corrupted() - } - return d.in[i] -} - -func (d *decoder) readBytes(length int32) []byte { - if length < 0 { - corrupted() - } - start := d.i - d.i += int(length) - if d.i < start || d.i > len(d.in) { - corrupted() - } - return d.in[start : start+int(length)] -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/encode.go b/vendor/gopkg.in.o/mgo.v2/bson/encode.go deleted file mode 100644 index add39e865..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/encode.go +++ /dev/null @@ -1,514 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// gobson - BSON library for Go. - -package bson - -import ( - "encoding/json" - "fmt" - "math" - "net/url" - "reflect" - "strconv" - "time" -) - -// -------------------------------------------------------------------------- -// Some internal infrastructure. - -var ( - typeBinary = reflect.TypeOf(Binary{}) - typeObjectId = reflect.TypeOf(ObjectId("")) - typeDBPointer = reflect.TypeOf(DBPointer{"", ObjectId("")}) - typeSymbol = reflect.TypeOf(Symbol("")) - typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0)) - typeOrderKey = reflect.TypeOf(MinKey) - typeDocElem = reflect.TypeOf(DocElem{}) - typeRawDocElem = reflect.TypeOf(RawDocElem{}) - typeRaw = reflect.TypeOf(Raw{}) - typeURL = reflect.TypeOf(url.URL{}) - typeTime = reflect.TypeOf(time.Time{}) - typeString = reflect.TypeOf("") - typeJSONNumber = reflect.TypeOf(json.Number("")) -) - -const itoaCacheSize = 32 - -var itoaCache []string - -func init() { - itoaCache = make([]string, itoaCacheSize) - for i := 0; i != itoaCacheSize; i++ { - itoaCache[i] = strconv.Itoa(i) - } -} - -func itoa(i int) string { - if i < itoaCacheSize { - return itoaCache[i] - } - return strconv.Itoa(i) -} - -// -------------------------------------------------------------------------- -// Marshaling of the document value itself. - -type encoder struct { - out []byte -} - -func (e *encoder) addDoc(v reflect.Value) { - for { - if vi, ok := v.Interface().(Getter); ok { - getv, err := vi.GetBSON() - if err != nil { - panic(err) - } - v = reflect.ValueOf(getv) - continue - } - if v.Kind() == reflect.Ptr { - v = v.Elem() - continue - } - break - } - - if v.Type() == typeRaw { - raw := v.Interface().(Raw) - if raw.Kind != 0x03 && raw.Kind != 0x00 { - panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document") - } - if len(raw.Data) == 0 { - panic("Attempted to marshal empty Raw document") - } - e.addBytes(raw.Data...) - return - } - - start := e.reserveInt32() - - switch v.Kind() { - case reflect.Map: - e.addMap(v) - case reflect.Struct: - e.addStruct(v) - case reflect.Array, reflect.Slice: - e.addSlice(v) - default: - panic("Can't marshal " + v.Type().String() + " as a BSON document") - } - - e.addBytes(0) - e.setInt32(start, int32(len(e.out)-start)) -} - -func (e *encoder) addMap(v reflect.Value) { - for _, k := range v.MapKeys() { - e.addElem(k.String(), v.MapIndex(k), false) - } -} - -func (e *encoder) addStruct(v reflect.Value) { - sinfo, err := getStructInfo(v.Type()) - if err != nil { - panic(err) - } - var value reflect.Value - if sinfo.InlineMap >= 0 { - m := v.Field(sinfo.InlineMap) - if m.Len() > 0 { - for _, k := range m.MapKeys() { - ks := k.String() - if _, found := sinfo.FieldsMap[ks]; found { - panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks)) - } - e.addElem(ks, m.MapIndex(k), false) - } - } - } - for _, info := range sinfo.FieldsList { - if info.Inline == nil { - value = v.Field(info.Num) - } else { - value = v.FieldByIndex(info.Inline) - } - if info.OmitEmpty && isZero(value) { - continue - } - e.addElem(info.Key, value, info.MinSize) - } -} - -func isZero(v reflect.Value) bool { - switch v.Kind() { - case reflect.String: - return len(v.String()) == 0 - case reflect.Ptr, reflect.Interface: - return v.IsNil() - case reflect.Slice: - return v.Len() == 0 - case reflect.Map: - return v.Len() == 0 - 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.Bool: - return !v.Bool() - case reflect.Struct: - vt := v.Type() - if vt == typeTime { - return v.Interface().(time.Time).IsZero() - } - for i := 0; i < v.NumField(); i++ { - if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous { - continue // Private field - } - if !isZero(v.Field(i)) { - return false - } - } - return true - } - return false -} - -func (e *encoder) addSlice(v reflect.Value) { - vi := v.Interface() - if d, ok := vi.(D); ok { - for _, elem := range d { - e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) - } - return - } - if d, ok := vi.(RawD); ok { - for _, elem := range d { - e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) - } - return - } - l := v.Len() - et := v.Type().Elem() - if et == typeDocElem { - for i := 0; i < l; i++ { - elem := v.Index(i).Interface().(DocElem) - e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) - } - return - } - if et == typeRawDocElem { - for i := 0; i < l; i++ { - elem := v.Index(i).Interface().(RawDocElem) - e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) - } - return - } - for i := 0; i < l; i++ { - e.addElem(itoa(i), v.Index(i), false) - } -} - -// -------------------------------------------------------------------------- -// Marshaling of elements in a document. - -func (e *encoder) addElemName(kind byte, name string) { - e.addBytes(kind) - e.addBytes([]byte(name)...) - e.addBytes(0) -} - -func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { - - if !v.IsValid() { - e.addElemName(0x0A, name) - return - } - - if getter, ok := v.Interface().(Getter); ok { - getv, err := getter.GetBSON() - if err != nil { - panic(err) - } - e.addElem(name, reflect.ValueOf(getv), minSize) - return - } - - switch v.Kind() { - - case reflect.Interface: - e.addElem(name, v.Elem(), minSize) - - case reflect.Ptr: - e.addElem(name, v.Elem(), minSize) - - case reflect.String: - s := v.String() - switch v.Type() { - case typeObjectId: - if len(s) != 12 { - panic("ObjectIDs must be exactly 12 bytes long (got " + - strconv.Itoa(len(s)) + ")") - } - e.addElemName(0x07, name) - e.addBytes([]byte(s)...) - case typeSymbol: - e.addElemName(0x0E, name) - e.addStr(s) - case typeJSONNumber: - n := v.Interface().(json.Number) - if i, err := n.Int64(); err == nil { - e.addElemName(0x12, name) - e.addInt64(i) - } else if f, err := n.Float64(); err == nil { - e.addElemName(0x01, name) - e.addFloat64(f) - } else { - panic("failed to convert json.Number to a number: " + s) - } - default: - e.addElemName(0x02, name) - e.addStr(s) - } - - case reflect.Float32, reflect.Float64: - e.addElemName(0x01, name) - e.addFloat64(v.Float()) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - u := v.Uint() - if int64(u) < 0 { - panic("BSON has no uint64 type, and value is too large to fit correctly in an int64") - } else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) { - e.addElemName(0x10, name) - e.addInt32(int32(u)) - } else { - e.addElemName(0x12, name) - e.addInt64(int64(u)) - } - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch v.Type() { - case typeMongoTimestamp: - e.addElemName(0x11, name) - e.addInt64(v.Int()) - - case typeOrderKey: - if v.Int() == int64(MaxKey) { - e.addElemName(0x7F, name) - } else { - e.addElemName(0xFF, name) - } - - default: - i := v.Int() - if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 { - // It fits into an int32, encode as such. - e.addElemName(0x10, name) - e.addInt32(int32(i)) - } else { - e.addElemName(0x12, name) - e.addInt64(i) - } - } - - case reflect.Bool: - e.addElemName(0x08, name) - if v.Bool() { - e.addBytes(1) - } else { - e.addBytes(0) - } - - case reflect.Map: - e.addElemName(0x03, name) - e.addDoc(v) - - case reflect.Slice: - vt := v.Type() - et := vt.Elem() - if et.Kind() == reflect.Uint8 { - e.addElemName(0x05, name) - e.addBinary(0x00, v.Bytes()) - } else if et == typeDocElem || et == typeRawDocElem { - e.addElemName(0x03, name) - e.addDoc(v) - } else { - e.addElemName(0x04, name) - e.addDoc(v) - } - - case reflect.Array: - et := v.Type().Elem() - if et.Kind() == reflect.Uint8 { - e.addElemName(0x05, name) - if v.CanAddr() { - e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte)) - } else { - n := v.Len() - e.addInt32(int32(n)) - e.addBytes(0x00) - for i := 0; i < n; i++ { - el := v.Index(i) - e.addBytes(byte(el.Uint())) - } - } - } else { - e.addElemName(0x04, name) - e.addDoc(v) - } - - case reflect.Struct: - switch s := v.Interface().(type) { - - case Raw: - kind := s.Kind - if kind == 0x00 { - kind = 0x03 - } - if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F { - panic("Attempted to marshal empty Raw document") - } - e.addElemName(kind, name) - e.addBytes(s.Data...) - - case Binary: - e.addElemName(0x05, name) - e.addBinary(s.Kind, s.Data) - - case Decimal128: - e.addElemName(0x13, name) - e.addInt64(int64(s.l)) - e.addInt64(int64(s.h)) - - case DBPointer: - e.addElemName(0x0C, name) - e.addStr(s.Namespace) - if len(s.Id) != 12 { - panic("ObjectIDs must be exactly 12 bytes long (got " + - strconv.Itoa(len(s.Id)) + ")") - } - e.addBytes([]byte(s.Id)...) - - case RegEx: - e.addElemName(0x0B, name) - e.addCStr(s.Pattern) - e.addCStr(s.Options) - - case JavaScript: - if s.Scope == nil { - e.addElemName(0x0D, name) - e.addStr(s.Code) - } else { - e.addElemName(0x0F, name) - start := e.reserveInt32() - e.addStr(s.Code) - e.addDoc(reflect.ValueOf(s.Scope)) - e.setInt32(start, int32(len(e.out)-start)) - } - - case time.Time: - // MongoDB handles timestamps as milliseconds. - e.addElemName(0x09, name) - e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6)) - - case url.URL: - e.addElemName(0x02, name) - e.addStr(s.String()) - - case undefined: - e.addElemName(0x06, name) - - default: - e.addElemName(0x03, name) - e.addDoc(v) - } - - default: - panic("Can't marshal " + v.Type().String() + " in a BSON document") - } -} - -// -------------------------------------------------------------------------- -// Marshaling of base types. - -func (e *encoder) addBinary(subtype byte, v []byte) { - if subtype == 0x02 { - // Wonder how that brilliant idea came to life. Obsolete, luckily. - e.addInt32(int32(len(v) + 4)) - e.addBytes(subtype) - e.addInt32(int32(len(v))) - } else { - e.addInt32(int32(len(v))) - e.addBytes(subtype) - } - e.addBytes(v...) -} - -func (e *encoder) addStr(v string) { - e.addInt32(int32(len(v) + 1)) - e.addCStr(v) -} - -func (e *encoder) addCStr(v string) { - e.addBytes([]byte(v)...) - e.addBytes(0) -} - -func (e *encoder) reserveInt32() (pos int) { - pos = len(e.out) - e.addBytes(0, 0, 0, 0) - return pos -} - -func (e *encoder) setInt32(pos int, v int32) { - e.out[pos+0] = byte(v) - e.out[pos+1] = byte(v >> 8) - e.out[pos+2] = byte(v >> 16) - e.out[pos+3] = byte(v >> 24) -} - -func (e *encoder) addInt32(v int32) { - u := uint32(v) - e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24)) -} - -func (e *encoder) addInt64(v int64) { - u := uint64(v) - e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24), - byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56)) -} - -func (e *encoder) addFloat64(v float64) { - e.addInt64(int64(math.Float64bits(v))) -} - -func (e *encoder) addBytes(v ...byte) { - e.out = append(e.out, v...) -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/json.go b/vendor/gopkg.in.o/mgo.v2/bson/json.go deleted file mode 100644 index 09df8260a..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/json.go +++ /dev/null @@ -1,380 +0,0 @@ -package bson - -import ( - "bytes" - "encoding/base64" - "fmt" - "gopkg.in/mgo.v2/internal/json" - "strconv" - "time" -) - -// UnmarshalJSON unmarshals a JSON value that may hold non-standard -// syntax as defined in BSON's extended JSON specification. -func UnmarshalJSON(data []byte, value interface{}) error { - d := json.NewDecoder(bytes.NewBuffer(data)) - d.Extend(&jsonExt) - return d.Decode(value) -} - -// MarshalJSON marshals a JSON value that may hold non-standard -// syntax as defined in BSON's extended JSON specification. -func MarshalJSON(value interface{}) ([]byte, error) { - var buf bytes.Buffer - e := json.NewEncoder(&buf) - e.Extend(&jsonExt) - err := e.Encode(value) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// jdec is used internally by the JSON decoding functions -// so they may unmarshal functions without getting into endless -// recursion due to keyed objects. -func jdec(data []byte, value interface{}) error { - d := json.NewDecoder(bytes.NewBuffer(data)) - d.Extend(&funcExt) - return d.Decode(value) -} - -var jsonExt json.Extension -var funcExt json.Extension - -// TODO -// - Shell regular expressions ("/regexp/opts") - -func init() { - jsonExt.DecodeUnquotedKeys(true) - jsonExt.DecodeTrailingCommas(true) - - funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary") - jsonExt.DecodeKeyed("$binary", jdecBinary) - jsonExt.DecodeKeyed("$binaryFunc", jdecBinary) - jsonExt.EncodeType([]byte(nil), jencBinarySlice) - jsonExt.EncodeType(Binary{}, jencBinaryType) - - funcExt.DecodeFunc("ISODate", "$dateFunc", "S") - funcExt.DecodeFunc("new Date", "$dateFunc", "S") - jsonExt.DecodeKeyed("$date", jdecDate) - jsonExt.DecodeKeyed("$dateFunc", jdecDate) - jsonExt.EncodeType(time.Time{}, jencDate) - - funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i") - jsonExt.DecodeKeyed("$timestamp", jdecTimestamp) - jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp) - - funcExt.DecodeConst("undefined", Undefined) - - jsonExt.DecodeKeyed("$regex", jdecRegEx) - jsonExt.EncodeType(RegEx{}, jencRegEx) - - funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id") - jsonExt.DecodeKeyed("$oid", jdecObjectId) - jsonExt.DecodeKeyed("$oidFunc", jdecObjectId) - jsonExt.EncodeType(ObjectId(""), jencObjectId) - - funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id") - jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef) - - funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N") - jsonExt.DecodeKeyed("$numberLong", jdecNumberLong) - jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong) - jsonExt.EncodeType(int64(0), jencNumberLong) - jsonExt.EncodeType(int(0), jencInt) - - funcExt.DecodeConst("MinKey", MinKey) - funcExt.DecodeConst("MaxKey", MaxKey) - jsonExt.DecodeKeyed("$minKey", jdecMinKey) - jsonExt.DecodeKeyed("$maxKey", jdecMaxKey) - jsonExt.EncodeType(orderKey(0), jencMinMaxKey) - - jsonExt.DecodeKeyed("$undefined", jdecUndefined) - jsonExt.EncodeType(Undefined, jencUndefined) - - jsonExt.Extend(&funcExt) -} - -func fbytes(format string, args ...interface{}) []byte { - var buf bytes.Buffer - fmt.Fprintf(&buf, format, args...) - return buf.Bytes() -} - -func jdecBinary(data []byte) (interface{}, error) { - var v struct { - Binary []byte `json:"$binary"` - Type string `json:"$type"` - Func struct { - Binary []byte `json:"$binary"` - Type int64 `json:"$type"` - } `json:"$binaryFunc"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - - var binData []byte - var binKind int64 - if v.Type == "" && v.Binary == nil { - binData = v.Func.Binary - binKind = v.Func.Type - } else if v.Type == "" { - return v.Binary, nil - } else { - binData = v.Binary - binKind, err = strconv.ParseInt(v.Type, 0, 64) - if err != nil { - binKind = -1 - } - } - - if binKind == 0 { - return binData, nil - } - if binKind < 0 || binKind > 255 { - return nil, fmt.Errorf("invalid type in binary object: %s", data) - } - - return Binary{Kind: byte(binKind), Data: binData}, nil -} - -func jencBinarySlice(v interface{}) ([]byte, error) { - in := v.([]byte) - out := make([]byte, base64.StdEncoding.EncodedLen(len(in))) - base64.StdEncoding.Encode(out, in) - return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil -} - -func jencBinaryType(v interface{}) ([]byte, error) { - in := v.(Binary) - out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data))) - base64.StdEncoding.Encode(out, in.Data) - return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil -} - -const jdateFormat = "2006-01-02T15:04:05.999Z" - -func jdecDate(data []byte) (interface{}, error) { - var v struct { - S string `json:"$date"` - Func struct { - S string - } `json:"$dateFunc"` - } - _ = jdec(data, &v) - if v.S == "" { - v.S = v.Func.S - } - if v.S != "" { - for _, format := range []string{jdateFormat, "2006-01-02"} { - t, err := time.Parse(format, v.S) - if err == nil { - return t, nil - } - } - return nil, fmt.Errorf("cannot parse date: %q", v.S) - } - - var vn struct { - Date struct { - N int64 `json:"$numberLong,string"` - } `json:"$date"` - Func struct { - S int64 - } `json:"$dateFunc"` - } - err := jdec(data, &vn) - if err != nil { - return nil, fmt.Errorf("cannot parse date: %q", data) - } - n := vn.Date.N - if n == 0 { - n = vn.Func.S - } - return time.Unix(n/1000, n%1000*1e6).UTC(), nil -} - -func jencDate(v interface{}) ([]byte, error) { - t := v.(time.Time) - return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil -} - -func jdecTimestamp(data []byte) (interface{}, error) { - var v struct { - Func struct { - T int32 `json:"t"` - I int32 `json:"i"` - } `json:"$timestamp"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil -} - -func jencTimestamp(v interface{}) ([]byte, error) { - ts := uint64(v.(MongoTimestamp)) - return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil -} - -func jdecRegEx(data []byte) (interface{}, error) { - var v struct { - Regex string `json:"$regex"` - Options string `json:"$options"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - return RegEx{v.Regex, v.Options}, nil -} - -func jencRegEx(v interface{}) ([]byte, error) { - re := v.(RegEx) - type regex struct { - Regex string `json:"$regex"` - Options string `json:"$options"` - } - return json.Marshal(regex{re.Pattern, re.Options}) -} - -func jdecObjectId(data []byte) (interface{}, error) { - var v struct { - Id string `json:"$oid"` - Func struct { - Id string - } `json:"$oidFunc"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - if v.Id == "" { - v.Id = v.Func.Id - } - return ObjectIdHex(v.Id), nil -} - -func jencObjectId(v interface{}) ([]byte, error) { - return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil -} - -func jdecDBRef(data []byte) (interface{}, error) { - // TODO Support unmarshaling $ref and $id into the input value. - var v struct { - Obj map[string]interface{} `json:"$dbrefFunc"` - } - // TODO Fix this. Must not be required. - v.Obj = make(map[string]interface{}) - err := jdec(data, &v) - if err != nil { - return nil, err - } - return v.Obj, nil -} - -func jdecNumberLong(data []byte) (interface{}, error) { - var v struct { - N int64 `json:"$numberLong,string"` - Func struct { - N int64 `json:",string"` - } `json:"$numberLongFunc"` - } - var vn struct { - N int64 `json:"$numberLong"` - Func struct { - N int64 - } `json:"$numberLongFunc"` - } - err := jdec(data, &v) - if err != nil { - err = jdec(data, &vn) - v.N = vn.N - v.Func.N = vn.Func.N - } - if err != nil { - return nil, err - } - if v.N != 0 { - return v.N, nil - } - return v.Func.N, nil -} - -func jencNumberLong(v interface{}) ([]byte, error) { - n := v.(int64) - f := `{"$numberLong":"%d"}` - if n <= 1<<53 { - f = `{"$numberLong":%d}` - } - return fbytes(f, n), nil -} - -func jencInt(v interface{}) ([]byte, error) { - n := v.(int) - f := `{"$numberLong":"%d"}` - if int64(n) <= 1<<53 { - f = `%d` - } - return fbytes(f, n), nil -} - -func jdecMinKey(data []byte) (interface{}, error) { - var v struct { - N int64 `json:"$minKey"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - if v.N != 1 { - return nil, fmt.Errorf("invalid $minKey object: %s", data) - } - return MinKey, nil -} - -func jdecMaxKey(data []byte) (interface{}, error) { - var v struct { - N int64 `json:"$maxKey"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - if v.N != 1 { - return nil, fmt.Errorf("invalid $maxKey object: %s", data) - } - return MaxKey, nil -} - -func jencMinMaxKey(v interface{}) ([]byte, error) { - switch v.(orderKey) { - case MinKey: - return []byte(`{"$minKey":1}`), nil - case MaxKey: - return []byte(`{"$maxKey":1}`), nil - } - panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v)) -} - -func jdecUndefined(data []byte) (interface{}, error) { - var v struct { - B bool `json:"$undefined"` - } - err := jdec(data, &v) - if err != nil { - return nil, err - } - if !v.B { - return nil, fmt.Errorf("invalid $undefined object: %s", data) - } - return Undefined, nil -} - -func jencUndefined(v interface{}) ([]byte, error) { - return []byte(`{"$undefined":true}`), nil -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/json_test.go b/vendor/gopkg.in.o/mgo.v2/bson/json_test.go deleted file mode 100644 index 866f51c34..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/json_test.go +++ /dev/null @@ -1,184 +0,0 @@ -package bson_test - -import ( - "gopkg.in/mgo.v2/bson" - - . "gopkg.in/check.v1" - "reflect" - "strings" - "time" -) - -type jsonTest struct { - a interface{} // value encoded into JSON (optional) - b string // JSON expected as output of , and used as input to - c interface{} // Value expected from decoding , defaults to - e string // error string, if decoding (b) should fail -} - -var jsonTests = []jsonTest{ - // $binary - { - a: []byte("foo"), - b: `{"$binary":"Zm9v","$type":"0x0"}`, - }, { - a: bson.Binary{Kind: 2, Data: []byte("foo")}, - b: `{"$binary":"Zm9v","$type":"0x2"}`, - }, { - b: `BinData(2,"Zm9v")`, - c: bson.Binary{Kind: 2, Data: []byte("foo")}, - }, - - // $date - { - a: time.Date(2016, 5, 15, 1, 2, 3, 4000000, time.UTC), - b: `{"$date":"2016-05-15T01:02:03.004Z"}`, - }, { - b: `{"$date": {"$numberLong": "1002"}}`, - c: time.Date(1970, 1, 1, 0, 0, 1, 2e6, time.UTC), - }, { - b: `ISODate("2016-05-15T01:02:03.004Z")`, - c: time.Date(2016, 5, 15, 1, 2, 3, 4000000, time.UTC), - }, { - b: `new Date(1000)`, - c: time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC), - }, { - b: `new Date("2016-05-15")`, - c: time.Date(2016, 5, 15, 0, 0, 0, 0, time.UTC), - }, - - // $timestamp - { - a: bson.MongoTimestamp(4294967298), - b: `{"$timestamp":{"t":1,"i":2}}`, - }, { - b: `Timestamp(1, 2)`, - c: bson.MongoTimestamp(4294967298), - }, - - // $regex - { - a: bson.RegEx{"pattern", "options"}, - b: `{"$regex":"pattern","$options":"options"}`, - }, - - // $oid - { - a: bson.ObjectIdHex("0123456789abcdef01234567"), - b: `{"$oid":"0123456789abcdef01234567"}`, - }, { - b: `ObjectId("0123456789abcdef01234567")`, - c: bson.ObjectIdHex("0123456789abcdef01234567"), - }, - - // $ref (no special type) - { - b: `DBRef("name", "id")`, - c: map[string]interface{}{"$ref": "name", "$id": "id"}, - }, - - // $numberLong - { - a: 123, - b: `123`, - }, { - a: int64(9007199254740992), - b: `{"$numberLong":9007199254740992}`, - }, { - a: int64(1<<53 + 1), - b: `{"$numberLong":"9007199254740993"}`, - }, { - a: 1<<53 + 1, - b: `{"$numberLong":"9007199254740993"}`, - c: int64(9007199254740993), - }, { - b: `NumberLong(9007199254740992)`, - c: int64(1 << 53), - }, { - b: `NumberLong("9007199254740993")`, - c: int64(1<<53 + 1), - }, - - // $minKey, $maxKey - { - a: bson.MinKey, - b: `{"$minKey":1}`, - }, { - a: bson.MaxKey, - b: `{"$maxKey":1}`, - }, { - b: `MinKey`, - c: bson.MinKey, - }, { - b: `MaxKey`, - c: bson.MaxKey, - }, { - b: `{"$minKey":0}`, - e: `invalid $minKey object: {"$minKey":0}`, - }, { - b: `{"$maxKey":0}`, - e: `invalid $maxKey object: {"$maxKey":0}`, - }, - - { - a: bson.Undefined, - b: `{"$undefined":true}`, - }, { - b: `undefined`, - c: bson.Undefined, - }, { - b: `{"v": undefined}`, - c: struct{ V interface{} }{bson.Undefined}, - }, - - // Unquoted keys and trailing commas - { - b: `{$foo: ["bar",],}`, - c: map[string]interface{}{"$foo": []interface{}{"bar"}}, - }, -} - -func (s *S) TestJSON(c *C) { - for i, item := range jsonTests { - c.Logf("------------ (#%d)", i) - c.Logf("A: %#v", item.a) - c.Logf("B: %#v", item.b) - - if item.c == nil { - item.c = item.a - } else { - c.Logf("C: %#v", item.c) - } - if item.e != "" { - c.Logf("E: %s", item.e) - } - - if item.a != nil { - data, err := bson.MarshalJSON(item.a) - c.Assert(err, IsNil) - c.Logf("Dumped: %#v", string(data)) - c.Assert(strings.TrimSuffix(string(data), "\n"), Equals, item.b) - } - - var zero interface{} - if item.c == nil { - zero = &struct{}{} - } else { - zero = reflect.New(reflect.TypeOf(item.c)).Interface() - } - err := bson.UnmarshalJSON([]byte(item.b), zero) - if item.e != "" { - c.Assert(err, NotNil) - c.Assert(err.Error(), Equals, item.e) - continue - } - c.Assert(err, IsNil) - zerov := reflect.ValueOf(zero) - value := zerov.Interface() - if zerov.Kind() == reflect.Ptr { - value = zerov.Elem().Interface() - } - c.Logf("Loaded: %#v", value) - c.Assert(value, DeepEquals, item.c) - } -} diff --git a/vendor/gopkg.in.o/mgo.v2/bson/specdata/update.sh b/vendor/gopkg.in.o/mgo.v2/bson/specdata/update.sh deleted file mode 100755 index 1efd3d3b6..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/specdata/update.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -e - -if [ ! -d specifications ]; then - git clone -b bson git@github.com:jyemin/specifications -fi - -TESTFILE="../specdata_test.go" - -cat < $TESTFILE -package bson_test - -var specTests = []string{ -END - -for file in specifications/source/bson/tests/*.yml; do - ( - echo '`' - cat $file - echo -n '`,' - ) >> $TESTFILE -done - -echo '}' >> $TESTFILE - -gofmt -w $TESTFILE diff --git a/vendor/gopkg.in.o/mgo.v2/bson/specdata_test.go b/vendor/gopkg.in.o/mgo.v2/bson/specdata_test.go deleted file mode 100644 index 513f9b209..000000000 --- a/vendor/gopkg.in.o/mgo.v2/bson/specdata_test.go +++ /dev/null @@ -1,241 +0,0 @@ -package bson_test - -var specTests = []string{ - ` ---- -description: "Array type" -documents: - - - decoded: - a : [] - encoded: 0D000000046100050000000000 - - - decoded: - a: [10] - encoded: 140000000461000C0000001030000A0000000000 - - - # Decode an array that uses an empty string as the key - decodeOnly : true - decoded: - a: [10] - encoded: 130000000461000B00000010000A0000000000 - - - # Decode an array that uses a non-numeric string as the key - decodeOnly : true - decoded: - a: [10] - encoded: 150000000461000D000000106162000A0000000000 - - -`, ` ---- -description: "Boolean type" -documents: - - - encoded: "090000000862000100" - decoded: { "b" : true } - - - encoded: "090000000862000000" - decoded: { "b" : false } - - - `, ` ---- -description: "Corrupted BSON" -documents: - - - encoded: "09000000016600" - error: "truncated double" - - - encoded: "09000000026600" - error: "truncated string" - - - encoded: "09000000036600" - error: "truncated document" - - - encoded: "09000000046600" - error: "truncated array" - - - encoded: "09000000056600" - error: "truncated binary" - - - encoded: "09000000076600" - error: "truncated objectid" - - - encoded: "09000000086600" - error: "truncated boolean" - - - encoded: "09000000096600" - error: "truncated date" - - - encoded: "090000000b6600" - error: "truncated regex" - - - encoded: "090000000c6600" - error: "truncated db pointer" - - - encoded: "0C0000000d6600" - error: "truncated javascript" - - - encoded: "0C0000000e6600" - error: "truncated symbol" - - - encoded: "0C0000000f6600" - error: "truncated javascript with scope" - - - encoded: "0C000000106600" - error: "truncated int32" - - - encoded: "0C000000116600" - error: "truncated timestamp" - - - encoded: "0C000000126600" - error: "truncated int64" - - - encoded: "0400000000" - error: basic - - - encoded: "0500000001" - error: basic - - - encoded: "05000000" - error: basic - - - encoded: "0700000002610078563412" - error: basic - - - encoded: "090000001061000500" - error: basic - - - encoded: "00000000000000000000" - error: basic - - - encoded: "1300000002666f6f00040000006261720000" - error: "basic" - - - encoded: "1800000003666f6f000f0000001062617200ffffff7f0000" - error: basic - - - encoded: "1500000003666f6f000c0000000862617200010000" - error: basic - - - encoded: "1c00000003666f6f001200000002626172000500000062617a000000" - error: basic - - - encoded: "1000000002610004000000616263ff00" - error: string is not null-terminated - - - encoded: "0c0000000200000000000000" - error: bad_string_length - - - encoded: "120000000200ffffffff666f6f6261720000" - error: bad_string_length - - - encoded: "0c0000000e00000000000000" - error: bad_string_length - - - encoded: "120000000e00ffffffff666f6f6261720000" - error: bad_string_length - - - encoded: "180000000c00fa5bd841d6585d9900" - error: "" - - - encoded: "1e0000000c00ffffffff666f6f626172005259b56afa5bd841d6585d9900" - error: bad_string_length - - - encoded: "0c0000000d00000000000000" - error: bad_string_length - - - encoded: "0c0000000d00ffffffff0000" - error: bad_string_length - - - encoded: "1c0000000f001500000000000000000c000000020001000000000000" - error: bad_string_length - - - encoded: "1c0000000f0015000000ffffffff000c000000020001000000000000" - error: bad_string_length - - - encoded: "1c0000000f001500000001000000000c000000020000000000000000" - error: bad_string_length - - - encoded: "1c0000000f001500000001000000000c0000000200ffffffff000000" - error: bad_string_length - - - encoded: "0E00000008616263646566676869707172737475" - error: "Run-on CString" - - - encoded: "0100000000" - error: "An object size that's too small to even include the object size, but is correctly encoded, along with a correct EOO (and no data)" - - - encoded: "1a0000000e74657374000c00000068656c6c6f20776f726c6400000500000000" - error: "One object, but with object size listed smaller than it is in the data" - - - encoded: "05000000" - error: "One object, missing the EOO at the end" - - - encoded: "0500000001" - error: "One object, sized correctly, with a spot for an EOO, but the EOO is 0x01" - - - encoded: "05000000ff" - error: "One object, sized correctly, with a spot for an EOO, but the EOO is 0xff" - - - encoded: "0500000070" - error: "One object, sized correctly, with a spot for an EOO, but the EOO is 0x70" - - - encoded: "07000000000000" - error: "Invalid BSON type low range" - - - encoded: "07000000800000" - error: "Invalid BSON type high range" - - - encoded: "090000000862000200" - error: "Invalid boolean value of 2" - - - encoded: "09000000086200ff00" - error: "Invalid boolean value of -1" - `, ` ---- -description: "Int32 type" -documents: - - - decoded: - i: -2147483648 - encoded: 0C0000001069000000008000 - - - decoded: - i: 2147483647 - encoded: 0C000000106900FFFFFF7F00 - - - decoded: - i: -1 - encoded: 0C000000106900FFFFFFFF00 - - - decoded: - i: 0 - encoded: 0C0000001069000000000000 - - - decoded: - i: 1 - encoded: 0C0000001069000100000000 - -`, ` ---- -description: "String type" -documents: - - - decoded: - s : "" - encoded: 0D000000027300010000000000 - - - decoded: - s: "a" - encoded: 0E00000002730002000000610000 - - - decoded: - s: "This is a string" - encoded: 1D0000000273001100000054686973206973206120737472696E670000 - - - decoded: - s: "κόσμε" - encoded: 180000000273000C000000CEBAE1BDB9CF83CEBCCEB50000 -`} diff --git a/vendor/gopkg.in.o/mgo.v2/internal/json/bench_test.go b/vendor/gopkg.in.o/mgo.v2/internal/json/bench_test.go deleted file mode 100644 index cd7380b1e..000000000 --- a/vendor/gopkg.in.o/mgo.v2/internal/json/bench_test.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Large data benchmark. -// The JSON data is a summary of agl's changes in the -// go, webkit, and chromium open source projects. -// We benchmark converting between the JSON form -// and in-memory data structures. - -package json - -import ( - "bytes" - "compress/gzip" - "io/ioutil" - "os" - "strings" - "testing" -) - -type codeResponse struct { - Tree *codeNode `json:"tree"` - Username string `json:"username"` -} - -type codeNode struct { - Name string `json:"name"` - Kids []*codeNode `json:"kids"` - CLWeight float64 `json:"cl_weight"` - Touches int `json:"touches"` - MinT int64 `json:"min_t"` - MaxT int64 `json:"max_t"` - MeanT int64 `json:"mean_t"` -} - -var codeJSON []byte -var codeStruct codeResponse - -func codeInit() { - f, err := os.Open("testdata/code.json.gz") - if err != nil { - panic(err) - } - defer f.Close() - gz, err := gzip.NewReader(f) - if err != nil { - panic(err) - } - data, err := ioutil.ReadAll(gz) - if err != nil { - panic(err) - } - - codeJSON = data - - if err := Unmarshal(codeJSON, &codeStruct); err != nil { - panic("unmarshal code.json: " + err.Error()) - } - - if data, err = Marshal(&codeStruct); err != nil { - panic("marshal code.json: " + err.Error()) - } - - if !bytes.Equal(data, codeJSON) { - println("different lengths", len(data), len(codeJSON)) - for i := 0; i < len(data) && i < len(codeJSON); i++ { - if data[i] != codeJSON[i] { - println("re-marshal: changed at byte", i) - println("orig: ", string(codeJSON[i-10:i+10])) - println("new: ", string(data[i-10:i+10])) - break - } - } - panic("re-marshal code.json: different result") - } -} - -func BenchmarkCodeEncoder(b *testing.B) { - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - enc := NewEncoder(ioutil.Discard) - for i := 0; i < b.N; i++ { - if err := enc.Encode(&codeStruct); err != nil { - b.Fatal("Encode:", err) - } - } - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeMarshal(b *testing.B) { - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - for i := 0; i < b.N; i++ { - if _, err := Marshal(&codeStruct); err != nil { - b.Fatal("Marshal:", err) - } - } - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeDecoder(b *testing.B) { - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - var buf bytes.Buffer - dec := NewDecoder(&buf) - var r codeResponse - for i := 0; i < b.N; i++ { - buf.Write(codeJSON) - // hide EOF - buf.WriteByte('\n') - buf.WriteByte('\n') - buf.WriteByte('\n') - if err := dec.Decode(&r); err != nil { - b.Fatal("Decode:", err) - } - } - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkDecoderStream(b *testing.B) { - b.StopTimer() - var buf bytes.Buffer - dec := NewDecoder(&buf) - buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n") - var x interface{} - if err := dec.Decode(&x); err != nil { - b.Fatal("Decode:", err) - } - ones := strings.Repeat(" 1\n", 300000) + "\n\n\n" - b.StartTimer() - for i := 0; i < b.N; i++ { - if i%300000 == 0 { - buf.WriteString(ones) - } - x = nil - if err := dec.Decode(&x); err != nil || x != 1.0 { - b.Fatalf("Decode: %v after %d", err, i) - } - } -} - -func BenchmarkCodeUnmarshal(b *testing.B) { - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - for i := 0; i < b.N; i++ { - var r codeResponse - if err := Unmarshal(codeJSON, &r); err != nil { - b.Fatal("Unmarshal:", err) - } - } - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeUnmarshalReuse(b *testing.B) { - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - var r codeResponse - for i := 0; i < b.N; i++ { - if err := Unmarshal(codeJSON, &r); err != nil { - b.Fatal("Unmarshal:", err) - } - } -} - -func BenchmarkUnmarshalString(b *testing.B) { - data := []byte(`"hello, world"`) - var s string - - for i := 0; i < b.N; i++ { - if err := Unmarshal(data, &s); err != nil { - b.Fatal("Unmarshal:", err) - } - } -} - -func BenchmarkUnmarshalFloat64(b *testing.B) { - var f float64 - data := []byte(`3.14`) - - for i := 0; i < b.N; i++ { - if err := Unmarshal(data, &f); err != nil { - b.Fatal("Unmarshal:", err) - } - } -} - -func BenchmarkUnmarshalInt64(b *testing.B) { - var x int64 - data := []byte(`3`) - - for i := 0; i < b.N; i++ { - if err := Unmarshal(data, &x); err != nil { - b.Fatal("Unmarshal:", err) - } - } -} - -func BenchmarkIssue10335(b *testing.B) { - b.ReportAllocs() - var s struct{} - j := []byte(`{"a":{ }}`) - for n := 0; n < b.N; n++ { - if err := Unmarshal(j, &s); err != nil { - b.Fatal(err) - } - } -} diff --git a/vendor/gopkg.in.o/mgo.v2/internal/json/decode.go b/vendor/gopkg.in.o/mgo.v2/internal/json/decode.go deleted file mode 100644 index ce7c7d249..000000000 --- a/vendor/gopkg.in.o/mgo.v2/internal/json/decode.go +++ /dev/null @@ -1,1685 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Represents JSON data structure using native Go types: booleans, floats, -// strings, arrays, and maps. - -package json - -import ( - "bytes" - "encoding" - "encoding/base64" - "errors" - "fmt" - "reflect" - "runtime" - "strconv" - "unicode" - "unicode/utf16" - "unicode/utf8" -) - -// Unmarshal parses the JSON-encoded data and stores the result -// in the value pointed to by v. -// -// Unmarshal uses the inverse of the encodings that -// Marshal uses, allocating maps, slices, and pointers as necessary, -// with the following additional rules: -// -// To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal -// allocates a new value for it to point to. -// -// To unmarshal JSON into a struct, Unmarshal matches incoming object -// keys to the keys used by Marshal (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. -// Unmarshal will only set exported fields of the struct. -// -// To unmarshal JSON into an interface value, -// Unmarshal stores one of these in the interface value: -// -// bool, for JSON booleans -// float64, for JSON numbers -// string, for JSON strings -// []interface{}, for JSON arrays -// map[string]interface{}, for JSON objects -// nil for JSON null -// -// To unmarshal a JSON array into a slice, Unmarshal resets the slice length -// to zero and then appends each element to the slice. -// As a special case, to unmarshal an empty JSON array into a slice, -// Unmarshal replaces the slice with a new empty slice. -// -// To unmarshal a JSON array into a Go array, Unmarshal decodes -// JSON array elements into corresponding Go array elements. -// If the Go array is smaller than the JSON array, -// the additional JSON array elements are discarded. -// If the JSON array is smaller than the Go array, -// the additional Go array elements are set to zero values. -// -// To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal -// reuses the existing map, keeping existing entries. Unmarshal then stores key- -// value pairs from the JSON object into the map. The map's key type must -// either be a string or implement encoding.TextUnmarshaler. -// -// If a JSON value is not appropriate for a given target type, -// or if a JSON number overflows the target type, Unmarshal -// skips that field and completes the unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns -// an UnmarshalTypeError describing the earliest such error. -// -// The JSON null value unmarshals into an interface, map, pointer, or slice -// by setting that Go value to nil. Because null is often used in JSON to mean -// ``not present,'' unmarshaling a JSON null into any other Go type has no effect -// on the value and produces no error. -// -// When unmarshaling quoted strings, invalid UTF-8 or -// invalid UTF-16 surrogate pairs are not treated as an error. -// Instead, they are replaced by the Unicode replacement -// character U+FFFD. -// -func Unmarshal(data []byte, v interface{}) error { - // Check for well-formedness. - // Avoids filling out half a data structure - // before discovering a JSON syntax error. - var d decodeState - err := checkValid(data, &d.scan) - if err != nil { - return err - } - - d.init(data) - return d.unmarshal(v) -} - -// Unmarshaler is the interface implemented by types -// that can unmarshal a JSON description of themselves. -// The input can be assumed to be a valid encoding of -// a JSON value. UnmarshalJSON must copy the JSON data -// if it wishes to retain the data after returning. -type Unmarshaler interface { - UnmarshalJSON([]byte) error -} - -// An UnmarshalTypeError describes a JSON value that was -// not appropriate for a value of a specific Go type. -type UnmarshalTypeError struct { - Value string // description of JSON value - "bool", "array", "number -5" - Type reflect.Type // type of Go value it could not be assigned to - Offset int64 // error occurred after reading Offset bytes -} - -func (e *UnmarshalTypeError) Error() string { - return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() -} - -// An UnmarshalFieldError describes a JSON object key that -// led to an unexported (and therefore unwritable) struct field. -// (No longer used; kept for compatibility.) -type UnmarshalFieldError struct { - Key string - Type reflect.Type - Field reflect.StructField -} - -func (e *UnmarshalFieldError) Error() string { - return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() -} - -// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. -// (The argument to Unmarshal must be a non-nil pointer.) -type InvalidUnmarshalError struct { - Type reflect.Type -} - -func (e *InvalidUnmarshalError) Error() string { - if e.Type == nil { - return "json: Unmarshal(nil)" - } - - if e.Type.Kind() != reflect.Ptr { - return "json: Unmarshal(non-pointer " + e.Type.String() + ")" - } - return "json: Unmarshal(nil " + e.Type.String() + ")" -} - -func (d *decodeState) unmarshal(v interface{}) (err error) { - defer func() { - if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } - err = r.(error) - } - }() - - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() { - return &InvalidUnmarshalError{reflect.TypeOf(v)} - } - - d.scan.reset() - // We decode rv not rv.Elem because the Unmarshaler interface - // test must be applied at the top level of the value. - d.value(rv) - return d.savedError -} - -// A Number represents a JSON number literal. -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { - return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { - return strconv.ParseInt(string(n), 10, 64) -} - -// isValidNumber reports whether s is a valid JSON number literal. -func isValidNumber(s string) bool { - // This function implements the JSON numbers grammar. - // See https://tools.ietf.org/html/rfc7159#section-6 - // and http://json.org/number.gif - - if s == "" { - return false - } - - // Optional - - if s[0] == '-' { - s = s[1:] - if s == "" { - return false - } - } - - // Digits - switch { - default: - return false - - case s[0] == '0': - s = s[1:] - - case '1' <= s[0] && s[0] <= '9': - s = s[1:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // . followed by 1 or more digits. - if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { - s = s[2:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // e or E followed by an optional - or + and - // 1 or more digits. - if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { - s = s[1:] - if s[0] == '+' || s[0] == '-' { - s = s[1:] - if s == "" { - return false - } - } - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // Make sure we are at the end. - return s == "" -} - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { - data []byte - off int // read offset in data - scan scanner - nextscan scanner // for calls to nextValue - savedError error - useNumber bool - ext Extension -} - -// errPhase is used for errors that should not happen unless -// there is a bug in the JSON decoder or something is editing -// the data slice while the decoder executes. -var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?") - -func (d *decodeState) init(data []byte) *decodeState { - d.data = data - d.off = 0 - d.savedError = nil - return d -} - -// error aborts the decoding by panicking with err. -func (d *decodeState) error(err error) { - panic(err) -} - -// saveError saves the first err it is called with, -// for reporting at the end of the unmarshal. -func (d *decodeState) saveError(err error) { - if d.savedError == nil { - d.savedError = err - } -} - -// next cuts off and returns the next full JSON value in d.data[d.off:]. -// The next value is known to be an object or array, not a literal. -func (d *decodeState) next() []byte { - c := d.data[d.off] - item, rest, err := nextValue(d.data[d.off:], &d.nextscan) - if err != nil { - d.error(err) - } - d.off = len(d.data) - len(rest) - - // Our scanner has seen the opening brace/bracket - // and thinks we're still in the middle of the object. - // invent a closing brace/bracket to get it out. - if c == '{' { - d.scan.step(&d.scan, '}') - } else if c == '[' { - d.scan.step(&d.scan, ']') - } else { - // Was inside a function name. Get out of it. - d.scan.step(&d.scan, '(') - d.scan.step(&d.scan, ')') - } - - return item -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -// It updates d.off and returns the new scan code. -func (d *decodeState) scanWhile(op int) int { - var newOp int - for { - if d.off >= len(d.data) { - newOp = d.scan.eof() - d.off = len(d.data) + 1 // mark processed EOF with len+1 - } else { - c := d.data[d.off] - d.off++ - newOp = d.scan.step(&d.scan, c) - } - if newOp != op { - break - } - } - return newOp -} - -// value decodes a JSON value from d.data[d.off:] into the value. -// it updates d.off to point past the decoded value. -func (d *decodeState) value(v reflect.Value) { - if !v.IsValid() { - _, rest, err := nextValue(d.data[d.off:], &d.nextscan) - if err != nil { - d.error(err) - } - d.off = len(d.data) - len(rest) - - // d.scan thinks we're still at the beginning of the item. - // Feed in an empty string - the shortest, simplest value - - // so that it knows we got to the end of the value. - if d.scan.redo { - // rewind. - d.scan.redo = false - d.scan.step = stateBeginValue - } - d.scan.step(&d.scan, '"') - d.scan.step(&d.scan, '"') - - n := len(d.scan.parseState) - if n > 0 && d.scan.parseState[n-1] == parseObjectKey { - // d.scan thinks we just read an object key; finish the object - d.scan.step(&d.scan, ':') - d.scan.step(&d.scan, '"') - d.scan.step(&d.scan, '"') - d.scan.step(&d.scan, '}') - } - - return - } - - switch op := d.scanWhile(scanSkipSpace); op { - default: - d.error(errPhase) - - case scanBeginArray: - d.array(v) - - case scanBeginObject: - d.object(v) - - case scanBeginLiteral: - d.literal(v) - - case scanBeginName: - d.name(v) - } -} - -type unquotedValue struct{} - -// valueQuoted is like value but decodes a -// quoted string literal or literal null into an interface value. -// If it finds anything other than a quoted string literal or null, -// valueQuoted returns unquotedValue{}. -func (d *decodeState) valueQuoted() interface{} { - switch op := d.scanWhile(scanSkipSpace); op { - default: - d.error(errPhase) - - case scanBeginArray: - d.array(reflect.Value{}) - - case scanBeginObject: - d.object(reflect.Value{}) - - case scanBeginName: - switch v := d.nameInterface().(type) { - case nil, string: - return v - } - - case scanBeginLiteral: - switch v := d.literalInterface().(type) { - case nil, string: - return v - } - } - return unquotedValue{} -} - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// if it encounters an Unmarshaler, indirect stops and returns that. -// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. -func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { - // If v is a named type and is addressable, - // start with its address, so that if the type has pointer methods, - // we find them. - if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { - v = v.Addr() - } - for { - // Load value from interface, but only if the result will be - // usefully addressable. - if v.Kind() == reflect.Interface && !v.IsNil() { - e := v.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { - v = e - continue - } - } - - if v.Kind() != reflect.Ptr { - break - } - - if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { - break - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - if v.Type().NumMethod() > 0 { - if u, ok := v.Interface().(Unmarshaler); ok { - return u, nil, v - } - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - return nil, u, v - } - } - v = v.Elem() - } - return nil, nil, v -} - -// array consumes an array from d.data[d.off-1:], decoding into the value v. -// the first byte of the array ('[') has been read already. -func (d *decodeState) array(v reflect.Value) { - // Check for unmarshaler. - u, ut, pv := d.indirect(v, false) - if u != nil { - d.off-- - err := u.UnmarshalJSON(d.next()) - if err != nil { - d.error(err) - } - return - } - if ut != nil { - d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) - d.off-- - d.next() - return - } - - v = pv - - // Check type of target. - switch v.Kind() { - case reflect.Interface: - if v.NumMethod() == 0 { - // Decoding into nil interface? Switch to non-reflect code. - v.Set(reflect.ValueOf(d.arrayInterface())) - return - } - // Otherwise it's invalid. - fallthrough - default: - d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) - d.off-- - d.next() - return - case reflect.Array: - case reflect.Slice: - break - } - - i := 0 - for { - // Look ahead for ] - can only happen on first iteration. - op := d.scanWhile(scanSkipSpace) - if op == scanEndArray { - break - } - - // Back up so d.value can have the byte we just read. - d.off-- - d.scan.undo(op) - - // Get element of array, growing if necessary. - if v.Kind() == reflect.Slice { - // Grow slice if necessary - if i >= v.Cap() { - newcap := v.Cap() + v.Cap()/2 - if newcap < 4 { - newcap = 4 - } - newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) - reflect.Copy(newv, v) - v.Set(newv) - } - if i >= v.Len() { - v.SetLen(i + 1) - } - } - - if i < v.Len() { - // Decode into element. - d.value(v.Index(i)) - } else { - // Ran out of fixed array: skip. - d.value(reflect.Value{}) - } - i++ - - // Next token must be , or ]. - op = d.scanWhile(scanSkipSpace) - if op == scanEndArray { - break - } - if op != scanArrayValue { - d.error(errPhase) - } - } - - if i < v.Len() { - if v.Kind() == reflect.Array { - // Array. Zero the rest. - z := reflect.Zero(v.Type().Elem()) - for ; i < v.Len(); i++ { - v.Index(i).Set(z) - } - } else { - v.SetLen(i) - } - } - if i == 0 && v.Kind() == reflect.Slice { - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) - } -} - -var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() - -// object consumes an object from d.data[d.off-1:], decoding into the value v. -// the first byte ('{') of the object has been read already. -func (d *decodeState) object(v reflect.Value) { - // Check for unmarshaler. - u, ut, pv := d.indirect(v, false) - if d.storeKeyed(pv) { - return - } - if u != nil { - d.off-- - err := u.UnmarshalJSON(d.next()) - if err != nil { - d.error(err) - } - return - } - if ut != nil { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return - } - v = pv - - // Decoding into nil interface? Switch to non-reflect code. - if v.Kind() == reflect.Interface && v.NumMethod() == 0 { - v.Set(reflect.ValueOf(d.objectInterface())) - return - } - - // Check type of target: - // struct or - // map[string]T or map[encoding.TextUnmarshaler]T - switch v.Kind() { - case reflect.Map: - // Map key must either have string kind or be an encoding.TextUnmarshaler. - t := v.Type() - if t.Key().Kind() != reflect.String && - !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return - } - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - case reflect.Struct: - - default: - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return - } - - var mapElem reflect.Value - - empty := true - for { - // Read opening " of string key or closing }. - op := d.scanWhile(scanSkipSpace) - if op == scanEndObject { - if !empty && !d.ext.trailingCommas { - d.syntaxError("beginning of object key string") - } - break - } - empty = false - if op == scanBeginName { - if !d.ext.unquotedKeys { - d.syntaxError("beginning of object key string") - } - } else if op != scanBeginLiteral { - d.error(errPhase) - } - unquotedKey := op == scanBeginName - - // Read key. - start := d.off - 1 - op = d.scanWhile(scanContinue) - item := d.data[start : d.off-1] - var key []byte - if unquotedKey { - key = item - // TODO Fix code below to quote item when necessary. - } else { - var ok bool - key, ok = unquoteBytes(item) - if !ok { - d.error(errPhase) - } - } - - // Figure out field corresponding to key. - var subv reflect.Value - destring := false // whether the value is wrapped in a string to be decoded first - - if v.Kind() == reflect.Map { - elemType := v.Type().Elem() - if !mapElem.IsValid() { - mapElem = reflect.New(elemType).Elem() - } else { - mapElem.Set(reflect.Zero(elemType)) - } - subv = mapElem - } else { - var f *field - fields := cachedTypeFields(v.Type()) - for i := range fields { - ff := &fields[i] - if bytes.Equal(ff.nameBytes, key) { - f = ff - break - } - if f == nil && ff.equalFold(ff.nameBytes, key) { - f = ff - } - } - if f != nil { - subv = v - destring = f.quoted - for _, i := range f.index { - if subv.Kind() == reflect.Ptr { - if subv.IsNil() { - subv.Set(reflect.New(subv.Type().Elem())) - } - subv = subv.Elem() - } - subv = subv.Field(i) - } - } - } - - // Read : before value. - if op == scanSkipSpace { - op = d.scanWhile(scanSkipSpace) - } - if op != scanObjectKey { - d.error(errPhase) - } - - // Read value. - if destring { - switch qv := d.valueQuoted().(type) { - case nil: - d.literalStore(nullLiteral, subv, false) - case string: - d.literalStore([]byte(qv), subv, true) - default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) - } - } else { - d.value(subv) - } - - // Write value back to map; - // if using struct, subv points into struct already. - if v.Kind() == reflect.Map { - kt := v.Type().Key() - var kv reflect.Value - switch { - case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(v.Type().Key()) - case reflect.PtrTo(kt).Implements(textUnmarshalerType): - kv = reflect.New(v.Type().Key()) - d.literalStore(item, kv, true) - kv = kv.Elem() - default: - panic("json: Unexpected key type") // should never occur - } - v.SetMapIndex(kv, subv) - } - - // Next token must be , or }. - op = d.scanWhile(scanSkipSpace) - if op == scanEndObject { - break - } - if op != scanObjectValue { - d.error(errPhase) - } - } -} - -// isNull returns whether there's a null literal at the provided offset. -func (d *decodeState) isNull(off int) bool { - if off+4 >= len(d.data) || d.data[off] != 'n' || d.data[off+1] != 'u' || d.data[off+2] != 'l' || d.data[off+3] != 'l' { - return false - } - d.nextscan.reset() - for i, c := range d.data[off:] { - if i > 4 { - return false - } - switch d.nextscan.step(&d.nextscan, c) { - case scanContinue, scanBeginName: - continue - } - break - } - return true -} - -// name consumes a const or function from d.data[d.off-1:], decoding into the value v. -// the first byte of the function name has been read already. -func (d *decodeState) name(v reflect.Value) { - if d.isNull(d.off-1) { - d.literal(v) - return - } - - // Check for unmarshaler. - u, ut, pv := d.indirect(v, false) - if d.storeKeyed(pv) { - return - } - if u != nil { - d.off-- - err := u.UnmarshalJSON(d.next()) - if err != nil { - d.error(err) - } - return - } - if ut != nil { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over function in input - return - } - v = pv - - // Decoding into nil interface? Switch to non-reflect code. - if v.Kind() == reflect.Interface && v.NumMethod() == 0 { - out := d.nameInterface() - if out == nil { - v.Set(reflect.Zero(v.Type())) - } else { - v.Set(reflect.ValueOf(out)) - } - return - } - - nameStart := d.off - 1 - - op := d.scanWhile(scanContinue) - - name := d.data[nameStart : d.off-1] - if op != scanParam { - // Back up so the byte just read is consumed next. - d.off-- - d.scan.undo(op) - if l, ok := d.convertLiteral(name); ok { - d.storeValue(v, l) - return - } - d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) - } - - funcName := string(name) - funcData := d.ext.funcs[funcName] - if funcData.key == "" { - d.error(fmt.Errorf("json: unknown function %q", funcName)) - } - - // Check type of target: - // struct or - // map[string]T or map[encoding.TextUnmarshaler]T - switch v.Kind() { - case reflect.Map: - // Map key must either have string kind or be an encoding.TextUnmarshaler. - t := v.Type() - if t.Key().Kind() != reflect.String && - !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return - } - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - case reflect.Struct: - - default: - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return - } - - // TODO Fix case of func field as map. - //topv := v - - // Figure out field corresponding to function. - key := []byte(funcData.key) - if v.Kind() == reflect.Map { - elemType := v.Type().Elem() - v = reflect.New(elemType).Elem() - } else { - var f *field - fields := cachedTypeFields(v.Type()) - for i := range fields { - ff := &fields[i] - if bytes.Equal(ff.nameBytes, key) { - f = ff - break - } - if f == nil && ff.equalFold(ff.nameBytes, key) { - f = ff - } - } - if f != nil { - for _, i := range f.index { - if v.Kind() == reflect.Ptr { - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - v = v.Elem() - } - v = v.Field(i) - } - if v.Kind() == reflect.Ptr { - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - v = v.Elem() - } - } - } - - // Check for unmarshaler on func field itself. - u, ut, pv = d.indirect(v, false) - if u != nil { - d.off = nameStart - err := u.UnmarshalJSON(d.next()) - if err != nil { - d.error(err) - } - return - } - - var mapElem reflect.Value - - // Parse function arguments. - for i := 0; ; i++ { - // closing ) - can only happen on first iteration. - op := d.scanWhile(scanSkipSpace) - if op == scanEndParams { - break - } - - // Back up so d.value can have the byte we just read. - d.off-- - d.scan.undo(op) - - if i >= len(funcData.args) { - d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) - } - key := []byte(funcData.args[i]) - - // Figure out field corresponding to key. - var subv reflect.Value - destring := false // whether the value is wrapped in a string to be decoded first - - if v.Kind() == reflect.Map { - elemType := v.Type().Elem() - if !mapElem.IsValid() { - mapElem = reflect.New(elemType).Elem() - } else { - mapElem.Set(reflect.Zero(elemType)) - } - subv = mapElem - } else { - var f *field - fields := cachedTypeFields(v.Type()) - for i := range fields { - ff := &fields[i] - if bytes.Equal(ff.nameBytes, key) { - f = ff - break - } - if f == nil && ff.equalFold(ff.nameBytes, key) { - f = ff - } - } - if f != nil { - subv = v - destring = f.quoted - for _, i := range f.index { - if subv.Kind() == reflect.Ptr { - if subv.IsNil() { - subv.Set(reflect.New(subv.Type().Elem())) - } - subv = subv.Elem() - } - subv = subv.Field(i) - } - } - } - - // Read value. - if destring { - switch qv := d.valueQuoted().(type) { - case nil: - d.literalStore(nullLiteral, subv, false) - case string: - d.literalStore([]byte(qv), subv, true) - default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) - } - } else { - d.value(subv) - } - - // Write value back to map; - // if using struct, subv points into struct already. - if v.Kind() == reflect.Map { - kt := v.Type().Key() - var kv reflect.Value - switch { - case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(v.Type().Key()) - case reflect.PtrTo(kt).Implements(textUnmarshalerType): - kv = reflect.New(v.Type().Key()) - d.literalStore(key, kv, true) - kv = kv.Elem() - default: - panic("json: Unexpected key type") // should never occur - } - v.SetMapIndex(kv, subv) - } - - // Next token must be , or ). - op = d.scanWhile(scanSkipSpace) - if op == scanEndParams { - break - } - if op != scanParam { - d.error(errPhase) - } - } -} - -// keyed attempts to decode an object or function using a keyed doc extension, -// and returns the value and true on success, or nil and false otherwise. -func (d *decodeState) keyed() (interface{}, bool) { - if len(d.ext.keyed) == 0 { - return nil, false - } - - unquote := false - - // Look-ahead first key to check for a keyed document extension. - d.nextscan.reset() - var start, end int - for i, c := range d.data[d.off-1:] { - switch op := d.nextscan.step(&d.nextscan, c); op { - case scanSkipSpace, scanContinue, scanBeginObject: - continue - case scanBeginLiteral, scanBeginName: - unquote = op == scanBeginLiteral - start = i - continue - } - end = i - break - } - - name := d.data[d.off-1+start : d.off-1+end] - - var key []byte - var ok bool - if unquote { - key, ok = unquoteBytes(name) - if !ok { - d.error(errPhase) - } - } else { - funcData, ok := d.ext.funcs[string(name)] - if !ok { - return nil, false - } - key = []byte(funcData.key) - } - - decode, ok := d.ext.keyed[string(key)] - if !ok { - return nil, false - } - - d.off-- - out, err := decode(d.next()) - if err != nil { - d.error(err) - } - return out, true -} - -func (d *decodeState) storeKeyed(v reflect.Value) bool { - keyed, ok := d.keyed() - if !ok { - return false - } - d.storeValue(v, keyed) - return true -} - -var ( - trueBytes = []byte("true") - falseBytes = []byte("false") - nullBytes = []byte("null") -) - -func (d *decodeState) storeValue(v reflect.Value, from interface{}) { - switch from { - case nil: - d.literalStore(nullBytes, v, false) - return - case true: - d.literalStore(trueBytes, v, false) - return - case false: - d.literalStore(falseBytes, v, false) - return - } - fromv := reflect.ValueOf(from) - for fromv.Kind() == reflect.Ptr && !fromv.IsNil() { - fromv = fromv.Elem() - } - fromt := fromv.Type() - for v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - vt := v.Type() - if fromt.AssignableTo(vt) { - v.Set(fromv) - } else if fromt.ConvertibleTo(vt) { - v.Set(fromv.Convert(vt)) - } else { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - } -} - -func (d *decodeState) convertLiteral(name []byte) (interface{}, bool) { - if len(name) == 0 { - return nil, false - } - switch name[0] { - case 't': - if bytes.Equal(name, trueBytes) { - return true, true - } - case 'f': - if bytes.Equal(name, falseBytes) { - return false, true - } - case 'n': - if bytes.Equal(name, nullBytes) { - return nil, true - } - } - if l, ok := d.ext.consts[string(name)]; ok { - return l, true - } - return nil, false -} - -// literal consumes a literal from d.data[d.off-1:], decoding into the value v. -// The first byte of the literal has been read already -// (that's how the caller knows it's a literal). -func (d *decodeState) literal(v reflect.Value) { - // All bytes inside literal return scanContinue op code. - start := d.off - 1 - op := d.scanWhile(scanContinue) - - // Scan read one byte too far; back up. - d.off-- - d.scan.undo(op) - - d.literalStore(d.data[start:d.off], v, false) -} - -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. -func (d *decodeState) convertNumber(s string) (interface{}, error) { - if d.useNumber { - return Number(s), nil - } - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} - } - return f, nil -} - -var numberType = reflect.TypeOf(Number("")) - -// literalStore decodes a literal stored in item into v. -// -// fromQuoted indicates whether this literal came from unwrapping a -// string from the ",string" struct tag option. this is used only to -// produce more helpful error messages. -func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) { - // Check for unmarshaler. - if len(item) == 0 { - //Empty string given - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return - } - wantptr := item[0] == 'n' // null - u, ut, pv := d.indirect(v, wantptr) - if u != nil { - err := u.UnmarshalJSON(item) - if err != nil { - d.error(err) - } - return - } - if ut != nil { - if item[0] != '"' { - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) - } - return - } - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.error(errPhase) - } - } - err := ut.UnmarshalText(s) - if err != nil { - d.error(err) - } - return - } - - v = pv - - switch c := item[0]; c { - case 'n': // null - switch v.Kind() { - case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - v.Set(reflect.Zero(v.Type())) - // otherwise, ignore null for primitives/string - } - case 't', 'f': // true, false - value := c == 't' - switch v.Kind() { - default: - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) - } - case reflect.Bool: - v.SetBool(value) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(value)) - } else { - d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) - } - } - - case '"': // string - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.error(errPhase) - } - } - switch v.Kind() { - default: - d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) - case reflect.Slice: - if v.Type().Elem().Kind() != reflect.Uint8 { - d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) - break - } - b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) - n, err := base64.StdEncoding.Decode(b, s) - if err != nil { - d.saveError(err) - break - } - v.SetBytes(b[:n]) - case reflect.String: - v.SetString(string(s)) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(string(s))) - } else { - d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) - } - } - - default: // number - if c != '-' && (c < '0' || c > '9') { - if fromQuoted { - d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.error(errPhase) - } - } - s := string(item) - switch v.Kind() { - default: - if v.Kind() == reflect.String && v.Type() == numberType { - v.SetString(s) - if !isValidNumber(s) { - d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) - } - break - } - if fromQuoted { - d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) - } - case reflect.Interface: - n, err := d.convertNumber(s) - if err != nil { - d.saveError(err) - break - } - if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) - break - } - v.Set(reflect.ValueOf(n)) - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) - break - } - v.SetInt(n) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) - break - } - v.SetUint(n) - - case reflect.Float32, reflect.Float64: - n, err := strconv.ParseFloat(s, v.Type().Bits()) - if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) - break - } - v.SetFloat(n) - } - } -} - -// The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, -// but they avoid the weight of reflection in this common case. - -// valueInterface is like value but returns interface{} -func (d *decodeState) valueInterface() interface{} { - switch d.scanWhile(scanSkipSpace) { - default: - d.error(errPhase) - panic("unreachable") - case scanBeginArray: - return d.arrayInterface() - case scanBeginObject: - return d.objectInterface() - case scanBeginLiteral: - return d.literalInterface() - case scanBeginName: - return d.nameInterface() - } -} - -func (d *decodeState) syntaxError(expected string) { - msg := fmt.Sprintf("invalid character '%c' looking for %s", d.data[d.off-1], expected) - d.error(&SyntaxError{msg, int64(d.off)}) -} - -// arrayInterface is like array but returns []interface{}. -func (d *decodeState) arrayInterface() []interface{} { - var v = make([]interface{}, 0) - for { - // Look ahead for ] - can only happen on first iteration. - op := d.scanWhile(scanSkipSpace) - if op == scanEndArray { - if len(v) > 0 && !d.ext.trailingCommas { - d.syntaxError("beginning of value") - } - break - } - - // Back up so d.value can have the byte we just read. - d.off-- - d.scan.undo(op) - - v = append(v, d.valueInterface()) - - // Next token must be , or ]. - op = d.scanWhile(scanSkipSpace) - if op == scanEndArray { - break - } - if op != scanArrayValue { - d.error(errPhase) - } - } - return v -} - -// objectInterface is like object but returns map[string]interface{}. -func (d *decodeState) objectInterface() interface{} { - v, ok := d.keyed() - if ok { - return v - } - - m := make(map[string]interface{}) - for { - // Read opening " of string key or closing }. - op := d.scanWhile(scanSkipSpace) - if op == scanEndObject { - if len(m) > 0 && !d.ext.trailingCommas { - d.syntaxError("beginning of object key string") - } - break - } - if op == scanBeginName { - if !d.ext.unquotedKeys { - d.syntaxError("beginning of object key string") - } - } else if op != scanBeginLiteral { - d.error(errPhase) - } - unquotedKey := op == scanBeginName - - // Read string key. - start := d.off - 1 - op = d.scanWhile(scanContinue) - item := d.data[start : d.off-1] - var key string - if unquotedKey { - key = string(item) - } else { - var ok bool - key, ok = unquote(item) - if !ok { - d.error(errPhase) - } - } - - // Read : before value. - if op == scanSkipSpace { - op = d.scanWhile(scanSkipSpace) - } - if op != scanObjectKey { - d.error(errPhase) - } - - // Read value. - m[key] = d.valueInterface() - - // Next token must be , or }. - op = d.scanWhile(scanSkipSpace) - if op == scanEndObject { - break - } - if op != scanObjectValue { - d.error(errPhase) - } - } - return m -} - -// literalInterface is like literal but returns an interface value. -func (d *decodeState) literalInterface() interface{} { - // All bytes inside literal return scanContinue op code. - start := d.off - 1 - op := d.scanWhile(scanContinue) - - // Scan read one byte too far; back up. - d.off-- - d.scan.undo(op) - item := d.data[start:d.off] - - switch c := item[0]; c { - case 'n': // null - return nil - - case 't', 'f': // true, false - return c == 't' - - case '"': // string - s, ok := unquote(item) - if !ok { - d.error(errPhase) - } - return s - - default: // number - if c != '-' && (c < '0' || c > '9') { - d.error(errPhase) - } - n, err := d.convertNumber(string(item)) - if err != nil { - d.saveError(err) - } - return n - } -} - -// nameInterface is like function but returns map[string]interface{}. -func (d *decodeState) nameInterface() interface{} { - v, ok := d.keyed() - if ok { - return v - } - - nameStart := d.off - 1 - - op := d.scanWhile(scanContinue) - - name := d.data[nameStart : d.off-1] - if op != scanParam { - // Back up so the byte just read is consumed next. - d.off-- - d.scan.undo(op) - if l, ok := d.convertLiteral(name); ok { - return l - } - d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) - } - - funcName := string(name) - funcData := d.ext.funcs[funcName] - if funcData.key == "" { - d.error(fmt.Errorf("json: unknown function %q", funcName)) - } - - m := make(map[string]interface{}) - for i := 0; ; i++ { - // Look ahead for ) - can only happen on first iteration. - op := d.scanWhile(scanSkipSpace) - if op == scanEndParams { - break - } - - // Back up so d.value can have the byte we just read. - d.off-- - d.scan.undo(op) - - if i >= len(funcData.args) { - d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) - } - m[funcData.args[i]] = d.valueInterface() - - // Next token must be , or ). - op = d.scanWhile(scanSkipSpace) - if op == scanEndParams { - break - } - if op != scanParam { - d.error(errPhase) - } - } - return map[string]interface{}{funcData.key: m} -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - r, err := strconv.ParseUint(string(s[2:6]), 16, 64) - if err != nil { - return -1 - } - return rune(r) -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -func unquote(s []byte) (t string, ok bool) { - s, ok = unquoteBytes(s) - t = string(s) - return -} - -func unquoteBytes(s []byte) (t []byte, ok bool) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - return - } - s = s[1 : len(s)-1] - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - r := 0 - for r < len(s) { - c := s[r] - if c == '\\' || c == '"' || c < ' ' { - break - } - if c < utf8.RuneSelf { - r++ - continue - } - rr, size := utf8.DecodeRune(s[r:]) - if rr == utf8.RuneError && size == 1 { - break - } - r += size - } - if r == len(s) { - return s, true - } - - b := make([]byte, len(s)+2*utf8.UTFMax) - w := copy(b, s[0:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-2*utf8.UTFMax { - nb := make([]byte, (len(b)+utf8.UTFMax)*2) - copy(nb, b[0:w]) - b = nb - } - switch c := s[r]; { - case c == '\\': - r++ - if r >= len(s) { - return - } - switch s[r] { - default: - return - case '"', '\\', '/', '\'': - b[w] = s[r] - r++ - w++ - case 'b': - b[w] = '\b' - r++ - w++ - case 'f': - b[w] = '\f' - r++ - w++ - case 'n': - b[w] = '\n' - r++ - w++ - case 'r': - b[w] = '\r' - r++ - w++ - case 't': - b[w] = '\t' - r++ - w++ - case 'u': - r-- - rr := getu4(s[r:]) - if rr < 0 { - return - } - r += 6 - if utf16.IsSurrogate(rr) { - rr1 := getu4(s[r:]) - if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} diff --git a/vendor/gopkg.in.o/mgo.v2/internal/json/decode_test.go b/vendor/gopkg.in.o/mgo.v2/internal/json/decode_test.go deleted file mode 100644 index 30e46ca44..000000000 --- a/vendor/gopkg.in.o/mgo.v2/internal/json/decode_test.go +++ /dev/null @@ -1,1512 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( - "bytes" - "encoding" - "errors" - "fmt" - "image" - "net" - "reflect" - "strings" - "testing" - "time" -) - -type T struct { - X string - Y int - Z int `json:"-"` -} - -type U struct { - Alphabet string `json:"alpha"` -} - -type V struct { - F1 interface{} - F2 int32 - F3 Number -} - -// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and -// without UseNumber -var ifaceNumAsFloat64 = map[string]interface{}{ - "k1": float64(1), - "k2": "s", - "k3": []interface{}{float64(1), float64(2.0), float64(3e-3)}, - "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)}, -} - -var ifaceNumAsNumber = map[string]interface{}{ - "k1": Number("1"), - "k2": "s", - "k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")}, - "k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")}, -} - -type tx struct { - x int -} - -// A type that can unmarshal itself. - -type unmarshaler struct { - T bool -} - -func (u *unmarshaler) UnmarshalJSON(b []byte) error { - *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called. - return nil -} - -type ustruct struct { - M unmarshaler -} - -type unmarshalerText struct { - A, B string -} - -// needed for re-marshaling tests -func (u unmarshalerText) MarshalText() ([]byte, error) { - return []byte(u.A + ":" + u.B), nil -} - -func (u *unmarshalerText) UnmarshalText(b []byte) error { - pos := bytes.Index(b, []byte(":")) - if pos == -1 { - return errors.New("missing separator") - } - u.A, u.B = string(b[:pos]), string(b[pos+1:]) - return nil -} - -var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) - -type ustructText struct { - M unmarshalerText -} - -var ( - um0, um1 unmarshaler // target2 of unmarshaling - ump = &um1 - umtrue = unmarshaler{true} - umslice = []unmarshaler{{true}} - umslicep = new([]unmarshaler) - umstruct = ustruct{unmarshaler{true}} - - um0T, um1T unmarshalerText // target2 of unmarshaling - umpType = &um1T - umtrueXY = unmarshalerText{"x", "y"} - umsliceXY = []unmarshalerText{{"x", "y"}} - umslicepType = new([]unmarshalerText) - umstructType = new(ustructText) - umstructXY = ustructText{unmarshalerText{"x", "y"}} - - ummapType = map[unmarshalerText]bool{} - ummapXY = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true} -) - -// Test data structures for anonymous fields. - -type Point struct { - Z int -} - -type Top struct { - Level0 int - Embed0 - *Embed0a - *Embed0b `json:"e,omitempty"` // treated as named - Embed0c `json:"-"` // ignored - Loop - Embed0p // has Point with X, Y, used - Embed0q // has Point with Z, used - embed // contains exported field -} - -type Embed0 struct { - Level1a int // overridden by Embed0a's Level1a with json tag - Level1b int // used because Embed0a's Level1b is renamed - Level1c int // used because Embed0a's Level1c is ignored - Level1d int // annihilated by Embed0a's Level1d - Level1e int `json:"x"` // annihilated by Embed0a.Level1e -} - -type Embed0a struct { - Level1a int `json:"Level1a,omitempty"` - Level1b int `json:"LEVEL1B,omitempty"` - Level1c int `json:"-"` - Level1d int // annihilated by Embed0's Level1d - Level1f int `json:"x"` // annihilated by Embed0's Level1e -} - -type Embed0b Embed0 - -type Embed0c Embed0 - -type Embed0p struct { - image.Point -} - -type Embed0q struct { - Point -} - -type embed struct { - Q int -} - -type Loop struct { - Loop1 int `json:",omitempty"` - Loop2 int `json:",omitempty"` - *Loop -} - -// From reflect test: -// The X in S6 and S7 annihilate, but they also block the X in S8.S9. -type S5 struct { - S6 - S7 - S8 -} - -type S6 struct { - X int -} - -type S7 S6 - -type S8 struct { - S9 -} - -type S9 struct { - X int - Y int -} - -// From reflect test: -// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. -type S10 struct { - S11 - S12 - S13 -} - -type S11 struct { - S6 -} - -type S12 struct { - S6 -} - -type S13 struct { - S8 -} - -type unmarshalTest struct { - in string - ptr interface{} - out interface{} - err error - useNumber bool -} - -type Ambig struct { - // Given "hello", the first match should win. - First int `json:"HELLO"` - Second int `json:"Hello"` -} - -type XYZ struct { - X interface{} - Y interface{} - Z interface{} -} - -func sliceAddr(x []int) *[]int { return &x } -func mapAddr(x map[string]int) *map[string]int { return &x } - -var unmarshalTests = []unmarshalTest{ - // basic types - {in: `true`, ptr: new(bool), out: true}, - {in: `1`, ptr: new(int), out: 1}, - {in: `1.2`, ptr: new(float64), out: 1.2}, - {in: `-5`, ptr: new(int16), out: int16(-5)}, - {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true}, - {in: `2`, ptr: new(Number), out: Number("2")}, - {in: `2`, ptr: new(interface{}), out: float64(2.0)}, - {in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true}, - {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, - {in: `"http:\/\/"`, ptr: new(string), out: "http://"}, - {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, - {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, - {in: "null", ptr: new(interface{}), out: nil}, - {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}}, - {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, - {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, - {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, - {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, - {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, - - // raw values with whitespace - {in: "\n true ", ptr: new(bool), out: true}, - {in: "\t 1 ", ptr: new(int), out: 1}, - {in: "\r 1.2 ", ptr: new(float64), out: 1.2}, - {in: "\t -5 \n", ptr: new(int16), out: int16(-5)}, - {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, - - // Z has a "-" tag. - {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, - - {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, - - // syntax errors - {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, - {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}}, - {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, - - // raw value errors - {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}}, - {in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}}, - {in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}}, - {in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}}, - - // array tests - {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, - {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, - {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, - - // empty array to interface test - {in: `[]`, ptr: new([]interface{}), out: []interface{}{}}, - {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, - {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, - {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}}, - - // composite tests - {in: allValueIndent, ptr: new(All), out: allValue}, - {in: allValueCompact, ptr: new(All), out: allValue}, - {in: allValueIndent, ptr: new(*All), out: &allValue}, - {in: allValueCompact, ptr: new(*All), out: &allValue}, - {in: pallValueIndent, ptr: new(All), out: pallValue}, - {in: pallValueCompact, ptr: new(All), out: pallValue}, - {in: pallValueIndent, ptr: new(*All), out: &pallValue}, - {in: pallValueCompact, ptr: new(*All), out: &pallValue}, - - // unmarshal interface test - {in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called - {in: `{"T":false}`, ptr: &ump, out: &umtrue}, - {in: `[{"T":false}]`, ptr: &umslice, out: umslice}, - {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice}, - {in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct}, - - // UnmarshalText interface test - {in: `"x:y"`, ptr: &um0T, out: umtrueXY}, - {in: `"x:y"`, ptr: &umpType, out: &umtrueXY}, - {in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY}, - {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, - {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, - - // Map keys can be encoding.TextUnmarshalers - {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, - // If multiple values for the same key exists, only the most recent value is used. - {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, - - // Overwriting of data. - // This is different from package xml, but it's what we've always done. - // Now documented and tested. - {in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}}, - {in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}}, - - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - out: Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - }, - }, - { - in: `{"hello": 1}`, - ptr: new(Ambig), - out: Ambig{First: 1}, - }, - - { - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - out: S5{S8: S8{S9: S9{Y: 2}}}, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, - }, - - // invalid UTF-8 is coerced to valid UTF-8. - { - in: "\"hello\xffworld\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - in: "\"hello\xc2\xc2world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\xc2\xffworld\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\\ud800world\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"", - ptr: new(string), - out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", - }, - - // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. - { - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: &map[time.Time]string{}, - out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, - }, - - // issue 8305 - { - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: &map[Point]string{}, - err: &UnmarshalTypeError{"object", reflect.TypeOf(map[Point]string{}), 1}, - }, - { - in: `{"asdf": "hello world"}`, - ptr: &map[unmarshaler]string{}, - err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1}, - }, -} - -func TestMarshal(t *testing.T) { - b, err := Marshal(allValue) - if err != nil { - t.Fatalf("Marshal allValue: %v", err) - } - if string(b) != allValueCompact { - t.Errorf("Marshal allValueCompact") - diff(t, b, []byte(allValueCompact)) - return - } - - b, err = Marshal(pallValue) - if err != nil { - t.Fatalf("Marshal pallValue: %v", err) - } - if string(b) != pallValueCompact { - t.Errorf("Marshal pallValueCompact") - diff(t, b, []byte(pallValueCompact)) - return - } -} - -var badUTF8 = []struct { - in, out string -}{ - {"hello\xffworld", `"hello\ufffdworld"`}, - {"", `""`}, - {"\xff", `"\ufffd"`}, - {"\xff\xff", `"\ufffd\ufffd"`}, - {"a\xffb", `"a\ufffdb"`}, - {"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`}, -} - -func TestMarshalBadUTF8(t *testing.T) { - for _, tt := range badUTF8 { - b, err := Marshal(tt.in) - if string(b) != tt.out || err != nil { - t.Errorf("Marshal(%q) = %#q, %v, want %#q, nil", tt.in, b, err, tt.out) - } - } -} - -func TestMarshalNumberZeroVal(t *testing.T) { - var n Number - out, err := Marshal(n) - if err != nil { - t.Fatal(err) - } - outStr := string(out) - if outStr != "0" { - t.Fatalf("Invalid zero val for Number: %q", outStr) - } -} - -func TestMarshalEmbeds(t *testing.T) { - top := &Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - } - b, err := Marshal(top) - if err != nil { - t.Fatal(err) - } - want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}" - if string(b) != want { - t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want) - } -} - -func TestUnmarshal(t *testing.T) { - for i, tt := range unmarshalTests { - var scan scanner - in := []byte(tt.in) - if err := checkValid(in, &scan); err != nil { - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("#%d: checkValid: %#v", i, err) - continue - } - } - if tt.ptr == nil { - continue - } - - // v = new(right-type) - v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec := NewDecoder(bytes.NewReader(in)) - if tt.useNumber { - dec.UseNumber() - } - if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) { - t.Errorf("#%d: %v, want %v", i, err, tt.err) - continue - } else if err != nil { - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) - data, _ := Marshal(v.Elem().Interface()) - println(string(data)) - data, _ = Marshal(tt.out) - println(string(data)) - continue - } - - // Check round trip. - if tt.err == nil { - enc, err := Marshal(v.Interface()) - if err != nil { - t.Errorf("#%d: error re-marshaling: %v", i, err) - continue - } - vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec = NewDecoder(bytes.NewReader(enc)) - if tt.useNumber { - dec.UseNumber() - } - if err := dec.Decode(vv.Interface()); err != nil { - t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err) - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface()) - t.Errorf(" In: %q", strings.Map(noSpace, string(in))) - t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc))) - continue - } - } - } -} - -func TestUnmarshalMarshal(t *testing.T) { - initBig() - var v interface{} - if err := Unmarshal(jsonBig, &v); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - b, err := Marshal(v) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if !bytes.Equal(jsonBig, b) { - t.Errorf("Marshal jsonBig") - diff(t, b, jsonBig) - return - } -} - -var numberTests = []struct { - in string - i int64 - intErr string - f float64 - floatErr string -}{ - {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1}, - {in: "-12", i: -12, f: -12.0}, - {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, -} - -// Independent of Decode, basic coverage of the accessors in Number -func TestNumberAccessors(t *testing.T) { - for _, tt := range numberTests { - n := Number(tt.in) - if s := n.String(); s != tt.in { - t.Errorf("Number(%q).String() is %q", tt.in, s) - } - if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i { - t.Errorf("Number(%q).Int64() is %d", tt.in, i) - } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) { - t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err) - } - if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f { - t.Errorf("Number(%q).Float64() is %g", tt.in, f) - } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) { - t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err) - } - } -} - -func TestLargeByteSlice(t *testing.T) { - s0 := make([]byte, 2000) - for i := range s0 { - s0[i] = byte(i) - } - b, err := Marshal(s0) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - var s1 []byte - if err := Unmarshal(b, &s1); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !bytes.Equal(s0, s1) { - t.Errorf("Marshal large byte slice") - diff(t, s0, s1) - } -} - -type Xint struct { - X int -} - -func TestUnmarshalInterface(t *testing.T) { - var xint Xint - var i interface{} = &xint - if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if xint.X != 1 { - t.Fatalf("Did not write to xint") - } -} - -func TestUnmarshalPtrPtr(t *testing.T) { - var xint Xint - pxint := &xint - if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if xint.X != 1 { - t.Fatalf("Did not write to xint") - } -} - -func TestEscape(t *testing.T) { - const input = `"foobar"` + " [\u2028 \u2029]" - const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"` - b, err := Marshal(input) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - if s := string(b); s != expected { - t.Errorf("Encoding of [%s]:\n got [%s]\nwant [%s]", input, s, expected) - } -} - -// WrongString is a struct that's misusing the ,string modifier. -type WrongString struct { - Message string `json:"result,string"` -} - -type wrongStringTest struct { - in, err string -} - -var wrongStringTests = []wrongStringTest{ - {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, - {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, - {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, - {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`}, -} - -// If people misuse the ,string modifier, the error message should be -// helpful, telling the user that they're doing it wrong. -func TestErrorMessageFromMisusedString(t *testing.T) { - for n, tt := range wrongStringTests { - r := strings.NewReader(tt.in) - var s WrongString - err := NewDecoder(r).Decode(&s) - got := fmt.Sprintf("%v", err) - if got != tt.err { - t.Errorf("%d. got err = %q, want %q", n, got, tt.err) - } - } -} - -func noSpace(c rune) rune { - if isSpace(byte(c)) { //only used for ascii - return -1 - } - return c -} - -type All struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Uintptr uintptr - Float32 float32 - Float64 float64 - - Foo string `json:"bar"` - Foo2 string `json:"bar2,dummyopt"` - - IntStr int64 `json:",string"` - - PBool *bool - PInt *int - PInt8 *int8 - PInt16 *int16 - PInt32 *int32 - PInt64 *int64 - PUint *uint - PUint8 *uint8 - PUint16 *uint16 - PUint32 *uint32 - PUint64 *uint64 - PUintptr *uintptr - PFloat32 *float32 - PFloat64 *float64 - - String string - PString *string - - Map map[string]Small - MapP map[string]*Small - PMap *map[string]Small - PMapP *map[string]*Small - - EmptyMap map[string]Small - NilMap map[string]Small - - Slice []Small - SliceP []*Small - PSlice *[]Small - PSliceP *[]*Small - - EmptySlice []Small - NilSlice []Small - - StringSlice []string - ByteSlice []byte - - Small Small - PSmall *Small - PPSmall **Small - - Interface interface{} - PInterface *interface{} - - unexported int -} - -type Small struct { - Tag string -} - -var allValue = All{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Uintptr: 12, - Float32: 14.1, - Float64: 15.1, - Foo: "foo", - Foo2: "foo2", - IntStr: 42, - String: "16", - Map: map[string]Small{ - "17": {Tag: "tag17"}, - "18": {Tag: "tag18"}, - }, - MapP: map[string]*Small{ - "19": {Tag: "tag19"}, - "20": nil, - }, - EmptyMap: map[string]Small{}, - Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, - SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, - EmptySlice: []Small{}, - StringSlice: []string{"str24", "str25", "str26"}, - ByteSlice: []byte{27, 28, 29}, - Small: Small{Tag: "tag30"}, - PSmall: &Small{Tag: "tag31"}, - Interface: 5.2, -} - -var pallValue = All{ - PBool: &allValue.Bool, - PInt: &allValue.Int, - PInt8: &allValue.Int8, - PInt16: &allValue.Int16, - PInt32: &allValue.Int32, - PInt64: &allValue.Int64, - PUint: &allValue.Uint, - PUint8: &allValue.Uint8, - PUint16: &allValue.Uint16, - PUint32: &allValue.Uint32, - PUint64: &allValue.Uint64, - PUintptr: &allValue.Uintptr, - PFloat32: &allValue.Float32, - PFloat64: &allValue.Float64, - PString: &allValue.String, - PMap: &allValue.Map, - PMapP: &allValue.MapP, - PSlice: &allValue.Slice, - PSliceP: &allValue.SliceP, - PPSmall: &allValue.PSmall, - PInterface: &allValue.Interface, -} - -var allValueIndent = `{ - "Bool": true, - "Int": 2, - "Int8": 3, - "Int16": 4, - "Int32": 5, - "Int64": 6, - "Uint": 7, - "Uint8": 8, - "Uint16": 9, - "Uint32": 10, - "Uint64": 11, - "Uintptr": 12, - "Float32": 14.1, - "Float64": 15.1, - "bar": "foo", - "bar2": "foo2", - "IntStr": "42", - "PBool": null, - "PInt": null, - "PInt8": null, - "PInt16": null, - "PInt32": null, - "PInt64": null, - "PUint": null, - "PUint8": null, - "PUint16": null, - "PUint32": null, - "PUint64": null, - "PUintptr": null, - "PFloat32": null, - "PFloat64": null, - "String": "16", - "PString": null, - "Map": { - "17": { - "Tag": "tag17" - }, - "18": { - "Tag": "tag18" - } - }, - "MapP": { - "19": { - "Tag": "tag19" - }, - "20": null - }, - "PMap": null, - "PMapP": null, - "EmptyMap": {}, - "NilMap": null, - "Slice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "SliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "PSlice": null, - "PSliceP": null, - "EmptySlice": [], - "NilSlice": null, - "StringSlice": [ - "str24", - "str25", - "str26" - ], - "ByteSlice": "Gxwd", - "Small": { - "Tag": "tag30" - }, - "PSmall": { - "Tag": "tag31" - }, - "PPSmall": null, - "Interface": 5.2, - "PInterface": null -}` - -var allValueCompact = strings.Map(noSpace, allValueIndent) - -var pallValueIndent = `{ - "Bool": false, - "Int": 0, - "Int8": 0, - "Int16": 0, - "Int32": 0, - "Int64": 0, - "Uint": 0, - "Uint8": 0, - "Uint16": 0, - "Uint32": 0, - "Uint64": 0, - "Uintptr": 0, - "Float32": 0, - "Float64": 0, - "bar": "", - "bar2": "", - "IntStr": "0", - "PBool": true, - "PInt": 2, - "PInt8": 3, - "PInt16": 4, - "PInt32": 5, - "PInt64": 6, - "PUint": 7, - "PUint8": 8, - "PUint16": 9, - "PUint32": 10, - "PUint64": 11, - "PUintptr": 12, - "PFloat32": 14.1, - "PFloat64": 15.1, - "String": "", - "PString": "16", - "Map": null, - "MapP": null, - "PMap": { - "17": { - "Tag": "tag17" - }, - "18": { - "Tag": "tag18" - } - }, - "PMapP": { - "19": { - "Tag": "tag19" - }, - "20": null - }, - "EmptyMap": null, - "NilMap": null, - "Slice": null, - "SliceP": null, - "PSlice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "PSliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "EmptySlice": null, - "NilSlice": null, - "StringSlice": null, - "ByteSlice": null, - "Small": { - "Tag": "" - }, - "PSmall": null, - "PPSmall": { - "Tag": "tag31" - }, - "Interface": null, - "PInterface": 5.2 -}` - -var pallValueCompact = strings.Map(noSpace, pallValueIndent) - -func TestRefUnmarshal(t *testing.T) { - type S struct { - // Ref is defined in encode_test.go. - R0 Ref - R1 *Ref - R2 RefText - R3 *RefText - } - want := S{ - R0: 12, - R1: new(Ref), - R2: 13, - R3: new(RefText), - } - *want.R1 = 12 - *want.R3 = 13 - - var got S - if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !reflect.DeepEqual(got, want) { - t.Errorf("got %+v, want %+v", got, want) - } -} - -// Test that the empty string doesn't panic decoding when ,string is specified -// Issue 3450 -func TestEmptyString(t *testing.T) { - type T2 struct { - Number1 int `json:",string"` - Number2 int `json:",string"` - } - data := `{"Number1":"1", "Number2":""}` - dec := NewDecoder(strings.NewReader(data)) - var t2 T2 - err := dec.Decode(&t2) - if err == nil { - t.Fatal("Decode: did not return error") - } - if t2.Number1 != 1 { - t.Fatal("Decode: did not set Number1") - } -} - -// Test that a null for ,string is not replaced with the previous quoted string (issue 7046). -// It should also not be an error (issue 2540, issue 8587). -func TestNullString(t *testing.T) { - type T struct { - A int `json:",string"` - B int `json:",string"` - C *int `json:",string"` - } - data := []byte(`{"A": "1", "B": null, "C": null}`) - var s T - s.B = 1 - s.C = new(int) - *s.C = 2 - err := Unmarshal(data, &s) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if s.B != 1 || s.C != nil { - t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) - } -} - -func intp(x int) *int { - p := new(int) - *p = x - return p -} - -func intpp(x *int) **int { - pp := new(*int) - *pp = x - return pp -} - -var interfaceSetTests = []struct { - pre interface{} - json string - post interface{} -}{ - {"foo", `"bar"`, "bar"}, - {"foo", `2`, 2.0}, - {"foo", `true`, true}, - {"foo", `null`, nil}, - - {nil, `null`, nil}, - {new(int), `null`, nil}, - {(*int)(nil), `null`, nil}, - {new(*int), `null`, new(*int)}, - {(**int)(nil), `null`, nil}, - {intp(1), `null`, nil}, - {intpp(nil), `null`, intpp(nil)}, - {intpp(intp(1)), `null`, intpp(nil)}, -} - -func TestInterfaceSet(t *testing.T) { - for _, tt := range interfaceSetTests { - b := struct{ X interface{} }{tt.pre} - blob := `{"X":` + tt.json + `}` - if err := Unmarshal([]byte(blob), &b); err != nil { - t.Errorf("Unmarshal %#q: %v", blob, err) - continue - } - if !reflect.DeepEqual(b.X, tt.post) { - t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post) - } - } -} - -// JSON null values should be ignored for primitives and string values instead of resulting in an error. -// Issue 2540 -func TestUnmarshalNulls(t *testing.T) { - jsonData := []byte(`{ - "Bool" : null, - "Int" : null, - "Int8" : null, - "Int16" : null, - "Int32" : null, - "Int64" : null, - "Uint" : null, - "Uint8" : null, - "Uint16" : null, - "Uint32" : null, - "Uint64" : null, - "Float32" : null, - "Float64" : null, - "String" : null}`) - - nulls := All{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Float32: 12.1, - Float64: 13.1, - String: "14"} - - err := Unmarshal(jsonData, &nulls) - if err != nil { - t.Errorf("Unmarshal of null values failed: %v", err) - } - if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 || - nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 || - nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" { - - t.Errorf("Unmarshal of null values affected primitives") - } -} - -func TestStringKind(t *testing.T) { - type stringKind string - - var m1, m2 map[stringKind]int - m1 = map[stringKind]int{ - "foo": 42, - } - - data, err := Marshal(m1) - if err != nil { - t.Errorf("Unexpected error marshaling: %v", err) - } - - err = Unmarshal(data, &m2) - if err != nil { - t.Errorf("Unexpected error unmarshaling: %v", err) - } - - if !reflect.DeepEqual(m1, m2) { - t.Error("Items should be equal after encoding and then decoding") - } -} - -// Custom types with []byte as underlying type could not be marshalled -// and then unmarshalled. -// Issue 8962. -func TestByteKind(t *testing.T) { - type byteKind []byte - - a := byteKind("hello") - - data, err := Marshal(a) - if err != nil { - t.Error(err) - } - var b byteKind - err = Unmarshal(data, &b) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, b) { - t.Errorf("expected %v == %v", a, b) - } -} - -// The fix for issue 8962 introduced a regression. -// Issue 12921. -func TestSliceOfCustomByte(t *testing.T) { - type Uint8 uint8 - - a := []Uint8("hello") - - data, err := Marshal(a) - if err != nil { - t.Fatal(err) - } - var b []Uint8 - err = Unmarshal(data, &b) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, b) { - t.Fatalf("expected %v == %v", a, b) - } -} - -var decodeTypeErrorTests = []struct { - dest interface{} - src string -}{ - {new(string), `{"user": "name"}`}, // issue 4628. - {new(error), `{}`}, // issue 4222 - {new(error), `[]`}, - {new(error), `""`}, - {new(error), `123`}, - {new(error), `true`}, -} - -func TestUnmarshalTypeError(t *testing.T) { - for _, item := range decodeTypeErrorTests { - err := Unmarshal([]byte(item.src), item.dest) - if _, ok := err.(*UnmarshalTypeError); !ok { - t.Errorf("expected type error for Unmarshal(%q, type %T): got %T", - item.src, item.dest, err) - } - } -} - -var unmarshalSyntaxTests = []string{ - "tru", - "fals", - "nul", - "123e", - `"hello`, - `[1,2,3`, - `{"key":1`, - `{"key":1,`, -} - -func TestUnmarshalSyntax(t *testing.T) { - var x interface{} - for _, src := range unmarshalSyntaxTests { - err := Unmarshal([]byte(src), &x) - if _, ok := err.(*SyntaxError); !ok { - t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err) - } - } -} - -// Test handling of unexported fields that should be ignored. -// Issue 4660 -type unexportedFields struct { - Name string - m map[string]interface{} `json:"-"` - m2 map[string]interface{} `json:"abcd"` -} - -func TestUnmarshalUnexported(t *testing.T) { - input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}` - want := &unexportedFields{Name: "Bob"} - - out := &unexportedFields{} - err := Unmarshal([]byte(input), out) - if err != nil { - t.Errorf("got error %v, expected nil", err) - } - if !reflect.DeepEqual(out, want) { - t.Errorf("got %q, want %q", out, want) - } -} - -// Time3339 is a time.Time which encodes to and from JSON -// as an RFC 3339 time in UTC. -type Time3339 time.Time - -func (t *Time3339) UnmarshalJSON(b []byte) error { - if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { - return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b) - } - tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1])) - if err != nil { - return err - } - *t = Time3339(tm) - return nil -} - -func TestUnmarshalJSONLiteralError(t *testing.T) { - var t3 Time3339 - err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3) - if err == nil { - t.Fatalf("expected error; got time %v", time.Time(t3)) - } - if !strings.Contains(err.Error(), "range") { - t.Errorf("got err = %v; want out of range error", err) - } -} - -// Test that extra object elements in an array do not result in a -// "data changing underfoot" error. -// Issue 3717 -func TestSkipArrayObjects(t *testing.T) { - json := `[{}]` - var dest [0]interface{} - - err := Unmarshal([]byte(json), &dest) - if err != nil { - t.Errorf("got error %q, want nil", err) - } -} - -// Test semantics of pre-filled struct fields and pre-filled map fields. -// Issue 4900. -func TestPrefilled(t *testing.T) { - ptrToMap := func(m map[string]interface{}) *map[string]interface{} { return &m } - - // Values here change, cannot reuse table across runs. - var prefillTests = []struct { - in string - ptr interface{} - out interface{} - }{ - { - in: `{"X": 1, "Y": 2}`, - ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5}, - out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5}, - }, - { - in: `{"X": 1, "Y": 2}`, - ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}), - out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}), - }, - } - - for _, tt := range prefillTests { - ptrstr := fmt.Sprintf("%v", tt.ptr) - err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here - if err != nil { - t.Errorf("Unmarshal: %v", err) - } - if !reflect.DeepEqual(tt.ptr, tt.out) { - t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out) - } - } -} - -var invalidUnmarshalTests = []struct { - v interface{} - want string -}{ - {nil, "json: Unmarshal(nil)"}, - {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {(*int)(nil), "json: Unmarshal(nil *int)"}, -} - -func TestInvalidUnmarshal(t *testing.T) { - buf := []byte(`{"a":"1"}`) - for _, tt := range invalidUnmarshalTests { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Errorf("Unmarshal expecting error, got nil") - continue - } - if got := err.Error(); got != tt.want { - t.Errorf("Unmarshal = %q; want %q", got, tt.want) - } - } -} - -var invalidUnmarshalTextTests = []struct { - v interface{} - want string -}{ - {nil, "json: Unmarshal(nil)"}, - {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {(*int)(nil), "json: Unmarshal(nil *int)"}, - {new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"}, -} - -func TestInvalidUnmarshalText(t *testing.T) { - buf := []byte(`123`) - for _, tt := range invalidUnmarshalTextTests { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Errorf("Unmarshal expecting error, got nil") - continue - } - if got := err.Error(); got != tt.want { - t.Errorf("Unmarshal = %q; want %q", got, tt.want) - } - } -} - -// Test that string option is ignored for invalid types. -// Issue 9812. -func TestInvalidStringOption(t *testing.T) { - num := 0 - item := struct { - T time.Time `json:",string"` - M map[string]string `json:",string"` - S []string `json:",string"` - A [1]string `json:",string"` - I interface{} `json:",string"` - P *int `json:",string"` - }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num} - - data, err := Marshal(item) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - - err = Unmarshal(data, &item) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } -} diff --git a/vendor/gopkg.in.o/mgo.v2/internal/json/encode.go b/vendor/gopkg.in.o/mgo.v2/internal/json/encode.go deleted file mode 100644 index 67a0f0062..000000000 --- a/vendor/gopkg.in.o/mgo.v2/internal/json/encode.go +++ /dev/null @@ -1,1256 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package json implements encoding and decoding of JSON as defined in -// RFC 4627. The mapping between JSON and Go values is described -// in the documentation for the Marshal and Unmarshal functions. -// -// See "JSON and Go" for an introduction to this package: -// https://golang.org/doc/articles/json_and_go.html -package json - -import ( - "bytes" - "encoding" - "encoding/base64" - "fmt" - "math" - "reflect" - "runtime" - "sort" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -// Marshal returns the JSON encoding of v. -// -// Marshal traverses the value v recursively. -// If an encountered value implements the Marshaler interface -// and is not a nil pointer, Marshal calls its MarshalJSON method -// to produce JSON. If no MarshalJSON method is present but the -// value implements encoding.TextMarshaler instead, Marshal calls -// its MarshalText method. -// The nil pointer exception is not strictly necessary -// but mimics a similar, necessary exception in the behavior of -// UnmarshalJSON. -// -// Otherwise, Marshal uses the following type-dependent default encodings: -// -// Boolean values encode as JSON booleans. -// -// Floating point, integer, and Number values encode as JSON numbers. -// -// String values encode as JSON strings coerced to valid UTF-8, -// replacing invalid bytes with the Unicode replacement rune. -// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" -// to keep some browsers from misinterpreting JSON output as HTML. -// Ampersand "&" is also escaped to "\u0026" for the same reason. -// This escaping can be disabled using an Encoder with DisableHTMLEscaping. -// -// Array and slice values encode as JSON arrays, except that -// []byte encodes as a base64-encoded string, and a nil slice -// encodes as the null JSON value. -// -// Struct values encode as JSON objects. Each exported struct field -// becomes a member of the object unless -// - the field's tag is "-", or -// - the field is empty and its tag specifies the "omitempty" option. -// The empty values are false, 0, any -// nil pointer or interface value, and any array, slice, map, or string of -// length zero. The object's default key string is the struct field name -// but can be specified in the struct field's tag value. The "json" key in -// the struct field's tag value is the key name, followed by an optional comma -// and options. Examples: -// -// // Field is ignored by this package. -// Field int `json:"-"` -// -// // Field appears in JSON as key "myName". -// Field int `json:"myName"` -// -// // Field appears in JSON as key "myName" and -// // the field is omitted from the object if its value is empty, -// // as defined above. -// Field int `json:"myName,omitempty"` -// -// // Field appears in JSON as key "Field" (the default), but -// // the field is skipped if empty. -// // Note the leading comma. -// Field int `json:",omitempty"` -// -// The "string" option signals that a field is stored as JSON inside a -// JSON-encoded string. It applies only to fields of string, floating point, -// integer, or boolean types. This extra level of encoding is sometimes used -// when communicating with JavaScript programs: -// -// Int64String int64 `json:",string"` -// -// The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, dollar signs, percent signs, hyphens, -// underscores and slashes. -// -// Anonymous struct fields are usually marshaled as if their inner exported fields -// were fields in the outer struct, subject to the usual Go visibility rules amended -// as described in the next paragraph. -// An anonymous struct field with a name given in its JSON tag is treated as -// having that name, rather than being anonymous. -// An anonymous struct field of interface type is treated the same as having -// that type as its name, rather than being anonymous. -// -// The Go visibility rules for struct fields are amended for JSON when -// deciding which field to marshal or unmarshal. If there are -// multiple fields at the same level, and that level is the least -// nested (and would therefore be the nesting level selected by the -// usual Go rules), the following extra rules apply: -// -// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, -// even if there are multiple untagged fields that would otherwise conflict. -// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. -// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. -// -// Handling of anonymous struct fields is new in Go 1.1. -// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of -// an anonymous struct field in both current and earlier versions, give the field -// a JSON tag of "-". -// -// Map values encode as JSON objects. The map's key type must either be a string -// or implement encoding.TextMarshaler. The map keys are used as JSON object -// keys, subject to the UTF-8 coercion described for string values above. -// -// Pointer values encode as the value pointed to. -// A nil pointer encodes as the null JSON value. -// -// Interface values encode as the value contained in the interface. -// A nil interface value encodes as the null JSON value. -// -// Channel, complex, and function values cannot be encoded in JSON. -// Attempting to encode such a value causes Marshal to return -// an UnsupportedTypeError. -// -// JSON cannot represent cyclic data structures and Marshal does not -// handle them. Passing cyclic structures to Marshal will result in -// an infinite recursion. -// -func Marshal(v interface{}) ([]byte, error) { - e := &encodeState{} - err := e.marshal(v, encOpts{escapeHTML: true}) - if err != nil { - return nil, err - } - return e.Bytes(), nil -} - -// MarshalIndent is like Marshal but applies Indent to format the output. -func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - b, err := Marshal(v) - if err != nil { - return nil, err - } - var buf bytes.Buffer - err = Indent(&buf, b, prefix, indent) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 -// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 -// so that the JSON will be safe to embed inside HTML