summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralabid <alabidan@gmail.com>2014-10-14 18:15:38 -0400
committeralabid <alabidan@gmail.com>2014-10-17 18:28:31 -0400
commitfcb1a3d5bc92beb19fbd6d6e6d5c0d81b0093399 (patch)
tree8a07d1b300306698aad82eaa5a3ec3221878a647
parent544a35e4e65e023b1cb1291df39df58077edcbbb (diff)
downloadmongo-fcb1a3d5bc92beb19fbd6d6e6d5c0d81b0093399.tar.gz
TOOLS-279 added basic unit tests for BSON -> JSON conversion
Former-commit-id: 4c116ef3645c5629c9e883b56a88fe0c1e6e5a63
-rw-r--r--common/bsonutil/converter.go21
-rw-r--r--common/bsonutil/converter_test.go295
-rw-r--r--common/json/csv_format.go7
-rw-r--r--common/json/json_format.go16
-rw-r--r--common/json/mongo_extjson.go9
-rw-r--r--src/github.com/mongodb/mongo-tools/common/bsonutil/converter_test.go268
6 files changed, 606 insertions, 10 deletions
diff --git a/common/bsonutil/converter.go b/common/bsonutil/converter.go
index 54187d36ead..17c44cb5fc2 100644
--- a/common/bsonutil/converter.go
+++ b/common/bsonutil/converter.go
@@ -11,7 +11,6 @@ import (
"time"
)
-
// ConvertJSONValueToBSON walks through a document or an array and
// replaces any extended JSON value with its corresponding BSON type.
func ConvertJSONValueToBSON(x interface{}) (interface{}, error) {
@@ -52,7 +51,7 @@ func ConvertJSONValueToBSON(x interface{}) (interface{}, error) {
case json.Date: // Date
n := int64(v)
- return time.Unix(n/1e3, n%1e3 * 1e6), nil
+ return time.Unix(n/1e3, n%1e3*1e6), nil
case json.NumberLong: // NumberLong
return int64(v), nil
@@ -70,6 +69,9 @@ func ConvertJSONValueToBSON(x interface{}) (interface{}, error) {
case json.DBRef: // DBRef
return mgo.DBRef{v.Collection, v.Id, v.Database}, nil
+ case json.DBPointer: // DBPointer, for backwards compatibility
+ return bson.DBPointer{v.Namespace, v.Id}, nil
+
case json.RegExp: // RegExp
return bson.RegEx{v.Pattern, v.Options}, nil
@@ -77,6 +79,9 @@ func ConvertJSONValueToBSON(x interface{}) (interface{}, error) {
ts := (int64(v.Seconds) << 32) | int64(v.Increment)
return bson.MongoTimestamp(ts), nil
+ case json.JavaScript: // Javascript
+ return bson.JavaScript{v.Code, v.Scope}, nil
+
case json.MinKey: // MinKey
return bson.MinKey, nil
@@ -85,6 +90,7 @@ func ConvertJSONValueToBSON(x interface{}) (interface{}, error) {
case json.Undefined: // undefined
return bson.Undefined, nil
+
default:
return nil, fmt.Errorf("Conversion of JSON type '%v' unsupported", v)
}
@@ -151,7 +157,7 @@ func ConvertBSONValueToJSON(x interface{}) (interface{}, error) {
return json.ObjectId(v.Hex()), nil
case time.Time: // Date
- return json.Date(v.UnixNano()/1e6), nil
+ return json.Date(v.UnixNano() / 1e6), nil
case int64: // NumberLong
return json.NumberLong(v), nil
@@ -176,6 +182,9 @@ func ConvertBSONValueToJSON(x interface{}) (interface{}, error) {
case mgo.DBRef: // DBRef
return json.DBRef{v.Collection, v.Id, v.Database}, nil
+ case bson.DBPointer: // DBPointer
+ return json.DBPointer{v.Namespace, v.Id}, nil
+
case bson.RegEx: // RegExp
return json.RegExp{v.Pattern, v.Options}, nil
@@ -185,9 +194,9 @@ func ConvertBSONValueToJSON(x interface{}) (interface{}, error) {
Seconds: uint32(timestamp >> 32),
Increment: uint32(timestamp),
}, nil
- case bson.JavaScript:
- //TODO handle code with scope
- return json.Javascript{v.Code, nil}, nil
+
+ case bson.JavaScript: // JavaScript
+ return json.JavaScript{v.Code, v.Scope}, nil
default:
switch x {
diff --git a/common/bsonutil/converter_test.go b/common/bsonutil/converter_test.go
new file mode 100644
index 00000000000..fa510aeb860
--- /dev/null
+++ b/common/bsonutil/converter_test.go
@@ -0,0 +1,295 @@
+package bsonutil
+
+import (
+ . "github.com/smartystreets/goconvey/convey"
+ "github.com/mongodb/mongo-tools/common/json"
+ "testing"
+ "gopkg.in/mgo.v2"
+ "gopkg.in/mgo.v2/bson"
+ "time"
+ "fmt"
+ "encoding/base64"
+)
+
+
+func TestObjectIdBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON ObjectId", t, func() {
+ Convey("that is valid to JSON should produce a json.ObjectId", func() {
+ bsonObjId := bson.NewObjectId()
+ jsonObjId := json.ObjectId(bsonObjId.Hex())
+
+ _jObjId, err := ConvertBSONValueToJSON(bsonObjId)
+ So(err, ShouldBeNil)
+ jObjId, ok := _jObjId.(json.ObjectId)
+ So(ok, ShouldBeTrue)
+
+ So(jObjId, ShouldNotEqual, bsonObjId)
+ So(jObjId, ShouldEqual, jsonObjId)
+ })
+ })
+}
+
+func TestArraysBSONToJSON(t *testing.T) {
+ Convey("Converting BSON arrays to JSON arrays", t, func() {
+ Convey("should work for empty arrays", func() {
+ jArr, err := ConvertBSONValueToJSON([]interface{}{})
+ So(err, ShouldBeNil)
+
+ So(jArr, ShouldResemble, []interface{}{})
+ })
+
+ Convey("should work for one-level deep arrays", func() {
+ objId := bson.NewObjectId()
+ bsonArr := []interface{}{objId, 28, 0.999, "plain"}
+ _jArr, err := ConvertBSONValueToJSON(bsonArr)
+ So(err, ShouldBeNil)
+ jArr, ok := _jArr.([]interface{})
+ So(ok, ShouldBeTrue)
+
+ So(len(jArr), ShouldEqual, 4)
+ So(jArr[0], ShouldEqual, json.ObjectId(objId.Hex()))
+ So(jArr[1], ShouldEqual, 28)
+ So(jArr[2], ShouldEqual, 0.999)
+ So(jArr[3], ShouldEqual, "plain")
+ })
+
+ Convey("should work for arrays with embedded objects", func() {
+ bsonObj := []interface{}{80, bson.M{"a":int64(20), "b":bson.M{"c": bson.RegEx{"hi", "i"}}}}
+
+ __jObj, err := ConvertBSONValueToJSON(bsonObj)
+ So(err, ShouldBeNil)
+ _jObj, ok := __jObj.([]interface{})
+ So(ok, ShouldBeTrue)
+ jObj, ok := _jObj[1].(map[string]interface{})
+ So(ok, ShouldBeTrue)
+ So(len(jObj), ShouldEqual, 2)
+ So(jObj["a"], ShouldEqual, json.NumberLong(20))
+ jjObj, ok := jObj["b"].(map[string]interface{})
+ So(ok, ShouldBeTrue)
+
+ So(jjObj["c"], ShouldResemble, json.RegExp{"hi", "i"})
+ So(jjObj["c"], ShouldNotResemble, json.RegExp{"i", "hi"})
+ })
+
+ })
+}
+
+func TestDateBSONToJSON(t *testing.T) {
+
+ timeNow := time.Now()
+ secs := int64(timeNow.Unix())
+ nanosecs := timeNow.Nanosecond()
+ millis := int64(nanosecs/1e6)
+
+ timeNowSecs := time.Unix(secs, int64(0))
+ timeNowMillis := time.Unix(secs, int64(millis*1e6))
+
+ Convey("Converting BSON time.Time 's dates to JSON", t, func() {
+ // json.Date is stored as an int64 representing the number of milliseconds since the epoch
+ Convey(fmt.Sprintf("should work with second granularity: %v", timeNowSecs), func() {
+ _jObj, err := ConvertBSONValueToJSON(timeNowSecs)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Date)
+ So(ok, ShouldBeTrue)
+
+ So(int64(jObj), ShouldEqual, secs*1e3)
+ })
+
+ Convey(fmt.Sprintf("should work with millisecond granularity: %v", timeNowMillis), func() {
+ _jObj, err := ConvertBSONValueToJSON(timeNowMillis)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Date)
+ So(ok, ShouldBeTrue)
+
+ So(int64(jObj), ShouldEqual, secs*1e3 + millis)
+ })
+
+ Convey(fmt.Sprintf("should work with nanosecond granularity: %v", timeNow), func() {
+ _jObj, err := ConvertBSONValueToJSON(timeNow)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Date)
+ So(ok, ShouldBeTrue)
+
+ // we lose nanosecond precision
+ So(int64(jObj), ShouldEqual, secs*1e3 + millis)
+ })
+
+ })
+}
+
+func TestMaxKeyBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Maxkey to JSON", t, func() {
+ Convey("should produce a json.MaxKey", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.MaxKey)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.MaxKey)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.MaxKey{})
+ })
+ })
+}
+
+func TestMinKeyBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Maxkey to JSON", t, func() {
+ Convey("should produce a json.MinKey", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.MinKey)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.MinKey)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.MinKey{})
+ })
+ })
+}
+
+func Test64BitIntBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON int64 to JSON", t, func() {
+ Convey("should produce a json.NumberLong", func() {
+ _jObj, err := ConvertBSONValueToJSON(int32(243))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.NumberInt)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldEqual, json.NumberInt(243))
+ })
+ })
+
+}
+
+func Test32BitIntBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON int32 integer to JSON", t, func() {
+ Convey("should produce a json.NumberInt", func() {
+ _jObj, err := ConvertBSONValueToJSON(int64(888234334343))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.NumberLong)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldEqual, json.NumberLong(888234334343))
+ })
+ })
+
+}
+
+func TestRegExBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Regular Expression (= /decision/gi) to JSON", t, func() {
+ Convey("should produce a json.RegExp", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.RegEx{"decision", "gi"})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.RegExp)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.RegExp{"decision", "gi"})
+ })
+ })
+
+}
+
+func TestUndefinedValueBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Undefined type to JSON", t, func() {
+ Convey("should produce a json.Undefined", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.Undefined)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Undefined)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.Undefined{})
+ })
+ })
+}
+
+func TestDBRefBSONToJSON(t *testing.T) {
+ Convey("Converting BSON DBRef to JSON", t, func() {
+ Convey("should produce a json.DBRef", func() {
+ _jObj, err := ConvertBSONValueToJSON(mgo.DBRef{"coll1", "some_id", "test"})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.DBRef)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.DBRef{"coll1", "some_id", "test"})
+ So(jObj, ShouldNotResemble, json.DBRef{"coll1", "test", "some_id"})
+ })
+ })
+}
+
+func TestTimestampBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Timestamp to JSON", t, func() {
+ Convey("should produce a json.Timestamp", func() {
+ // {t:803434343, i:9} == bson.MongoTimestamp(803434343*2**32 + 9)
+ _jObj, err := ConvertBSONValueToJSON(bson.MongoTimestamp(uint64(803434343<<32) | uint64(9)))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Timestamp)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.Timestamp{Seconds:803434343, Increment:9})
+ So(jObj, ShouldNotResemble, json.Timestamp{Seconds:803434343, Increment:8})
+ })
+ })
+}
+
+func TestBinaryBSONToJSON(t *testing.T) {
+ Convey("Converting BSON Binary data to JSON", t, func() {
+ Convey("should produce a json.BinData", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.Binary{'\x01', []byte("\x05\x20\x02\xae\xf7")})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.BinData)
+ So(ok, ShouldBeTrue)
+
+ base64data1 := base64.StdEncoding.EncodeToString([]byte("\x05\x20\x02\xae\xf7"))
+ base64data2 := base64.StdEncoding.EncodeToString([]byte("\x05\x20\x02\xaf\xf7"))
+ So(jObj, ShouldResemble, json.BinData{'\x01', base64data1})
+ So(jObj, ShouldNotResemble, json.BinData{'\x01', base64data2})
+ })
+ })
+}
+
+func TestGenericBytesBSONToJSON(t *testing.T) {
+ Convey("Converting Go bytes to JSON", t, func() {
+ Convey("should produce a json.BinData with Type=0x00 (Generic)", func() {
+ _jObj, err := ConvertBSONValueToJSON([]byte("this is something that's cool"))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.BinData)
+ So(ok, ShouldBeTrue)
+
+ base64data := base64.StdEncoding.EncodeToString([]byte("this is something that's cool"))
+ So(jObj, ShouldResemble, json.BinData{0x00, base64data})
+ So(jObj, ShouldNotResemble, json.BinData{0x01, base64data})
+ })
+ })
+}
+
+func TestUnknownBSONTypeToJSON(t *testing.T) {
+ Convey("Converting an unknown BSON type to JSON", t, func() {
+ Convey("should produce an error", func() {
+ _, err := ConvertBSONValueToJSON(func(){})
+ So(err, ShouldNotBeNil)
+ })
+ })
+}
+
+func TestJSCodeBSONToJSON(t *testing.T) {
+ Convey("Converting BSON Javascript code to JSON", t, func() {
+ Convey("should produce a json.Javascript", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.JavaScript{"function() { return null; }", nil})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.JavaScript)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.JavaScript{"function() { return null; }", nil})
+ })
+ })
+}
+
+func TestDBPointerBSONToJSON(t *testing.T) {
+ Convey("Converting BSON DBPointer to JSON", t, func() {
+ Convey("should produce a json.DBPointer", func() {
+ objId := bson.NewObjectId()
+ _jObj, err := ConvertBSONValueToJSON(bson.DBPointer{"dbrefnamespace", objId})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.DBPointer)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.DBPointer{"dbrefnamespace", objId})
+ })
+ })
+}
diff --git a/common/json/csv_format.go b/common/json/csv_format.go
index fca3373f7f3..15be6857d5f 100644
--- a/common/json/csv_format.go
+++ b/common/json/csv_format.go
@@ -19,7 +19,7 @@ func (b BinData) String() string {
return fmt.Sprintf("%X", data) // use uppercase hexadecimal
}
-func (js Javascript) String() string {
+func (js JavaScript) String() string {
return js.Code
}
@@ -39,6 +39,11 @@ func (d DBRef) String() string {
d.Collection, d.Id, d.Database)
}
+func (d DBPointer) String() string {
+ return fmt.Sprintf(`{ "$ref": "%v", "$id": %v }`,
+ d.Namespace, d.Id)
+}
+
func (f Float) String() string {
return fmt.Sprintf("%v", float64(f))
}
diff --git a/common/json/json_format.go b/common/json/json_format.go
index 90f7ad75778..ebe8eb9d2d4 100644
--- a/common/json/json_format.go
+++ b/common/json/json_format.go
@@ -13,7 +13,7 @@ func (b BinData) MarshalJSON() ([]byte, error) {
return []byte(data), nil
}
-func (js Javascript) MarshalJSON() ([]byte, error) {
+func (js JavaScript) MarshalJSON() ([]byte, error) {
return []byte(js.Code), nil
}
@@ -43,8 +43,9 @@ func (d DBRef) MarshalJSON() ([]byte, error) {
var dbChunk []byte
if d.Database != "" {
- dbChunk = []byte(fmt.Sprintf(`, "$db": "%v" }`, d.Database))
+ dbChunk = []byte(fmt.Sprintf(`, "$db": "%v" `, d.Database))
}
+ dbChunk = append(dbChunk, '}')
data := make([]byte, len(refChunk)+len(idChunk)+len(dbChunk))
copy(data, refChunk)
@@ -54,6 +55,17 @@ func (d DBRef) MarshalJSON() ([]byte, error) {
return data, nil
}
+func (d DBPointer) MarshalJSON() ([]byte, error) {
+ // Convert the $id field to JSON
+ idChunk, err := Marshal(d.Id)
+ if err != nil {
+ return nil, err
+ }
+
+ data := append([]byte(fmt.Sprintf(`{ "$ref": "%v", "$id": `, d.Namespace)), idChunk...)
+ return append(data, '}'), nil
+}
+
func (_ MinKey) MarshalJSON() ([]byte, error) {
data := `{ "$minKey": 1 }`
return []byte(data), nil
diff --git a/common/json/mongo_extjson.go b/common/json/mongo_extjson.go
index e61a18fff66..99390e32b16 100644
--- a/common/json/mongo_extjson.go
+++ b/common/json/mongo_extjson.go
@@ -22,6 +22,13 @@ type DBRef struct {
Database string // optional
}
+// Refers to a document in some namespace by wrapping a string containing the namespace
+// and the objectId in which the _id of the document is contained
+type DBPointer struct {
+ Namespace string
+ Id bson.ObjectId
+}
+
// Represents the literal MinKey.
type MinKey struct{}
@@ -48,7 +55,7 @@ type Timestamp struct {
Increment uint32
}
-type Javascript struct {
+type JavaScript struct {
Code string
Scope interface{}
}
diff --git a/src/github.com/mongodb/mongo-tools/common/bsonutil/converter_test.go b/src/github.com/mongodb/mongo-tools/common/bsonutil/converter_test.go
new file mode 100644
index 00000000000..3f60f5bcd6f
--- /dev/null
+++ b/src/github.com/mongodb/mongo-tools/common/bsonutil/converter_test.go
@@ -0,0 +1,268 @@
+package bsonutil
+
+import (
+ . "github.com/smartystreets/goconvey/convey"
+ "github.com/mongodb/mongo-tools/common/json"
+ "testing"
+ "gopkg.in/mgo.v2"
+ "gopkg.in/mgo.v2/bson"
+ "time"
+ "fmt"
+ "encoding/base64"
+)
+
+
+func TestObjectIdBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON ObjectId", t, func() {
+ Convey("that is valid to JSON should produce a json.ObjectId", func() {
+ bsonObjId := bson.NewObjectId()
+ jsonObjId := json.ObjectId(bsonObjId.Hex())
+
+ _jObjId, err := ConvertBSONValueToJSON(bsonObjId)
+ So(err, ShouldBeNil)
+ jObjId, ok := _jObjId.(json.ObjectId)
+ So(ok, ShouldBeTrue)
+
+ So(jObjId, ShouldNotEqual, bsonObjId)
+ So(jObjId, ShouldEqual, jsonObjId)
+ })
+ })
+}
+
+func TestArraysBSONToJSON(t *testing.T) {
+ Convey("Converting BSON arrays to JSON arrays", t, func() {
+ Convey("should work for empty arrays", func() {
+ jArr, err := ConvertBSONValueToJSON([]interface{}{})
+ So(err, ShouldBeNil)
+
+ So(jArr, ShouldResemble, []interface{}{})
+ })
+
+ Convey("should work for one-level deep arrays", func() {
+ objId := bson.NewObjectId()
+ bsonArr := []interface{}{objId, 28, 0.999, "plain"}
+ _jArr, err := ConvertBSONValueToJSON(bsonArr)
+ So(err, ShouldBeNil)
+ jArr, ok := _jArr.([]interface{})
+ So(ok, ShouldBeTrue)
+
+ So(len(jArr), ShouldEqual, 4)
+ So(jArr[0], ShouldEqual, json.ObjectId(objId.Hex()))
+ So(jArr[1], ShouldEqual, 28)
+ So(jArr[2], ShouldEqual, 0.999)
+ So(jArr[3], ShouldEqual, "plain")
+ })
+
+ Convey("should work for arrays with embedded objects", func() {
+ bsonObj := []interface{}{80, bson.M{"a":int64(20), "b":bson.M{"c": bson.RegEx{"hi", "i"}}}}
+
+ __jObj, err := ConvertBSONValueToJSON(bsonObj)
+ So(err, ShouldBeNil)
+ _jObj, ok := __jObj.([]interface{})
+ So(ok, ShouldBeTrue)
+ jObj, ok := _jObj[1].(map[string]interface{})
+ So(ok, ShouldBeTrue)
+ So(len(jObj), ShouldEqual, 2)
+ So(jObj["a"], ShouldEqual, json.NumberLong(20))
+ jjObj, ok := jObj["b"].(map[string]interface{})
+ So(ok, ShouldBeTrue)
+
+ So(jjObj["c"], ShouldResemble, json.RegExp{"hi", "i"})
+ So(jjObj["c"], ShouldNotResemble, json.RegExp{"i", "hi"})
+ })
+
+ })
+}
+
+func TestDateBSONToJSON(t *testing.T) {
+
+ timeNow := time.Now()
+ secs := int64(timeNow.Unix())
+ nanosecs := timeNow.Nanosecond()
+ millis := int64(nanosecs/1e6)
+
+ timeNowSecs := time.Unix(secs, int64(0))
+ timeNowMillis := time.Unix(secs, int64(millis*1e6))
+
+ Convey("Converting BSON time.Time 's dates to JSON", t, func() {
+ // json.Date is stored as an int64 representing the number of milliseconds since the epoch
+ Convey(fmt.Sprintf("should work with second granularity: %v", timeNowSecs), func() {
+ _jObj, err := ConvertBSONValueToJSON(timeNowSecs)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Date)
+ So(ok, ShouldBeTrue)
+
+ So(int64(jObj), ShouldEqual, secs*1e3)
+ })
+
+ Convey(fmt.Sprintf("should work with millisecond granularity: %v", timeNowMillis), func() {
+ _jObj, err := ConvertBSONValueToJSON(timeNowMillis)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Date)
+ So(ok, ShouldBeTrue)
+
+ So(int64(jObj), ShouldEqual, secs*1e3 + millis)
+ })
+
+ Convey(fmt.Sprintf("should work with nanosecond granularity: %v", timeNow), func() {
+ _jObj, err := ConvertBSONValueToJSON(timeNow)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Date)
+ So(ok, ShouldBeTrue)
+
+ // we lose nanosecond precision
+ So(int64(jObj), ShouldEqual, secs*1e3 + millis)
+ })
+
+ })
+}
+
+func TestMaxKeyBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Maxkey to JSON", t, func() {
+ Convey("should produce a json.MaxKey", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.MaxKey)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.MaxKey)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.MaxKey{})
+ })
+ })
+}
+
+func TestMinKeyBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Maxkey to JSON", t, func() {
+ Convey("should produce a json.MinKey", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.MinKey)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.MinKey)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.MinKey{})
+ })
+ })
+}
+
+func Test64BitIntBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON int64 to JSON", t, func() {
+ Convey("should produce a json.NumberLong", func() {
+ _jObj, err := ConvertBSONValueToJSON(int32(243))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.NumberInt)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldEqual, json.NumberInt(243))
+ })
+ })
+
+}
+
+func Test32BitIntBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON int32 integer to JSON", t, func() {
+ Convey("should produce a json.NumberInt", func() {
+ _jObj, err := ConvertBSONValueToJSON(int64(888234334343))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.NumberLong)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldEqual, json.NumberLong(888234334343))
+ })
+ })
+
+}
+
+func TestRegExBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Regular Expression (= /decision/gi) to JSON", t, func() {
+ Convey("should produce a json.RegExp", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.RegEx{"decision", "gi"})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.RegExp)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.RegExp{"decision", "gi"})
+ })
+ })
+
+}
+
+func TestUndefinedValueBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Undefined type to JSON", t, func() {
+ Convey("should produce a json.Undefined", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.Undefined)
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Undefined)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.Undefined{})
+ })
+ })
+}
+
+func TestDBRefBSONToJSON(t *testing.T) {
+ Convey("Converting BSON DBRef to JSON", t, func() {
+ Convey("should produce a json.DBRef", func() {
+ _jObj, err := ConvertBSONValueToJSON(mgo.DBRef{"coll1", "some_id", "test"})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.DBRef)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.DBRef{"coll1", "some_id", "test"})
+ So(jObj, ShouldNotResemble, json.DBRef{"coll1", "test", "some_id"})
+ })
+ })
+}
+
+func TestTimestampBSONToJSON(t *testing.T) {
+ Convey("Converting a BSON Timestamp to JSON", t, func() {
+ Convey("should produce a json.Timestamp", func() {
+ // {t:803434343, i:9} == bson.MongoTimestamp(803434343*2**32 + 9)
+ _jObj, err := ConvertBSONValueToJSON(bson.MongoTimestamp(uint64(803434343<<32) | uint64(9)))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.Timestamp)
+ So(ok, ShouldBeTrue)
+
+ So(jObj, ShouldResemble, json.Timestamp{Seconds:803434343, Increment:9})
+ So(jObj, ShouldNotResemble, json.Timestamp{Seconds:803434343, Increment:8})
+ })
+ })
+}
+
+func TestBinaryBSONToJSON(t *testing.T) {
+ Convey("Converting BSON Binary data to JSON", t, func() {
+ Convey("should produce a json.BinData", func() {
+ _jObj, err := ConvertBSONValueToJSON(bson.Binary{'\x01', []byte("\x05\x20\x02\xae\xf7")})
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.BinData)
+ So(ok, ShouldBeTrue)
+
+ base64data1 := base64.StdEncoding.EncodeToString([]byte("\x05\x20\x02\xae\xf7"))
+ base64data2 := base64.StdEncoding.EncodeToString([]byte("\x05\x20\x02\xaf\xf7"))
+ So(jObj, ShouldResemble, json.BinData{'\x01', base64data1})
+ So(jObj, ShouldNotResemble, json.BinData{'\x01', base64data2})
+ })
+ })
+}
+
+func TestGenericBytesBSONToJSON(t *testing.T) {
+ Convey("Converting Go bytes to JSON", t, func() {
+ Convey("should produce a json.BinData with Type=0x00 (Generic)", func() {
+ _jObj, err := ConvertBSONValueToJSON([]byte("this is something that's cool"))
+ So(err, ShouldBeNil)
+ jObj, ok := _jObj.(json.BinData)
+ So(ok, ShouldBeTrue)
+
+ base64data := base64.StdEncoding.EncodeToString([]byte("this is something that's cool"))
+ So(jObj, ShouldResemble, json.BinData{0x00, base64data})
+ So(jObj, ShouldNotResemble, json.BinData{0x01, base64data})
+ })
+ })
+}
+
+func TestUnknownBSONTypeToJSON(t *testing.T) {
+ Convey("Converting an unknown BSON type to JSON", t, func() {
+ Convey("should produce an error", func() {
+ _, err := ConvertBSONValueToJSON(func(){})
+ So(err, ShouldNotBeNil)
+ })
+ })
+}