These files are restored from git here: https://github.com/mongodb/bson-rust/tree/main/src/tests

diff --git a/src/tests/binary_subtype.rs b/src/tests/binary_subtype.rs
new file mode 100644
index 0000000..71f2d71
--- /dev/null
+++ b/src/tests/binary_subtype.rs
@@ -0,0 +1,14 @@
+use crate::{spec::BinarySubtype, tests::LOCK};
+
+#[test]
+fn from_u8() {
+    let _guard = LOCK.run_concurrently();
+    // Check the endpoints of the defined, reserved, and user-defined subtype ranges.
+    assert_eq!(BinarySubtype::from(0x00), BinarySubtype::Generic);
+    assert_eq!(BinarySubtype::from(0x06), BinarySubtype::Encrypted);
+    assert_eq!(BinarySubtype::from(0x07), BinarySubtype::Column);
+    assert_eq!(BinarySubtype::from(0x08), BinarySubtype::Sensitive);
+    assert_eq!(BinarySubtype::from(0x7F), BinarySubtype::Reserved(0x7F));
+    assert_eq!(BinarySubtype::from(0x80), BinarySubtype::UserDefined(0x80));
+    assert_eq!(BinarySubtype::from(0xFF), BinarySubtype::UserDefined(0xFF));
+}
diff --git a/src/tests/datetime.rs b/src/tests/datetime.rs
new file mode 100644
index 0000000..56bba31
--- /dev/null
+++ b/src/tests/datetime.rs
@@ -0,0 +1,61 @@
+use std::time::Duration;
+
+use crate::tests::LOCK;
+
+#[test]
+fn rfc3339_to_datetime() {
+    let _guard = LOCK.run_concurrently();
+
+    let rfc = "2020-06-09T10:58:07.095Z";
+    let date =
+        time::OffsetDateTime::parse(rfc, &time::format_description::well_known::Rfc3339).unwrap();
+    let parsed = crate::DateTime::parse_rfc3339_str(rfc).unwrap();
+    assert_eq!(parsed, crate::DateTime::from_time_0_3(date));
+    assert_eq!(crate::DateTime::try_to_rfc3339_string(parsed).unwrap(), rfc);
+}
+
+#[test]
+fn invalid_rfc3339_to_datetime() {
+    let _guard = LOCK.run_concurrently();
+
+    let a = "2020-06-09T10:58:07-095Z";
+    let b = "2020-06-09T10:58:07.095";
+    let c = "2020-06-09T10:62:07.095Z";
+    assert!(crate::DateTime::parse_rfc3339_str(a).is_err());
+    assert!(crate::DateTime::parse_rfc3339_str(b).is_err());
+    assert!(crate::DateTime::parse_rfc3339_str(c).is_err());
+}
+
+#[test]
+fn datetime_to_rfc3339() {
+    assert_eq!(
+        crate::DateTime::from_millis(0)
+            .try_to_rfc3339_string()
+            .unwrap(),
+        "1970-01-01T00:00:00Z"
+    );
+}
+
+#[test]
+fn invalid_datetime_to_rfc3339() {
+    assert!(crate::DateTime::MAX.try_to_rfc3339_string().is_err());
+}
+
+#[test]
+fn duration_since() {
+    let _guard = LOCK.run_concurrently();
+
+    let date1 = crate::DateTime::from_millis(100);
+    let date2 = crate::DateTime::from_millis(1000);
+
+    assert_eq!(
+        date2.checked_duration_since(date1),
+        Some(Duration::from_millis(900))
+    );
+    assert_eq!(
+        date2.saturating_duration_since(date1),
+        Duration::from_millis(900)
+    );
+    assert!(date1.checked_duration_since(date2).is_none());
+    assert_eq!(date1.saturating_duration_since(date2), Duration::ZERO);
+}
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
new file mode 100644
index 0000000..23deeea
--- /dev/null
+++ b/src/tests/mod.rs
@@ -0,0 +1,10 @@
+mod binary_subtype;
+mod datetime;
+mod modules;
+mod serde;
+mod spec;
+
+use modules::TestLock;
+use once_cell::sync::Lazy;
+
+pub(crate) static LOCK: Lazy<TestLock> = Lazy::new(TestLock::new);
diff --git a/src/tests/modules/binary.rs b/src/tests/modules/binary.rs
new file mode 100644
index 0000000..d26c4d6
--- /dev/null
+++ b/src/tests/modules/binary.rs
@@ -0,0 +1,21 @@
+use crate::{spec::BinarySubtype, tests::LOCK, Binary};
+
+#[test]
+fn binary_from_base64() {
+    let _guard = LOCK.run_concurrently();
+
+    let input = base64::encode("hello");
+    let produced = Binary::from_base64(input, None).unwrap();
+    let expected = Binary {
+        bytes: "hello".as_bytes().to_vec(),
+        subtype: BinarySubtype::Generic,
+    };
+    assert_eq!(produced, expected);
+
+    let produced = Binary::from_base64("", BinarySubtype::Uuid).unwrap();
+    let expected = Binary {
+        bytes: "".as_bytes().to_vec(),
+        subtype: BinarySubtype::Uuid,
+    };
+    assert_eq!(produced, expected);
+}
diff --git a/src/tests/modules/bson.rs b/src/tests/modules/bson.rs
new file mode 100644
index 0000000..8bb66f8
--- /dev/null
+++ b/src/tests/modules/bson.rs
@@ -0,0 +1,488 @@
+use std::{
+    convert::TryFrom,
+    time::{Duration, SystemTime},
+};
+
+use crate::{
+    doc,
+    oid::ObjectId,
+    spec::BinarySubtype,
+    tests::LOCK,
+    Binary,
+    Bson,
+    DateTime,
+    Document,
+    JavaScriptCodeWithScope,
+    Regex,
+    Timestamp,
+};
+
+use serde_json::{json, Value};
+
+#[test]
+fn to_json() {
+    let _guard = LOCK.run_concurrently();
+    let mut doc = Document::new();
+    doc.insert(
+        "_id",
+        Bson::ObjectId(ObjectId::from_bytes(*b"abcdefghijkl")),
+    );
+    doc.insert("first", Bson::Int32(1));
+    doc.insert("second", Bson::String("foo".to_owned()));
+    doc.insert("alphanumeric", Bson::String("bar".to_owned()));
+    let data: Value = Bson::Document(doc).into();
+
+    assert!(data.is_object());
+    let obj = data.as_object().unwrap();
+
+    let id = obj.get("_id").unwrap();
+    assert!(id.is_object());
+    let id_val = id.get("$oid").unwrap();
+    assert!(id_val.is_string());
+    assert_eq!(id_val, "6162636465666768696a6b6c");
+
+    let first = obj.get("first").unwrap();
+    assert!(first.is_number());
+    assert_eq!(first.as_i64().unwrap(), 1);
+
+    let second = obj.get("second").unwrap();
+    assert!(second.is_string());
+    assert_eq!(second.as_str().unwrap(), "foo");
+
+    let alphanumeric = obj.get("alphanumeric").unwrap();
+    assert!(alphanumeric.is_string());
+    assert_eq!(alphanumeric.as_str().unwrap(), "bar");
+}
+
+#[test]
+fn bson_default() {
+    let _guard = LOCK.run_concurrently();
+    let bson1 = Bson::default();
+    assert_eq!(bson1, Bson::Null);
+}
+
+#[test]
+fn test_display_timestamp_type() {
+    let x = Timestamp {
+        time: 100,
+        increment: 200,
+    };
+    let output = "Timestamp(100, 200)";
+    assert_eq!(format!("{}", x), output);
+    assert_eq!(format!("{}", Bson::from(x)), output);
+}
+
+#[test]
+fn test_display_regex_type() {
+    let x = Regex {
+        pattern: String::from("pattern"),
+        options: String::from("options"),
+    };
+    let output = "/pattern/options";
+    assert_eq!(format!("{}", x), output);
+    assert_eq!(format!("{}", Bson::from(x)), output);
+}
+
+#[test]
+fn test_display_jscodewithcontext_type() {
+    let x = JavaScriptCodeWithScope {
+        code: String::from("code"),
+        scope: doc! {"x": 2},
+    };
+    let output = "code";
+    assert_eq!(format!("{}", x), output);
+    assert_eq!(format!("{}", Bson::from(x)), output);
+}
+
+#[test]
+fn test_display_binary_type() {
+    let encoded_bytes = "aGVsbG8gd29ybGQ=";
+    let bytes = base64::decode(encoded_bytes).unwrap();
+    let x = Binary {
+        subtype: BinarySubtype::Generic,
+        bytes,
+    };
+    let output = format!("Binary(0x0, {})", encoded_bytes);
+    assert_eq!(format!("{}", x), output);
+    assert_eq!(format!("{}", Bson::from(x)), output);
+}
+
+#[test]
+fn document_default() {
+    let _guard = LOCK.run_concurrently();
+    let doc1 = Document::default();
+    assert_eq!(doc1.keys().count(), 0);
+    assert_eq!(doc1, Document::new());
+}
+
+#[test]
+fn from_impls() {
+    let _guard = LOCK.run_concurrently();
+    assert_eq!(Bson::from(1.5f32), Bson::Double(1.5));
+    assert_eq!(Bson::from(2.25f64), Bson::Double(2.25));
+    assert_eq!(Bson::from("data"), Bson::String(String::from("data")));
+    assert_eq!(
+        Bson::from(String::from("data")),
+        Bson::String(String::from("data"))
+    );
+    assert_eq!(Bson::from(doc! {}), Bson::Document(Document::new()));
+    assert_eq!(Bson::from(false), Bson::Boolean(false));
+    assert_eq!(
+        Bson::from(Regex {
+            pattern: String::from("\\s+$"),
+            options: String::from("i")
+        }),
+        Bson::RegularExpression(Regex {
+            pattern: String::from("\\s+$"),
+            options: String::from("i")
+        })
+    );
+    assert_eq!(
+        Bson::from(JavaScriptCodeWithScope {
+            code: String::from("alert(\"hi\");"),
+            scope: doc! {}
+        }),
+        Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
+            code: String::from("alert(\"hi\");"),
+            scope: doc! {}
+        })
+    );
+    //
+    assert_eq!(
+        Bson::from(Binary {
+            subtype: BinarySubtype::Generic,
+            bytes: vec![1, 2, 3]
+        }),
+        Bson::Binary(Binary {
+            subtype: BinarySubtype::Generic,
+            bytes: vec![1, 2, 3]
+        })
+    );
+    assert_eq!(Bson::from(-48i32), Bson::Int32(-48));
+    assert_eq!(Bson::from(-96i64), Bson::Int64(-96));
+    assert_eq!(Bson::from(152u32), Bson::Int32(152));
+
+    let oid = ObjectId::new();
+    assert_eq!(
+        Bson::from(b"abcdefghijkl"),
+        Bson::ObjectId(ObjectId::from_bytes(*b"abcdefghijkl"))
+    );
+    assert_eq!(Bson::from(oid), Bson::ObjectId(oid));
+    assert_eq!(
+        Bson::from(vec![1, 2, 3]),
+        Bson::Array(vec![Bson::Int32(1), Bson::Int32(2), Bson::Int32(3)])
+    );
+    assert_eq!(
+        Bson::try_from(json!({"_id": {"$oid": oid.to_hex()}, "name": ["bson-rs"]})).unwrap(),
+        Bson::Document(doc! {"_id": &oid, "name": ["bson-rs"]})
+    );
+
+    // References
+    assert_eq!(Bson::from(&24i32), Bson::Int32(24));
+    #[allow(clippy::unnecessary_fallible_conversions)]
+    {
+        assert_eq!(
+            Bson::try_from(&String::from("data")).unwrap(),
+            Bson::String(String::from("data"))
+        );
+    }
+    assert_eq!(Bson::from(&oid), Bson::ObjectId(oid));
+    assert_eq!(
+        Bson::from(&doc! {"a": "b"}),
+        Bson::Document(doc! {"a": "b"})
+    );
+
+    // Optionals
+    assert_eq!(Bson::from(Some(4)), Bson::Int32(4));
+    assert_eq!(
+        Bson::from(Some(String::from("data"))),
+        Bson::String(String::from("data"))
+    );
+    assert_eq!(Bson::from(None::<i32>), Bson::Null);
+    assert_eq!(Bson::from(None::<String>), Bson::Null);
+    assert_eq!(doc! {"x": Some(4)}, doc! {"x": 4});
+    assert_eq!(doc! {"x": None::<i32>}, doc! {"x": Bson::Null});
+
+    let db_pointer = Bson::try_from(json!({
+        "$dbPointer": {
+            "$ref": "db.coll",
+            "$id": { "$oid": "507f1f77bcf86cd799439011" },
+        }
+    }))
+    .unwrap();
+    let db_pointer = db_pointer.as_db_pointer().unwrap();
+    assert_eq!(Bson::from(db_pointer), Bson::DbPointer(db_pointer.clone()));
+}
+
+#[test]
+fn timestamp_ordering() {
+    let _guard = LOCK.run_concurrently();
+    let ts1 = Timestamp {
+        time: 0,
+        increment: 1,
+    };
+    let ts2 = Timestamp {
+        time: 0,
+        increment: 2,
+    };
+    let ts3 = Timestamp {
+        time: 1,
+        increment: 0,
+    };
+    assert!(ts1 < ts2);
+    assert!(ts1 < ts3);
+    assert!(ts2 < ts3);
+}
+
+#[test]
+fn from_external_datetime() {
+    use time::macros::datetime;
+
+    let _guard = LOCK.run_concurrently();
+
+    fn assert_millisecond_precision(dt: DateTime) {
+        assert!(dt.to_time_0_3().microsecond() % 1000 == 0);
+    }
+    fn assert_subsec_millis(dt: DateTime, millis: u32) {
+        assert_eq!(dt.to_time_0_3().millisecond() as u32, millis)
+    }
+
+    let now = time::OffsetDateTime::now_utc();
+    let dt = DateTime::from_time_0_3(now);
+    assert_millisecond_precision(dt);
+
+    #[cfg(feature = "time-0_3")]
+    {
+        let bson = Bson::from(now);
+        assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+
+        let from_time = DateTime::from(now);
+        assert_millisecond_precision(from_time);
+    }
+    #[cfg(feature = "chrono-0_4")]
+    {
+        let now = chrono::Utc::now();
+        let bson = Bson::from(now);
+        assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+
+        let from_chrono = DateTime::from(now);
+        assert_millisecond_precision(from_chrono);
+    }
+
+    let no_subsec_millis = datetime!(2014-11-28 12:00:09 UTC);
+    let dt = DateTime::from_time_0_3(no_subsec_millis);
+    assert_millisecond_precision(dt);
+    assert_subsec_millis(dt, 0);
+
+    #[cfg(feature = "time-0_3")]
+    {
+        let bson = Bson::from(dt);
+        assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+        assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 0);
+    }
+    #[cfg(feature = "chrono-0_4")]
+    {
+        let no_subsec_millis: chrono::DateTime<chrono::Utc> =
+            "2014-11-28T12:00:09Z".parse().unwrap();
+        let dt = DateTime::from(no_subsec_millis);
+        assert_millisecond_precision(dt);
+        assert_subsec_millis(dt, 0);
+
+        let bson = Bson::from(dt);
+        assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+        assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 0);
+    }
+
+    for s in &[
+        "2014-11-28T12:00:09.123Z",
+        "2014-11-28T12:00:09.123456Z",
+        "2014-11-28T12:00:09.123456789Z",
+    ] {
+        let time_dt =
+            time::OffsetDateTime::parse(s, &time::format_description::well_known::Rfc3339).unwrap();
+        let dt = DateTime::from_time_0_3(time_dt);
+        assert_millisecond_precision(dt);
+        assert_subsec_millis(dt, 123);
+
+        #[cfg(feature = "time-0_3")]
+        {
+            let bson = Bson::from(time_dt);
+            assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+            assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 123);
+        }
+        #[cfg(feature = "chrono-0_4")]
+        {
+            let chrono_dt: chrono::DateTime<chrono::Utc> = s.parse().unwrap();
+            let dt = DateTime::from(chrono_dt);
+            assert_millisecond_precision(dt);
+            assert_subsec_millis(dt, 123);
+
+            let bson = Bson::from(chrono_dt);
+            assert_millisecond_precision(bson.as_datetime().unwrap().to_owned());
+            assert_subsec_millis(bson.as_datetime().unwrap().to_owned(), 123);
+        }
+    }
+
+    #[cfg(feature = "time-0_3")]
+    {
+        let max = time::PrimitiveDateTime::MAX.assume_utc();
+        let bdt = DateTime::from(max);
+        assert_eq!(
+            bdt.to_time_0_3().unix_timestamp_nanos() / 1_000_000, // truncate to millis
+            max.unix_timestamp_nanos() / 1_000_000
+        );
+
+        let min = time::PrimitiveDateTime::MIN.assume_utc();
+        let bdt = DateTime::from(min);
+        assert_eq!(
+            bdt.to_time_0_3().unix_timestamp_nanos() / 1_000_000,
+            min.unix_timestamp_nanos() / 1_000_000
+        );
+
+        let bdt = DateTime::MAX;
+        assert_eq!(bdt.to_time_0_3(), max);
+
+        let bdt = DateTime::MIN;
+        assert_eq!(bdt.to_time_0_3(), min);
+    }
+    #[cfg(feature = "chrono-0_4")]
+    {
+        use chrono::Utc;
+
+        let bdt = DateTime::from(chrono::DateTime::<Utc>::MAX_UTC);
+        assert_eq!(
+            bdt.to_chrono().timestamp_millis(),
+            chrono::DateTime::<Utc>::MAX_UTC.timestamp_millis()
+        );
+
+        let bdt = DateTime::from(chrono::DateTime::<Utc>::MIN_UTC);
+        assert_eq!(
+            bdt.to_chrono().timestamp_millis(),
+            chrono::DateTime::<Utc>::MIN_UTC.timestamp_millis()
+        );
+
+        let bdt = DateTime::MAX;
+        assert_eq!(bdt.to_chrono(), chrono::DateTime::<Utc>::MAX_UTC);
+
+        let bdt = DateTime::MIN;
+        assert_eq!(bdt.to_chrono(), chrono::DateTime::<Utc>::MIN_UTC);
+    }
+}
+
+#[test]
+fn from_datetime_builder() {
+    {
+        let dt = DateTime::builder()
+            .year(2022)
+            .month(9)
+            .day(15)
+            .minute(2)
+            .millisecond(1)
+            .build();
+        assert!(dt.is_ok());
+        assert_eq!(
+            DateTime::from_time_0_3(time::macros::datetime!(2022 - 09 - 15 00:02:00.001 UTC)),
+            dt.unwrap()
+        );
+    }
+
+    {
+        let dt = DateTime::builder()
+            .year(2022)
+            .month(18)
+            .day(15)
+            .minute(2)
+            .millisecond(1)
+            .build();
+        assert!(dt.is_err());
+    }
+
+    {
+        let dt = DateTime::builder()
+            .year(2022)
+            .day(15)
+            .month(18)
+            .minute(83)
+            .millisecond(1)
+            .build();
+        assert!(dt.is_err());
+    }
+}
+
+#[test]
+fn system_time() {
+    let _guard = LOCK.run_concurrently();
+
+    let st = SystemTime::now();
+    let bt_into: crate::DateTime = st.into();
+    let bt_from = crate::DateTime::from_system_time(st);
+
+    assert_eq!(bt_into, bt_from);
+    assert_eq!(
+        bt_into.timestamp_millis(),
+        st.duration_since(SystemTime::UNIX_EPOCH)
+            .unwrap()
+            .as_millis() as i64
+    );
+
+    let st = SystemTime::UNIX_EPOCH
+        .checked_add(Duration::from_millis(1234))
+        .unwrap();
+    let bt = crate::DateTime::from_system_time(st);
+    assert_eq!(bt.timestamp_millis(), 1234);
+    assert_eq!(bt.to_system_time(), st);
+
+    assert_eq!(
+        crate::DateTime::MAX.to_system_time(),
+        SystemTime::UNIX_EPOCH + Duration::from_millis(i64::MAX as u64)
+    );
+    assert_eq!(
+        crate::DateTime::MIN.to_system_time(),
+        SystemTime::UNIX_EPOCH - Duration::from_millis((i64::MIN as i128).unsigned_abs() as u64)
+    );
+
+    assert_eq!(
+        crate::DateTime::from_system_time(SystemTime::UNIX_EPOCH).timestamp_millis(),
+        0
+    );
+}
+
+#[test]
+fn debug_print() {
+    let oid = ObjectId::parse_str("000000000000000000000000").unwrap();
+
+    let doc = doc! {
+        "oid": oid,
+        "arr": Bson::Array(vec! [
+            Bson::Null,
+            Bson::Timestamp(Timestamp { time: 1, increment: 1 }),
+        ]),
+        "doc": doc! { "a": 1, "b": "data"},
+    };
+    let normal_print = "Document({\"oid\": ObjectId(\"000000000000000000000000\"), \"arr\": \
+                        Array([Null, Timestamp { time: 1, increment: 1 }]), \"doc\": \
+                        Document({\"a\": Int32(1), \"b\": String(\"data\")})})";
+    let pretty_print = "Document({
+    \"oid\": ObjectId(
+        \"000000000000000000000000\",
+    ),
+    \"arr\": Array([
+        Null,
+        Timestamp {
+            time: 1,
+            increment: 1,
+        },
+    ]),
+    \"doc\": Document({
+        \"a\": Int32(
+            1,
+        ),
+        \"b\": String(
+            \"data\",
+        ),
+    }),
+})";
+
+    assert_eq!(format!("{:?}", doc), normal_print);
+    assert_eq!(format!("{:#?}", doc), pretty_print);
+}
diff --git a/src/tests/modules/document.rs b/src/tests/modules/document.rs
new file mode 100644
index 0000000..85fc62f
--- /dev/null
+++ b/src/tests/modules/document.rs
@@ -0,0 +1,247 @@
+use crate::{
+    doc,
+    document::ValueAccessError,
+    oid::ObjectId,
+    spec::BinarySubtype,
+    tests::LOCK,
+    Binary,
+    Bson,
+    Document,
+    Timestamp,
+};
+use time::OffsetDateTime;
+
+#[test]
+fn ordered_insert() {
+    let _guard = LOCK.run_concurrently();
+    let mut doc = Document::new();
+    doc.insert("first".to_owned(), Bson::Int32(1));
+    doc.insert("second".to_owned(), Bson::String("foo".to_owned()));
+    doc.insert("alphanumeric".to_owned(), Bson::String("bar".to_owned()));
+
+    let expected_keys = vec![
+        "first".to_owned(),
+        "second".to_owned(),
+        "alphanumeric".to_owned(),
+    ];
+
+    let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
+    assert_eq!(expected_keys, keys);
+}
+
+#[test]
+fn ordered_insert_shorthand() {
+    let _guard = LOCK.run_concurrently();
+    let mut doc = Document::new();
+    doc.insert("first", 1i32);
+    doc.insert("second", "foo");
+    doc.insert("alphanumeric", "bar".to_owned());
+
+    let expected_keys = vec![
+        "first".to_owned(),
+        "second".to_owned(),
+        "alphanumeric".to_owned(),
+    ];
+
+    let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
+    assert_eq!(expected_keys, keys);
+}
+
+#[test]
+fn test_getters() {
+    let _guard = LOCK.run_concurrently();
+    let datetime = OffsetDateTime::now_utc();
+    let cloned_dt = crate::DateTime::from_time_0_3(datetime);
+    let binary = vec![0, 1, 2, 3, 4];
+    let mut doc = doc! {
+        "floating_point": 10.0,
+        "string": "a value",
+        "array": [10, 20, 30],
+        "doc": { "key": 1 },
+        "bool": true,
+        "i32": 1i32,
+        "i64": 1i64,
+        "datetime": cloned_dt,
+        "binary": Binary { subtype: BinarySubtype::Generic, bytes: binary.clone() }
+    };
+
+    assert_eq!(None, doc.get("nonsense"));
+    assert_eq!(Err(ValueAccessError::NotPresent), doc.get_str("nonsense"));
+    assert_eq!(
+        Err(ValueAccessError::UnexpectedType),
+        doc.get_str("floating_point")
+    );
+
+    assert_eq!(Some(&Bson::Double(10.0)), doc.get("floating_point"));
+    assert_eq!(Ok(10.0), doc.get_f64("floating_point"));
+
+    assert_eq!(
+        Some(&Bson::String("a value".to_string())),
+        doc.get("string")
+    );
+    assert_eq!(Ok("a value"), doc.get_str("string"));
+
+    let array = vec![Bson::Int32(10), Bson::Int32(20), Bson::Int32(30)];
+    assert_eq!(Some(&Bson::Array(array.clone())), doc.get("array"));
+    assert_eq!(Ok(&array), doc.get_array("array"));
+
+    let embedded = doc! { "key": 1 };
+    assert_eq!(Some(&Bson::Document(embedded.clone())), doc.get("doc"));
+    assert_eq!(Ok(&embedded), doc.get_document("doc"));
+
+    assert_eq!(Some(&Bson::Boolean(true)), doc.get("bool"));
+    assert_eq!(Ok(true), doc.get_bool("bool"));
+
+    doc.insert("null".to_string(), Bson::Null);
+    assert_eq!(Some(&Bson::Null), doc.get("null"));
+    assert!(doc.is_null("null"));
+    assert!(!doc.is_null("array"));
+
+    assert_eq!(Some(&Bson::Int32(1)), doc.get("i32"));
+    assert_eq!(Ok(1i32), doc.get_i32("i32"));
+
+    assert_eq!(Some(&Bson::Int64(1)), doc.get("i64"));
+    assert_eq!(Ok(1i64), doc.get_i64("i64"));
+
+    doc.insert(
+        "timestamp".to_string(),
+        Bson::Timestamp(Timestamp {
+            time: 0,
+            increment: 100,
+        }),
+    );
+    assert_eq!(
+        Some(&Bson::Timestamp(Timestamp {
+            time: 0,
+            increment: 100
+        })),
+        doc.get("timestamp")
+    );
+    assert_eq!(
+        Ok(Timestamp {
+            time: 0,
+            increment: 100,
+        }),
+        doc.get_timestamp("timestamp")
+    );
+
+    let dt = crate::DateTime::from_time_0_3(datetime);
+    assert_eq!(Some(&Bson::DateTime(dt)), doc.get("datetime"));
+    assert_eq!(Ok(&dt), doc.get_datetime("datetime"));
+
+    let object_id = ObjectId::new();
+    doc.insert("_id".to_string(), Bson::ObjectId(object_id));
+    assert_eq!(Some(&Bson::ObjectId(object_id)), doc.get("_id"));
+    assert_eq!(Ok(object_id), doc.get_object_id("_id"));
+
+    assert_eq!(
+        Some(&Bson::Binary(Binary {
+            subtype: BinarySubtype::Generic,
+            bytes: binary.clone()
+        })),
+        doc.get("binary")
+    );
+    assert_eq!(Ok(&binary), doc.get_binary_generic("binary"));
+}
+
+#[test]
+fn remove() {
+    let _guard = LOCK.run_concurrently();
+
+    let mut doc = Document::new();
+    doc.insert("first", 1i32);
+    doc.insert("second", "foo");
+    doc.insert("third", "bar".to_owned());
+    doc.insert("fourth", "bar".to_owned());
+
+    let mut expected_keys = vec![
+        "first".to_owned(),
+        "second".to_owned(),
+        "third".to_owned(),
+        "fourth".to_owned(),
+    ];
+
+    let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
+    assert_eq!(expected_keys, keys);
+
+    assert_eq!(doc.remove("none"), None);
+
+    assert!(doc.remove("second").is_some());
+    expected_keys.remove(1);
+    let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
+    assert_eq!(keys, expected_keys);
+
+    assert!(doc.remove("first").is_some());
+    expected_keys.remove(0);
+    let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
+    assert_eq!(keys, expected_keys);
+}
+
+#[test]
+fn entry() {
+    let _guard = LOCK.run_concurrently();
+    let mut doc = doc! {
+        "first": 1i32,
+        "second": "foo",
+        "alphanumeric": "bar",
+    };
+
+    {
+        let first_entry = doc.entry("first".to_owned());
+        assert_eq!(first_entry.key(), "first");
+
+        let v = first_entry.or_insert_with(|| {
+            Bson::Timestamp(Timestamp {
+                time: 0,
+                increment: 27,
+            })
+        });
+        assert_eq!(v, &mut Bson::Int32(1));
+    }
+
+    {
+        let fourth_entry = doc.entry("fourth".to_owned());
+        assert_eq!(fourth_entry.key(), "fourth");
+
+        let v = fourth_entry.or_insert(Bson::Null);
+        assert_eq!(v, &mut Bson::Null);
+    }
+
+    assert_eq!(
+        doc,
+        doc! {
+            "first": 1i32,
+            "second": "foo",
+            "alphanumeric": "bar",
+            "fourth": Bson::Null,
+        },
+    );
+}
+
+#[test]
+fn extend() {
+    let _guard = LOCK.run_concurrently();
+    let mut doc1 = doc! {
+        "first": 1,
+        "second": "data",
+        "subdoc": doc! { "a": 1, "b": 2 },
+    };
+
+    let doc2 = doc! {
+        "third": "abcdefg",
+        "first": 2,
+        "subdoc": doc! { "c": 3 },
+    };
+
+    doc1.extend(doc2);
+
+    assert_eq!(
+        doc1,
+        doc! {
+            "first": 2,
+            "second": "data",
+            "third": "abcdefg",
+            "subdoc": doc! { "c": 3 },
+        },
+    );
+}
diff --git a/src/tests/modules/lock.rs b/src/tests/modules/lock.rs
new file mode 100644
index 0000000..37963dd
--- /dev/null
+++ b/src/tests/modules/lock.rs
@@ -0,0 +1,20 @@
+use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
+
+#[derive(Default)]
+pub struct TestLock {
+    inner: RwLock<()>,
+}
+
+impl TestLock {
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run_concurrently(&self) -> RwLockReadGuard<'_, ()> {
+        self.inner.read().unwrap()
+    }
+
+    pub fn run_exclusively(&self) -> RwLockWriteGuard<'_, ()> {
+        self.inner.write().unwrap()
+    }
+}
diff --git a/src/tests/modules/macros.rs b/src/tests/modules/macros.rs
new file mode 100644
index 0000000..150e22d
--- /dev/null
+++ b/src/tests/modules/macros.rs
@@ -0,0 +1,275 @@
+use crate::{
+    doc,
+    oid::ObjectId,
+    spec::BinarySubtype,
+    tests::LOCK,
+    Binary,
+    Bson,
+    RawBson,
+    Regex,
+    Timestamp,
+};
+use pretty_assertions::assert_eq;
+
+#[test]
+fn standard_format() {
+    let _guard = LOCK.run_concurrently();
+    let id_string = "thisismyname";
+    let string_bytes: Vec<_> = id_string.bytes().collect();
+    let mut bytes = [0; 12];
+    bytes[..12].clone_from_slice(&string_bytes[..12]);
+
+    let id = ObjectId::from_bytes(bytes);
+    let date = time::OffsetDateTime::now_utc();
+
+    let doc = doc! {
+        "float": 2.4,
+        "string": "hello",
+        "array": ["testing", 1, true, [1, 2]],
+        "doc": {
+            "fish": "in",
+            "a": "barrel",
+            "!": 1,
+        },
+        "bool": true,
+        "null": null,
+        "regexp": Bson::RegularExpression(Regex { pattern: "s[ao]d".to_owned(), options: "i".to_owned() }),
+        "with_wrapped_parens": (-20),
+        "code": Bson::JavaScriptCode("function(x) { return x._id; }".to_owned()),
+        "i32": 12,
+        "i64": -55,
+        "timestamp": Bson::Timestamp(Timestamp { time: 0, increment: 229_999_444 }),
+        "binary": Binary { subtype: BinarySubtype::Md5, bytes: "thingies".to_owned().into_bytes() },
+        "encrypted": Binary { subtype: BinarySubtype::Encrypted, bytes: "secret".to_owned().into_bytes() },
+        "_id": id,
+        "date": Bson::DateTime(crate::DateTime::from_time_0_3(date)),
+    };
+
+    let rawdoc = rawdoc! {
+        "float": 2.4,
+        "string": "hello",
+        "array": ["testing", 1, true, [1, 2]],
+        "doc": {
+            "fish": "in",
+            "a": "barrel",
+            "!": 1,
+        },
+        "bool": true,
+        "null": null,
+        "regexp": Regex { pattern: "s[ao]d".to_owned(), options: "i".to_owned() },
+        "with_wrapped_parens": (-20),
+        "code": RawBson::JavaScriptCode("function(x) { return x._id; }".to_owned()),
+        "i32": 12,
+        "i64": -55,
+        "timestamp": Timestamp { time: 0, increment: 229_999_444 },
+        "binary": Binary { subtype: BinarySubtype::Md5, bytes: "thingies".to_owned().into_bytes() },
+        "encrypted": Binary { subtype: BinarySubtype::Encrypted, bytes: "secret".to_owned().into_bytes() },
+        "_id": id,
+        "date": crate::DateTime::from_time_0_3(date),
+    };
+
+    let ts_nanos = date.unix_timestamp_nanos();
+    let ts_millis = ts_nanos - (ts_nanos % 1_000_000);
+    let date_trunc = time::OffsetDateTime::from_unix_timestamp_nanos(ts_millis).unwrap();
+    let expected = format!(
+        "{{ \"float\": 2.4, \"string\": \"hello\", \"array\": [\"testing\", 1, true, [1, 2]], \
+         \"doc\": {{ \"fish\": \"in\", \"a\": \"barrel\", \"!\": 1 }}, \"bool\": true, \"null\": \
+         null, \"regexp\": /s[ao]d/i, \"with_wrapped_parens\": -20, \"code\": function(x) {{ \
+         return x._id; }}, \"i32\": 12, \"i64\": -55, \"timestamp\": Timestamp(0, 229999444), \
+         \"binary\": Binary(0x5, {}), \"encrypted\": Binary(0x6, {}), \"_id\": ObjectId(\"{}\"), \
+         \"date\": DateTime(\"{}\") }}",
+        base64::encode("thingies"),
+        base64::encode("secret"),
+        hex::encode(id_string),
+        date_trunc,
+    );
+
+    assert_eq!(expected, format!("{}", doc));
+
+    assert_eq!(rawdoc.into_bytes(), crate::to_vec(&doc).unwrap());
+}
+
+#[test]
+fn non_trailing_comma() {
+    let _guard = LOCK.run_concurrently();
+    let doc = doc! {
+        "a": "foo",
+        "b": { "ok": "then" }
+    };
+
+    let expected = "{ \"a\": \"foo\", \"b\": { \"ok\": \"then\" } }".to_string();
+    assert_eq!(expected, format!("{}", doc));
+}
+
+#[test]
+#[allow(clippy::float_cmp)]
+fn recursive_macro() {
+    let _guard = LOCK.run_concurrently();
+    let doc = doc! {
+        "a": "foo",
+        "b": {
+            "bar": {
+                "harbor": ["seal", false],
+                "jelly": 42.0,
+            },
+            "grape": 27,
+        },
+        "c": [-7],
+        "d": [
+            {
+                "apple": "ripe",
+            }
+        ],
+        "e": { "single": "test" },
+        "n": (Bson::Null),
+    };
+    let rawdoc = rawdoc! {
+        "a": "foo",
+        "b": {
+            "bar": {
+                "harbor": ["seal", false],
+                "jelly": 42.0,
+            },
+            "grape": 27,
+        },
+        "c": [-7],
+        "d": [
+            {
+                "apple": "ripe",
+            }
+        ],
+        "e": { "single": "test" },
+        "n": (RawBson::Null),
+    };
+
+    match doc.get("a") {
+        Some(Bson::String(s)) => assert_eq!("foo", s),
+        _ => panic!("String 'foo' was not inserted correctly."),
+    }
+
+    // Inner Doc 1
+    match doc.get("b") {
+        Some(Bson::Document(doc)) => {
+            // Inner doc 2
+            match doc.get("bar") {
+                Some(Bson::Document(inner_doc)) => {
+                    // Inner array
+                    match inner_doc.get("harbor") {
+                        Some(Bson::Array(arr)) => {
+                            assert_eq!(2, arr.len());
+
+                            // Match array items
+                            match arr.first() {
+                                Some(Bson::String(ref s)) => assert_eq!("seal", s),
+                                _ => panic!(
+                                    "String 'seal' was not inserted into inner array correctly."
+                                ),
+                            }
+                            match arr.get(1) {
+                                Some(Bson::Boolean(ref b)) => assert!(!b),
+                                _ => panic!(
+                                    "Bool 'false' was not inserted into inner array correctly."
+                                ),
+                            }
+                        }
+                        _ => panic!("Inner array was not inserted correctly."),
+                    }
+
+                    // Inner floating point
+                    match inner_doc.get("jelly") {
+                        Some(Bson::Double(fp)) => assert_eq!(42.0, *fp),
+                        _ => panic!("Floating point 42.0 was not inserted correctly."),
+                    }
+                }
+                _ => panic!("Second inner document was not inserted correctly."),
+            }
+        }
+        _ => panic!("Inner document was not inserted correctly."),
+    }
+
+    // Single-item array
+    match doc.get("c") {
+        Some(Bson::Array(arr)) => {
+            assert_eq!(1, arr.len());
+
+            // Integer type
+            match arr.first() {
+                Some(Bson::Int32(ref i)) => assert_eq!(-7, *i),
+                _ => panic!("I32 '-7' was not inserted correctly."),
+            }
+        }
+        _ => panic!("Single-item array was not inserted correctly."),
+    }
+
+    // Document nested in array
+    match doc.get("d") {
+        Some(Bson::Array(arr)) => {
+            assert_eq!(1, arr.len());
+
+            // Nested document
+            match arr.first() {
+                Some(Bson::Document(ref doc)) => {
+                    // String
+                    match doc.get("apple") {
+                        Some(Bson::String(s)) => assert_eq!("ripe", s),
+                        _ => panic!("String 'ripe' was not inserted correctly."),
+                    }
+                }
+                _ => panic!("Document was not inserted into array correctly."),
+            }
+        }
+        _ => panic!("Array was not inserted correctly."),
+    }
+
+    // Single-item document
+    match doc.get("e") {
+        Some(Bson::Document(bdoc)) => {
+            // String
+            match bdoc.get("single") {
+                Some(Bson::String(s)) => assert_eq!("test", s),
+                _ => panic!("String 'test' was not inserted correctly."),
+            }
+        }
+        _ => panic!("Single-item document was not inserted correctly."),
+    }
+
+    match doc.get("n") {
+        Some(&Bson::Null) => {
+            // It was null
+        }
+        _ => panic!("Null was not inserted correctly."),
+    }
+
+    assert_eq!(rawdoc.into_bytes(), crate::to_vec(&doc).unwrap());
+}
+
+#[test]
+#[allow(clippy::from_over_into)]
+fn can_use_macro_with_into_bson() {
+    struct Custom;
+
+    impl Into<Bson> for Custom {
+        fn into(self) -> Bson {
+            "foo".into()
+        }
+    }
+
+    impl Into<RawBson> for Custom {
+        fn into(self) -> RawBson {
+            "foo".into()
+        }
+    }
+
+    _ = bson!({
+        "a": Custom,
+    });
+    _ = doc! {
+        "a": Custom,
+    };
+    _ = rawbson!({
+        "a": Custom,
+    });
+    _ = rawdoc! {
+        "a": Custom,
+    };
+}
diff --git a/src/tests/modules/mod.rs b/src/tests/modules/mod.rs
new file mode 100644
index 0000000..d55a287
--- /dev/null
+++ b/src/tests/modules/mod.rs
@@ -0,0 +1,10 @@
+mod binary;
+mod bson;
+mod document;
+mod lock;
+mod macros;
+mod oid;
+mod ser;
+mod serializer_deserializer;
+
+pub use self::lock::TestLock;
diff --git a/src/tests/modules/oid.rs b/src/tests/modules/oid.rs
new file mode 100644
index 0000000..b875eaa
--- /dev/null
+++ b/src/tests/modules/oid.rs
@@ -0,0 +1,60 @@
+use crate::{oid::ObjectId, tests::LOCK};
+
+#[test]
+fn string_oid() {
+    let _guard = LOCK.run_concurrently();
+    let s = "123456789012123456789012";
+    let oid_res = ObjectId::parse_str(s);
+    assert!(oid_res.is_ok());
+    let actual_s = hex::encode(oid_res.unwrap().bytes());
+    assert_eq!(s.to_owned(), actual_s);
+}
+
+#[test]
+fn byte_string_oid() {
+    let _guard = LOCK.run_concurrently();
+    let s = "541b1a00e8a23afa832b218e";
+    let oid_res = ObjectId::parse_str(s);
+    assert!(oid_res.is_ok());
+    let oid = oid_res.unwrap();
+    let bytes: [u8; 12] = [
+        0x54u8, 0x1Bu8, 0x1Au8, 0x00u8, 0xE8u8, 0xA2u8, 0x3Au8, 0xFAu8, 0x83u8, 0x2Bu8, 0x21u8,
+        0x8Eu8,
+    ];
+
+    assert_eq!(bytes, oid.bytes());
+    assert_eq!(s, oid.to_string());
+}
+
+#[test]
+#[allow(clippy::eq_op)]
+fn oid_equals() {
+    let _guard = LOCK.run_concurrently();
+    let oid = ObjectId::new();
+    assert_eq!(oid, oid);
+}
+
+#[test]
+fn oid_not_equals() {
+    let _guard = LOCK.run_concurrently();
+    assert!(ObjectId::new() != ObjectId::new());
+}
+
+// check that the last byte in objectIDs is increasing
+#[test]
+fn counter_increasing() {
+    let _guard = LOCK.run_concurrently();
+    let oid1_bytes = ObjectId::new().bytes();
+    let oid2_bytes = ObjectId::new().bytes();
+    assert!(oid1_bytes[11] < oid2_bytes[11]);
+}
+
+#[test]
+fn fromstr_oid() {
+    let _guard = LOCK.run_concurrently();
+    let s = "123456789012123456789012";
+    let oid_res = s.parse::<ObjectId>();
+    assert!(oid_res.is_ok(), "oid parse failed");
+    let actual_s = hex::encode(oid_res.unwrap().bytes());
+    assert_eq!(s, &actual_s, "parsed and expected oids differ");
+}
diff --git a/src/tests/modules/ser.rs b/src/tests/modules/ser.rs
new file mode 100644
index 0000000..3b93bbb
--- /dev/null
+++ b/src/tests/modules/ser.rs
@@ -0,0 +1,172 @@
+use std::{collections::BTreeMap, u16, u32, u64, u8};
+
+use assert_matches::assert_matches;
+
+use crate::{from_bson, oid::ObjectId, ser, tests::LOCK, to_bson, to_vec, Bson, Document, Regex};
+
+#[test]
+#[allow(clippy::float_cmp)]
+fn floating_point() {
+    let _guard = LOCK.run_concurrently();
+    let obj = Bson::Double(240.5);
+    let f: f64 = from_bson(obj.clone()).unwrap();
+    assert_eq!(f, 240.5);
+
+    let deser: Bson = to_bson(&f).unwrap();
+    assert_eq!(obj, deser);
+}
+
+#[test]
+fn string() {
+    let _guard = LOCK.run_concurrently();
+    let obj = Bson::String("avocado".to_owned());
+    let s: String = from_bson(obj.clone()).unwrap();
+    assert_eq!(s, "avocado");
+
+    let deser: Bson = to_bson(&s).unwrap();
+    assert_eq!(obj, deser);
+}
+
+#[test]
+fn arr() {
+    let _guard = LOCK.run_concurrently();
+    let obj = Bson::Array(vec![
+        Bson::Int32(0),
+        Bson::Int32(1),
+        Bson::Int32(2),
+        Bson::Int32(3),
+    ]);
+    let arr: Vec<i32> = from_bson(obj.clone()).unwrap();
+    assert_eq!(arr, vec![0i32, 1i32, 2i32, 3i32]);
+
+    let deser: Bson = to_bson(&arr).unwrap();
+    assert_eq!(deser, obj);
+}
+
+#[test]
+fn boolean() {
+    let _guard = LOCK.run_concurrently();
+    let obj = Bson::Boolean(true);
+    let b: bool = from_bson(obj.clone()).unwrap();
+    assert!(b);
+
+    let deser: Bson = to_bson(&b).unwrap();
+    assert_eq!(deser, obj);
+}
+
+#[test]
+fn int32() {
+    let _guard = LOCK.run_concurrently();
+    let obj = Bson::Int32(101);
+    let i: i32 = from_bson(obj.clone()).unwrap();
+
+    assert_eq!(i, 101);
+
+    let deser: Bson = to_bson(&i).unwrap();
+    assert_eq!(deser, obj);
+}
+
+#[test]
+fn uint8_u2i() {
+    let _guard = LOCK.run_concurrently();
+    let obj: Bson = to_bson(&u8::MIN).unwrap();
+    let deser: u8 = from_bson(obj).unwrap();
+    assert_eq!(deser, u8::MIN);
+
+    let obj_max: Bson = to_bson(&u8::MAX).unwrap();
+    let deser_max: u8 = from_bson(obj_max).unwrap();
+    assert_eq!(deser_max, u8::MAX);
+}
+
+#[test]
+fn uint16_u2i() {
+    let _guard = LOCK.run_concurrently();
+    let obj: Bson = to_bson(&u16::MIN).unwrap();
+    let deser: u16 = from_bson(obj).unwrap();
+    assert_eq!(deser, u16::MIN);
+
+    let obj_max: Bson = to_bson(&u16::MAX).unwrap();
+    let deser_max: u16 = from_bson(obj_max).unwrap();
+    assert_eq!(deser_max, u16::MAX);
+}
+
+#[test]
+fn uint32_u2i() {
+    let _guard = LOCK.run_concurrently();
+    let obj_min: Bson = to_bson(&u32::MIN).unwrap();
+    let deser_min: u32 = from_bson(obj_min).unwrap();
+    assert_eq!(deser_min, u32::MIN);
+
+    let obj_max: Bson = to_bson(&u32::MAX).unwrap();
+    let deser_max: u32 = from_bson(obj_max).unwrap();
+    assert_eq!(deser_max, u32::MAX);
+}
+
+#[test]
+fn uint64_u2i() {
+    let _guard = LOCK.run_concurrently();
+    let obj_min: Bson = to_bson(&u64::MIN).unwrap();
+    let deser_min: u64 = from_bson(obj_min).unwrap();
+    assert_eq!(deser_min, u64::MIN);
+
+    let obj_max: ser::Result<Bson> = to_bson(&u64::MAX);
+    assert_matches!(
+        obj_max,
+        Err(ser::Error::UnsignedIntegerExceededRange(u64::MAX))
+    );
+}
+
+#[test]
+fn int64() {
+    let _guard = LOCK.run_concurrently();
+    let obj = Bson::Int64(101);
+    let i: i64 = from_bson(obj.clone()).unwrap();
+    assert_eq!(i, 101);
+
+    let deser: Bson = to_bson(&i).unwrap();
+    assert_eq!(deser, obj);
+}
+
+#[test]
+fn oid() {
+    let _guard = LOCK.run_concurrently();
+    let oid = ObjectId::new();
+    let obj = Bson::ObjectId(oid);
+    let s: BTreeMap<String, String> = from_bson(obj.clone()).unwrap();
+
+    let mut expected = BTreeMap::new();
+    expected.insert("$oid".to_owned(), oid.to_string());
+    assert_eq!(s, expected);
+
+    let deser: Bson = to_bson(&s).unwrap();
+    assert_eq!(deser, obj);
+}
+
+#[test]
+fn cstring_null_bytes_error() {
+    let _guard = LOCK.run_concurrently();
+
+    let doc = doc! { "\0": "a" };
+    verify_doc(doc);
+
+    let doc = doc! { "a": { "\0": "b" } };
+    verify_doc(doc);
+
+    let regex = doc! { "regex": Regex { pattern: "\0".into(), options: "a".into() } };
+    verify_doc(regex);
+
+    let regex = doc! { "regex": Regex { pattern: "a".into(), options: "\0".into() } };
+    verify_doc(regex);
+
+    fn verify_doc(doc: Document) {
+        let mut vec = Vec::new();
+        assert!(matches!(
+            doc.to_writer(&mut vec).unwrap_err(),
+            ser::Error::InvalidCString(_)
+        ));
+        assert!(matches!(
+            to_vec(&doc).unwrap_err(),
+            ser::Error::InvalidCString(_)
+        ));
+    }
+}
diff --git a/src/tests/modules/serializer_deserializer.rs b/src/tests/modules/serializer_deserializer.rs
new file mode 100644
index 0000000..2f47684
--- /dev/null
+++ b/src/tests/modules/serializer_deserializer.rs
@@ -0,0 +1,573 @@
+use std::{
+    convert::TryFrom,
+    io::{Cursor, Write},
+};
+
+use serde::{Deserialize, Serialize};
+
+use crate::{
+    de::from_document,
+    doc,
+    oid::ObjectId,
+    ser::Error,
+    spec::BinarySubtype,
+    tests::LOCK,
+    to_document,
+    Binary,
+    Bson,
+    Decimal128,
+    Document,
+    JavaScriptCodeWithScope,
+    Regex,
+    Timestamp,
+};
+use serde_json::json;
+
+#[test]
+fn test_serialize_deserialize_floating_point() {
+    let _guard = LOCK.run_concurrently();
+    let src = 1020.123;
+    let dst = vec![
+        18, 0, 0, 0, 1, 107, 101, 121, 0, 68, 139, 108, 231, 251, 224, 143, 64, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_utf8_string() {
+    let _guard = LOCK.run_concurrently();
+    let src = "test你好吗".to_owned();
+    let dst = vec![
+        28, 0, 0, 0, 2, 107, 101, 121, 0, 14, 0, 0, 0, 116, 101, 115, 116, 228, 189, 160, 229, 165,
+        189, 229, 144, 151, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_encode_decode_utf8_string_invalid() {
+    let bytes = b"\x80\xae".to_vec();
+    let src = unsafe { String::from_utf8_unchecked(bytes) };
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    let expected = doc! { "key": "��" };
+    let decoded = Document::from_reader_utf8_lossy(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(decoded, expected);
+}
+
+#[test]
+fn test_serialize_deserialize_array() {
+    let _guard = LOCK.run_concurrently();
+    let src = vec![Bson::Double(1.01), Bson::String("xyz".to_owned())];
+    let dst = vec![
+        37, 0, 0, 0, 4, 107, 101, 121, 0, 27, 0, 0, 0, 1, 48, 0, 41, 92, 143, 194, 245, 40, 240,
+        63, 2, 49, 0, 4, 0, 0, 0, 120, 121, 122, 0, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize() {
+    let _guard = LOCK.run_concurrently();
+    let src = doc! { "subkey": 1 };
+    let dst = vec![
+        27, 0, 0, 0, 3, 107, 101, 121, 0, 17, 0, 0, 0, 16, 115, 117, 98, 107, 101, 121, 0, 1, 0, 0,
+        0, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_boolean() {
+    let _guard = LOCK.run_concurrently();
+    let src = true;
+    let dst = vec![11, 0, 0, 0, 8, 107, 101, 121, 0, 1, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_null() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::Null;
+    let dst = vec![10, 0, 0, 0, 10, 107, 101, 121, 0, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_regexp() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::RegularExpression(Regex {
+        pattern: "1".to_owned(),
+        options: "2".to_owned(),
+    });
+    let dst = vec![14, 0, 0, 0, 11, 107, 101, 121, 0, 49, 0, 50, 0, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_javascript_code() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::JavaScriptCode("1".to_owned());
+    let dst = vec![16, 0, 0, 0, 13, 107, 101, 121, 0, 2, 0, 0, 0, 49, 0, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_javascript_code_with_scope() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope {
+        code: "1".to_owned(),
+        scope: doc! {},
+    });
+    let dst = vec![
+        25, 0, 0, 0, 15, 107, 101, 121, 0, 15, 0, 0, 0, 2, 0, 0, 0, 49, 0, 5, 0, 0, 0, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_i32() {
+    let _guard = LOCK.run_concurrently();
+    let src = 100i32;
+    let dst = vec![14, 0, 0, 0, 16, 107, 101, 121, 0, 100, 0, 0, 0, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_i64() {
+    let _guard = LOCK.run_concurrently();
+    let src = 100i64;
+    let dst = vec![
+        18, 0, 0, 0, 18, 107, 101, 121, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_timestamp() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::Timestamp(Timestamp {
+        time: 0,
+        increment: 100,
+    });
+    let dst = vec![
+        18, 0, 0, 0, 17, 107, 101, 121, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_binary_generic() {
+    let _guard = LOCK.run_concurrently();
+    let src = Binary {
+        subtype: BinarySubtype::Generic,
+        bytes: vec![0, 1, 2, 3, 4],
+    };
+    let dst = vec![
+        20, 0, 0, 0, 5, 107, 101, 121, 0, 5, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_object_id() {
+    let _guard = LOCK.run_concurrently();
+    let src = ObjectId::parse_str("507f1f77bcf86cd799439011").unwrap();
+    let dst = vec![
+        22, 0, 0, 0, 7, 107, 101, 121, 0, 80, 127, 31, 119, 188, 248, 108, 215, 153, 67, 144, 17, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_utc_date_time() {
+    #[cfg(feature = "chrono-0_4")]
+    use chrono::offset::TimeZone;
+    let _guard = LOCK.run_concurrently();
+    #[cfg(not(any(feature = "chrono-0_4", feature = "time-0_3")))]
+    let src = crate::DateTime::from_time_0_3(
+        time::OffsetDateTime::from_unix_timestamp(1_286_705_410).unwrap(),
+    );
+    #[cfg(feature = "time-0_3")]
+    #[allow(unused)]
+    let src = time::OffsetDateTime::from_unix_timestamp(1_286_705_410).unwrap();
+    #[cfg(feature = "chrono-0_4")]
+    let src = chrono::Utc.timestamp_opt(1_286_705_410, 0).unwrap();
+    let dst = vec![
+        18, 0, 0, 0, 9, 107, 101, 121, 0, 208, 111, 158, 149, 43, 1, 0, 0, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_symbol() {
+    let _guard = LOCK.run_concurrently();
+    let symbol = Bson::Symbol("abc".to_owned());
+    let dst = vec![
+        18, 0, 0, 0, 14, 107, 101, 121, 0, 4, 0, 0, 0, 97, 98, 99, 0, 0,
+    ];
+
+    let doc = doc! { "key": symbol };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_deserialize_utc_date_time_overflows() {
+    let _guard = LOCK.run_concurrently();
+    let t: i64 = 1_530_492_218 * 1_000 + 999;
+
+    let mut raw0 = vec![0x09, b'A', 0x00];
+    raw0.write_all(&t.to_le_bytes()).unwrap();
+
+    let mut raw = vec![];
+    raw.write_all(&((raw0.len() + 4 + 1) as i32).to_le_bytes())
+        .unwrap();
+    raw.write_all(&raw0).unwrap();
+    raw.write_all(&[0]).unwrap();
+
+    let deserialized = Document::from_reader(&mut Cursor::new(raw)).unwrap();
+
+    let expected = doc! { "A": crate::DateTime::from_time_0_3(time::OffsetDateTime::from_unix_timestamp(1_530_492_218).unwrap() + time::Duration::nanoseconds(999 * 1_000_000))};
+    assert_eq!(deserialized, expected);
+}
+
+#[test]
+fn test_deserialize_invalid_utf8_string_issue64() {
+    let _guard = LOCK.run_concurrently();
+    let buffer = b"\x13\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x00foo\x00\x13\x05\x00\x00\x00";
+
+    assert!(Document::from_reader(&mut Cursor::new(buffer)).is_err());
+}
+
+#[test]
+fn test_deserialize_multiply_overflows_issue64() {
+    let _guard = LOCK.run_concurrently();
+    let buffer = b"*\xc9*\xc9\t\x00\x00\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\x01\t\x00\x00\x01\x10";
+
+    assert!(Document::from_reader(&mut Cursor::new(&buffer[..])).is_err());
+}
+
+#[test]
+fn test_serialize_deserialize_decimal128() {
+    let _guard = LOCK.run_concurrently();
+    let val = Bson::Decimal128(Decimal128 {
+        bytes: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 34],
+    });
+    let dst = vec![
+        26, 0, 0, 0, 19, 107, 101, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 34, 0,
+    ];
+
+    let doc = doc! { "key": val };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_illegal_size() {
+    let _guard = LOCK.run_concurrently();
+    let buffer = [
+        0x06, 0xcc, 0xf9, 0x0a, 0x05, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff,
+    ];
+    assert!(Document::from_reader(&mut Cursor::new(&buffer[..])).is_err());
+}
+
+#[test]
+fn test_serialize_deserialize_undefined() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::Undefined;
+    let dst = vec![10, 0, 0, 0, 6, 107, 101, 121, 0, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_min_key() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::MinKey;
+    let dst = vec![10, 0, 0, 0, 255, 107, 101, 121, 0, 0];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_max_key() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::MaxKey;
+    let dst = vec![10, 0, 0, 0, 127, 107, 101, 121, 0, 0];
+
+    let doc = doc! {"key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_db_pointer() {
+    let _guard = LOCK.run_concurrently();
+    let src = Bson::try_from(json!({
+        "$dbPointer": {
+            "$ref": "db.coll",
+            "$id": { "$oid": "507f1f77bcf86cd799439011" },
+        }
+    }))
+    .unwrap();
+    let dst = vec![
+        34, 0, 0, 0, 12, 107, 101, 121, 0, 8, 0, 0, 0, 100, 98, 46, 99, 111, 108, 108, 0, 80, 127,
+        31, 119, 188, 248, 108, 215, 153, 67, 144, 17, 0,
+    ];
+
+    let doc = doc! { "key": src };
+
+    let mut buf = Vec::new();
+    doc.to_writer(&mut buf).unwrap();
+
+    assert_eq!(buf, dst);
+
+    let deserialized = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    assert_eq!(deserialized, doc);
+}
+
+#[test]
+fn test_serialize_deserialize_document() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Point {
+        x: i32,
+        y: i32,
+    }
+    let src = Point { x: 1, y: 2 };
+
+    let doc = to_document(&src).unwrap();
+    assert_eq!(doc, doc! { "x": 1, "y": 2 });
+
+    let point: Point = from_document(doc).unwrap();
+    assert_eq!(src, point);
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Line {
+        p1: Point,
+        p2: Point,
+    }
+    let src = Line {
+        p1: Point { x: 0, y: 0 },
+        p2: Point { x: 1, y: 1 },
+    };
+
+    let doc = to_document(&src).unwrap();
+    assert_eq!(
+        doc,
+        doc! { "p1": { "x": 0, "y": 0 }, "p2": { "x": 1, "y": 1 } }
+    );
+
+    let line: Line = from_document(doc).unwrap();
+    assert_eq!(src, line);
+
+    let x = 1;
+    let err = to_document(&x).unwrap_err();
+    match err {
+        Error::SerializationError { message } => {
+            assert!(message.contains("Could not be serialized to Document"));
+        }
+        e => panic!("expected SerializationError, got {}", e),
+    }
+
+    let bad_point = doc! { "x": "one", "y": "two" };
+    let bad_point: Result<Point, crate::de::Error> = from_document(bad_point);
+    assert!(bad_point.is_err());
+}
+
+/// [RUST-713](https://jira.mongodb.org/browse/RUST-713)
+#[test]
+fn test_deserialize_invalid_array_length() {
+    let _guard = LOCK.run_concurrently();
+    let buffer = b"\n\x00\x00\x00\x04\x00\x00\x00\x00\x00";
+    Document::from_reader(&mut std::io::Cursor::new(buffer))
+        .expect_err("expected deserialization to fail");
+}
+
+/// [RUST-713](https://jira.mongodb.org/browse/RUST-713)
+#[test]
+fn test_deserialize_invalid_old_binary_length() {
+    let _guard = LOCK.run_concurrently();
+    let buffer = b"\x0F\x00\x00\x00\x05\x00\x00\x00\x00\x00\x02\xFC\xFF\xFF\xFF";
+    Document::from_reader(&mut std::io::Cursor::new(buffer))
+        .expect_err("expected deserialization to fail");
+
+    let buffer = b".\x00\x00\x00\x05\x01\x00\x00\x00\x00\x00\x02\xfc\xff\xff\xff\xff\xff\xff\xff\x00\x00*\x00h\x0e\x10++\x00h\x0e++\x00\x00\t\x00\x00\x00\x00\x00*\x0e\x10++";
+    Document::from_reader(&mut std::io::Cursor::new(buffer))
+        .expect_err("expected deserialization to fail");
+}
diff --git a/src/tests/serde.rs b/src/tests/serde.rs
new file mode 100644
index 0000000..29d3253
--- /dev/null
+++ b/src/tests/serde.rs
@@ -0,0 +1,1050 @@
+#![allow(clippy::disallowed_names)]
+
+use crate::{
+    bson,
+    doc,
+    from_bson,
+    from_document,
+    oid::ObjectId,
+    serde_helpers,
+    serde_helpers::{
+        bson_datetime_as_rfc3339_string,
+        hex_string_as_object_id,
+        i64_as_bson_datetime,
+        rfc3339_string_as_bson_datetime,
+        serialize_object_id_as_hex_string,
+        timestamp_as_u32,
+        u32_as_timestamp,
+    },
+    spec::BinarySubtype,
+    tests::LOCK,
+    to_bson,
+    to_document,
+    Binary,
+    Bson,
+    DateTime,
+    Deserializer,
+    Document,
+    Serializer,
+    Timestamp,
+};
+
+use serde::{Deserialize, Serialize};
+use serde_json::json;
+
+use std::{
+    collections::BTreeMap,
+    convert::{TryFrom, TryInto},
+};
+
+#[test]
+fn test_ser_vec() {
+    let _guard = LOCK.run_concurrently();
+    let vec = vec![1, 2, 3];
+
+    let serializer = Serializer::new();
+    let result = vec.serialize(serializer).unwrap();
+
+    let expected = bson!([1, 2, 3]);
+    assert_eq!(expected, result);
+}
+
+#[test]
+fn test_ser_map() {
+    let _guard = LOCK.run_concurrently();
+    let mut map = BTreeMap::new();
+    map.insert("x", 0);
+    map.insert("y", 1);
+
+    let serializer = Serializer::new();
+    let result = map.serialize(serializer).unwrap();
+
+    let expected = bson!({ "x": 0, "y": 1 });
+    assert_eq!(expected, result);
+}
+
+#[test]
+fn test_de_vec() {
+    let _guard = LOCK.run_concurrently();
+    let bson = bson!([1, 2, 3]);
+
+    let deserializer = Deserializer::new(bson);
+    let vec = Vec::<i32>::deserialize(deserializer).unwrap();
+
+    let expected = vec![1, 2, 3];
+    assert_eq!(expected, vec);
+}
+
+#[test]
+fn test_de_map() {
+    let _guard = LOCK.run_concurrently();
+    let bson = bson!({ "x": 0, "y": 1 });
+
+    let deserializer = Deserializer::new(bson);
+    let map = BTreeMap::<String, i32>::deserialize(deserializer).unwrap();
+
+    let mut expected = BTreeMap::new();
+    expected.insert("x".to_string(), 0);
+    expected.insert("y".to_string(), 1);
+    assert_eq!(expected, map);
+}
+
+#[test]
+fn test_ser_timestamp() {
+    let _guard = LOCK.run_concurrently();
+    use bson::Timestamp;
+
+    #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
+    struct Foo {
+        ts: Timestamp,
+    }
+
+    let foo = Foo {
+        ts: Timestamp {
+            time: 12,
+            increment: 10,
+        },
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! { "ts": Bson::Timestamp(Timestamp { time: 0x0000_000C, increment: 0x0000_000A }) }
+    );
+
+    let xfoo: Foo = from_bson(x).unwrap();
+    assert_eq!(xfoo, foo);
+}
+
+#[test]
+fn test_de_timestamp() {
+    let _guard = LOCK.run_concurrently();
+    use bson::Timestamp;
+
+    #[derive(Deserialize, Eq, PartialEq, Debug)]
+    struct Foo {
+        ts: Timestamp,
+    }
+
+    let foo: Foo = from_bson(Bson::Document(doc! {
+        "ts": Bson::Timestamp(Timestamp { time: 0x0000_000C, increment: 0x0000_000A }),
+    }))
+    .unwrap();
+
+    assert_eq!(
+        foo.ts,
+        Timestamp {
+            time: 12,
+            increment: 10
+        }
+    );
+}
+
+#[test]
+fn test_ser_regex() {
+    let _guard = LOCK.run_concurrently();
+    use bson::Regex;
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    struct Foo {
+        regex: Regex,
+    }
+
+    let regex = Regex {
+        pattern: "12".into(),
+        options: "01".into(),
+    };
+
+    let foo = Foo {
+        regex: regex.clone(),
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! { "regex": Bson::RegularExpression(regex) }
+    );
+
+    let xfoo: Foo = from_bson(x).unwrap();
+    assert_eq!(xfoo, foo);
+}
+
+#[test]
+fn test_de_regex() {
+    let _guard = LOCK.run_concurrently();
+    use bson::Regex;
+
+    #[derive(Deserialize, PartialEq, Debug)]
+    struct Foo {
+        regex: Regex,
+    }
+
+    let regex = Regex {
+        pattern: "12".into(),
+        options: "01".into(),
+    };
+
+    let foo: Foo = from_bson(Bson::Document(doc! {
+        "regex": Bson::RegularExpression(regex.clone()),
+    }))
+    .unwrap();
+
+    assert_eq!(foo.regex, regex);
+}
+
+#[test]
+fn test_ser_code_with_scope() {
+    let _guard = LOCK.run_concurrently();
+    use bson::JavaScriptCodeWithScope;
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    struct Foo {
+        code_with_scope: JavaScriptCodeWithScope,
+    }
+
+    let code_with_scope = JavaScriptCodeWithScope {
+        code: "x".into(),
+        scope: doc! { "x": 12 },
+    };
+
+    let foo = Foo {
+        code_with_scope: code_with_scope.clone(),
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! { "code_with_scope": Bson::JavaScriptCodeWithScope(code_with_scope) }
+    );
+
+    let xfoo: Foo = from_bson(x).unwrap();
+    assert_eq!(xfoo, foo);
+}
+
+#[test]
+fn test_de_code_with_scope() {
+    let _guard = LOCK.run_concurrently();
+    use bson::JavaScriptCodeWithScope;
+
+    #[derive(Deserialize, PartialEq, Debug)]
+    struct Foo {
+        code_with_scope: JavaScriptCodeWithScope,
+    }
+
+    let code_with_scope = JavaScriptCodeWithScope {
+        code: "x".into(),
+        scope: doc! { "x": 12 },
+    };
+
+    let foo: Foo = from_bson(Bson::Document(doc! {
+        "code_with_scope": Bson::JavaScriptCodeWithScope(code_with_scope.clone()),
+    }))
+    .unwrap();
+
+    assert_eq!(foo.code_with_scope, code_with_scope);
+}
+
+#[test]
+fn test_ser_datetime() {
+    let _guard = LOCK.run_concurrently();
+    use crate::DateTime;
+
+    #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
+    struct Foo {
+        date: DateTime,
+    }
+
+    let now = DateTime::now();
+
+    let foo = Foo { date: now };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! { "date": (Bson::DateTime(now)) }
+    );
+
+    let xfoo: Foo = from_bson(x).unwrap();
+    assert_eq!(xfoo, foo);
+}
+
+#[test]
+fn test_binary_generic_roundtrip() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    pub struct Foo {
+        data: Bson,
+    }
+
+    let x = Foo {
+        data: Bson::Binary(Binary {
+            subtype: BinarySubtype::Generic,
+            bytes: b"12345abcde".to_vec(),
+        }),
+    };
+
+    let b = to_bson(&x).unwrap();
+    assert_eq!(
+        b.as_document().unwrap(),
+        &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })}
+    );
+
+    let f = from_bson::<Foo>(b).unwrap();
+    assert_eq!(x, f);
+}
+
+#[test]
+fn test_binary_non_generic_roundtrip() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    pub struct Foo {
+        data: Bson,
+    }
+
+    let x = Foo {
+        data: Bson::Binary(Binary {
+            subtype: BinarySubtype::BinaryOld,
+            bytes: b"12345abcde".to_vec(),
+        }),
+    };
+
+    let b = to_bson(&x).unwrap();
+    assert_eq!(
+        b.as_document().unwrap(),
+        &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::BinaryOld, bytes: b"12345abcde".to_vec() })}
+    );
+
+    let f = from_bson::<Foo>(b).unwrap();
+    assert_eq!(x, f);
+}
+
+#[test]
+fn test_binary_helper_generic_roundtrip() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    pub struct Foo {
+        data: Binary,
+    }
+
+    let x = Foo {
+        data: Binary {
+            subtype: BinarySubtype::Generic,
+            bytes: b"12345abcde".to_vec(),
+        },
+    };
+
+    let b = to_bson(&x).unwrap();
+    assert_eq!(
+        b.as_document().unwrap(),
+        &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })}
+    );
+
+    let f = from_bson::<Foo>(b).unwrap();
+    assert_eq!(x, f);
+}
+
+#[test]
+fn test_binary_helper_non_generic_roundtrip() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Serialize, Deserialize, Debug, PartialEq)]
+    pub struct Foo {
+        data: Binary,
+    }
+
+    let x = Foo {
+        data: Binary {
+            subtype: BinarySubtype::BinaryOld,
+            bytes: b"12345abcde".to_vec(),
+        },
+    };
+
+    let b = to_bson(&x).unwrap();
+    assert_eq!(
+        b.as_document().unwrap(),
+        &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::BinaryOld, bytes: b"12345abcde".to_vec() })}
+    );
+
+    let f = from_bson::<Foo>(b).unwrap();
+    assert_eq!(x, f);
+}
+
+#[test]
+fn test_byte_vec() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Serialize, Debug, Eq, PartialEq)]
+    pub struct AuthChallenge<'a> {
+        #[serde(with = "serde_bytes")]
+        pub challenge: &'a [u8],
+    }
+
+    let x = AuthChallenge {
+        challenge: b"18762b98b7c34c25bf9dc3154e4a5ca3",
+    };
+
+    let b = to_bson(&x).unwrap();
+    assert_eq!(
+        b,
+        Bson::Document(
+            doc! { "challenge": (Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: x.challenge.to_vec() }))}
+        )
+    );
+
+    // let mut buf = Vec::new();
+    // b.as_document().unwrap().to_writer(&mut buf).unwrap();
+
+    // let xb = Document::from_reader(&mut Cursor::new(buf)).unwrap();
+    // assert_eq!(b.as_document().unwrap(), &xb);
+}
+
+#[test]
+fn test_serde_bytes() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+    pub struct Foo {
+        #[serde(with = "serde_bytes")]
+        data: Vec<u8>,
+    }
+
+    let x = Foo {
+        data: b"12345abcde".to_vec(),
+    };
+
+    let b = to_bson(&x).unwrap();
+    assert_eq!(
+        b.as_document().unwrap(),
+        &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })}
+    );
+
+    let f = from_bson::<Foo>(b).unwrap();
+    assert_eq!(x, f);
+}
+
+#[test]
+fn test_serde_newtype_struct() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+    struct Email(String);
+
+    let email_1 = Email(String::from("bson@serde.rs"));
+    let b = to_bson(&email_1).unwrap();
+    assert_eq!(b, Bson::String(email_1.0));
+
+    let s = String::from("root@localho.st");
+    let de = Bson::String(s.clone());
+    let email_2 = from_bson::<Email>(de).unwrap();
+    assert_eq!(email_2, Email(s));
+}
+
+#[test]
+fn test_serde_tuple_struct() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+    struct Name(String, String); // first, last
+
+    let name_1 = Name(String::from("Graydon"), String::from("Hoare"));
+    let b = to_bson(&name_1).unwrap();
+    assert_eq!(b, bson!([name_1.0.clone(), name_1.1]));
+
+    let (first, last) = (String::from("Donald"), String::from("Knuth"));
+    let de = bson!([first.clone(), last.clone()]);
+    let name_2 = from_bson::<Name>(de).unwrap();
+    assert_eq!(name_2, Name(first, last));
+}
+
+#[test]
+fn test_serde_newtype_variant() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Debug, PartialEq, Serialize, Deserialize)]
+    #[serde(tag = "type", content = "value")]
+    enum Number {
+        Int(i64),
+        Float(f64),
+    }
+
+    let n = 42;
+    let num_1 = Number::Int(n);
+    let b = to_bson(&num_1).unwrap();
+    assert_eq!(b, bson!({ "type": "Int", "value": n }));
+
+    let x = 1337.0;
+    let de = bson!({ "type": "Float", "value": x });
+    let num_2 = from_bson::<Number>(de).unwrap();
+    assert_eq!(num_2, Number::Float(x));
+}
+
+#[test]
+fn test_serde_tuple_variant() {
+    let _guard = LOCK.run_concurrently();
+    #[derive(Debug, PartialEq, Serialize, Deserialize)]
+    enum Point {
+        TwoDim(f64, f64),
+        ThreeDim(f64, f64, f64),
+    }
+
+    #[allow(clippy::approx_constant)]
+    let (x1, y1) = (3.14, -2.71);
+    let p1 = Point::TwoDim(x1, y1);
+    let b = to_bson(&p1).unwrap();
+    assert_eq!(b, bson!({ "TwoDim": [x1, y1] }));
+
+    let (x2, y2, z2) = (0.0, -13.37, 4.2);
+    let de = bson!({ "ThreeDim": [x2, y2, z2] });
+    let p2 = from_bson::<Point>(de).unwrap();
+    assert_eq!(p2, Point::ThreeDim(x2, y2, z2));
+}
+
+#[test]
+fn test_ser_db_pointer() {
+    let _guard = LOCK.run_concurrently();
+    use bson::DbPointer;
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    struct Foo {
+        db_pointer: DbPointer,
+    }
+
+    let db_pointer = Bson::try_from(json!({
+        "$dbPointer": {
+            "$ref": "db.coll",
+            "$id": { "$oid": "507f1f77bcf86cd799439011" },
+        }
+    }))
+    .unwrap();
+
+    let db_pointer = db_pointer.as_db_pointer().unwrap();
+
+    let foo = Foo {
+        db_pointer: db_pointer.clone(),
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! {"db_pointer": Bson::DbPointer(db_pointer.clone()) }
+    );
+
+    let xfoo: Foo = from_bson(x).unwrap();
+    assert_eq!(xfoo, foo);
+}
+
+#[test]
+fn test_de_db_pointer() {
+    let _guard = LOCK.run_concurrently();
+    use bson::DbPointer;
+
+    #[derive(Deserialize, PartialEq, Debug)]
+    struct Foo {
+        db_pointer: DbPointer,
+    }
+
+    let db_pointer = Bson::try_from(json!({
+        "$dbPointer": {
+            "$ref": "db.coll",
+            "$id": { "$oid": "507f1f77bcf86cd799439011" },
+        }
+    }))
+    .unwrap();
+    let db_pointer = db_pointer.as_db_pointer().unwrap();
+
+    let foo: Foo = from_bson(Bson::Document(
+        doc! {"db_pointer": Bson::DbPointer(db_pointer.clone())},
+    ))
+    .unwrap();
+
+    assert_eq!(foo.db_pointer, db_pointer.clone());
+}
+
+#[cfg(feature = "uuid-0_8")]
+#[test]
+fn test_serde_legacy_uuid_0_8() {
+    use uuid_0_8::Uuid;
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct Foo {
+        #[serde(with = "serde_helpers::uuid_as_java_legacy_binary")]
+        java_legacy: Uuid,
+        #[serde(with = "serde_helpers::uuid_as_python_legacy_binary")]
+        python_legacy: Uuid,
+        #[serde(with = "serde_helpers::uuid_as_c_sharp_legacy_binary")]
+        csharp_legacy: Uuid,
+    }
+    let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap();
+    let foo = Foo {
+        java_legacy: uuid,
+        python_legacy: uuid,
+        csharp_legacy: uuid,
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! {
+            "java_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("7766554433221100FFEEDDCCBBAA9988").unwrap(),
+            }),
+            "python_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("00112233445566778899AABBCCDDEEFF").unwrap(),
+            }),
+            "csharp_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("33221100554477668899AABBCCDDEEFF").unwrap(),
+            })
+        }
+    );
+
+    let foo: Foo = from_bson(x).unwrap();
+    assert_eq!(foo.java_legacy, uuid);
+    assert_eq!(foo.python_legacy, uuid);
+    assert_eq!(foo.csharp_legacy, uuid);
+}
+
+#[cfg(feature = "uuid-1")]
+#[test]
+fn test_serde_legacy_uuid_1() {
+    use uuid::Uuid;
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct Foo {
+        #[serde(with = "serde_helpers::uuid_1_as_java_legacy_binary")]
+        java_legacy: Uuid,
+        #[serde(with = "serde_helpers::uuid_1_as_python_legacy_binary")]
+        python_legacy: Uuid,
+        #[serde(with = "serde_helpers::uuid_1_as_c_sharp_legacy_binary")]
+        csharp_legacy: Uuid,
+    }
+    let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF").unwrap();
+    let foo = Foo {
+        java_legacy: uuid,
+        python_legacy: uuid,
+        csharp_legacy: uuid,
+    };
+
+    let x = to_bson(&foo).unwrap();
+    assert_eq!(
+        x.as_document().unwrap(),
+        &doc! {
+            "java_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("7766554433221100FFEEDDCCBBAA9988").unwrap(),
+            }),
+            "python_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("00112233445566778899AABBCCDDEEFF").unwrap(),
+            }),
+            "csharp_legacy": Bson::Binary(Binary{
+                subtype:BinarySubtype::UuidOld,
+                bytes: hex::decode("33221100554477668899AABBCCDDEEFF").unwrap(),
+            })
+        }
+    );
+
+    let foo: Foo = from_bson(x).unwrap();
+    assert_eq!(foo.java_legacy, uuid);
+    assert_eq!(foo.python_legacy, uuid);
+    assert_eq!(foo.csharp_legacy, uuid);
+}
+
+#[test]
+fn test_de_oid_string() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Debug, Deserialize)]
+    struct Foo {
+        pub oid: ObjectId,
+    }
+
+    let foo: Foo = serde_json::from_str("{ \"oid\": \"507f1f77bcf86cd799439011\" }").unwrap();
+    let oid = ObjectId::parse_str("507f1f77bcf86cd799439011").unwrap();
+    assert_eq!(foo.oid, oid);
+}
+
+#[test]
+fn test_serialize_deserialize_unsigned_numbers() {
+    let _guard = LOCK.run_concurrently();
+
+    let num = 1;
+    let json = format!("{{ \"num\": {} }}", num);
+    let doc: Document = serde_json::from_str(&json).unwrap();
+    assert_eq!(doc.get_i32("num").unwrap(), num);
+
+    let num = i32::MAX as u64 + 1;
+    let json = format!("{{ \"num\": {} }}", num);
+    let doc: Document = serde_json::from_str(&json).unwrap();
+    assert_eq!(doc.get_i64("num").unwrap(), num as i64);
+
+    let num = u64::MAX;
+    let json = format!("{{ \"num\": {} }}", num);
+    let doc_result: Result<Document, serde_json::Error> = serde_json::from_str(&json);
+    assert!(doc_result.is_err());
+}
+
+#[test]
+fn test_unsigned_helpers() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize)]
+    struct A {
+        #[serde(serialize_with = "serde_helpers::serialize_u32_as_i32")]
+        num_1: u32,
+        #[serde(serialize_with = "serde_helpers::serialize_u64_as_i32")]
+        num_2: u64,
+    }
+
+    let a = A { num_1: 1, num_2: 2 };
+    let doc = to_document(&a).unwrap();
+    assert!(doc.get_i32("num_1").unwrap() == 1);
+    assert!(doc.get_i32("num_2").unwrap() == 2);
+
+    let a = A {
+        num_1: u32::MAX,
+        num_2: 1,
+    };
+    let doc_result = to_document(&a);
+    assert!(doc_result.is_err());
+
+    let a = A {
+        num_1: 1,
+        num_2: u64::MAX,
+    };
+    let doc_result = to_document(&a);
+    assert!(doc_result.is_err());
+
+    #[derive(Serialize)]
+    struct B {
+        #[serde(serialize_with = "serde_helpers::serialize_u32_as_i64")]
+        num_1: u32,
+        #[serde(serialize_with = "serde_helpers::serialize_u64_as_i64")]
+        num_2: u64,
+    }
+
+    let b = B {
+        num_1: u32::MAX,
+        num_2: i64::MAX as u64,
+    };
+    let doc = to_document(&b).unwrap();
+    assert!(doc.get_i64("num_1").unwrap() == u32::MAX as i64);
+    assert!(doc.get_i64("num_2").unwrap() == i64::MAX);
+
+    let b = B {
+        num_1: 1,
+        num_2: i64::MAX as u64 + 1,
+    };
+    let doc_result = to_document(&b);
+    assert!(doc_result.is_err());
+
+    #[derive(Deserialize, Serialize, Debug, PartialEq)]
+    struct F {
+        #[serde(with = "serde_helpers::u32_as_f64")]
+        num_1: u32,
+        #[serde(with = "serde_helpers::u64_as_f64")]
+        num_2: u64,
+    }
+
+    let f = F {
+        num_1: 101,
+        num_2: 12345,
+    };
+    let doc = to_document(&f).unwrap();
+    assert!((doc.get_f64("num_1").unwrap() - 101.0).abs() < f64::EPSILON);
+    assert!((doc.get_f64("num_2").unwrap() - 12345.0).abs() < f64::EPSILON);
+
+    let back: F = from_document(doc).unwrap();
+    assert_eq!(back, f);
+
+    let f = F {
+        num_1: 1,
+        // f64 cannot represent many large integers exactly, u64::MAX included
+        num_2: u64::MAX,
+    };
+    let doc_result = to_document(&f);
+    assert!(doc_result.is_err());
+
+    let f = F {
+        num_1: 1,
+        num_2: u64::MAX - 255,
+    };
+    let doc_result = to_document(&f);
+    assert!(doc_result.is_err());
+}
+
+#[test]
+fn test_datetime_helpers() {
+    use time::{format_description::well_known::Rfc3339, OffsetDateTime};
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Deserialize, Serialize)]
+    struct A {
+        #[serde(with = "bson_datetime_as_rfc3339_string")]
+        pub date: DateTime,
+    }
+
+    let iso = "1996-12-20T00:39:57Z";
+    let date = OffsetDateTime::parse(iso, &Rfc3339).unwrap();
+    let a = A {
+        date: crate::DateTime::from_time_0_3(date),
+    };
+    let doc = to_document(&a).unwrap();
+    assert_eq!(doc.get_str("date").unwrap(), iso);
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.date.to_time_0_3(), date);
+
+    #[cfg(feature = "time-0_3")]
+    {
+        use time::macros::datetime;
+
+        #[derive(Deserialize, Serialize)]
+        struct B {
+            #[serde(with = "serde_helpers::time_0_3_offsetdatetime_as_bson_datetime")]
+            pub date: time::OffsetDateTime,
+        }
+
+        let date = r#"
+    {
+        "date": {
+                "$date": {
+                    "$numberLong": "1591700287095"
+                }
+        }
+    }"#;
+        let json: serde_json::Value = serde_json::from_str(date).unwrap();
+        let b: B = serde_json::from_value(json).unwrap();
+        let expected = datetime!(2020-06-09 10:58:07.095 UTC);
+        assert_eq!(b.date, expected);
+        let doc = to_document(&b).unwrap();
+        assert_eq!(doc.get_datetime("date").unwrap().to_time_0_3(), expected);
+        let b: B = from_document(doc).unwrap();
+        assert_eq!(b.date, expected);
+    }
+
+    #[cfg(feature = "chrono-0_4")]
+    {
+        use std::str::FromStr;
+        #[derive(Deserialize, Serialize)]
+        struct B {
+            #[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime")]
+            pub date: chrono::DateTime<chrono::Utc>,
+        }
+
+        let date = r#"
+    {
+        "date": {
+                "$date": {
+                    "$numberLong": "1591700287095"
+                }
+        }
+    }"#;
+        let json: serde_json::Value = serde_json::from_str(date).unwrap();
+        let b: B = serde_json::from_value(json).unwrap();
+        let expected: chrono::DateTime<chrono::Utc> =
+            chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap();
+        assert_eq!(b.date, expected);
+        let doc = to_document(&b).unwrap();
+        assert_eq!(doc.get_datetime("date").unwrap().to_chrono(), expected);
+        let b: B = from_document(doc).unwrap();
+        assert_eq!(b.date, expected);
+    }
+
+    #[derive(Deserialize, Serialize)]
+    struct C {
+        #[serde(with = "rfc3339_string_as_bson_datetime")]
+        pub date: String,
+    }
+
+    let date = "2020-06-09T10:58:07.095Z";
+    let c = C {
+        date: date.to_string(),
+    };
+    let doc = to_document(&c).unwrap();
+    assert!(doc.get_datetime("date").is_ok());
+    let c: C = from_document(doc).unwrap();
+    assert_eq!(c.date.as_str(), date);
+}
+
+#[test]
+fn test_oid_helpers() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct A {
+        #[serde(with = "hex_string_as_object_id")]
+        oid: String,
+    }
+
+    let oid = ObjectId::new();
+    let a = A {
+        oid: oid.to_string(),
+    };
+    let doc = to_document(&a).unwrap();
+    assert_eq!(doc.get_object_id("oid").unwrap(), oid);
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.oid, oid.to_string());
+}
+
+#[test]
+fn test_i64_as_bson_datetime() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct A {
+        #[serde(with = "i64_as_bson_datetime")]
+        now: i64,
+    }
+
+    let now = DateTime::now();
+    let a = A {
+        now: now.timestamp_millis(),
+    };
+    let doc = to_document(&a).unwrap();
+    assert_eq!(doc.get_datetime("now").unwrap(), &now);
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.now, now.timestamp_millis());
+}
+
+#[test]
+#[cfg(feature = "uuid-0_8")]
+fn test_uuid_0_8_helpers() {
+    use serde_helpers::uuid_as_binary;
+    use uuid_0_8::Uuid;
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct A {
+        #[serde(with = "uuid_as_binary")]
+        uuid: Uuid,
+    }
+
+    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
+    let a = A { uuid };
+    let doc = to_document(&a).unwrap();
+    match doc.get("uuid").unwrap() {
+        Bson::Binary(bin) => {
+            assert_eq!(bin.subtype, BinarySubtype::Uuid);
+            assert_eq!(bin.bytes, uuid.as_bytes());
+        }
+        _ => panic!("expected Bson::Binary"),
+    }
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.uuid, uuid);
+}
+
+#[test]
+#[cfg(feature = "uuid-1")]
+fn test_uuid_1_helpers() {
+    use serde_helpers::uuid_1_as_binary;
+    use uuid::Uuid;
+
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize, Deserialize)]
+    struct A {
+        #[serde(with = "uuid_1_as_binary")]
+        uuid: Uuid,
+    }
+
+    let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap();
+    let a = A { uuid };
+    let doc = to_document(&a).unwrap();
+    match doc.get("uuid").unwrap() {
+        Bson::Binary(bin) => {
+            assert_eq!(bin.subtype, BinarySubtype::Uuid);
+            assert_eq!(bin.bytes, uuid.as_bytes());
+        }
+        _ => panic!("expected Bson::Binary"),
+    }
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.uuid, uuid);
+}
+
+#[test]
+fn test_timestamp_helpers() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Deserialize, Serialize)]
+    struct A {
+        #[serde(with = "u32_as_timestamp")]
+        pub time: u32,
+    }
+
+    let time = 12345;
+    let a = A { time };
+    let doc = to_document(&a).unwrap();
+    let timestamp = doc.get_timestamp("time").unwrap();
+    assert_eq!(timestamp.time, time);
+    assert_eq!(timestamp.increment, 0);
+    let a: A = from_document(doc).unwrap();
+    assert_eq!(a.time, time);
+
+    #[derive(Deserialize, Serialize)]
+    struct B {
+        #[serde(with = "timestamp_as_u32")]
+        pub timestamp: Timestamp,
+    }
+
+    let time = 12345;
+    let timestamp = Timestamp { time, increment: 0 };
+    let b = B { timestamp };
+    let val = serde_json::to_value(b).unwrap();
+    assert_eq!(val["timestamp"], time);
+    let b: B = serde_json::from_value(val).unwrap();
+    assert_eq!(b.timestamp, timestamp);
+
+    let timestamp = Timestamp {
+        time: 12334,
+        increment: 1,
+    };
+    let b = B { timestamp };
+    assert!(serde_json::to_value(b).is_err());
+}
+
+#[test]
+fn large_dates() {
+    let _guard = LOCK.run_concurrently();
+
+    let json = json!({ "d": { "$date": { "$numberLong": i64::MAX.to_string() } } });
+    let d = serde_json::from_value::<Document>(json.clone()).unwrap();
+    assert_eq!(d.get_datetime("d").unwrap(), &DateTime::MAX);
+    let d: Bson = json.try_into().unwrap();
+    assert_eq!(
+        d.as_document().unwrap().get_datetime("d").unwrap(),
+        &DateTime::MAX
+    );
+
+    let json = json!({ "d": { "$date": { "$numberLong": i64::MIN.to_string() } } });
+    let d = serde_json::from_value::<Document>(json.clone()).unwrap();
+    assert_eq!(d.get_datetime("d").unwrap(), &DateTime::MIN);
+    let d: Bson = json.try_into().unwrap();
+    assert_eq!(
+        d.as_document().unwrap().get_datetime("d").unwrap(),
+        &DateTime::MIN
+    );
+}
+
+#[test]
+fn oid_as_hex_string() {
+    let _guard = LOCK.run_concurrently();
+
+    #[derive(Serialize)]
+    struct Foo {
+        #[serde(serialize_with = "serialize_object_id_as_hex_string")]
+        oid: ObjectId,
+    }
+
+    let oid = ObjectId::new();
+    let foo = Foo { oid };
+    let doc = to_document(&foo).unwrap();
+    assert_eq!(doc.get_str("oid").unwrap(), oid.to_hex());
+}
+
+#[test]
+fn fuzz_regression_00() {
+    let buf: &[u8] = &[227, 0, 35, 4, 2, 0, 255, 255, 255, 127, 255, 255, 255, 47];
+    let _ = crate::from_slice::<Document>(buf);
+}
diff --git a/src/tests/spec/corpus.rs b/src/tests/spec/corpus.rs
new file mode 100644
index 0000000..88d872c
--- /dev/null
+++ b/src/tests/spec/corpus.rs
@@ -0,0 +1,573 @@
+use std::{
+    convert::{TryFrom, TryInto},
+    iter::FromIterator,
+    marker::PhantomData,
+    str::FromStr,
+};
+
+use crate::{
+    raw::{RawBsonRef, RawDocument},
+    tests::LOCK,
+    Bson,
+    Document,
+    RawBson,
+    RawDocumentBuf,
+};
+use pretty_assertions::assert_eq;
+use serde::{Deserialize, Deserializer};
+
+use super::run_spec_test;
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct TestFile {
+    description: String,
+    bson_type: String,
+    test_key: Option<String>,
+
+    #[serde(default)]
+    valid: Vec<Valid>,
+
+    #[serde(rename = "decodeErrors")]
+    #[serde(default)]
+    decode_errors: Vec<DecodeError>,
+
+    #[serde(rename = "parseErrors")]
+    #[serde(default)]
+    parse_errors: Vec<ParseError>,
+
+    #[allow(dead_code)]
+    deprecated: Option<bool>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct Valid {
+    description: String,
+    canonical_bson: String,
+    canonical_extjson: String,
+    relaxed_extjson: Option<String>,
+    degenerate_bson: Option<String>,
+    degenerate_extjson: Option<String>,
+    #[allow(dead_code)]
+    converted_bson: Option<String>,
+    #[allow(dead_code)]
+    converted_extjson: Option<String>,
+    lossy: Option<bool>,
+}
+
+#[derive(Debug, Deserialize)]
+struct DecodeError {
+    description: String,
+    bson: String,
+}
+
+#[derive(Debug, Deserialize)]
+struct ParseError {
+    description: String,
+    string: String,
+}
+
+struct FieldVisitor<'a, T>(&'a str, PhantomData<T>);
+
+impl<'de, 'a, T> serde::de::Visitor<'de> for FieldVisitor<'a, T>
+where
+    T: Deserialize<'de>,
+{
+    type Value = T;
+
+    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(formatter, "expecting RawBson at field {}", self.0)
+    }
+
+    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+    where
+        A: serde::de::MapAccess<'de>,
+    {
+        while let Some((k, v)) = map.next_entry::<String, T>()? {
+            if k.as_str() == self.0 {
+                return Ok(v);
+            }
+        }
+        Err(serde::de::Error::custom(format!(
+            "missing field: {}",
+            self.0
+        )))
+    }
+}
+
+fn run_test(test: TestFile) {
+    let _guard = LOCK.run_concurrently();
+    for valid in test.valid {
+        let description = format!("{}: {}", test.description, valid.description);
+
+        let canonical_bson = hex::decode(&valid.canonical_bson).expect(&description);
+
+        // these four cover the four ways to create a [`Document`] from the provided BSON.
+        let documentfromreader_cb =
+            Document::from_reader(canonical_bson.as_slice()).expect(&description);
+
+        let fromreader_cb: Document =
+            crate::from_reader(canonical_bson.as_slice()).expect(&description);
+
+        let fromdocument_documentfromreader_cb: Document =
+            crate::from_document(documentfromreader_cb.clone()).expect(&description);
+
+        let todocument_documentfromreader_cb: Document =
+            crate::to_document(&documentfromreader_cb).expect(&description);
+
+        let canonical_raw_document =
+            RawDocument::from_bytes(canonical_bson.as_slice()).expect(&description);
+        let document_from_raw_document: Document =
+            canonical_raw_document.try_into().expect(&description);
+
+        let canonical_raw_bson_from_slice =
+            crate::from_slice::<RawBsonRef>(canonical_bson.as_slice())
+                .expect(&description)
+                .as_document()
+                .expect(&description);
+
+        let canonical_owned_raw_bson_from_slice =
+            crate::from_slice::<RawBson>(canonical_bson.as_slice()).expect(&description);
+
+        let canonical_raw_document_from_slice =
+            crate::from_slice::<&RawDocument>(canonical_bson.as_slice()).expect(&description);
+
+        // These cover the ways to serialize those [`Documents`] back to BSON.
+        let mut documenttowriter_documentfromreader_cb = Vec::new();
+        documentfromreader_cb
+            .to_writer(&mut documenttowriter_documentfromreader_cb)
+            .expect(&description);
+
+        let mut documenttowriter_fromreader_cb = Vec::new();
+        fromreader_cb
+            .to_writer(&mut documenttowriter_fromreader_cb)
+            .expect(&description);
+
+        let mut documenttowriter_fromdocument_documentfromreader_cb = Vec::new();
+        fromdocument_documentfromreader_cb
+            .to_writer(&mut documenttowriter_fromdocument_documentfromreader_cb)
+            .expect(&description);
+
+        let mut documenttowriter_todocument_documentfromreader_cb = Vec::new();
+        todocument_documentfromreader_cb
+            .to_writer(&mut documenttowriter_todocument_documentfromreader_cb)
+            .expect(&description);
+
+        let tovec_documentfromreader_cb =
+            crate::to_vec(&documentfromreader_cb).expect(&description);
+
+        let mut documenttowriter_document_from_raw_document = Vec::new();
+        document_from_raw_document
+            .to_writer(&mut documenttowriter_document_from_raw_document)
+            .expect(&description);
+
+        // Serialize the raw versions "back" to BSON also.
+        let tovec_rawdocument = crate::to_vec(&canonical_raw_document).expect(&description);
+        let tovec_rawdocument_from_slice =
+            crate::to_vec(&canonical_raw_document_from_slice).expect(&description);
+        let tovec_rawbson = crate::to_vec(&canonical_raw_bson_from_slice).expect(&description);
+        let tovec_ownedrawbson =
+            crate::to_vec(&canonical_owned_raw_bson_from_slice).expect(&description);
+
+        // test Bson / RawBson field deserialization
+        if let Some(ref test_key) = test.test_key {
+            // skip regex tests that don't have the value at the test key
+            if !description.contains("$regex query operator") {
+                // deserialize the field from raw Bytes into a RawBson
+                let mut deserializer_raw =
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false);
+                let raw_bson_field = deserializer_raw
+                    .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBsonRef>))
+                    .expect(&description);
+                // convert to an owned Bson and put into a Document
+                let bson: Bson = raw_bson_field.try_into().expect(&description);
+                let from_raw_doc = doc! {
+                    test_key: bson
+                };
+
+                // deserialize the field from raw Bytes into an OwnedRawBson
+                let mut deserializer_raw =
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false);
+                let owned_raw_bson_field = deserializer_raw
+                    .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
+                    .expect(&description);
+                let from_slice_owned_vec =
+                    RawDocumentBuf::from_iter([(test_key, owned_raw_bson_field)]).into_bytes();
+
+                // deserialize the field from raw Bytes into a Bson
+                let mut deserializer_value =
+                    crate::de::RawDeserializer::new(canonical_bson.as_slice(), false);
+                let bson_field = deserializer_value
+                    .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<Bson>))
+                    .expect(&description);
+                // put into a Document
+                let from_slice_value_doc = doc! {
+                    test_key: bson_field,
+                };
+
+                // deserialize the field from a Bson into a Bson
+                let deserializer_value_value =
+                    crate::Deserializer::new(Bson::Document(documentfromreader_cb.clone()));
+                let bson_field = deserializer_value_value
+                    .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<Bson>))
+                    .expect(&description);
+                // put into a Document
+                let from_value_value_doc = doc! {
+                    test_key: bson_field,
+                };
+
+                // deserialize the field from a Bson into a RawBson
+                let deserializer_value_raw =
+                    crate::Deserializer::new(Bson::Document(documentfromreader_cb.clone()));
+                let raw_bson_field = deserializer_value_raw
+                    .deserialize_any(FieldVisitor(test_key.as_str(), PhantomData::<RawBson>))
+                    .expect(&description);
+                let from_value_raw_doc = doc! {
+                    test_key: Bson::try_from(raw_bson_field).expect(&description),
+                };
+
+                // convert back into raw BSON for comparison with canonical BSON
+                let from_raw_vec = crate::to_vec(&from_raw_doc).expect(&description);
+                let from_slice_value_vec =
+                    crate::to_vec(&from_slice_value_doc).expect(&description);
+                let from_bson_value_vec = crate::to_vec(&from_value_value_doc).expect(&description);
+                let from_value_raw_vec = crate::to_vec(&from_value_raw_doc).expect(&description);
+
+                assert_eq!(from_raw_vec, canonical_bson, "{}", description);
+                assert_eq!(from_slice_value_vec, canonical_bson, "{}", description);
+                assert_eq!(from_bson_value_vec, canonical_bson, "{}", description);
+                assert_eq!(from_slice_owned_vec, canonical_bson, "{}", description);
+                assert_eq!(from_value_raw_vec, canonical_bson, "{}", description);
+            }
+        }
+
+        // native_to_bson( bson_to_native(cB) ) = cB
+
+        // now we ensure the hex for all 5 are equivalent to the canonical BSON provided by the
+        // test.
+        assert_eq!(
+            hex::encode(documenttowriter_documentfromreader_cb).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        assert_eq!(
+            hex::encode(documenttowriter_fromreader_cb).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        assert_eq!(
+            hex::encode(documenttowriter_fromdocument_documentfromreader_cb).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        assert_eq!(
+            hex::encode(documenttowriter_todocument_documentfromreader_cb).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        assert_eq!(
+            hex::encode(tovec_documentfromreader_cb).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        assert_eq!(
+            hex::encode(documenttowriter_document_from_raw_document).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        assert_eq!(tovec_rawdocument, tovec_rawbson, "{}", description);
+        assert_eq!(
+            tovec_rawdocument, tovec_rawdocument_from_slice,
+            "{}",
+            description
+        );
+        assert_eq!(tovec_rawdocument, tovec_ownedrawbson, "{}", description);
+
+        assert_eq!(
+            hex::encode(tovec_rawdocument).to_lowercase(),
+            valid.canonical_bson.to_lowercase(),
+            "{}",
+            description,
+        );
+
+        // NaN == NaN is false, so we skip document comparisons that contain NaN
+        if !description.to_ascii_lowercase().contains("nan") && !description.contains("decq541") {
+            assert_eq!(documentfromreader_cb, fromreader_cb, "{}", description);
+
+            assert_eq!(
+                documentfromreader_cb, fromdocument_documentfromreader_cb,
+                "{}",
+                description
+            );
+
+            assert_eq!(
+                documentfromreader_cb, todocument_documentfromreader_cb,
+                "{}",
+                description
+            );
+
+            assert_eq!(
+                document_from_raw_document, documentfromreader_cb,
+                "{}",
+                description
+            );
+        }
+
+        // native_to_bson( bson_to_native(dB) ) = cB
+
+        if let Some(db) = valid.degenerate_bson {
+            let db = hex::decode(&db).expect(&description);
+
+            let bson_to_native_db = Document::from_reader(db.as_slice()).expect(&description);
+            let mut native_to_bson_bson_to_native_db = Vec::new();
+            bson_to_native_db
+                .to_writer(&mut native_to_bson_bson_to_native_db)
+                .unwrap();
+            assert_eq!(
+                hex::encode(native_to_bson_bson_to_native_db).to_lowercase(),
+                valid.canonical_bson.to_lowercase(),
+                "{}",
+                description,
+            );
+
+            let bson_to_native_db_serde: Document =
+                crate::from_reader(db.as_slice()).expect(&description);
+            let mut native_to_bson_bson_to_native_db_serde = Vec::new();
+            bson_to_native_db_serde
+                .to_writer(&mut native_to_bson_bson_to_native_db_serde)
+                .unwrap();
+            assert_eq!(
+                hex::encode(native_to_bson_bson_to_native_db_serde).to_lowercase(),
+                valid.canonical_bson.to_lowercase(),
+                "{}",
+                description,
+            );
+
+            let document_from_raw_document: Document = RawDocument::from_bytes(db.as_slice())
+                .expect(&description)
+                .try_into()
+                .expect(&description);
+            let mut documenttowriter_document_from_raw_document = Vec::new();
+            document_from_raw_document
+                .to_writer(&mut documenttowriter_document_from_raw_document)
+                .expect(&description);
+            assert_eq!(
+                hex::encode(documenttowriter_document_from_raw_document).to_lowercase(),
+                valid.canonical_bson.to_lowercase(),
+                "{}",
+                description,
+            );
+
+            // NaN == NaN is false, so we skip document comparisons that contain NaN
+            if !description.contains("NaN") {
+                assert_eq!(
+                    bson_to_native_db_serde, documentfromreader_cb,
+                    "{}",
+                    description
+                );
+
+                assert_eq!(
+                    document_from_raw_document, documentfromreader_cb,
+                    "{}",
+                    description
+                );
+            }
+        }
+
+        let cej: serde_json::Value =
+            serde_json::from_str(&valid.canonical_extjson).expect(&description);
+
+        // native_to_canonical_extended_json( bson_to_native(cB) ) = cEJ
+
+        let mut cej_updated_float = cej.clone();
+
+        // Rust doesn't format f64 with exponential notation by default, and the spec doesn't give
+        // guidance on when to use it, so we manually parse any $numberDouble fields with
+        // exponential notation and replace them with non-exponential notation.
+        if let Some(ref key) = test.test_key {
+            if let Some(serde_json::Value::Object(subdoc)) = cej_updated_float.get_mut(key) {
+                if let Some(&mut serde_json::Value::String(ref mut s)) =
+                    subdoc.get_mut("$numberDouble")
+                {
+                    if s.to_lowercase().contains('e') {
+                        let d = f64::from_str(s).unwrap();
+                        let mut fixed_string = format!("{}", d);
+
+                        if d.fract() == 0.0 {
+                            fixed_string.push_str(".0");
+                        }
+
+                        *s = fixed_string;
+                    }
+                }
+            }
+        }
+
+        assert_eq!(
+            Bson::Document(documentfromreader_cb.clone()).into_canonical_extjson(),
+            cej_updated_float,
+            "{}",
+            description
+        );
+
+        // native_to_relaxed_extended_json( bson_to_native(cB) ) = cEJ
+
+        if let Some(ref relaxed_extjson) = valid.relaxed_extjson {
+            let rej: serde_json::Value = serde_json::from_str(relaxed_extjson).expect(&description);
+
+            assert_eq!(
+                Bson::Document(documentfromreader_cb.clone()).into_relaxed_extjson(),
+                rej,
+                "{}",
+                description
+            );
+        }
+
+        // native_to_canonical_extended_json( json_to_native(cEJ) ) = cEJ
+
+        let json_to_native_cej: Bson = cej.clone().try_into().expect("cej into bson should work");
+
+        let native_to_canonical_extended_json_bson_to_native_cej =
+            json_to_native_cej.clone().into_canonical_extjson();
+
+        assert_eq!(
+            native_to_canonical_extended_json_bson_to_native_cej, cej_updated_float,
+            "{}",
+            description,
+        );
+
+        // native_to_bson( json_to_native(cEJ) ) = cB (unless lossy)
+
+        if valid.lossy != Some(true) {
+            let mut native_to_bson_json_to_native_cej = Vec::new();
+            json_to_native_cej
+                .as_document()
+                .unwrap()
+                .to_writer(&mut native_to_bson_json_to_native_cej)
+                .unwrap();
+
+            assert_eq!(
+                hex::encode(native_to_bson_json_to_native_cej).to_lowercase(),
+                valid.canonical_bson.to_lowercase(),
+                "{}",
+                description,
+            );
+        }
+
+        if let Some(ref degenerate_extjson) = valid.degenerate_extjson {
+            let dej: serde_json::Value =
+                serde_json::from_str(degenerate_extjson).expect(&description);
+
+            let json_to_native_dej: Bson = dej.clone().try_into().unwrap();
+
+            // native_to_canonical_extended_json( json_to_native(dEJ) ) = cEJ
+
+            let native_to_canonical_extended_json_json_to_native_dej =
+                json_to_native_dej.clone().into_canonical_extjson();
+
+            assert_eq!(
+                native_to_canonical_extended_json_json_to_native_dej, cej,
+                "{}",
+                description,
+            );
+
+            // native_to_bson( json_to_native(dEJ) ) = cB (unless lossy)
+
+            if valid.lossy != Some(true) {
+                let mut native_to_bson_json_to_native_dej = Vec::new();
+                json_to_native_dej
+                    .as_document()
+                    .unwrap()
+                    .to_writer(&mut native_to_bson_json_to_native_dej)
+                    .unwrap();
+
+                assert_eq!(
+                    hex::encode(native_to_bson_json_to_native_dej).to_lowercase(),
+                    valid.canonical_bson.to_lowercase(),
+                    "{}",
+                    description,
+                );
+            }
+        }
+
+        // native_to_relaxed_extended_json( json_to_native(rEJ) ) = rEJ
+
+        if let Some(ref rej) = valid.relaxed_extjson {
+            let rej: serde_json::Value = serde_json::from_str(rej).unwrap();
+
+            let json_to_native_rej: Bson = rej.clone().try_into().unwrap();
+
+            let native_to_relaxed_extended_json_bson_to_native_rej =
+                json_to_native_rej.clone().into_relaxed_extjson();
+
+            assert_eq!(
+                native_to_relaxed_extended_json_bson_to_native_rej, rej,
+                "{}",
+                description,
+            );
+        }
+    }
+
+    for decode_error in test.decode_errors.iter() {
+        let description = format!(
+            "{} decode error: {}",
+            test.bson_type, decode_error.description
+        );
+        let bson = hex::decode(&decode_error.bson).expect("should decode from hex");
+
+        if let Ok(doc) = RawDocument::from_bytes(bson.as_slice()) {
+            Document::try_from(doc).expect_err(description.as_str());
+        }
+
+        // No meaningful definition of "byte count" for an arbitrary reader.
+        if decode_error.description
+            == "Stated length less than byte count, with garbage after envelope"
+        {
+            continue;
+        }
+
+        Document::from_reader(bson.as_slice()).expect_err(&description);
+        crate::from_reader::<_, Document>(bson.as_slice()).expect_err(description.as_str());
+
+        if decode_error.description.contains("invalid UTF-8") {
+            crate::from_reader_utf8_lossy::<_, Document>(bson.as_slice()).unwrap_or_else(|err| {
+                panic!(
+                    "{}: utf8_lossy should not fail (failed with {:?})",
+                    description, err
+                )
+            });
+        }
+    }
+
+    for parse_error in test.parse_errors {
+        // no special support for dbref convention
+        if parse_error.description.contains("DBRef") {
+            continue;
+        }
+
+        let json: serde_json::Value = serde_json::Value::String(parse_error.string);
+
+        if let Ok(bson) = Bson::try_from(json.clone()) {
+            // if converting to bson succeeds, assert that translating that bson to bytes fails
+            assert!(crate::to_vec(&bson).is_err());
+        }
+    }
+}
+
+#[test]
+fn run() {
+    run_spec_test(&["bson-corpus"], run_test);
+}
diff --git a/src/tests/spec/json/bson-corpus/array.json b/src/tests/spec/json/bson-corpus/array.json
new file mode 100644
index 0000000..9ff953e
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/array.json
@@ -0,0 +1,49 @@
+{
+    "description": "Array",
+    "bson_type": "0x04",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Empty",
+            "canonical_bson": "0D000000046100050000000000",
+            "canonical_extjson": "{\"a\" : []}"
+        },
+        {
+            "description": "Single Element Array",
+            "canonical_bson": "140000000461000C0000001030000A0000000000",
+            "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}]}"
+        },
+        {
+            "description": "Single Element Array with index set incorrectly to empty string",
+            "degenerate_bson": "130000000461000B00000010000A0000000000",
+            "canonical_bson": "140000000461000C0000001030000A0000000000",
+            "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}]}"
+        },
+        {
+            "description": "Single Element Array with index set incorrectly to ab",
+            "degenerate_bson": "150000000461000D000000106162000A0000000000",
+            "canonical_bson": "140000000461000C0000001030000A0000000000",
+            "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}]}"
+        },
+        {
+            "description": "Multi Element Array with duplicate indexes",
+            "degenerate_bson": "1b000000046100130000001030000a000000103000140000000000",
+            "canonical_bson": "1b000000046100130000001030000a000000103100140000000000",
+            "canonical_extjson": "{\"a\" : [{\"$numberInt\": \"10\"}, {\"$numberInt\": \"20\"}]}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Array length too long: eats outer terminator",
+            "bson": "140000000461000D0000001030000A0000000000"
+        },
+        {
+            "description": "Array length too short: leaks terminator",
+            "bson": "140000000461000B0000001030000A0000000000"
+        },
+        {
+            "description": "Invalid Array: bad string length in field",
+            "bson": "1A00000004666F6F00100000000230000500000062617A000000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/binary.json b/src/tests/spec/json/bson-corpus/binary.json
new file mode 100644
index 0000000..20aaef7
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/binary.json
@@ -0,0 +1,123 @@
+{
+    "description": "Binary type",
+    "bson_type": "0x05",
+    "test_key": "x",
+    "valid": [
+        {
+            "description": "subtype 0x00 (Zero-length)",
+            "canonical_bson": "0D000000057800000000000000",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"\", \"subType\" : \"00\"}}}"
+        },
+        {
+            "description": "subtype 0x00 (Zero-length, keys reversed)",
+            "canonical_bson": "0D000000057800000000000000",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"\", \"subType\" : \"00\"}}}",
+            "degenerate_extjson": "{\"x\" : { \"$binary\" : {\"subType\" : \"00\", \"base64\" : \"\"}}}"
+        },
+        {
+            "description": "subtype 0x00",
+            "canonical_bson": "0F0000000578000200000000FFFF00",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"00\"}}}"
+        },
+        {
+            "description": "subtype 0x01",
+            "canonical_bson": "0F0000000578000200000001FFFF00",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"01\"}}}"
+        },
+        {
+            "description": "subtype 0x02",
+            "canonical_bson": "13000000057800060000000202000000FFFF00",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"02\"}}}"
+        },
+        {
+            "description": "subtype 0x03",
+            "canonical_bson": "1D000000057800100000000373FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"03\"}}}"
+        },
+        {
+            "description": "subtype 0x04",
+            "canonical_bson": "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"04\"}}}"
+        },
+        {
+            "description": "subtype 0x04 UUID",
+            "canonical_bson": "1D000000057800100000000473FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"04\"}}}",
+            "degenerate_extjson": "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}"
+        },
+        {
+            "description": "subtype 0x05",
+            "canonical_bson": "1D000000057800100000000573FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"05\"}}}"
+        },
+        {
+            "description": "subtype 0x07",
+            "canonical_bson": "1D000000057800100000000773FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"07\"}}}"
+        },
+        {
+            "description": "subtype 0x08",
+            "canonical_bson": "1D000000057800100000000873FFD26444B34C6990E8E7D1DFC035D400",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"c//SZESzTGmQ6OfR38A11A==\", \"subType\" : \"08\"}}}"
+        },
+        {
+            "description": "subtype 0x80",
+            "canonical_bson": "0F0000000578000200000080FFFF00",
+            "canonical_extjson": "{\"x\" : { \"$binary\" : {\"base64\" : \"//8=\", \"subType\" : \"80\"}}}"
+        },
+        {
+            "description": "$type query operator (conflicts with legacy $binary form with $type field)",
+            "canonical_bson": "1F000000037800170000000224747970650007000000737472696E67000000",
+            "canonical_extjson": "{\"x\" : { \"$type\" : \"string\"}}"
+        },
+        {
+            "description": "$type query operator (conflicts with legacy $binary form with $type field)",
+            "canonical_bson": "180000000378001000000010247479706500020000000000",
+            "canonical_extjson": "{\"x\" : { \"$type\" : {\"$numberInt\": \"2\"}}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Length longer than document",
+            "bson": "1D000000057800FF0000000573FFD26444B34C6990E8E7D1DFC035D400"
+        },
+        {
+            "description": "Negative length",
+            "bson": "0D000000057800FFFFFFFF0000"
+        },
+        {
+            "description": "subtype 0x02 length too long ",
+            "bson": "13000000057800060000000203000000FFFF00"
+        },
+        {
+            "description": "subtype 0x02 length too short",
+            "bson": "13000000057800060000000201000000FFFF00"
+        },
+        {
+            "description": "subtype 0x02 length negative one",
+            "bson": "130000000578000600000002FFFFFFFFFFFF00"
+        }
+    ],
+    "parseErrors": [
+        {
+            "description": "$uuid wrong type",
+            "string": "{\"x\" : { \"$uuid\" : { \"data\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4\"}}}"
+        },
+        {
+            "description": "$uuid invalid value--too short",
+            "string": "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-90e8-e7d1dfc035d4\"}}"
+        },
+        {
+            "description": "$uuid invalid value--too long",
+            "string": "{\"x\" : { \"$uuid\" : \"73ffd264-44b3-4c69-90e8-e7d1dfc035d4-789e4\"}}"
+        },
+        {
+            "description": "$uuid invalid value--misplaced hyphens",
+            "string": "{\"x\" : { \"$uuid\" : \"73ff-d26444b-34c6-990e8e-7d1dfc035d4\"}}"
+        },
+        {
+            "description": "$uuid invalid value--too many hyphens",
+            "string": "{\"x\" : { \"$uuid\" : \"----d264-44b3-4--9-90e8-e7d1dfc0----\"}}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/boolean.json b/src/tests/spec/json/bson-corpus/boolean.json
new file mode 100644
index 0000000..84c2822
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/boolean.json
@@ -0,0 +1,27 @@
+{
+    "description": "Boolean",
+    "bson_type": "0x08",
+    "test_key": "b",
+    "valid": [
+        {
+            "description": "True",
+            "canonical_bson": "090000000862000100",
+            "canonical_extjson": "{\"b\" : true}"
+        },
+        {
+            "description": "False",
+            "canonical_bson": "090000000862000000",
+            "canonical_extjson": "{\"b\" : false}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Invalid boolean value of 2",
+            "bson": "090000000862000200"
+        },
+        {
+            "description": "Invalid boolean value of -1",
+            "bson": "09000000086200FF00"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/bsonview b/src/tests/spec/json/bson-corpus/bsonview
new file mode 100755
index 0000000..b803fc8
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/bsonview
@@ -0,0 +1,434 @@
+#!/usr/bin/env perl
+use v5.10;
+use strict;
+use warnings;
+use utf8;
+use open qw/:std :utf8/;
+
+use Getopt::Long;
+use Pod::Usage;
+
+use if $^O eq 'MSWin32', 'Win32::Console::ANSI';
+use Term::ANSIColor;
+
+use constant {
+    NULL              => "\x00",
+    BSON_TYPE         => "C",
+    BSON_ENAME        => "Z*",
+    BSON_TYPE_NAME    => "CZ*",
+    BSON_DOUBLE       => "d",
+    BSON_STRING       => "l/A",
+    BSON_BOOLEAN      => "C",
+    BSON_REGEX        => "Z*Z*",
+    BSON_JSCODE       => "",
+    BSON_INT32        => "l",
+    BSON_INT64        => "q",
+    BSON_TIMESTAMP    => "q",
+    BSON_CODE_W_SCOPE => "l",
+    BSON_REMAINING    => 'a*',
+    BSON_SKIP_4_BYTES => 'x4',
+    BSON_OBJECTID     => 'a12',
+    BSON_BINARY_TYPE  => 'C',
+    BSON_CSTRING      => 'Z*',
+    BSON_BYTES        => 'a*'
+};
+
+my $BOLD = $^O eq 'MSWin32' ? "bold " : "";
+
+# minimum field size
+my %FIELD_SIZES = (
+    0x01 => 8,
+    0x02 => 5,
+    0x03 => 5,
+    0x04 => 5,
+    0x05 => 5,
+    0x06 => 0,
+    0x07 => 12,
+    0x08 => 1,
+    0x09 => 8,
+    0x0A => 0,
+    0x0B => 2,
+    0x0C => 17,
+    0x0D => 5,
+    0x0E => 5,
+    0x0F => 14,
+    0x10 => 4,
+    0x11 => 8,
+    0x12 => 8,
+    0x7F => 0,
+    0xFF => 0,
+);
+
+sub main {
+    my ( $hex, $file, $help );
+    GetOptions(
+        "file=s" => \$file,
+        "x"      => \$hex,
+        "help|h" => \$help,
+    ) or die("Error in command line args");
+    pod2usage( { -exitval => 2, -verbose => 2, } ) if $help;
+
+    if ( $file ) {
+        dump_file($file);
+    }
+    else {
+        dump_stdin($hex);
+    }
+}
+
+sub dump_stdin {
+    my $hex = shift;
+    while ( defined( my $bson = <STDIN> ) ) {
+        chomp $bson;
+        if ( !length($bson) ) {
+            print_error("[ no document ]\n");
+            next;
+        }
+        # in -x mode, treat leading # as a comment
+        if ( $hex && index( $bson, "#" ) == 0 ) {
+            say $bson;
+            next;
+        }
+        $bson =~ s[ ][]g if $hex;
+        $bson = pack( "H*", $bson ) if $hex;
+        dump_document( \$bson );
+        print "\n";
+    }
+}
+
+sub dump_file {
+    my $file = shift;
+    open my $fh, "<", $file;
+    binmode($fh);
+    my $data = do { local $/; <$fh> };
+    while ( length $data ) {
+        my $len = unpack( BSON_INT32, $data );
+        my $bson = substr($data,0,$len,'');
+        dump_document(\$bson);
+        print "\n";
+    }
+}
+
+sub dump_document {
+    my ( $ref, $is_array ) = @_;
+    print $is_array ? " [" : " {" if defined $is_array;
+    dump_header($ref);
+    1 while dump_field($ref);
+    print_error( " " . unpack( "H*", $$ref ) ) if length($$ref);
+    print $is_array ? " ]" : " }" if defined $is_array;
+    return;
+}
+
+sub dump_header {
+    my ($ref) = @_;
+
+    my $len = get_length( $ref, 4 );
+    return unless defined $len;
+
+    if ( $len < 5 || $len < length($$ref) + 4 ) {
+        print_length( $len, 'red' );
+    }
+    else {
+        print_length( $len, 'blue' );
+    }
+}
+
+sub dump_field {
+    my ($ref) = @_;
+
+    # detect end of document
+    if ( length($$ref) < 2 ) {
+        if ( length($$ref) == 0 ) {
+            print_error(" [missing terminator]");
+        }
+        else {
+            my $end = substr( $$ref, 0, 1, '' );
+            print_hex( $end, $end eq NULL ? 'blue' : 'red' );
+        }
+        return;
+    }
+
+    # unpack type
+    my $type = unpack( BSON_TYPE, substr( $$ref, 0, 1, '' ) );
+
+    if ( !exists $FIELD_SIZES{$type} ) {
+        print_type( $type, 'red' );
+        return;
+    }
+
+    print_type($type);
+
+    # check for key termination
+    my $key_end = index( $$ref, NULL );
+    return if $key_end == -1;
+
+    # unpack key
+    my $key = unpack( BSON_CSTRING, substr( $$ref, 0, $key_end + 1, '' ) );
+    print_key($key);
+
+    # Check if there is enough data to complete field for this type
+    # This is greedy, so it checks length, not length -1
+    my $min_size = $FIELD_SIZES{$type};
+    return if length($$ref) < $min_size;
+
+    # fields without payload: 0x06, 0x0A, 0x7F, 0xFF
+    return 1 if $min_size == 0;
+
+    # document or array
+    if ( $type == 0x03 || $type == 0x04 ) {
+        my ($len) = unpack( BSON_INT32, $$ref );
+        my $doc = substr( $$ref, 0, $len, '' );
+        dump_document( \$doc, $type == 0x04 );
+        return 1;
+    }
+
+    # fixed width fields
+    if (   $type == 0x01
+        || $type == 0x07
+        || $type == 0x09
+        || $type == 0x10
+        || $type == 0x11
+        || $type == 0x12 )
+    {
+        my $len = ( $type == 0x10 ? 4 : $type == 0x07 ? 12 : 8 );
+        print_hex( substr( $$ref, 0, $len, '' ) );
+        return 1;
+    }
+
+    # boolean
+    if ( $type == 0x08 ) {
+        my $bool = substr( $$ref, 0, 1, '' );
+        print_hex( $bool, ( $bool eq "\x00" || $bool eq "\x01" ) ? 'green' : 'red' );
+        return 1;
+    }
+
+    # binary field
+    if ( $type == 0x05 ) {
+        my $len = get_length( $ref, -1 );
+        my $subtype = substr( $$ref, 0, 1, '' );
+
+        if ( !defined($len) ) {
+            print_hex($subtype);
+            return;
+        }
+
+        my $binary = substr( $$ref, 0, $len, '' );
+
+        print_length($len);
+        print_hex($subtype);
+
+        if ( $subtype eq "\x02" ) {
+            my $bin_len = get_length( \$binary );
+            if ( !defined($bin_len) ) {
+                print_hex( $binary, 'red' );
+                return;
+            }
+            if ( $bin_len != length($binary) ) {
+                print_length( $bin_len, 'red' );
+                print_hex( $binary, 'red' );
+                return;
+            }
+        }
+
+        print_hex($binary) if length($binary);
+        return 1;
+    }
+
+    # string or symbol or code
+    if ( $type == 0x02 || $type == 0x0e || $type == 0x0d ) {
+        my ( $len, $string ) = get_string($ref);
+        return unless defined $len;
+
+        print_length( $len, 'cyan' );
+        print_string($string);
+        return 1;
+
+    }
+
+    # regex 0x0B
+    if ( $type == 0x0B ) {
+        my ( $pattern, $flag ) = unpack( BSON_CSTRING . BSON_CSTRING, $$ref );
+        substr( $$ref, 0, length($pattern) + length($flag) + 2, '' );
+        print_string($pattern);
+        print_string($flag);
+        return 1;
+    }
+
+    # code with scope 0x0F
+    if ( $type == 0x0F ) {
+        my $len = get_length( $ref, 4 );
+        return unless defined $len;
+
+        # len + string + doc minimum size is 4 + 5 + 5
+        if ( $len < 14 ) {
+            print_length( $len, 'red' );
+            return;
+        }
+
+        print_length($len);
+
+        my $cws = substr( $$ref, 0, $len - 4, '' );
+
+        my ( $strlen, $string ) = get_string( \$cws );
+
+        if ( !defined $strlen ) {
+            print_hex( $cws, 'red' );
+            return;
+        }
+
+        print_length($strlen);
+        print_string($string);
+
+        dump_document( \$cws, 0 );
+
+        return 1;
+    }
+
+    # dbpointer 0x0C
+    if ( $type == 0x0C ) {
+        my ( $len, $string ) = get_string($ref);
+        return unless defined $len;
+
+        print_length($len);
+        print_string($string);
+
+        # Check if there are 12 bytes (plus terminator) or more
+        return if length($$ref) < 13;
+
+        my $oid = substr( $$ref, 0, 12, '' );
+        print_hex($oid);
+
+        return 1;
+    }
+
+    die "Shouldn't reach here";
+}
+
+sub get_length {
+    my ( $ref, $adj ) = @_;
+    $adj ||= 0;
+    my $len = unpack( BSON_INT32, substr( $$ref, 0, 4, '' ) );
+    return unless defined $len;
+
+    # check if requested length is too long
+    if ( $len < 0 || $len > length($$ref) + $adj ) {
+        print_length( $len, 'red' );
+        return;
+    }
+
+    return $len;
+}
+
+sub get_string {
+    my ($ref) = @_;
+
+    my $len = get_length($ref);
+    return unless defined $len;
+
+    # len must be at least 1 for trailing 0x00
+    if ( $len == 0 ) {
+        print_length( $len, 'red' );
+        return;
+    }
+
+    my $string = substr( $$ref, 0, $len, '' );
+
+    # check if null terminated
+    if ( substr( $string, -1, 1 ) ne NULL ) {
+        print_length($len);
+        print_hex( $string, 'red' );
+        return;
+    }
+
+    # remove trailing null
+    chop($string);
+
+    # try to decode to UTF-8
+    if ( !utf8::decode($string) ) {
+        print_length($len);
+        print_hex( $string . "\x00", 'red' );
+        return;
+    }
+
+    return ( $len, $string );
+}
+
+sub print_error {
+    my ($text) = @_;
+    print colored( ["${BOLD}red"], $text );
+}
+
+sub print_type {
+    my ( $type, $color ) = @_;
+    $color ||= 'magenta';
+    print colored( ["$BOLD$color"], sprintf( " %02x", $type ) );
+}
+
+sub print_key {
+    my ($string) = @_;
+    print_string( $string, 'yellow' );
+}
+
+sub print_string {
+    my ( $string, $color ) = @_;
+    $color ||= 'green';
+    $string =~ s{([^[:graph:]])}{sprintf("\\x%02x",ord($1))}ge;
+    print colored( ["$BOLD$color"], qq[ "$string"] . " 00" );
+}
+
+sub print_length {
+    my ( $len, $color ) = @_;
+    $color ||= 'cyan';
+    print colored( ["$BOLD$color"], " " . unpack( "H*", pack( BSON_INT32, $len ) ) );
+}
+
+sub print_hex {
+    my ( $value, $color ) = @_;
+    $color ||= 'green';
+    print colored( ["$BOLD$color"], " " . uc( unpack( "H*", $value ) ) );
+}
+
+main();
+
+__END__
+
+=head1 NAME
+
+bsonview - dump a BSON string with color output showing structure
+
+=head1 SYNOPSIS
+
+    cat file.bson | bsondump
+
+    echo "0500000000" | bsondump -x
+
+=head1 OPTIONS
+
+    -x          input is in hex format (default is 0)
+    --help, -h  show help
+
+=head1 USAGE
+
+Reads from C<STDIN> and dumps colored structures to C<STDOUT>.
+
+=head1 AUTHOR
+
+=over 4
+
+=item *
+
+David Golden <david@mongodb.com>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is Copyright (c) 2016 by MongoDB, Inc..
+
+This is free software, licensed under:
+
+  The Apache License, Version 2.0, January 2004
+
+=cut
+
+=cut
diff --git a/src/tests/spec/json/bson-corpus/code.json b/src/tests/spec/json/bson-corpus/code.json
new file mode 100644
index 0000000..b8482b2
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/code.json
@@ -0,0 +1,67 @@
+{
+    "description": "Javascript Code",
+    "bson_type": "0x0D",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Empty string",
+            "canonical_bson": "0D0000000D6100010000000000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"\"}}"
+        },
+        {
+            "description": "Single character",
+            "canonical_bson": "0E0000000D610002000000620000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"b\"}}"
+        },
+        {
+            "description": "Multi-character",
+            "canonical_bson": "190000000D61000D0000006162616261626162616261620000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"abababababab\"}}"
+        },
+        {
+            "description": "two-byte UTF-8 (\u00e9)",
+            "canonical_bson": "190000000D61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}}"
+        },
+        {
+            "description": "three-byte UTF-8 (\u2606)",
+            "canonical_bson": "190000000D61000D000000E29886E29886E29886E298860000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"\\u2606\\u2606\\u2606\\u2606\"}}"
+        },
+        {
+            "description": "Embedded nulls",
+            "canonical_bson": "190000000D61000D0000006162006261620062616261620000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"ab\\u0000bab\\u0000babab\"}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "bad code string length: 0 (but no 0x00 either)",
+            "bson": "0C0000000D61000000000000"
+        },
+        {
+            "description": "bad code string length: -1",
+            "bson": "0C0000000D6100FFFFFFFF00"
+        },
+        {
+            "description": "bad code string length: eats terminator",
+            "bson": "100000000D6100050000006200620000"
+        },
+        {
+            "description": "bad code string length: longer than rest of document",
+            "bson": "120000000D00FFFFFF00666F6F6261720000"
+        },
+        {
+            "description": "code string is not null-terminated",
+            "bson": "100000000D610004000000616263FF00"
+        },
+        {
+            "description": "empty code string, but extra null",
+            "bson": "0E0000000D610001000000000000"
+        },
+        {
+            "description": "invalid UTF-8",
+            "bson": "0E0000000D610002000000E90000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/code_w_scope.json b/src/tests/spec/json/bson-corpus/code_w_scope.json
new file mode 100644
index 0000000..f956bcd
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/code_w_scope.json
@@ -0,0 +1,78 @@
+{
+    "description": "Javascript Code with Scope",
+    "bson_type": "0x0F",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Empty code string, empty scope",
+            "canonical_bson": "160000000F61000E0000000100000000050000000000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"\", \"$scope\" : {}}}"
+        },
+        {
+            "description": "Non-empty code string, empty scope",
+            "canonical_bson": "1A0000000F610012000000050000006162636400050000000000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"abcd\", \"$scope\" : {}}}"
+        },
+        {
+            "description": "Empty code string, non-empty scope",
+            "canonical_bson": "1D0000000F61001500000001000000000C000000107800010000000000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"\", \"$scope\" : {\"x\" : {\"$numberInt\": \"1\"}}}}"
+        },
+        {
+            "description": "Non-empty code string and non-empty scope",
+            "canonical_bson": "210000000F6100190000000500000061626364000C000000107800010000000000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"abcd\", \"$scope\" : {\"x\" : {\"$numberInt\": \"1\"}}}}"
+        },
+        {
+            "description": "Unicode and embedded null in code string, empty scope",
+            "canonical_bson": "1A0000000F61001200000005000000C3A9006400050000000000",
+            "canonical_extjson": "{\"a\" : {\"$code\" : \"\\u00e9\\u0000d\", \"$scope\" : {}}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "field length zero",
+            "bson": "280000000F6100000000000500000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "field length negative",
+            "bson": "280000000F6100FFFFFFFF0500000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "field length too short (less than minimum size)",
+            "bson": "160000000F61000D0000000100000000050000000000"
+        },
+        {
+            "description": "field length too short (truncates scope)",
+            "bson": "280000000F61001F0000000500000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "field length too long (clips outer doc)",
+            "bson": "280000000F6100210000000500000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "field length too long (longer than outer doc)",
+            "bson": "280000000F6100FF0000000500000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "bad code string: length too short",
+            "bson": "280000000F6100200000000400000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "bad code string: length too long (clips scope)",
+            "bson": "280000000F6100200000000600000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "bad code string: negative length",
+            "bson": "280000000F610020000000FFFFFFFF61626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "bad code string: length longer than field",
+            "bson": "280000000F610020000000FF00000061626364001300000010780001000000107900010000000000"
+        },
+        {
+            "description": "bad scope doc (field has bad string length)",
+            "bson": "1C0000000F001500000001000000000C000000020000000000000000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/datetime.json b/src/tests/spec/json/bson-corpus/datetime.json
new file mode 100644
index 0000000..f857afd
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/datetime.json
@@ -0,0 +1,42 @@
+{
+    "description": "DateTime",
+    "bson_type": "0x09",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "epoch",
+            "canonical_bson": "10000000096100000000000000000000",
+            "relaxed_extjson": "{\"a\" : {\"$date\" : \"1970-01-01T00:00:00Z\"}}",
+            "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"0\"}}}"
+        },
+        {
+            "description": "positive ms",
+            "canonical_bson": "10000000096100C5D8D6CC3B01000000",
+            "relaxed_extjson": "{\"a\" : {\"$date\" : \"2012-12-24T12:15:30.501Z\"}}",
+            "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330501\"}}}"
+        },
+        {
+            "description": "negative",
+            "canonical_bson": "10000000096100C33CE7B9BDFFFFFF00",
+            "relaxed_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"-284643869501\"}}}",
+            "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"-284643869501\"}}}"
+        },
+        {
+            "description" : "Y10K",
+            "canonical_bson" : "1000000009610000DC1FD277E6000000",
+            "canonical_extjson" : "{\"a\":{\"$date\":{\"$numberLong\":\"253402300800000\"}}}"
+        },
+        {
+            "description": "leading zero ms",
+            "canonical_bson": "10000000096100D1D6D6CC3B01000000",
+            "relaxed_extjson": "{\"a\" : {\"$date\" : \"2012-12-24T12:15:30.001Z\"}}",
+            "canonical_extjson": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330001\"}}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "datetime field truncated",
+            "bson": "0C0000000961001234567800"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/dbpointer.json b/src/tests/spec/json/bson-corpus/dbpointer.json
new file mode 100644
index 0000000..377e556
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/dbpointer.json
@@ -0,0 +1,56 @@
+{
+    "description": "DBPointer type (deprecated)",
+    "bson_type": "0x0C",
+    "deprecated": true,
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "DBpointer",
+            "canonical_bson": "1A0000000C610002000000620056E1FC72E0C917E9C471416100",
+            "canonical_extjson": "{\"a\": {\"$dbPointer\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}}",
+            "converted_bson": "2a00000003610022000000022472656600020000006200072469640056e1fc72e0c917e9c47141610000",
+            "converted_extjson": "{\"a\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}"
+        },
+        {
+            "description": "DBpointer with opposite key order",
+            "canonical_bson": "1A0000000C610002000000620056E1FC72E0C917E9C471416100",
+            "canonical_extjson": "{\"a\": {\"$dbPointer\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}}",
+            "degenerate_extjson": "{\"a\": {\"$dbPointer\": {\"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}, \"$ref\": \"b\"}}}",
+            "converted_bson": "2a00000003610022000000022472656600020000006200072469640056e1fc72e0c917e9c47141610000",
+            "converted_extjson": "{\"a\": {\"$ref\": \"b\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}"
+        },
+        {
+            "description": "With two-byte UTF-8",
+            "canonical_bson": "1B0000000C610003000000C3A90056E1FC72E0C917E9C471416100",
+            "canonical_extjson": "{\"a\": {\"$dbPointer\": {\"$ref\": \"é\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}}",
+            "converted_bson": "2B0000000361002300000002247265660003000000C3A900072469640056E1FC72E0C917E9C47141610000",
+            "converted_extjson": "{\"a\": {\"$ref\": \"é\", \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "String with negative length",
+            "bson": "1A0000000C6100FFFFFFFF620056E1FC72E0C917E9C471416100"
+        },
+        {
+            "description": "String with zero length",
+            "bson": "1A0000000C610000000000620056E1FC72E0C917E9C471416100"
+        },
+        {
+            "description": "String not null terminated",
+            "bson": "1A0000000C610002000000626256E1FC72E0C917E9C471416100"
+        },
+        {
+            "description": "short OID (less than minimum length for field)",
+            "bson": "160000000C61000300000061620056E1FC72E0C91700"
+        },
+        {
+            "description": "short OID (greater than minimum, but truncated)",
+            "bson": "1A0000000C61000300000061620056E1FC72E0C917E9C4716100"
+        },
+        {
+            "description": "String with bad UTF-8",
+            "bson": "1A0000000C610002000000E90056E1FC72E0C917E9C471416100"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/dbref.json b/src/tests/spec/json/bson-corpus/dbref.json
new file mode 100644
index 0000000..41c0b09
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/dbref.json
@@ -0,0 +1,51 @@
+{
+    "description": "Document type (DBRef sub-documents)",
+    "bson_type": "0x03",
+    "valid": [
+        {
+            "description": "DBRef",
+            "canonical_bson": "37000000036462726566002b0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}}}"
+        },
+        {
+            "description": "DBRef with database",
+            "canonical_bson": "4300000003646272656600370000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0224646200030000006462000000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$db\": \"db\"}}"
+        },
+        {
+            "description": "DBRef with database and additional fields",
+            "canonical_bson": "48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e0010246964002a00000002246462000300000064620002666f6f0004000000626172000000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$numberInt\": \"42\"}, \"$db\": \"db\", \"foo\": \"bar\"}}"
+        },
+        {
+            "description": "DBRef with additional fields",
+            "canonical_bson": "4400000003646272656600380000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e02666f6f0004000000626172000000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"foo\": \"bar\"}}"
+        },
+        {
+            "description": "Document with key names similar to those of a DBRef",
+            "canonical_bson": "3e0000000224726566000c0000006e6f742d612d646272656600072469640058921b3e6e32ab156a22b59e022462616e616e6100050000007065656c0000",
+            "canonical_extjson": "{\"$ref\": \"not-a-dbref\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$banana\": \"peel\"}"
+        },
+        {
+            "description": "DBRef with additional dollar-prefixed and dotted fields",
+            "canonical_bson": "48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e10612e62000100000010246300010000000000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"a.b\": {\"$numberInt\": \"1\"}, \"$c\": {\"$numberInt\": \"1\"}}}"
+        },
+        {
+            "description": "Sub-document resembles DBRef but $id is missing",
+            "canonical_bson": "26000000036462726566001a0000000224726566000b000000636f6c6c656374696f6e000000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\"}}"
+        },
+        {
+            "description": "Sub-document resembles DBRef but $ref is not a string",
+            "canonical_bson": "2c000000036462726566002000000010247265660001000000072469640058921b3e6e32ab156a22b59e0000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": {\"$numberInt\": \"1\"}, \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}}}"
+        },
+        {
+            "description": "Sub-document resembles DBRef but $db is not a string",
+            "canonical_bson": "4000000003646272656600340000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e1024646200010000000000",
+            "canonical_extjson": "{\"dbref\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$db\": {\"$numberInt\": \"1\"}}}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/decimal128-1.json b/src/tests/spec/json/bson-corpus/decimal128-1.json
new file mode 100644
index 0000000..7eefec6
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-1.json
@@ -0,0 +1,317 @@
+{
+    "description": "Decimal128",
+    "bson_type": "0x13",
+    "test_key": "d",
+    "valid": [
+        {
+            "description": "Special - Canonical NaN",
+            "canonical_bson": "180000001364000000000000000000000000000000007C00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
+        },
+        {
+            "description": "Special - Negative NaN",
+            "canonical_bson": "18000000136400000000000000000000000000000000FC00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - Negative NaN",
+            "canonical_bson": "18000000136400000000000000000000000000000000FC00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - Canonical SNaN",
+            "canonical_bson": "180000001364000000000000000000000000000000007E00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - Negative SNaN",
+            "canonical_bson": "18000000136400000000000000000000000000000000FE00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - NaN with a payload",
+            "canonical_bson": "180000001364001200000000000000000000000000007E00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - Canonical Positive Infinity",
+            "canonical_bson": "180000001364000000000000000000000000000000007800",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+        },
+        {
+            "description": "Special - Canonical Negative Infinity",
+            "canonical_bson": "18000000136400000000000000000000000000000000F800",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+        },
+        {
+            "description": "Special - Invalid representation treated as 0",
+            "canonical_bson": "180000001364000000000000000000000000000000106C00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - Invalid representation treated as -0",
+            "canonical_bson": "18000000136400DCBA9876543210DEADBEEF00000010EC00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Special - Invalid representation treated as 0E3",
+            "canonical_bson": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF116C00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Regular - Adjusted Exponent Limit",
+            "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF22F00",
+            "canonical_extjson": "{\"d\": { \"$numberDecimal\": \"0.000001234567890123456789012345678901234\" }}"
+        },
+        {
+            "description": "Regular - Smallest",
+            "canonical_bson": "18000000136400D204000000000000000000000000343000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001234\"}}"
+        },
+        {
+            "description": "Regular - Smallest with Trailing Zeros",
+            "canonical_bson": "1800000013640040EF5A07000000000000000000002A3000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00123400000\"}}"
+        },
+        {
+            "description": "Regular - 0.1",
+            "canonical_bson": "1800000013640001000000000000000000000000003E3000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1\"}}"
+        },
+        {
+            "description": "Regular - 0.1234567890123456789012345678901234",
+            "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFC2F00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1234567890123456789012345678901234\"}}"
+        },
+        {
+            "description": "Regular - 0",
+            "canonical_bson": "180000001364000000000000000000000000000000403000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+        },
+        {
+            "description": "Regular - -0",
+            "canonical_bson": "18000000136400000000000000000000000000000040B000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}"
+        },
+        {
+            "description": "Regular - -0.0",
+            "canonical_bson": "1800000013640000000000000000000000000000003EB000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}"
+        },
+        {
+            "description": "Regular - 2",
+            "canonical_bson": "180000001364000200000000000000000000000000403000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2\"}}"
+        },
+        {
+            "description": "Regular - 2.000",
+            "canonical_bson": "18000000136400D0070000000000000000000000003A3000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2.000\"}}"
+        },
+        {
+            "description": "Regular - Largest",
+            "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}"
+        },
+        {
+            "description": "Scientific - Tiniest",
+            "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09ED010000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E-6143\"}}"
+        },
+        {
+            "description": "Scientific - Tiny",
+            "canonical_bson": "180000001364000100000000000000000000000000000000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}"
+        },
+        {
+            "description": "Scientific - Negative Tiny",
+            "canonical_bson": "180000001364000100000000000000000000000000008000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}"
+        },
+        {
+            "description": "Scientific - Adjusted Exponent Limit",
+            "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CF02F00",
+            "canonical_extjson": "{\"d\": { \"$numberDecimal\": \"1.234567890123456789012345678901234E-7\" }}"
+        },
+        {
+            "description": "Scientific - Fractional",
+            "canonical_bson": "1800000013640064000000000000000000000000002CB000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}"
+        },
+        {
+            "description": "Scientific - 0 with Exponent",
+            "canonical_bson": "180000001364000000000000000000000000000000205F00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6000\"}}"
+        },
+        {
+            "description": "Scientific - 0 with Negative Exponent",
+            "canonical_bson": "1800000013640000000000000000000000000000007A2B00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-611\"}}"
+        },
+        {
+            "description": "Scientific - No Decimal with Signed Exponent",
+            "canonical_bson": "180000001364000100000000000000000000000000463000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}"
+        },
+        {
+            "description": "Scientific - Trailing Zero",
+            "canonical_bson": "180000001364001A04000000000000000000000000423000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.050E+4\"}}"
+        },
+        {
+            "description": "Scientific - With Decimal",
+            "canonical_bson": "180000001364006900000000000000000000000000423000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.05E+3\"}}"
+        },
+        {
+            "description": "Scientific - Full",
+            "canonical_bson": "18000000136400FFFFFFFFFFFFFFFFFFFFFFFFFFFF403000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5192296858534827628530496329220095\"}}"
+        },
+        {
+            "description": "Scientific - Large",
+            "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}"
+        },
+        {
+            "description": "Scientific - Largest",
+            "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - Exponent Normalization",
+            "canonical_bson": "1800000013640064000000000000000000000000002CB000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-100E-10\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00E-8\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - Unsigned Positive Exponent",
+            "canonical_bson": "180000001364000100000000000000000000000000463000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E3\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - Lowercase Exponent Identifier",
+            "canonical_bson": "180000001364000100000000000000000000000000463000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+3\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+3\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - Long Significand with Exponent",
+            "canonical_bson": "1800000013640079D9E0F9763ADA429D0200000000583000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12345689012345789012345E+12\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.2345689012345789012345E+34\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - Positive Sign",
+            "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+1234567890123456789012345678901234\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - Long Decimal String",
+            "canonical_bson": "180000001364000100000000000000000000000000722800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-999\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - nan",
+            "canonical_bson": "180000001364000000000000000000000000000000007C00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"nan\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - nAn",
+            "canonical_bson": "180000001364000000000000000000000000000000007C00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"nAn\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - +infinity",
+            "canonical_bson": "180000001364000000000000000000000000000000007800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+infinity\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - infinity",
+            "canonical_bson": "180000001364000000000000000000000000000000007800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"infinity\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - infiniTY",
+            "canonical_bson": "180000001364000000000000000000000000000000007800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"infiniTY\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - inf",
+            "canonical_bson": "180000001364000000000000000000000000000000007800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"inf\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - inF",
+            "canonical_bson": "180000001364000000000000000000000000000000007800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"inF\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - -infinity",
+            "canonical_bson": "18000000136400000000000000000000000000000000F800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-infinity\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - -infiniTy",
+            "canonical_bson": "18000000136400000000000000000000000000000000F800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-infiniTy\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - -Inf",
+            "canonical_bson": "18000000136400000000000000000000000000000000F800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - -inf",
+            "canonical_bson": "18000000136400000000000000000000000000000000F800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-inf\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+        },
+        {
+            "description": "Non-Canonical Parsing - -inF",
+            "canonical_bson": "18000000136400000000000000000000000000000000F800",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-inF\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+        },
+        {
+           "description": "Rounded Subnormal number",
+           "canonical_bson": "180000001364000100000000000000000000000000000000",
+           "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E-6177\"}}",
+           "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}"
+        },
+        {
+           "description": "Clamped",
+           "canonical_bson": "180000001364000a00000000000000000000000000fe5f00",
+           "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E6112\"}}",
+           "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}"
+        },
+        {
+           "description": "Exact rounding",
+           "canonical_bson": "18000000136400000000000a5bc138938d44c64d31cc3700",
+           "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}",
+           "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+999\"}}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/decimal128-2.json b/src/tests/spec/json/bson-corpus/decimal128-2.json
new file mode 100644
index 0000000..316d3b0
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-2.json
@@ -0,0 +1,793 @@
+{
+    "description": "Decimal128",
+    "bson_type": "0x13",
+    "test_key": "d",
+    "valid": [
+       {
+          "description": "[decq021] Normality",
+          "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C40B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1234567890123456789012345678901234\"}}"
+       },
+       {
+          "description": "[decq823] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400010000800000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483649\"}}"
+       },
+       {
+          "description": "[decq822] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400000000800000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483648\"}}"
+       },
+       {
+          "description": "[decq821] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400FFFFFF7F0000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483647\"}}"
+       },
+       {
+          "description": "[decq820] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400FEFFFF7F0000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-2147483646\"}}"
+       },
+       {
+          "description": "[decq152] fold-downs (more below)",
+          "canonical_bson": "18000000136400393000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-12345\"}}"
+       },
+       {
+          "description": "[decq154] fold-downs (more below)",
+          "canonical_bson": "18000000136400D20400000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1234\"}}"
+       },
+       {
+          "description": "[decq006] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE0200000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-750\"}}"
+       },
+       {
+          "description": "[decq164] fold-downs (more below)",
+          "canonical_bson": "1800000013640039300000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-123.45\"}}"
+       },
+       {
+          "description": "[decq156] fold-downs (more below)",
+          "canonical_bson": "180000001364007B0000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-123\"}}"
+       },
+       {
+          "description": "[decq008] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE020000000000000000000000003EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-75.0\"}}"
+       },
+       {
+          "description": "[decq158] fold-downs (more below)",
+          "canonical_bson": "180000001364000C0000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-12\"}}"
+       },
+       {
+          "description": "[decq122] Nmax and similar",
+          "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFFDF00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.999999999999999999999999999999999E+6144\"}}"
+       },
+       {
+          "description": "[decq002] (mostly derived from the Strawman 4 document and examples)",
+          "canonical_bson": "18000000136400EE020000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50\"}}"
+       },
+       {
+          "description": "[decq004] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE0200000000000000000000000042B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50E+3\"}}"
+       },
+       {
+          "description": "[decq018] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE020000000000000000000000002EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-7.50E-7\"}}"
+       },
+       {
+          "description": "[decq125] Nmax and similar",
+          "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFEDF00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.234567890123456789012345678901234E+6144\"}}"
+       },
+       {
+          "description": "[decq131] fold-downs (more below)",
+          "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFEDF00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.230000000000000000000000000000000E+6144\"}}"
+       },
+       {
+          "description": "[decq162] fold-downs (more below)",
+          "canonical_bson": "180000001364007B000000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.23\"}}"
+       },
+       {
+          "description": "[decq176] Nmin and below",
+          "canonical_bson": "18000000136400010000000A5BC138938D44C64D31008000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000001E-6143\"}}"
+       },
+       {
+          "description": "[decq174] Nmin and below",
+          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31008000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E-6143\"}}"
+       },
+       {
+          "description": "[decq133] fold-downs (more below)",
+          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FEDF00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E+6144\"}}"
+       },
+       {
+          "description": "[decq160] fold-downs (more below)",
+          "canonical_bson": "18000000136400010000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1\"}}"
+       },
+       {
+          "description": "[decq172] Nmin and below",
+          "canonical_bson": "180000001364000100000000000000000000000000428000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6143\"}}"
+       },
+       {
+          "description": "[decq010] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE020000000000000000000000003AB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.750\"}}"
+       },
+       {
+          "description": "[decq012] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE0200000000000000000000000038B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0750\"}}"
+       },
+       {
+          "description": "[decq014] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE0200000000000000000000000034B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000750\"}}"
+       },
+       {
+          "description": "[decq016] derivative canonical plain strings",
+          "canonical_bson": "18000000136400EE0200000000000000000000000030B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000750\"}}"
+       },
+       {
+          "description": "[decq404] zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000000000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}"
+       },
+       {
+          "description": "[decq424] negative zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000008000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}"
+       },
+       {
+          "description": "[decq407] zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}"
+       },
+       {
+          "description": "[decq427] negative zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}"
+       },
+       {
+          "description": "[decq409] zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[decq428] negative zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}"
+       },
+       {
+          "description": "[decq700] Selected DPD codes",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[decq406] zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}"
+       },
+       {
+          "description": "[decq426] negative zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}"
+       },
+       {
+          "description": "[decq410] zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000463000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}"
+       },
+       {
+          "description": "[decq431] negative zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000046B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+3\"}}"
+       },
+       {
+          "description": "[decq419] clamped zeros...",
+          "canonical_bson": "180000001364000000000000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}"
+       },
+       {
+          "description": "[decq432] negative zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000FEDF00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}"
+       },
+       {
+          "description": "[decq405] zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000000000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}"
+       },
+       {
+          "description": "[decq425] negative zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000008000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}"
+       },
+       {
+          "description": "[decq508] Specials",
+          "canonical_bson": "180000001364000000000000000000000000000000007800",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
+       },
+       {
+          "description": "[decq528] Specials",
+          "canonical_bson": "18000000136400000000000000000000000000000000F800",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
+       },
+       {
+          "description": "[decq541] Specials",
+          "canonical_bson": "180000001364000000000000000000000000000000007C00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
+       },
+       {
+          "description": "[decq074] Nmin and below",
+          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31000000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E-6143\"}}"
+       },
+       {
+          "description": "[decq602] fold-down full sequence",
+          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}"
+       },
+       {
+          "description": "[decq604] fold-down full sequence",
+          "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E+6143\"}}"
+       },
+       {
+          "description": "[decq606] fold-down full sequence",
+          "canonical_bson": "1800000013640000000080264B91C02220BE377E00FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000000E+6142\"}}"
+       },
+       {
+          "description": "[decq608] fold-down full sequence",
+          "canonical_bson": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000E+6141\"}}"
+       },
+       {
+          "description": "[decq610] fold-down full sequence",
+          "canonical_bson": "18000000136400000000A0CA17726DAE0F1E430100FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000E+6140\"}}"
+       },
+       {
+          "description": "[decq612] fold-down full sequence",
+          "canonical_bson": "18000000136400000000106102253E5ECE4F200000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000E+6139\"}}"
+       },
+       {
+          "description": "[decq614] fold-down full sequence",
+          "canonical_bson": "18000000136400000000E83C80D09F3C2E3B030000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000E+6138\"}}"
+       },
+       {
+          "description": "[decq616] fold-down full sequence",
+          "canonical_bson": "18000000136400000000E4D20CC8DCD2B752000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000E+6137\"}}"
+       },
+       {
+          "description": "[decq618] fold-down full sequence",
+          "canonical_bson": "180000001364000000004A48011416954508000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000E+6136\"}}"
+       },
+       {
+          "description": "[decq620] fold-down full sequence",
+          "canonical_bson": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000E+6135\"}}"
+       },
+       {
+          "description": "[decq622] fold-down full sequence",
+          "canonical_bson": "18000000136400000080F64AE1C7022D1500000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000E+6134\"}}"
+       },
+       {
+          "description": "[decq624] fold-down full sequence",
+          "canonical_bson": "18000000136400000040B2BAC9E0191E0200000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000E+6133\"}}"
+       },
+       {
+          "description": "[decq626] fold-down full sequence",
+          "canonical_bson": "180000001364000000A0DEC5ADC935360000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000E+6132\"}}"
+       },
+       {
+          "description": "[decq628] fold-down full sequence",
+          "canonical_bson": "18000000136400000010632D5EC76B050000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000E+6131\"}}"
+       },
+       {
+          "description": "[decq630] fold-down full sequence",
+          "canonical_bson": "180000001364000000E8890423C78A000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000E+6130\"}}"
+       },
+       {
+          "description": "[decq632] fold-down full sequence",
+          "canonical_bson": "18000000136400000064A7B3B6E00D000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000E+6129\"}}"
+       },
+       {
+          "description": "[decq634] fold-down full sequence",
+          "canonical_bson": "1800000013640000008A5D78456301000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000E+6128\"}}"
+       },
+       {
+          "description": "[decq636] fold-down full sequence",
+          "canonical_bson": "180000001364000000C16FF2862300000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000E+6127\"}}"
+       },
+       {
+          "description": "[decq638] fold-down full sequence",
+          "canonical_bson": "180000001364000080C6A47E8D0300000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000E+6126\"}}"
+       },
+       {
+          "description": "[decq640] fold-down full sequence",
+          "canonical_bson": "1800000013640000407A10F35A0000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000E+6125\"}}"
+       },
+       {
+          "description": "[decq642] fold-down full sequence",
+          "canonical_bson": "1800000013640000A0724E18090000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000E+6124\"}}"
+       },
+       {
+          "description": "[decq644] fold-down full sequence",
+          "canonical_bson": "180000001364000010A5D4E8000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000E+6123\"}}"
+       },
+       {
+          "description": "[decq646] fold-down full sequence",
+          "canonical_bson": "1800000013640000E8764817000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000E+6122\"}}"
+       },
+       {
+          "description": "[decq648] fold-down full sequence",
+          "canonical_bson": "1800000013640000E40B5402000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000E+6121\"}}"
+       },
+       {
+          "description": "[decq650] fold-down full sequence",
+          "canonical_bson": "1800000013640000CA9A3B00000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000E+6120\"}}"
+       },
+       {
+          "description": "[decq652] fold-down full sequence",
+          "canonical_bson": "1800000013640000E1F50500000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000E+6119\"}}"
+       },
+       {
+          "description": "[decq654] fold-down full sequence",
+          "canonical_bson": "180000001364008096980000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000E+6118\"}}"
+       },
+       {
+          "description": "[decq656] fold-down full sequence",
+          "canonical_bson": "1800000013640040420F0000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000E+6117\"}}"
+       },
+       {
+          "description": "[decq658] fold-down full sequence",
+          "canonical_bson": "18000000136400A086010000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000E+6116\"}}"
+       },
+       {
+          "description": "[decq660] fold-down full sequence",
+          "canonical_bson": "180000001364001027000000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000E+6115\"}}"
+       },
+       {
+          "description": "[decq662] fold-down full sequence",
+          "canonical_bson": "18000000136400E803000000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000E+6114\"}}"
+       },
+       {
+          "description": "[decq664] fold-down full sequence",
+          "canonical_bson": "180000001364006400000000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+6113\"}}"
+       },
+       {
+          "description": "[decq666] fold-down full sequence",
+          "canonical_bson": "180000001364000A00000000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}"
+       },
+       {
+          "description": "[decq060] fold-downs (more below)",
+          "canonical_bson": "180000001364000100000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1\"}}"
+       },
+       {
+          "description": "[decq670] fold-down full sequence",
+          "canonical_bson": "180000001364000100000000000000000000000000FC5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6110\"}}"
+       },
+       {
+          "description": "[decq668] fold-down full sequence",
+          "canonical_bson": "180000001364000100000000000000000000000000FE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6111\"}}"
+       },
+       {
+          "description": "[decq072] Nmin and below",
+          "canonical_bson": "180000001364000100000000000000000000000000420000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6143\"}}"
+       },
+       {
+          "description": "[decq076] Nmin and below",
+          "canonical_bson": "18000000136400010000000A5BC138938D44C64D31000000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000001E-6143\"}}"
+       },
+       {
+          "description": "[decq036] fold-downs (more below)",
+          "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.230000000000000000000000000000000E+6144\"}}"
+       },
+       {
+          "description": "[decq062] fold-downs (more below)",
+          "canonical_bson": "180000001364007B000000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23\"}}"
+       },
+       {
+          "description": "[decq034] Nmax and similar",
+          "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3CFE5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.234567890123456789012345678901234E+6144\"}}"
+       },
+       {
+          "description": "[decq441] exponent lengths",
+          "canonical_bson": "180000001364000700000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7\"}}"
+       },
+       {
+          "description": "[decq449] exponent lengths",
+          "canonical_bson": "1800000013640007000000000000000000000000001E5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+5999\"}}"
+       },
+       {
+          "description": "[decq447] exponent lengths",
+          "canonical_bson": "1800000013640007000000000000000000000000000E3800",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+999\"}}"
+       },
+       {
+          "description": "[decq445] exponent lengths",
+          "canonical_bson": "180000001364000700000000000000000000000000063100",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+99\"}}"
+       },
+       {
+          "description": "[decq443] exponent lengths",
+          "canonical_bson": "180000001364000700000000000000000000000000523000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+9\"}}"
+       },
+       {
+          "description": "[decq842] VG testcase",
+          "canonical_bson": "180000001364000000FED83F4E7C9FE4E269E38A5BCD1700",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7.049000000000010795488000000000000E-3097\"}}"
+       },
+       {
+          "description": "[decq841] VG testcase",
+          "canonical_bson": "180000001364000000203B9DB5056F000000000000002400",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"8.000000000000000000E-1550\"}}"
+       },
+       {
+          "description": "[decq840] VG testcase",
+          "canonical_bson": "180000001364003C17258419D710C42F0000000000002400",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"8.81125000000001349436E-1548\"}}"
+       },
+       {
+          "description": "[decq701] Selected DPD codes",
+          "canonical_bson": "180000001364000900000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9\"}}"
+       },
+       {
+          "description": "[decq032] Nmax and similar",
+          "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09EDFF5F00",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.999999999999999999999999999999999E+6144\"}}"
+       },
+       {
+          "description": "[decq702] Selected DPD codes",
+          "canonical_bson": "180000001364000A00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}"
+       },
+       {
+          "description": "[decq057] fold-downs (more below)",
+          "canonical_bson": "180000001364000C00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12\"}}"
+       },
+       {
+          "description": "[decq703] Selected DPD codes",
+          "canonical_bson": "180000001364001300000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"19\"}}"
+       },
+       {
+          "description": "[decq704] Selected DPD codes",
+          "canonical_bson": "180000001364001400000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"20\"}}"
+       },
+       {
+          "description": "[decq705] Selected DPD codes",
+          "canonical_bson": "180000001364001D00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"29\"}}"
+       },
+       {
+          "description": "[decq706] Selected DPD codes",
+          "canonical_bson": "180000001364001E00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"30\"}}"
+       },
+       {
+          "description": "[decq707] Selected DPD codes",
+          "canonical_bson": "180000001364002700000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"39\"}}"
+       },
+       {
+          "description": "[decq708] Selected DPD codes",
+          "canonical_bson": "180000001364002800000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"40\"}}"
+       },
+       {
+          "description": "[decq709] Selected DPD codes",
+          "canonical_bson": "180000001364003100000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"49\"}}"
+       },
+       {
+          "description": "[decq710] Selected DPD codes",
+          "canonical_bson": "180000001364003200000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"50\"}}"
+       },
+       {
+          "description": "[decq711] Selected DPD codes",
+          "canonical_bson": "180000001364003B00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"59\"}}"
+       },
+       {
+          "description": "[decq712] Selected DPD codes",
+          "canonical_bson": "180000001364003C00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"60\"}}"
+       },
+       {
+          "description": "[decq713] Selected DPD codes",
+          "canonical_bson": "180000001364004500000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"69\"}}"
+       },
+       {
+          "description": "[decq714] Selected DPD codes",
+          "canonical_bson": "180000001364004600000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"70\"}}"
+       },
+       {
+          "description": "[decq715] Selected DPD codes",
+          "canonical_bson": "180000001364004700000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"71\"}}"
+       },
+       {
+          "description": "[decq716] Selected DPD codes",
+          "canonical_bson": "180000001364004800000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"72\"}}"
+       },
+       {
+          "description": "[decq717] Selected DPD codes",
+          "canonical_bson": "180000001364004900000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"73\"}}"
+       },
+       {
+          "description": "[decq718] Selected DPD codes",
+          "canonical_bson": "180000001364004A00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"74\"}}"
+       },
+       {
+          "description": "[decq719] Selected DPD codes",
+          "canonical_bson": "180000001364004B00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"75\"}}"
+       },
+       {
+          "description": "[decq720] Selected DPD codes",
+          "canonical_bson": "180000001364004C00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"76\"}}"
+       },
+       {
+          "description": "[decq721] Selected DPD codes",
+          "canonical_bson": "180000001364004D00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"77\"}}"
+       },
+       {
+          "description": "[decq722] Selected DPD codes",
+          "canonical_bson": "180000001364004E00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"78\"}}"
+       },
+       {
+          "description": "[decq723] Selected DPD codes",
+          "canonical_bson": "180000001364004F00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"79\"}}"
+       },
+       {
+          "description": "[decq056] fold-downs (more below)",
+          "canonical_bson": "180000001364007B00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123\"}}"
+       },
+       {
+          "description": "[decq064] fold-downs (more below)",
+          "canonical_bson": "1800000013640039300000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123.45\"}}"
+       },
+       {
+          "description": "[decq732] Selected DPD codes",
+          "canonical_bson": "180000001364000802000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"520\"}}"
+       },
+       {
+          "description": "[decq733] Selected DPD codes",
+          "canonical_bson": "180000001364000902000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"521\"}}"
+       },
+       {
+          "description": "[decq740] DPD: one of each of the huffman groups",
+          "canonical_bson": "180000001364000903000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"777\"}}"
+       },
+       {
+          "description": "[decq741] DPD: one of each of the huffman groups",
+          "canonical_bson": "180000001364000A03000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"778\"}}"
+       },
+       {
+          "description": "[decq742] DPD: one of each of the huffman groups",
+          "canonical_bson": "180000001364001303000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"787\"}}"
+       },
+       {
+          "description": "[decq746] DPD: one of each of the huffman groups",
+          "canonical_bson": "180000001364001F03000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"799\"}}"
+       },
+       {
+          "description": "[decq743] DPD: one of each of the huffman groups",
+          "canonical_bson": "180000001364006D03000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"877\"}}"
+       },
+       {
+          "description": "[decq753] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "180000001364007803000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"888\"}}"
+       },
+       {
+          "description": "[decq754] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "180000001364007903000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"889\"}}"
+       },
+       {
+          "description": "[decq760] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "180000001364008203000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"898\"}}"
+       },
+       {
+          "description": "[decq764] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "180000001364008303000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"899\"}}"
+       },
+       {
+          "description": "[decq745] DPD: one of each of the huffman groups",
+          "canonical_bson": "18000000136400D303000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"979\"}}"
+       },
+       {
+          "description": "[decq770] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "18000000136400DC03000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"988\"}}"
+       },
+       {
+          "description": "[decq774] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "18000000136400DD03000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"989\"}}"
+       },
+       {
+          "description": "[decq730] Selected DPD codes",
+          "canonical_bson": "18000000136400E203000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"994\"}}"
+       },
+       {
+          "description": "[decq731] Selected DPD codes",
+          "canonical_bson": "18000000136400E303000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"995\"}}"
+       },
+       {
+          "description": "[decq744] DPD: one of each of the huffman groups",
+          "canonical_bson": "18000000136400E503000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"997\"}}"
+       },
+       {
+          "description": "[decq780] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "18000000136400E603000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"998\"}}"
+       },
+       {
+          "description": "[decq787] DPD all-highs cases (includes the 24 redundant codes)",
+          "canonical_bson": "18000000136400E703000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"999\"}}"
+       },
+       {
+          "description": "[decq053] fold-downs (more below)",
+          "canonical_bson": "18000000136400D204000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234\"}}"
+       },
+       {
+          "description": "[decq052] fold-downs (more below)",
+          "canonical_bson": "180000001364003930000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12345\"}}"
+       },
+       {
+          "description": "[decq792] Miscellaneous (testers' queries, etc.)",
+          "canonical_bson": "180000001364003075000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"30000\"}}"
+       },
+       {
+          "description": "[decq793] Miscellaneous (testers' queries, etc.)",
+          "canonical_bson": "1800000013640090940D0000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"890000\"}}"
+       },
+       {
+          "description": "[decq824] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400FEFFFF7F00000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483646\"}}"
+       },
+       {
+          "description": "[decq825] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400FFFFFF7F00000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483647\"}}"
+       },
+       {
+          "description": "[decq826] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "180000001364000000008000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483648\"}}"
+       },
+       {
+          "description": "[decq827] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "180000001364000100008000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2147483649\"}}"
+       },
+       {
+          "description": "[decq828] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400FEFFFFFF00000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967294\"}}"
+       },
+       {
+          "description": "[decq829] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "18000000136400FFFFFFFF00000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967295\"}}"
+       },
+       {
+          "description": "[decq830] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "180000001364000000000001000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967296\"}}"
+       },
+       {
+          "description": "[decq831] values around [u]int32 edges (zeros done earlier)",
+          "canonical_bson": "180000001364000100000001000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4294967297\"}}"
+       },
+       {
+          "description": "[decq022] Normality",
+          "canonical_bson": "18000000136400C7711CC7B548F377DC80A131C836403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1111111111111111111111111111111111\"}}"
+       },
+       {
+          "description": "[decq020] Normality",
+          "canonical_bson": "18000000136400F2AF967ED05C82DE3297FF6FDE3C403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1234567890123456789012345678901234\"}}"
+       },
+       {
+          "description": "[decq550] Specials",
+          "canonical_bson": "18000000136400FFFFFFFF638E8D37C087ADBE09ED413000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9999999999999999999999999999999999\"}}"
+       }
+    ]
+}
+
diff --git a/src/tests/spec/json/bson-corpus/decimal128-3.json b/src/tests/spec/json/bson-corpus/decimal128-3.json
new file mode 100644
index 0000000..9b01534
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-3.json
@@ -0,0 +1,1771 @@
+{
+    "description": "Decimal128",
+    "bson_type": "0x13",
+    "test_key": "d",
+    "valid": [
+       {
+          "description": "[basx066] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE0000000000000000000038B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-00345678.5432\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}"
+       },
+       {
+          "description": "[basx065] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE0000000000000000000038B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0345678.5432\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}"
+       },
+       {
+          "description": "[basx064] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE0000000000000000000038B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-345678.5432\"}}"
+       },
+       {
+          "description": "[basx041] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364004C0000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-76\"}}"
+       },
+       {
+          "description": "[basx027] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000F270000000000000000000000003AB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.999\"}}"
+       },
+       {
+          "description": "[basx026] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364009F230000000000000000000000003AB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.119\"}}"
+       },
+       {
+          "description": "[basx025] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364008F030000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.11\"}}"
+       },
+       {
+          "description": "[basx024] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364005B000000000000000000000000003EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.1\"}}"
+       },
+       {
+          "description": "[dqbsr531] negatives (Rounded)",
+          "canonical_bson": "1800000013640099761CC7B548F377DC80A131C836FEAF00",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.1111111111111111111111111111123450\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.111111111111111111111111111112345\"}}"
+       },
+       {
+          "description": "[basx022] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000A000000000000000000000000003EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0\"}}"
+       },
+       {
+          "description": "[basx021] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "18000000136400010000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1\"}}"
+       },
+       {
+          "description": "[basx601] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}"
+       },
+       {
+          "description": "[basx622] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002EB000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-9\"}}"
+       },
+       {
+          "description": "[basx602] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000000\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}"
+       },
+       {
+          "description": "[basx621] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000030B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000000\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-8\"}}"
+       },
+       {
+          "description": "[basx603] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000000\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}"
+       },
+       {
+          "description": "[basx620] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000032B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000000\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-7\"}}"
+       },
+       {
+          "description": "[basx604] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}"
+       },
+       {
+          "description": "[basx619] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000034B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000\"}}"
+       },
+       {
+          "description": "[basx605] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000363000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}"
+       },
+       {
+          "description": "[basx618] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000036B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}"
+       },
+       {
+          "description": "[basx680] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"000000.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx606] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000383000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}"
+       },
+       {
+          "description": "[basx617] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000038B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}"
+       },
+       {
+          "description": "[basx681] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00000.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx686] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+00000.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx687] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000040B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-00000.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}"
+       },
+       {
+          "description": "[basx019] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640000000000000000000000000000003CB000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-00.00\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}"
+       },
+       {
+          "description": "[basx607] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}"
+       },
+       {
+          "description": "[basx616] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003AB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}"
+       },
+       {
+          "description": "[basx682] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0000.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx155] Numbers with E",
+          "canonical_bson": "1800000013640000000000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000e+0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}"
+       },
+       {
+          "description": "[basx130] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}"
+       },
+       {
+          "description": "[basx290] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000038B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}"
+       },
+       {
+          "description": "[basx131] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}"
+       },
+       {
+          "description": "[basx291] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000036B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}"
+       },
+       {
+          "description": "[basx132] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}"
+       },
+       {
+          "description": "[basx292] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000034B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000\"}}"
+       },
+       {
+          "description": "[basx133] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}"
+       },
+       {
+          "description": "[basx293] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000032B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-7\"}}"
+       },
+       {
+          "description": "[basx608] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}"
+       },
+       {
+          "description": "[basx615] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003CB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}"
+       },
+       {
+          "description": "[basx683] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"000.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx630] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}"
+       },
+       {
+          "description": "[basx670] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}"
+       },
+       {
+          "description": "[basx631] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}"
+       },
+       {
+          "description": "[basx671] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}"
+       },
+       {
+          "description": "[basx134] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}"
+       },
+       {
+          "description": "[basx294] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000038B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}"
+       },
+       {
+          "description": "[basx632] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx672] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}"
+       },
+       {
+          "description": "[basx135] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}"
+       },
+       {
+          "description": "[basx295] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000036B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000\"}}"
+       },
+       {
+          "description": "[basx633] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}"
+       },
+       {
+          "description": "[basx673] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}"
+       },
+       {
+          "description": "[basx136] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}"
+       },
+       {
+          "description": "[basx674] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}"
+       },
+       {
+          "description": "[basx634] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}"
+       },
+       {
+          "description": "[basx137] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}"
+       },
+       {
+          "description": "[basx635] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000463000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}"
+       },
+       {
+          "description": "[basx675] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}"
+       },
+       {
+          "description": "[basx636] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000483000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}"
+       },
+       {
+          "description": "[basx676] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}"
+       },
+       {
+          "description": "[basx637] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}"
+       },
+       {
+          "description": "[basx677] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}"
+       },
+       {
+          "description": "[basx638] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}"
+       },
+       {
+          "description": "[basx678] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-10\"}}"
+       },
+       {
+          "description": "[basx149] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"000E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}"
+       },
+       {
+          "description": "[basx639] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}"
+       },
+       {
+          "description": "[basx679] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00E-9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-11\"}}"
+       },
+       {
+          "description": "[basx063] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE00000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+00345678.5432\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}"
+       },
+       {
+          "description": "[basx018] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640000000000000000000000000000003EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}"
+       },
+       {
+          "description": "[basx609] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}"
+       },
+       {
+          "description": "[basx614] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}"
+       },
+       {
+          "description": "[basx684] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx640] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}"
+       },
+       {
+          "description": "[basx660] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}"
+       },
+       {
+          "description": "[basx641] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx661] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00\"}}"
+       },
+       {
+          "description": "[basx296] some more negative zeros [systematic tests below]",
+          "canonical_bson": "1800000013640000000000000000000000000000003AB000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}"
+       },
+       {
+          "description": "[basx642] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}"
+       },
+       {
+          "description": "[basx662] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000\"}}"
+       },
+       {
+          "description": "[basx297] some more negative zeros [systematic tests below]",
+          "canonical_bson": "18000000136400000000000000000000000000000038B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0000\"}}"
+       },
+       {
+          "description": "[basx643] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}"
+       },
+       {
+          "description": "[basx663] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000\"}}"
+       },
+       {
+          "description": "[basx644] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000463000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}"
+       },
+       {
+          "description": "[basx664] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000\"}}"
+       },
+       {
+          "description": "[basx645] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000483000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}"
+       },
+       {
+          "description": "[basx665] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000\"}}"
+       },
+       {
+          "description": "[basx646] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}"
+       },
+       {
+          "description": "[basx666] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-7\"}}"
+       },
+       {
+          "description": "[basx647] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}"
+       },
+       {
+          "description": "[basx667] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8\"}}"
+       },
+       {
+          "description": "[basx648] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}"
+       },
+       {
+          "description": "[basx668] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}"
+       },
+       {
+          "description": "[basx160] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}"
+       },
+       {
+          "description": "[basx161] Numbers with E",
+          "canonical_bson": "1800000013640000000000000000000000000000002E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00E-9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-9\"}}"
+       },
+       {
+          "description": "[basx649] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000503000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8\"}}"
+       },
+       {
+          "description": "[basx669] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000002C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0E-9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-10\"}}"
+       },
+       {
+          "description": "[basx062] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE00000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0345678.5432\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}"
+       },
+       {
+          "description": "[basx001] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx017] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "18000000136400000000000000000000000000000040B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}"
+       },
+       {
+          "description": "[basx611] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx613] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000040B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}"
+       },
+       {
+          "description": "[basx685] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx688] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx689] Zeros",
+          "canonical_bson": "18000000136400000000000000000000000000000040B000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0\"}}"
+       },
+       {
+          "description": "[basx650] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0\"}}"
+       },
+       {
+          "description": "[basx651] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000423000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+1\"}}"
+       },
+       {
+          "description": "[basx298] some more negative zeros [systematic tests below]",
+          "canonical_bson": "1800000013640000000000000000000000000000003CB000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00\"}}"
+       },
+       {
+          "description": "[basx652] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000443000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+2\"}}"
+       },
+       {
+          "description": "[basx299] some more negative zeros [systematic tests below]",
+          "canonical_bson": "1800000013640000000000000000000000000000003AB000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000\"}}"
+       },
+       {
+          "description": "[basx653] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000463000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+3\"}}"
+       },
+       {
+          "description": "[basx654] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000483000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+4\"}}"
+       },
+       {
+          "description": "[basx655] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+5\"}}"
+       },
+       {
+          "description": "[basx656] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6\"}}"
+       },
+       {
+          "description": "[basx657] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000004E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+7\"}}"
+       },
+       {
+          "description": "[basx658] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000503000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8\"}}"
+       },
+       {
+          "description": "[basx138] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}"
+       },
+       {
+          "description": "[basx139] Numbers with E",
+          "canonical_bson": "18000000136400000000000000000000000000000052B000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+9\"}}"
+       },
+       {
+          "description": "[basx144] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000523000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}"
+       },
+       {
+          "description": "[basx154] Numbers with E",
+          "canonical_bson": "180000001364000000000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}"
+       },
+       {
+          "description": "[basx659] Zeros",
+          "canonical_bson": "180000001364000000000000000000000000000000523000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+9\"}}"
+       },
+       {
+          "description": "[basx042] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400FC040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+12.76\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}"
+       },
+       {
+          "description": "[basx143] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+1E+009\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx061] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE00000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+345678.5432\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}"
+       },
+       {
+          "description": "[basx036] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640015CD5B0700000000000000000000203000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000000123456789\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23456789E-8\"}}"
+       },
+       {
+          "description": "[basx035] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640015CD5B0700000000000000000000223000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000123456789\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23456789E-7\"}}"
+       },
+       {
+          "description": "[basx034] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640015CD5B0700000000000000000000243000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000123456789\"}}"
+       },
+       {
+          "description": "[basx053] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364003200000000000000000000000000323000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000050\"}}"
+       },
+       {
+          "description": "[basx033] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640015CD5B0700000000000000000000263000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000123456789\"}}"
+       },
+       {
+          "description": "[basx016] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000C000000000000000000000000003A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.012\"}}"
+       },
+       {
+          "description": "[basx015] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364007B000000000000000000000000003A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123\"}}"
+       },
+       {
+          "description": "[basx037] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640078DF0D8648700000000000000000223000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123456789012344\"}}"
+       },
+       {
+          "description": "[basx038] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640079DF0D8648700000000000000000223000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.123456789012345\"}}"
+       },
+       {
+          "description": "[basx250] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000383000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}"
+       },
+       {
+          "description": "[basx257] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}"
+       },
+       {
+          "description": "[basx256] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}"
+       },
+       {
+          "description": "[basx258] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}"
+       },
+       {
+          "description": "[basx251] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000103000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-21\"}}"
+       },
+       {
+          "description": "[basx263] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000603000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+19\"}}"
+       },
+       {
+          "description": "[basx255] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}"
+       },
+       {
+          "description": "[basx259] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}"
+       },
+       {
+          "description": "[basx254] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0001265\"}}"
+       },
+       {
+          "description": "[basx260] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}"
+       },
+       {
+          "description": "[basx253] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00001265\"}}"
+       },
+       {
+          "description": "[basx261] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}"
+       },
+       {
+          "description": "[basx252] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000283000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-9\"}}"
+       },
+       {
+          "description": "[basx262] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000483000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265E+8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+7\"}}"
+       },
+       {
+          "description": "[basx159] Numbers with E",
+          "canonical_bson": "1800000013640049000000000000000000000000002E3000",
+          "degenerate_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).",
+          "canonical_bson": "1800000013640064000000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00\"}}"
+       },
+       {
+          "description": "[basx003] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000A000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0\"}}"
+       },
+       {
+          "description": "[basx002] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000100000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1\"}}"
+       },
+       {
+          "description": "[basx148] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+009\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx153] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E009\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx141] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+09\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx146] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+09\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx151] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e09\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx142] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000F43000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}"
+       },
+       {
+          "description": "[basx147] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000F43000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e+90\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}"
+       },
+       {
+          "description": "[basx152] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000F43000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E90\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+90\"}}"
+       },
+       {
+          "description": "[basx140] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx150] Numbers with E",
+          "canonical_bson": "180000001364000100000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+9\"}}"
+       },
+       {
+          "description": "[basx014] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "18000000136400D2040000000000000000000000003A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.234\"}}"
+       },
+       {
+          "description": "[basx170] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}"
+       },
+       {
+          "description": "[basx177] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}"
+       },
+       {
+          "description": "[basx176] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}"
+       },
+       {
+          "description": "[basx178] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}"
+       },
+       {
+          "description": "[basx171] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000123000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-20\"}}"
+       },
+       {
+          "description": "[basx183] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000623000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+20\"}}"
+       },
+       {
+          "description": "[basx175] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}"
+       },
+       {
+          "description": "[basx179] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}"
+       },
+       {
+          "description": "[basx174] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}"
+       },
+       {
+          "description": "[basx180] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}"
+       },
+       {
+          "description": "[basx173] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0001265\"}}"
+       },
+       {
+          "description": "[basx181] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000423000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}"
+       },
+       {
+          "description": "[basx172] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000002A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-8\"}}"
+       },
+       {
+          "description": "[basx182] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000004A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+8\"}}"
+       },
+       {
+          "description": "[basx157] Numbers with E",
+          "canonical_bson": "180000001364000400000000000000000000000000523000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4E+9\"}}"
+       },
+       {
+          "description": "[basx067] examples",
+          "canonical_bson": "180000001364000500000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000005\"}}"
+       },
+       {
+          "description": "[basx069] examples",
+          "canonical_bson": "180000001364000500000000000000000000000000323000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-7\"}}"
+       },
+       {
+          "description": "[basx385] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7\"}}"
+       },
+       {
+          "description": "[basx365] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000543000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E10\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+10\"}}"
+       },
+       {
+          "description": "[basx405] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000002C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-10\"}}"
+       },
+       {
+          "description": "[basx363] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000563000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E11\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+11\"}}"
+       },
+       {
+          "description": "[basx407] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000002A3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-11\"}}"
+       },
+       {
+          "description": "[basx361] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000583000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E12\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+12\"}}"
+       },
+       {
+          "description": "[basx409] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000283000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-12\"}}"
+       },
+       {
+          "description": "[basx411] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000263000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-13\"}}"
+       },
+       {
+          "description": "[basx383] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+1\"}}"
+       },
+       {
+          "description": "[basx387] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.7\"}}"
+       },
+       {
+          "description": "[basx381] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+2\"}}"
+       },
+       {
+          "description": "[basx389] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.07\"}}"
+       },
+       {
+          "description": "[basx379] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000463000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+3\"}}"
+       },
+       {
+          "description": "[basx391] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.007\"}}"
+       },
+       {
+          "description": "[basx377] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000483000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+4\"}}"
+       },
+       {
+          "description": "[basx393] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0007\"}}"
+       },
+       {
+          "description": "[basx375] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000004A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+5\"}}"
+       },
+       {
+          "description": "[basx395] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00007\"}}"
+       },
+       {
+          "description": "[basx373] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000004C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+6\"}}"
+       },
+       {
+          "description": "[basx397] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000007\"}}"
+       },
+       {
+          "description": "[basx371] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000004E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+7\"}}"
+       },
+       {
+          "description": "[basx399] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000323000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-7\"}}"
+       },
+       {
+          "description": "[basx369] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000503000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+8\"}}"
+       },
+       {
+          "description": "[basx401] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000303000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-8\"}}"
+       },
+       {
+          "description": "[basx367] Engineering notation tests",
+          "canonical_bson": "180000001364000700000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E+9\"}}"
+       },
+       {
+          "description": "[basx403] Engineering notation tests",
+          "canonical_bson": "1800000013640007000000000000000000000000002E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"7E-9\"}}"
+       },
+       {
+          "description": "[basx007] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640064000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.0\"}}"
+       },
+       {
+          "description": "[basx005] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364000A00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}"
+       },
+       {
+          "description": "[basx165] Numbers with E",
+          "canonical_bson": "180000001364000A00000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+009\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}"
+       },
+       {
+          "description": "[basx163] Numbers with E",
+          "canonical_bson": "180000001364000A00000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+09\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}"
+       },
+       {
+          "description": "[basx325] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10\"}}"
+       },
+       {
+          "description": "[basx305] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000543000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e10\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+11\"}}"
+       },
+       {
+          "description": "[basx345] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000002C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-10\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-9\"}}"
+       },
+       {
+          "description": "[basx303] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000563000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e11\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+12\"}}"
+       },
+       {
+          "description": "[basx347] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000002A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-11\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-10\"}}"
+       },
+       {
+          "description": "[basx301] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000583000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e12\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+13\"}}"
+       },
+       {
+          "description": "[basx349] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000283000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-12\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-11\"}}"
+       },
+       {
+          "description": "[basx351] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000263000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-13\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-12\"}}"
+       },
+       {
+          "description": "[basx323] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+2\"}}"
+       },
+       {
+          "description": "[basx327] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0\"}}"
+       },
+       {
+          "description": "[basx321] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+3\"}}"
+       },
+       {
+          "description": "[basx329] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.10\"}}"
+       },
+       {
+          "description": "[basx319] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000463000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+4\"}}"
+       },
+       {
+          "description": "[basx331] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.010\"}}"
+       },
+       {
+          "description": "[basx317] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000483000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+5\"}}"
+       },
+       {
+          "description": "[basx333] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0010\"}}"
+       },
+       {
+          "description": "[basx315] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000004A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6\"}}"
+       },
+       {
+          "description": "[basx335] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00010\"}}"
+       },
+       {
+          "description": "[basx313] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000004C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+7\"}}"
+       },
+       {
+          "description": "[basx337] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-6\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000010\"}}"
+       },
+       {
+          "description": "[basx311] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000004E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+8\"}}"
+       },
+       {
+          "description": "[basx339] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000010\"}}"
+       },
+       {
+          "description": "[basx309] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000503000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+9\"}}"
+       },
+       {
+          "description": "[basx341] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-7\"}}"
+       },
+       {
+          "description": "[basx164] Numbers with E",
+          "canonical_bson": "180000001364000A00000000000000000000000000F43000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e+90\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+91\"}}"
+       },
+       {
+          "description": "[basx162] Numbers with E",
+          "canonical_bson": "180000001364000A00000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}"
+       },
+       {
+          "description": "[basx307] Engineering notation tests",
+          "canonical_bson": "180000001364000A00000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+10\"}}"
+       },
+       {
+          "description": "[basx343] Engineering notation tests",
+          "canonical_bson": "180000001364000A000000000000000000000000002E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"10e-9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-8\"}}"
+       },
+       {
+          "description": "[basx008] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640065000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.1\"}}"
+       },
+       {
+          "description": "[basx009] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640068000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.4\"}}"
+       },
+       {
+          "description": "[basx010] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640069000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.5\"}}"
+       },
+       {
+          "description": "[basx011] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364006A000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.6\"}}"
+       },
+       {
+          "description": "[basx012] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364006D000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"10.9\"}}"
+       },
+       {
+          "description": "[basx013] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "180000001364006E000000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"11.0\"}}"
+       },
+       {
+          "description": "[basx040] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364000C00000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12\"}}"
+       },
+       {
+          "description": "[basx190] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}"
+       },
+       {
+          "description": "[basx197] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}"
+       },
+       {
+          "description": "[basx196] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}"
+       },
+       {
+          "description": "[basx198] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}"
+       },
+       {
+          "description": "[basx191] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000143000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-19\"}}"
+       },
+       {
+          "description": "[basx203] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000643000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+21\"}}"
+       },
+       {
+          "description": "[basx195] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}"
+       },
+       {
+          "description": "[basx199] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}"
+       },
+       {
+          "description": "[basx194] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}"
+       },
+       {
+          "description": "[basx200] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}"
+       },
+       {
+          "description": "[basx193] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000343000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.001265\"}}"
+       },
+       {
+          "description": "[basx201] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}"
+       },
+       {
+          "description": "[basx192] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000002C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-7\"}}"
+       },
+       {
+          "description": "[basx202] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000004C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65E+8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+9\"}}"
+       },
+       {
+          "description": "[basx044] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400FC040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"012.76\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}"
+       },
+       {
+          "description": "[basx042] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400FC040000000000000000000000003C3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}"
+       },
+       {
+          "description": "[basx046] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364001100000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"17.\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"17\"}}"
+       },
+       {
+          "description": "[basx049] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364002C00000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0044\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"44\"}}"
+       },
+       {
+          "description": "[basx048] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364002C00000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"044\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"44\"}}"
+       },
+       {
+          "description": "[basx158] Numbers with E",
+          "canonical_bson": "180000001364002C00000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"44E+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"4.4E+10\"}}"
+       },
+       {
+          "description": "[basx068] examples",
+          "canonical_bson": "180000001364003200000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"50E-7\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000050\"}}"
+       },
+       {
+          "description": "[basx169] Numbers with E",
+          "canonical_bson": "180000001364006400000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+009\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}"
+       },
+       {
+          "description": "[basx167] Numbers with E",
+          "canonical_bson": "180000001364006400000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+09\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}"
+       },
+       {
+          "description": "[basx168] Numbers with E",
+          "canonical_bson": "180000001364006400000000000000000000000000F43000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100E+90\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+92\"}}"
+       },
+       {
+          "description": "[basx166] Numbers with E",
+          "canonical_bson": "180000001364006400000000000000000000000000523000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"100e+9\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+11\"}}"
+       },
+       {
+          "description": "[basx210] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003E3000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}"
+       },
+       {
+          "description": "[basx217] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}"
+       },
+       {
+          "description": "[basx216] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}"
+       },
+       {
+          "description": "[basx218] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}"
+       },
+       {
+          "description": "[basx211] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000163000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-18\"}}"
+       },
+       {
+          "description": "[basx223] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000663000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+22\"}}"
+       },
+       {
+          "description": "[basx215] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}"
+       },
+       {
+          "description": "[basx219] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}"
+       },
+       {
+          "description": "[basx214] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}"
+       },
+       {
+          "description": "[basx220] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}"
+       },
+       {
+          "description": "[basx213] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.01265\"}}"
+       },
+       {
+          "description": "[basx221] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000463000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E+4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+6\"}}"
+       },
+       {
+          "description": "[basx212] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000002E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5E-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000001265\"}}"
+       },
+       {
+          "description": "[basx222] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000004E3000",
+          "degenerate_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).",
+          "canonical_bson": "18000000136400E803000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1000\"}}"
+       },
+       {
+          "description": "[basx230] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}"
+       },
+       {
+          "description": "[basx237] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000403000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265\"}}"
+       },
+       {
+          "description": "[basx236] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"126.5\"}}"
+       },
+       {
+          "description": "[basx238] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000423000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+1\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+4\"}}"
+       },
+       {
+          "description": "[basx231] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000183000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E-17\"}}"
+       },
+       {
+          "description": "[basx243] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000683000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+20\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+23\"}}"
+       },
+       {
+          "description": "[basx235] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.65\"}}"
+       },
+       {
+          "description": "[basx239] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000443000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+2\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+5\"}}"
+       },
+       {
+          "description": "[basx234] Numbers with E",
+          "canonical_bson": "18000000136400F1040000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265\"}}"
+       },
+       {
+          "description": "[basx240] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000463000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+3\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+6\"}}"
+       },
+       {
+          "description": "[basx233] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000383000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.1265\"}}"
+       },
+       {
+          "description": "[basx241] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000483000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+4\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+7\"}}"
+       },
+       {
+          "description": "[basx232] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E-8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00001265\"}}"
+       },
+       {
+          "description": "[basx242] Numbers with E",
+          "canonical_bson": "18000000136400F104000000000000000000000000503000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1265E+8\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.265E+11\"}}"
+       },
+       {
+          "description": "[basx060] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400185C0ACE00000000000000000000383000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.5432\"}}"
+       },
+       {
+          "description": "[basx059] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400F198670C08000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0345678.54321\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.54321\"}}"
+       },
+       {
+          "description": "[basx058] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364006AF90B7C50000000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"345678.543210\"}}"
+       },
+       {
+          "description": "[basx057] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364006A19562522020000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"2345678.543210\"}}"
+       },
+       {
+          "description": "[basx056] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364006AB9C8733A0B0000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12345678.543210\"}}"
+       },
+       {
+          "description": "[basx031] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640040AF0D8648700000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789.000000\"}}"
+       },
+       {
+          "description": "[basx030] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640080910F8648700000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789.123456\"}}"
+       },
+       {
+          "description": "[basx032] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640080910F8648700000000000000000403000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"123456789123456\"}}"
+       }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/decimal128-4.json b/src/tests/spec/json/bson-corpus/decimal128-4.json
new file mode 100644
index 0000000..0957019
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-4.json
@@ -0,0 +1,165 @@
+{
+    "description": "Decimal128",
+    "bson_type": "0x13",
+    "test_key": "d",
+    "valid": [
+       {
+          "description": "[basx023] conform to rules and exponent will be in permitted range).",
+          "canonical_bson": "1800000013640001000000000000000000000000003EB000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.1\"}}"
+       },
+
+       {
+          "description": "[basx045] strings without E cannot generate E in result",
+          "canonical_bson": "1800000013640003000000000000000000000000003A3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+0.003\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.003\"}}"
+       },
+       {
+          "description": "[basx610] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0\"}}"
+       },
+       {
+          "description": "[basx612] Zeros",
+          "canonical_bson": "1800000013640000000000000000000000000000003EB000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-.0\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.0\"}}"
+       },
+       {
+          "description": "[basx043] strings without E cannot generate E in result",
+          "canonical_bson": "18000000136400FC040000000000000000000000003C3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+12.76\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"12.76\"}}"
+       },
+       {
+          "description": "[basx055] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364000500000000000000000000000000303000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000005\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-8\"}}"
+       },
+       {
+          "description": "[basx054] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364000500000000000000000000000000323000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0000005\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"5E-7\"}}"
+       },
+       {
+          "description": "[basx052] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364000500000000000000000000000000343000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000005\"}}"
+       },
+       {
+          "description": "[basx051] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364000500000000000000000000000000363000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"00.00005\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00005\"}}"
+       },
+       {
+          "description": "[basx050] strings without E cannot generate E in result",
+          "canonical_bson": "180000001364000500000000000000000000000000383000",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.0005\"}}"
+       },
+       {
+          "description": "[basx047] strings without E cannot generate E in result",
+          "canonical_bson": "1800000013640005000000000000000000000000003E3000",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".5\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.5\"}}"
+       },
+       {
+          "description": "[dqbsr431] check rounding modes heeded (Rounded)",
+          "canonical_bson": "1800000013640099761CC7B548F377DC80A131C836FE2F00",
+          "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.1111111111111111111111111111123450\"}}",
+          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.111111111111111111111111111112345\"}}"
+       },
+       {
+          "description": "OK2",
+          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FC2F00",
+          "degenerate_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"
+       }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/decimal128-5.json b/src/tests/spec/json/bson-corpus/decimal128-5.json
new file mode 100644
index 0000000..e976eae
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-5.json
@@ -0,0 +1,402 @@
+{
+    "description": "Decimal128",
+    "bson_type": "0x13",
+    "test_key": "d",
+    "valid": [
+        {
+            "description": "[decq035] fold-downs (more below) (Clamped)",
+            "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.23E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.230000000000000000000000000000000E+6144\"}}"
+        },
+        {
+            "description": "[decq037] fold-downs (more below) (Clamped)",
+            "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}"
+        },
+        {
+            "description": "[decq077] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.100000000000000000000000000000000E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E-6144\"}}"
+        },
+        {
+            "description": "[decq078] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04000000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E-6144\"}}"
+        },
+        {
+            "description": "[decq079] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000A00000000000000000000000000000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000000000000000000000000010E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-6175\"}}"
+        },
+        {
+            "description": "[decq080] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000A00000000000000000000000000000000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E-6175\"}}"
+        },
+        {
+            "description": "[decq081] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000020000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.00000000000000000000000000000001E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6175\"}}"
+        },
+        {
+            "description": "[decq082] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000020000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6175\"}}"
+        },
+        {
+            "description": "[decq083] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0.000000000000000000000000000000001E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}"
+        },
+        {
+            "description": "[decq084] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000000000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}"
+        },
+        {
+            "description": "[decq090] underflows cannot be tested for simple copies, check edge cases (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1e-6176\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-6176\"}}"
+        },
+        {
+            "description": "[decq100] underflows cannot be tested for simple copies, check edge cases (Subnormal)",
+            "canonical_bson": "18000000136400FFFFFFFF095BC138938D44C64D31000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"999999999999999999999999999999999e-6176\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"9.99999999999999999999999999999999E-6144\"}}"
+        },
+        {
+            "description": "[decq130] fold-downs (more below) (Clamped)",
+            "canonical_bson": "18000000136400000000807F1BCF85B27059C8A43CFEDF00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.23E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.230000000000000000000000000000000E+6144\"}}"
+        },
+        {
+            "description": "[decq132] fold-downs (more below) (Clamped)",
+            "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FEDF00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.000000000000000000000000000000000E+6144\"}}"
+        },
+        {
+            "description": "[decq177] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.100000000000000000000000000000000E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00000000000000000000000000000000E-6144\"}}"
+        },
+        {
+            "description": "[decq178] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04008000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.00000000000000000000000000000000E-6144\"}}"
+        },
+        {
+            "description": "[decq179] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000A00000000000000000000000000008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000000000000000000000000010E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0E-6175\"}}"
+        },
+        {
+            "description": "[decq180] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000A00000000000000000000000000008000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1.0E-6175\"}}"
+        },
+        {
+            "description": "[decq181] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000028000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.00000000000000000000000000000001E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6175\"}}"
+        },
+        {
+            "description": "[decq182] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000028000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6175\"}}"
+        },
+        {
+            "description": "[decq183] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0.000000000000000000000000000000001E-6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}"
+        },
+        {
+            "description": "[decq184] Nmin and below (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000008000",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}"
+        },
+        {
+            "description": "[decq190] underflow edge cases (Subnormal)",
+            "canonical_bson": "180000001364000100000000000000000000000000008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1e-6176\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-1E-6176\"}}"
+        },
+        {
+            "description": "[decq200] underflow edge cases (Subnormal)",
+            "canonical_bson": "18000000136400FFFFFFFF095BC138938D44C64D31008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-999999999999999999999999999999999e-6176\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-9.99999999999999999999999999999999E-6144\"}}"
+        },
+        {
+            "description": "[decq400] zeros (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-8000\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}"
+        },
+        {
+            "description": "[decq401] zeros (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000000000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6177\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E-6176\"}}"
+        },
+        {
+            "description": "[decq414] clamped zeros... (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6112\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}"
+        },
+        {
+            "description": "[decq416] clamped zeros... (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}"
+        },
+        {
+            "description": "[decq418] clamped zeros... (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+8000\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"0E+6111\"}}"
+        },
+        {
+            "description": "[decq420] negative zeros (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-8000\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}"
+        },
+        {
+            "description": "[decq421] negative zeros (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000008000",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6177\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E-6176\"}}"
+        },
+        {
+            "description": "[decq434] clamped zeros... (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000FEDF00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6112\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}"
+        },
+        {
+            "description": "[decq436] clamped zeros... (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000FEDF00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}"
+        },
+        {
+            "description": "[decq438] clamped zeros... (Clamped)",
+            "canonical_bson": "180000001364000000000000000000000000000000FEDF00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+8000\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-0E+6111\"}}"
+        },
+        {
+            "description": "[decq601] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6144\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}"
+        },
+        {
+            "description": "[decq603] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000000000081EFAC855B416D2DEE04FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6143\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000000E+6143\"}}"
+        },
+        {
+            "description": "[decq605] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000000080264B91C02220BE377E00FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6142\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000000E+6142\"}}"
+        },
+        {
+            "description": "[decq607] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000000040EAED7446D09C2C9F0C00FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6141\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000E+6141\"}}"
+        },
+        {
+            "description": "[decq609] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000000A0CA17726DAE0F1E430100FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6140\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000000E+6140\"}}"
+        },
+        {
+            "description": "[decq611] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000000106102253E5ECE4F200000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6139\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000000E+6139\"}}"
+        },
+        {
+            "description": "[decq613] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000000E83C80D09F3C2E3B030000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6138\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000E+6138\"}}"
+        },
+        {
+            "description": "[decq615] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000000E4D20CC8DCD2B752000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6137\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000000E+6137\"}}"
+        },
+        {
+            "description": "[decq617] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000000004A48011416954508000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6136\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000000E+6136\"}}"
+        },
+        {
+            "description": "[decq619] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000000A1EDCCCE1BC2D300000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6135\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000E+6135\"}}"
+        },
+        {
+            "description": "[decq621] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000080F64AE1C7022D1500000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6134\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000000E+6134\"}}"
+        },
+        {
+            "description": "[decq623] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000040B2BAC9E0191E0200000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6133\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000000E+6133\"}}"
+        },
+        {
+            "description": "[decq625] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000000A0DEC5ADC935360000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6132\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000E+6132\"}}"
+        },
+        {
+            "description": "[decq627] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000010632D5EC76B050000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6131\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000000E+6131\"}}"
+        },
+        {
+            "description": "[decq629] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000000E8890423C78A000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6130\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000000E+6130\"}}"
+        },
+        {
+            "description": "[decq631] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400000064A7B3B6E00D000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6129\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000E+6129\"}}"
+        },
+        {
+            "description": "[decq633] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000008A5D78456301000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6128\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000000E+6128\"}}"
+        },
+        {
+            "description": "[decq635] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000000C16FF2862300000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6127\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000000E+6127\"}}"
+        },
+        {
+            "description": "[decq637] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000080C6A47E8D0300000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6126\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000E+6126\"}}"
+        },
+        {
+            "description": "[decq639] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000407A10F35A0000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6125\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000000E+6125\"}}"
+        },
+        {
+            "description": "[decq641] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000A0724E18090000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6124\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000000E+6124\"}}"
+        },
+        {
+            "description": "[decq643] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000010A5D4E8000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6123\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000E+6123\"}}"
+        },
+        {
+            "description": "[decq645] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000E8764817000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6122\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000000E+6122\"}}"
+        },
+        {
+            "description": "[decq647] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000E40B5402000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6121\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000000E+6121\"}}"
+        },
+        {
+            "description": "[decq649] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000CA9A3B00000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6120\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000E+6120\"}}"
+        },
+        {
+            "description": "[decq651] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640000E1F50500000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6119\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000000E+6119\"}}"
+        },
+        {
+            "description": "[decq653] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364008096980000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6118\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000000E+6118\"}}"
+        },
+        {
+            "description": "[decq655] fold-down full sequence (Clamped)",
+            "canonical_bson": "1800000013640040420F0000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6117\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000E+6117\"}}"
+        },
+        {
+            "description": "[decq657] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400A086010000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6116\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00000E+6116\"}}"
+        },
+        {
+            "description": "[decq659] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364001027000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6115\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0000E+6115\"}}"
+        },
+        {
+            "description": "[decq661] fold-down full sequence (Clamped)",
+            "canonical_bson": "18000000136400E803000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6114\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000E+6114\"}}"
+        },
+        {
+            "description": "[decq663] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364006400000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6113\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.00E+6113\"}}"
+        },
+        {
+            "description": "[decq665] fold-down full sequence (Clamped)",
+            "canonical_bson": "180000001364000A00000000000000000000000000FE5F00",
+            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E+6112\"}}",
+            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.0E+6112\"}}"
+        }
+    ]
+}
+
diff --git a/src/tests/spec/json/bson-corpus/decimal128-6.json b/src/tests/spec/json/bson-corpus/decimal128-6.json
new file mode 100644
index 0000000..eba6764
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-6.json
@@ -0,0 +1,131 @@
+{
+    "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"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/decimal128-7.json b/src/tests/spec/json/bson-corpus/decimal128-7.json
new file mode 100644
index 0000000..0b78f12
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/decimal128-7.json
@@ -0,0 +1,327 @@
+{
+    "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/src/tests/spec/json/bson-corpus/document.json b/src/tests/spec/json/bson-corpus/document.json
new file mode 100644
index 0000000..698e7ae
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/document.json
@@ -0,0 +1,60 @@
+{
+    "description": "Document type (sub-documents)",
+    "bson_type": "0x03",
+    "test_key": "x",
+    "valid": [
+        {
+            "description": "Empty subdoc",
+            "canonical_bson": "0D000000037800050000000000",
+            "canonical_extjson": "{\"x\" : {}}"
+        },
+        {
+            "description": "Empty-string key subdoc",
+            "canonical_bson": "150000000378000D00000002000200000062000000",
+            "canonical_extjson": "{\"x\" : {\"\" : \"b\"}}"
+        },
+        {
+            "description": "Single-character key subdoc",
+            "canonical_bson": "160000000378000E0000000261000200000062000000",
+            "canonical_extjson": "{\"x\" : {\"a\" : \"b\"}}"
+        },
+        {
+            "description": "Dollar-prefixed key in sub-document",
+            "canonical_bson": "170000000378000F000000022461000200000062000000",
+            "canonical_extjson": "{\"x\" : {\"$a\" : \"b\"}}"
+        },
+        {
+            "description": "Dollar as key in sub-document",
+            "canonical_bson": "160000000378000E0000000224000200000061000000",
+            "canonical_extjson": "{\"x\" : {\"$\" : \"a\"}}"
+        },
+        {
+            "description": "Dotted key in sub-document",
+            "canonical_bson": "180000000378001000000002612E62000200000063000000",
+            "canonical_extjson": "{\"x\" : {\"a.b\" : \"c\"}}"
+        },
+        {
+            "description": "Dot as key in sub-document",
+            "canonical_bson": "160000000378000E000000022E000200000061000000",
+            "canonical_extjson": "{\"x\" : {\".\" : \"a\"}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Subdocument length too long: eats outer terminator",
+            "bson": "1800000003666F6F000F0000001062617200FFFFFF7F0000"
+        },
+        {
+            "description": "Subdocument length too short: leaks terminator",
+            "bson": "1500000003666F6F000A0000000862617200010000"
+        },
+        {
+            "description": "Invalid subdocument: bad string length in field",
+            "bson": "1C00000003666F6F001200000002626172000500000062617A000000"
+        },
+        {
+            "description": "Null byte in sub-document key",
+            "bson": "150000000378000D00000010610000010000000000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/double.json b/src/tests/spec/json/bson-corpus/double.json
new file mode 100644
index 0000000..d5b8fb3
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/double.json
@@ -0,0 +1,87 @@
+{
+    "description": "Double type",
+    "bson_type": "0x01",
+    "test_key": "d",
+    "valid": [
+        {
+            "description": "+1.0",
+            "canonical_bson": "10000000016400000000000000F03F00",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"1.0\"}}",
+            "relaxed_extjson": "{\"d\" : 1.0}"
+        },
+        {
+            "description": "-1.0",
+            "canonical_bson": "10000000016400000000000000F0BF00",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-1.0\"}}",
+            "relaxed_extjson": "{\"d\" : -1.0}"
+        },
+        {
+            "description": "+1.0001220703125",
+            "canonical_bson": "10000000016400000000008000F03F00",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"1.0001220703125\"}}",
+            "relaxed_extjson": "{\"d\" : 1.0001220703125}"
+        },
+        {
+            "description": "-1.0001220703125",
+            "canonical_bson": "10000000016400000000008000F0BF00",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-1.0001220703125\"}}",
+            "relaxed_extjson": "{\"d\" : -1.0001220703125}"
+        },
+        {
+            "description": "1.2345678921232E+18",
+            "canonical_bson": "100000000164002a1bf5f41022b14300",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"1.2345678921232E+18\"}}",
+            "relaxed_extjson": "{\"d\" : 1.2345678921232E+18}"
+        },
+        {
+            "description": "-1.2345678921232E+18",
+            "canonical_bson": "100000000164002a1bf5f41022b1c300",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-1.2345678921232E+18\"}}",
+            "relaxed_extjson": "{\"d\" : -1.2345678921232E+18}"
+        },
+        {
+            "description": "0.0",
+            "canonical_bson": "10000000016400000000000000000000",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"0.0\"}}",
+            "relaxed_extjson": "{\"d\" : 0.0}"
+        },
+        {
+            "description": "-0.0",
+            "canonical_bson": "10000000016400000000000000008000",
+            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-0.0\"}}",
+            "relaxed_extjson": "{\"d\" : -0.0}"
+        },
+        {
+            "description": "NaN",
+            "canonical_bson": "10000000016400000000000000F87F00",
+            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
+            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "NaN with payload",
+            "canonical_bson": "10000000016400120000000000F87F00",
+            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
+            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
+            "lossy": true
+        },
+        {
+            "description": "Inf",
+            "canonical_bson": "10000000016400000000000000F07F00",
+            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"Infinity\"}}",
+            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"Infinity\"}}"
+        },
+        {
+            "description": "-Inf",
+            "canonical_bson": "10000000016400000000000000F0FF00",
+            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"-Infinity\"}}",
+            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"-Infinity\"}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "double truncated",
+            "bson": "0B0000000164000000F03F00"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/int32.json b/src/tests/spec/json/bson-corpus/int32.json
new file mode 100644
index 0000000..1353fc3
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/int32.json
@@ -0,0 +1,43 @@
+{
+    "description": "Int32 type",
+    "bson_type": "0x10",
+    "test_key": "i",
+    "valid": [
+        {
+            "description": "MinValue",
+            "canonical_bson": "0C0000001069000000008000",
+            "canonical_extjson": "{\"i\" : {\"$numberInt\": \"-2147483648\"}}",
+            "relaxed_extjson": "{\"i\" : -2147483648}"
+        },
+        {
+            "description": "MaxValue",
+            "canonical_bson": "0C000000106900FFFFFF7F00",
+            "canonical_extjson": "{\"i\" : {\"$numberInt\": \"2147483647\"}}",
+            "relaxed_extjson": "{\"i\" : 2147483647}"
+        },
+        {
+            "description": "-1",
+            "canonical_bson": "0C000000106900FFFFFFFF00",
+            "canonical_extjson": "{\"i\" : {\"$numberInt\": \"-1\"}}",
+            "relaxed_extjson": "{\"i\" : -1}"
+        },
+        {
+            "description": "0",
+            "canonical_bson": "0C0000001069000000000000",
+            "canonical_extjson": "{\"i\" : {\"$numberInt\": \"0\"}}",
+            "relaxed_extjson": "{\"i\" : 0}"
+        },
+        {
+            "description": "1",
+            "canonical_bson": "0C0000001069000100000000",
+            "canonical_extjson": "{\"i\" : {\"$numberInt\": \"1\"}}",
+            "relaxed_extjson": "{\"i\" : 1}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Bad int32 field length",
+            "bson": "090000001061000500"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/int64.json b/src/tests/spec/json/bson-corpus/int64.json
new file mode 100644
index 0000000..91f4abf
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/int64.json
@@ -0,0 +1,43 @@
+{
+    "description": "Int64 type",
+    "bson_type": "0x12",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "MinValue",
+            "canonical_bson": "10000000126100000000000000008000",
+            "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"-9223372036854775808\"}}",
+            "relaxed_extjson": "{\"a\" : -9223372036854775808}"
+        },
+        {
+            "description": "MaxValue",
+            "canonical_bson": "10000000126100FFFFFFFFFFFFFF7F00",
+            "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"9223372036854775807\"}}",
+            "relaxed_extjson": "{\"a\" : 9223372036854775807}"
+        },
+        {
+            "description": "-1",
+            "canonical_bson": "10000000126100FFFFFFFFFFFFFFFF00",
+            "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"-1\"}}",
+            "relaxed_extjson": "{\"a\" : -1}"
+        },
+        {
+            "description": "0",
+            "canonical_bson": "10000000126100000000000000000000",
+            "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"0\"}}",
+            "relaxed_extjson": "{\"a\" : 0}"
+        },
+        {
+            "description": "1",
+            "canonical_bson": "10000000126100010000000000000000",
+            "canonical_extjson": "{\"a\" : {\"$numberLong\" : \"1\"}}",
+            "relaxed_extjson": "{\"a\" : 1}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "int64 field truncated",
+            "bson": "0C0000001261001234567800"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/maxkey.json b/src/tests/spec/json/bson-corpus/maxkey.json
new file mode 100644
index 0000000..67cad6d
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/maxkey.json
@@ -0,0 +1,12 @@
+{
+    "description": "Maxkey type",
+    "bson_type": "0x7F",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Maxkey",
+            "canonical_bson": "080000007F610000",
+            "canonical_extjson": "{\"a\" : {\"$maxKey\" : 1}}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/minkey.json b/src/tests/spec/json/bson-corpus/minkey.json
new file mode 100644
index 0000000..8adee45
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/minkey.json
@@ -0,0 +1,12 @@
+{
+    "description": "Minkey type",
+    "bson_type": "0xFF",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Minkey",
+            "canonical_bson": "08000000FF610000",
+            "canonical_extjson": "{\"a\" : {\"$minKey\" : 1}}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/multi-type-deprecated.json b/src/tests/spec/json/bson-corpus/multi-type-deprecated.json
new file mode 100644
index 0000000..665f388
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/multi-type-deprecated.json
@@ -0,0 +1,15 @@
+{
+    "description": "Multiple types within the same document",
+    "bson_type": "0x00",
+    "deprecated": true,
+    "valid": [
+        {
+            "description": "All BSON types",
+            "canonical_bson": "38020000075F69640057E193D7A9CC81B4027498B50E53796D626F6C000700000073796D626F6C0002537472696E670007000000737472696E670010496E743332002A00000012496E743634002A0000000000000001446F75626C6500000000000000F0BF0542696E617279001000000003A34C38F7C3ABEDC8A37814A992AB8DB60542696E61727955736572446566696E656400050000008001020304050D436F6465000E00000066756E6374696F6E2829207B7D000F436F64655769746853636F7065001B0000000E00000066756E6374696F6E2829207B7D00050000000003537562646F63756D656E74001200000002666F6F0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696D657374616D7000010000002A0000000B5265676578007061747465726E0000094461746574696D6545706F6368000000000000000000094461746574696D65506F73697469766500FFFFFF7F00000000094461746574696D654E656761746976650000000080FFFFFFFF085472756500010846616C736500000C4442506F696E746572000B000000636F6C6C656374696F6E0057E193D7A9CC81B4027498B1034442526566003D0000000224726566000B000000636F6C6C656374696F6E00072469640057FD71E96E32AB4225B723FB02246462000900000064617461626173650000FF4D696E6B6579007F4D61786B6579000A4E756C6C0006556E646566696E65640000",
+            "converted_bson": "48020000075f69640057e193d7a9cc81b4027498b50253796d626f6c000700000073796d626f6c0002537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c73650000034442506f696e746572002b0000000224726566000b000000636f6c6c656374696f6e00072469640057e193d7a9cc81b4027498b100034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c000a556e646566696e65640000",
+            "canonical_extjson": "{\"_id\": {\"$oid\": \"57e193d7a9cc81b4027498b5\"}, \"Symbol\": {\"$symbol\": \"symbol\"}, \"String\": \"string\", \"Int32\": {\"$numberInt\": \"42\"}, \"Int64\": {\"$numberLong\": \"42\"}, \"Double\": {\"$numberDouble\": \"-1.0\"}, \"Binary\": { \"$binary\" : {\"base64\": \"o0w498Or7cijeBSpkquNtg==\", \"subType\": \"03\"}}, \"BinaryUserDefined\": { \"$binary\" : {\"base64\": \"AQIDBAU=\", \"subType\": \"80\"}}, \"Code\": {\"$code\": \"function() {}\"}, \"CodeWithScope\": {\"$code\": \"function() {}\", \"$scope\": {}}, \"Subdocument\": {\"foo\": \"bar\"}, \"Array\": [{\"$numberInt\": \"1\"}, {\"$numberInt\": \"2\"}, {\"$numberInt\": \"3\"}, {\"$numberInt\": \"4\"}, {\"$numberInt\": \"5\"}], \"Timestamp\": {\"$timestamp\": {\"t\": 42, \"i\": 1}}, \"Regex\": {\"$regularExpression\": {\"pattern\": \"pattern\", \"options\": \"\"}}, \"DatetimeEpoch\": {\"$date\": {\"$numberLong\": \"0\"}}, \"DatetimePositive\": {\"$date\": {\"$numberLong\": \"2147483647\"}}, \"DatetimeNegative\": {\"$date\": {\"$numberLong\": \"-2147483648\"}}, \"True\": true, \"False\": false, \"DBPointer\": {\"$dbPointer\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57e193d7a9cc81b4027498b1\"}}}, \"DBRef\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57fd71e96e32ab4225b723fb\"}, \"$db\": \"database\"}, \"Minkey\": {\"$minKey\": 1}, \"Maxkey\": {\"$maxKey\": 1}, \"Null\": null, \"Undefined\": {\"$undefined\": true}}",
+            "converted_extjson": "{\"_id\": {\"$oid\": \"57e193d7a9cc81b4027498b5\"}, \"Symbol\": \"symbol\", \"String\": \"string\", \"Int32\": {\"$numberInt\": \"42\"}, \"Int64\": {\"$numberLong\": \"42\"}, \"Double\": {\"$numberDouble\": \"-1.0\"}, \"Binary\": { \"$binary\" : {\"base64\": \"o0w498Or7cijeBSpkquNtg==\", \"subType\": \"03\"}}, \"BinaryUserDefined\": { \"$binary\" : {\"base64\": \"AQIDBAU=\", \"subType\": \"80\"}}, \"Code\": {\"$code\": \"function() {}\"}, \"CodeWithScope\": {\"$code\": \"function() {}\", \"$scope\": {}}, \"Subdocument\": {\"foo\": \"bar\"}, \"Array\": [{\"$numberInt\": \"1\"}, {\"$numberInt\": \"2\"}, {\"$numberInt\": \"3\"}, {\"$numberInt\": \"4\"}, {\"$numberInt\": \"5\"}], \"Timestamp\": {\"$timestamp\": {\"t\": 42, \"i\": 1}}, \"Regex\": {\"$regularExpression\": {\"pattern\": \"pattern\", \"options\": \"\"}}, \"DatetimeEpoch\": {\"$date\": {\"$numberLong\": \"0\"}}, \"DatetimePositive\": {\"$date\": {\"$numberLong\": \"2147483647\"}}, \"DatetimeNegative\": {\"$date\": {\"$numberLong\": \"-2147483648\"}}, \"True\": true, \"False\": false, \"DBPointer\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57e193d7a9cc81b4027498b1\"}}, \"DBRef\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57fd71e96e32ab4225b723fb\"}, \"$db\": \"database\"}, \"Minkey\": {\"$minKey\": 1}, \"Maxkey\": {\"$maxKey\": 1}, \"Null\": null, \"Undefined\": null}"
+        }
+    ]
+}
+
diff --git a/src/tests/spec/json/bson-corpus/multi-type.json b/src/tests/spec/json/bson-corpus/multi-type.json
new file mode 100644
index 0000000..1e1d557
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/multi-type.json
@@ -0,0 +1,11 @@
+{
+    "description": "Multiple types within the same document",
+    "bson_type": "0x00",
+    "valid": [
+        {
+            "description": "All BSON types",
+            "canonical_bson": "F4010000075F69640057E193D7A9CC81B4027498B502537472696E670007000000737472696E670010496E743332002A00000012496E743634002A0000000000000001446F75626C6500000000000000F0BF0542696E617279001000000003A34C38F7C3ABEDC8A37814A992AB8DB60542696E61727955736572446566696E656400050000008001020304050D436F6465000E00000066756E6374696F6E2829207B7D000F436F64655769746853636F7065001B0000000E00000066756E6374696F6E2829207B7D00050000000003537562646F63756D656E74001200000002666F6F0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696D657374616D7000010000002A0000000B5265676578007061747465726E0000094461746574696D6545706F6368000000000000000000094461746574696D65506F73697469766500FFFFFF7F00000000094461746574696D654E656761746976650000000080FFFFFFFF085472756500010846616C73650000034442526566003D0000000224726566000B000000636F6C6C656374696F6E00072469640057FD71E96E32AB4225B723FB02246462000900000064617461626173650000FF4D696E6B6579007F4D61786B6579000A4E756C6C0000",
+            "canonical_extjson": "{\"_id\": {\"$oid\": \"57e193d7a9cc81b4027498b5\"}, \"String\": \"string\", \"Int32\": {\"$numberInt\": \"42\"}, \"Int64\": {\"$numberLong\": \"42\"}, \"Double\": {\"$numberDouble\": \"-1.0\"}, \"Binary\": { \"$binary\" : {\"base64\": \"o0w498Or7cijeBSpkquNtg==\", \"subType\": \"03\"}}, \"BinaryUserDefined\": { \"$binary\" : {\"base64\": \"AQIDBAU=\", \"subType\": \"80\"}}, \"Code\": {\"$code\": \"function() {}\"}, \"CodeWithScope\": {\"$code\": \"function() {}\", \"$scope\": {}}, \"Subdocument\": {\"foo\": \"bar\"}, \"Array\": [{\"$numberInt\": \"1\"}, {\"$numberInt\": \"2\"}, {\"$numberInt\": \"3\"}, {\"$numberInt\": \"4\"}, {\"$numberInt\": \"5\"}], \"Timestamp\": {\"$timestamp\": {\"t\": 42, \"i\": 1}}, \"Regex\": {\"$regularExpression\": {\"pattern\": \"pattern\", \"options\": \"\"}}, \"DatetimeEpoch\": {\"$date\": {\"$numberLong\": \"0\"}}, \"DatetimePositive\": {\"$date\": {\"$numberLong\": \"2147483647\"}}, \"DatetimeNegative\": {\"$date\": {\"$numberLong\": \"-2147483648\"}}, \"True\": true, \"False\": false, \"DBRef\": {\"$ref\": \"collection\", \"$id\": {\"$oid\": \"57fd71e96e32ab4225b723fb\"}, \"$db\": \"database\"}, \"Minkey\": {\"$minKey\": 1}, \"Maxkey\": {\"$maxKey\": 1}, \"Null\": null}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/null.json b/src/tests/spec/json/bson-corpus/null.json
new file mode 100644
index 0000000..f9b2694
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/null.json
@@ -0,0 +1,12 @@
+{
+    "description": "Null type",
+    "bson_type": "0x0A",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Null",
+            "canonical_bson": "080000000A610000",
+            "canonical_extjson": "{\"a\" : null}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/oid.json b/src/tests/spec/json/bson-corpus/oid.json
new file mode 100644
index 0000000..14e9caf
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/oid.json
@@ -0,0 +1,28 @@
+{
+    "description": "ObjectId",
+    "bson_type": "0x07",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "All zeroes",
+            "canonical_bson": "1400000007610000000000000000000000000000",
+            "canonical_extjson": "{\"a\" : {\"$oid\" : \"000000000000000000000000\"}}"
+        },
+        {
+            "description": "All ones",
+            "canonical_bson": "14000000076100FFFFFFFFFFFFFFFFFFFFFFFF00",
+            "canonical_extjson": "{\"a\" : {\"$oid\" : \"ffffffffffffffffffffffff\"}}"
+        },
+        {
+            "description": "Random",
+            "canonical_bson": "1400000007610056E1FC72E0C917E9C471416100",
+            "canonical_extjson": "{\"a\" : {\"$oid\" : \"56e1fc72e0c917e9c4714161\"}}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "OID truncated",
+            "bson": "1200000007610056E1FC72E0C917E9C471"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/regex.json b/src/tests/spec/json/bson-corpus/regex.json
new file mode 100644
index 0000000..2238021
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/regex.json
@@ -0,0 +1,65 @@
+{
+    "description": "Regular Expression type",
+    "bson_type": "0x0B",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "empty regex with no options",
+            "canonical_bson": "0A0000000B6100000000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"\", \"options\" : \"\"}}}"
+        },
+        {
+            "description": "regex without options",
+            "canonical_bson": "0D0000000B6100616263000000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"\"}}}"
+        },
+        {
+            "description": "regex with options",
+            "canonical_bson": "0F0000000B610061626300696D0000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"im\"}}}"
+        },
+        {
+            "description": "regex with options (keys reversed)",
+            "canonical_bson": "0F0000000B610061626300696D0000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"im\"}}}",
+            "degenerate_extjson": "{\"a\" : {\"$regularExpression\" : {\"options\" : \"im\", \"pattern\": \"abc\"}}}"
+        },
+        {
+            "description": "regex with slash",
+            "canonical_bson": "110000000B610061622F636400696D0000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"ab/cd\", \"options\" : \"im\"}}}"
+        },
+        {
+            "description": "flags not alphabetized",
+            "degenerate_bson": "100000000B6100616263006D69780000",
+            "canonical_bson": "100000000B610061626300696D780000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"imx\"}}}",
+            "degenerate_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"abc\", \"options\" : \"mix\"}}}"
+        },
+        {
+            "description" : "Required escapes",
+            "canonical_bson" : "100000000B610061625C226162000000",
+            "canonical_extjson": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"ab\\\\\\\"ab\", \"options\" : \"\"}}}"
+        },
+        {
+            "description" : "Regular expression as value of $regex query operator",
+            "canonical_bson" : "180000000B247265676578007061747465726E0069780000",
+            "canonical_extjson": "{\"$regex\" : {\"$regularExpression\" : { \"pattern\": \"pattern\", \"options\" : \"ix\"}}}"
+        },
+        {
+            "description" : "Regular expression as value of $regex query operator with $options",
+            "canonical_bson" : "270000000B247265676578007061747465726E000002246F7074696F6E73000300000069780000",
+            "canonical_extjson": "{\"$regex\" : {\"$regularExpression\" : { \"pattern\": \"pattern\", \"options\" : \"\"}}, \"$options\" : \"ix\"}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Null byte in pattern string",
+            "bson": "0F0000000B610061006300696D0000"
+        },
+        {
+            "description": "Null byte in flags string",
+            "bson": "100000000B61006162630069006D0000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/string.json b/src/tests/spec/json/bson-corpus/string.json
new file mode 100644
index 0000000..148334d
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/string.json
@@ -0,0 +1,72 @@
+{
+    "description": "String",
+    "bson_type": "0x02",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Empty string",
+            "canonical_bson": "0D000000026100010000000000",
+            "canonical_extjson": "{\"a\" : \"\"}"
+        },
+        {
+            "description": "Single character",
+            "canonical_bson": "0E00000002610002000000620000",
+            "canonical_extjson": "{\"a\" : \"b\"}"
+        },
+        {
+            "description": "Multi-character",
+            "canonical_bson": "190000000261000D0000006162616261626162616261620000",
+            "canonical_extjson": "{\"a\" : \"abababababab\"}"
+        },
+        {
+            "description": "two-byte UTF-8 (\u00e9)",
+            "canonical_bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+            "canonical_extjson": "{\"a\" : \"\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\\u00e9\"}"
+        },
+        {
+            "description": "three-byte UTF-8 (\u2606)",
+            "canonical_bson": "190000000261000D000000E29886E29886E29886E298860000",
+            "canonical_extjson": "{\"a\" : \"\\u2606\\u2606\\u2606\\u2606\"}"
+        },
+        {
+            "description": "Embedded nulls",
+            "canonical_bson": "190000000261000D0000006162006261620062616261620000",
+            "canonical_extjson": "{\"a\" : \"ab\\u0000bab\\u0000babab\"}"
+        },
+        {
+            "description": "Required escapes",
+            "canonical_bson" : "320000000261002600000061625C220102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F61620000",
+            "canonical_extjson" : "{\"a\":\"ab\\\\\\\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001fab\"}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "bad string length: 0 (but no 0x00 either)",
+            "bson": "0C0000000261000000000000"
+        },
+        {
+            "description": "bad string length: -1",
+            "bson": "0C000000026100FFFFFFFF00"
+        },
+        {
+            "description": "bad string length: eats terminator",
+            "bson": "10000000026100050000006200620000"
+        },
+        {
+            "description": "bad string length: longer than rest of document",
+            "bson": "120000000200FFFFFF00666F6F6261720000"
+        },
+        {
+            "description": "string is not null-terminated",
+            "bson": "1000000002610004000000616263FF00"
+        },
+        {
+            "description": "empty string, but extra null",
+            "bson": "0E00000002610001000000000000"
+        },
+        {
+            "description": "invalid UTF-8",
+            "bson": "0E00000002610002000000E90000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/symbol.json b/src/tests/spec/json/bson-corpus/symbol.json
new file mode 100644
index 0000000..3dd3577
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/symbol.json
@@ -0,0 +1,80 @@
+{
+    "description": "Symbol",
+    "bson_type": "0x0E",
+    "deprecated": true,
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Empty string",
+            "canonical_bson": "0D0000000E6100010000000000",
+            "canonical_extjson": "{\"a\": {\"$symbol\": \"\"}}",
+            "converted_bson": "0D000000026100010000000000",
+            "converted_extjson": "{\"a\": \"\"}"
+        },
+        {
+            "description": "Single character",
+            "canonical_bson": "0E0000000E610002000000620000",
+            "canonical_extjson": "{\"a\": {\"$symbol\": \"b\"}}",
+            "converted_bson": "0E00000002610002000000620000",
+            "converted_extjson": "{\"a\": \"b\"}"
+        },
+        {
+            "description": "Multi-character",
+            "canonical_bson": "190000000E61000D0000006162616261626162616261620000",
+            "canonical_extjson": "{\"a\": {\"$symbol\": \"abababababab\"}}",
+            "converted_bson": "190000000261000D0000006162616261626162616261620000",
+            "converted_extjson": "{\"a\": \"abababababab\"}"
+        },
+        {
+            "description": "two-byte UTF-8 (\u00e9)",
+            "canonical_bson": "190000000E61000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+            "canonical_extjson": "{\"a\": {\"$symbol\": \"éééééé\"}}",
+            "converted_bson": "190000000261000D000000C3A9C3A9C3A9C3A9C3A9C3A90000",
+            "converted_extjson": "{\"a\": \"éééééé\"}"
+        },
+        {
+            "description": "three-byte UTF-8 (\u2606)",
+            "canonical_bson": "190000000E61000D000000E29886E29886E29886E298860000",
+            "canonical_extjson": "{\"a\": {\"$symbol\": \"☆☆☆☆\"}}",
+            "converted_bson": "190000000261000D000000E29886E29886E29886E298860000",
+            "converted_extjson": "{\"a\": \"☆☆☆☆\"}"
+        },
+        {
+            "description": "Embedded nulls",
+            "canonical_bson": "190000000E61000D0000006162006261620062616261620000",
+            "canonical_extjson": "{\"a\": {\"$symbol\": \"ab\\u0000bab\\u0000babab\"}}",
+            "converted_bson": "190000000261000D0000006162006261620062616261620000",
+            "converted_extjson": "{\"a\": \"ab\\u0000bab\\u0000babab\"}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "bad symbol length: 0 (but no 0x00 either)",
+            "bson": "0C0000000E61000000000000"
+        },
+        {
+            "description": "bad symbol length: -1",
+            "bson": "0C0000000E6100FFFFFFFF00"
+        },
+        {
+            "description": "bad symbol length: eats terminator",
+            "bson": "100000000E6100050000006200620000"
+        },
+        {
+            "description": "bad symbol length: longer than rest of document",
+            "bson": "120000000E00FFFFFF00666F6F6261720000"
+        },
+        {
+            "description": "symbol is not null-terminated",
+            "bson": "100000000E610004000000616263FF00"
+        },
+        {
+            "description": "empty symbol, but extra null",
+            "bson": "0E0000000E610001000000000000"
+        },
+        {
+            "description": "invalid UTF-8",
+            "bson": "0E0000000E610002000000E90000"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/timestamp.json b/src/tests/spec/json/bson-corpus/timestamp.json
new file mode 100644
index 0000000..6f46564
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/timestamp.json
@@ -0,0 +1,34 @@
+{
+    "description": "Timestamp type",
+    "bson_type": "0x11",
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Timestamp: (123456789, 42)",
+            "canonical_bson": "100000001161002A00000015CD5B0700",
+            "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : 42} } }"
+        },
+        {
+            "description": "Timestamp: (123456789, 42) (keys reversed)",
+            "canonical_bson": "100000001161002A00000015CD5B0700",
+            "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : 42} } }",
+            "degenerate_extjson": "{\"a\" : {\"$timestamp\" : {\"i\" : 42, \"t\" : 123456789} } }"
+        },
+        {
+            "description": "Timestamp with high-order bit set on both seconds and increment",
+            "canonical_bson": "10000000116100FFFFFFFFFFFFFFFF00",
+            "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 4294967295, \"i\" :  4294967295} } }"
+        },
+        {
+            "description": "Timestamp with high-order bit set on both seconds and increment (not UINT32_MAX)",
+            "canonical_bson": "1000000011610000286BEE00286BEE00", 
+            "canonical_extjson": "{\"a\" : {\"$timestamp\" : {\"t\" : 4000000000, \"i\" :  4000000000} } }"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "Truncated timestamp field",
+            "bson": "0f0000001161002A00000015CD5B00"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/top.json b/src/tests/spec/json/bson-corpus/top.json
new file mode 100644
index 0000000..9c649b5
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/top.json
@@ -0,0 +1,266 @@
+{
+    "description": "Top-level document validity",
+    "bson_type": "0x00",
+    "valid": [
+        {
+            "description": "Dollar-prefixed key in top-level document",
+            "canonical_bson": "0F00000010246B6579002A00000000",
+            "canonical_extjson": "{\"$key\": {\"$numberInt\": \"42\"}}"
+        },
+        {
+            "description": "Dollar as key in top-level document",
+            "canonical_bson": "0E00000002240002000000610000",
+            "canonical_extjson": "{\"$\": \"a\"}"
+        },
+        {
+            "description": "Dotted key in top-level document",
+            "canonical_bson": "1000000002612E620002000000630000",
+            "canonical_extjson": "{\"a.b\": \"c\"}"
+        },
+        {
+            "description": "Dot as key in top-level document",
+            "canonical_bson": "0E000000022E0002000000610000",
+            "canonical_extjson": "{\".\": \"a\"}"
+        }
+    ],
+    "decodeErrors": [
+        {
+            "description": "An object size that's too small to even include the object size, but is a well-formed, empty object",
+            "bson": "0100000000"
+        },
+        {
+            "description": "An object size that's only enough for the object size, but is a well-formed, empty object",
+            "bson": "0400000000"
+        },
+        {
+            "description": "One object, with length shorter than size (missing EOO)",
+            "bson": "05000000"
+        },
+        {
+            "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0x01",
+            "bson": "0500000001"
+        },
+        {
+            "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0xff",
+            "bson": "05000000FF"
+        },
+        {
+            "description": "One object, sized correctly, with a spot for an EOO, but the EOO is 0x70",
+            "bson": "0500000070"
+        },
+        {
+            "description": "Byte count is zero (with non-zero input length)",
+            "bson": "00000000000000000000"
+        },
+        {
+            "description": "Stated length exceeds byte count, with truncated document",
+            "bson": "1200000002666F6F0004000000626172"
+        },
+        {
+            "description": "Stated length less than byte count, with garbage after envelope",
+            "bson": "1200000002666F6F00040000006261720000DEADBEEF"
+        },
+        {
+            "description": "Stated length exceeds byte count, with valid envelope",
+            "bson": "1300000002666F6F00040000006261720000"
+        },
+        {
+            "description": "Stated length less than byte count, with valid envelope",
+            "bson": "1100000002666F6F00040000006261720000"
+        },
+        {
+            "description": "Invalid BSON type low range",
+            "bson": "07000000000000"
+        },
+        {
+            "description": "Invalid BSON type high range",
+            "bson": "07000000800000"
+        },
+        {
+            "description": "Document truncated mid-key",
+            "bson": "1200000002666F"
+        },
+        {
+            "description": "Null byte in document key",
+            "bson": "0D000000107800000100000000"
+        }
+    ],
+    "parseErrors": [
+        {
+            "description" : "Bad $regularExpression (extra field)",
+            "string" : "{\"a\" : {\"$regularExpression\": {\"pattern\": \"abc\", \"options\": \"\", \"unrelated\": true}}}"
+        },
+        {
+            "description" : "Bad $regularExpression (missing options field)",
+            "string" : "{\"a\" : {\"$regularExpression\": {\"pattern\": \"abc\"}}}"
+        },
+        {
+            "description": "Bad $regularExpression (pattern is number, not string)",
+            "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": 42, \"options\" : \"\"}}}"
+        },
+        {
+            "description": "Bad $regularExpression (options are number, not string)",
+            "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": \"a\", \"options\" : 0}}}"
+        },
+        {
+            "description" : "Bad $regularExpression (missing pattern field)",
+            "string" : "{\"a\" : {\"$regularExpression\": {\"options\":\"ix\"}}}"
+        },
+        {
+            "description": "Bad $oid (number, not string)",
+            "string": "{\"a\" : {\"$oid\" : 42}}"
+        },
+        {
+            "description": "Bad $oid (extra field)",
+            "string": "{\"a\" : {\"$oid\" : \"56e1fc72e0c917e9c4714161\", \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $numberInt (number, not string)",
+            "string": "{\"a\" : {\"$numberInt\" : 42}}"
+        },
+        {
+            "description": "Bad $numberInt (extra field)",
+            "string": "{\"a\" : {\"$numberInt\" : \"42\", \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $numberLong (number, not string)",
+            "string": "{\"a\" : {\"$numberLong\" : 42}}"
+        },
+        {
+            "description": "Bad $numberLong (extra field)",
+            "string": "{\"a\" : {\"$numberLong\" : \"42\", \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $numberDouble (number, not string)",
+            "string": "{\"a\" : {\"$numberDouble\" : 42}}"
+        },
+        {
+            "description": "Bad $numberDouble (extra field)",
+            "string": "{\"a\" : {\"$numberDouble\" : \".1\", \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $numberDecimal (number, not string)",
+            "string": "{\"a\" : {\"$numberDecimal\" : 42}}"
+        },
+        {
+            "description": "Bad $numberDecimal (extra field)",
+            "string": "{\"a\" : {\"$numberDecimal\" : \".1\", \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $binary (binary is number, not string)",
+            "string": "{\"x\" : {\"$binary\" : {\"base64\" : 0, \"subType\" : \"00\"}}}"
+        },
+        {
+            "description": "Bad $binary (type is number, not string)",
+            "string": "{\"x\" : {\"$binary\" : {\"base64\" : \"\", \"subType\" : 0}}}"
+        },
+        {
+            "description": "Bad $binary (missing $type)",
+            "string": "{\"x\" : {\"$binary\" : {\"base64\" : \"//8=\"}}}"
+        },
+        {
+            "description": "Bad $binary (missing $binary)",
+            "string": "{\"x\" : {\"$binary\" : {\"subType\" : \"00\"}}}"
+        },
+        {
+            "description": "Bad $binary (extra field)",
+            "string": "{\"x\" : {\"$binary\" : {\"base64\" : \"//8=\", \"subType\" : 0, \"unrelated\": true}}}"
+        },
+        {
+            "description": "Bad $code (type is number, not string)",
+            "string": "{\"a\" : {\"$code\" : 42}}"
+        },
+        {
+            "description": "Bad $code (type is number, not string) when $scope is also present",
+            "string": "{\"a\" : {\"$code\" : 42, \"$scope\" : {}}}"
+        },
+        {
+            "description": "Bad $code (extra field)",
+            "string": "{\"a\" : {\"$code\" : \"\", \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $code with $scope (scope is number, not doc)",
+            "string": "{\"x\" : {\"$code\" : \"\", \"$scope\" : 42}}"
+        },
+        {
+            "description": "Bad $timestamp (type is number, not doc)",
+            "string": "{\"a\" : {\"$timestamp\" : 42} }"
+        },
+        {
+            "description": "Bad $timestamp ('t' type is string, not number)",
+            "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\", \"i\" : 42} } }"
+        },
+        {
+            "description": "Bad $timestamp ('i' type is string, not number)",
+            "string": "{\"a\" : {\"$timestamp\" : {\"t\" : 123456789, \"i\" : \"42\"} } }"
+        },
+        {
+            "description": "Bad $timestamp (extra field at same level as $timestamp)",
+            "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\", \"i\" : \"42\"}, \"unrelated\": true } }"
+        },
+        {
+            "description": "Bad $timestamp (extra field at same level as t and i)",
+            "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\", \"i\" : \"42\", \"unrelated\": true} } }"
+        },
+        {
+            "description": "Bad $timestamp (missing t)",
+            "string": "{\"a\" : {\"$timestamp\" : {\"i\" : \"42\"} } }"
+        },
+        {
+            "description": "Bad $timestamp (missing i)",
+            "string": "{\"a\" : {\"$timestamp\" : {\"t\" : \"123456789\"} } }"
+        },
+        {
+            "description": "Bad $date (number, not string or hash)",
+            "string": "{\"a\" : {\"$date\" : 42}}"
+        },
+        {
+            "description": "Bad $date (extra field)",
+            "string": "{\"a\" : {\"$date\" : {\"$numberLong\" : \"1356351330501\"}, \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $minKey (boolean, not integer)",
+            "string": "{\"a\" : {\"$minKey\" : true}}"
+        },
+        {
+            "description": "Bad $minKey (wrong integer)",
+            "string": "{\"a\" : {\"$minKey\" : 0}}"
+        },
+        {
+            "description": "Bad $minKey (extra field)",
+            "string": "{\"a\" : {\"$minKey\" : 1, \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad $maxKey (boolean, not integer)",
+            "string": "{\"a\" : {\"$maxKey\" : true}}"
+        },
+        {
+            "description": "Bad $maxKey (wrong integer)",
+            "string": "{\"a\" : {\"$maxKey\" : 0}}"
+        },
+        {
+            "description": "Bad $maxKey (extra field)",
+            "string": "{\"a\" : {\"$maxKey\" : 1, \"unrelated\": true}}"
+        },
+        {
+            "description": "Bad DBpointer (extra field)",
+            "string": "{\"a\": {\"$dbPointer\": {\"a\": {\"$numberInt\": \"1\"}, \"$id\": {\"$oid\": \"56e1fc72e0c917e9c4714161\"}, \"c\": {\"$numberInt\": \"2\"}, \"$ref\": \"b\"}}}"
+        },
+        {
+            "description" : "Null byte in document key",
+            "string" : "{\"a\\u0000\": 1 }"
+        },
+        {
+            "description" : "Null byte in sub-document key",
+            "string" : "{\"a\" : {\"b\\u0000\": 1 }}"
+        },
+        {
+            "description": "Null byte in $regularExpression pattern",
+            "string": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"b\\u0000\", \"options\" : \"i\"}}}"
+        },
+        {
+            "description": "Null byte in $regularExpression options",
+            "string": "{\"a\" : {\"$regularExpression\" : { \"pattern\": \"b\", \"options\" : \"i\\u0000\"}}}"
+        }
+    ]
+}
diff --git a/src/tests/spec/json/bson-corpus/undefined.json b/src/tests/spec/json/bson-corpus/undefined.json
new file mode 100644
index 0000000..285f068
--- /dev/null
+++ b/src/tests/spec/json/bson-corpus/undefined.json
@@ -0,0 +1,15 @@
+{
+    "description": "Undefined type (deprecated)",
+    "bson_type": "0x06",
+    "deprecated": true,
+    "test_key": "a",
+    "valid": [
+        {
+            "description": "Undefined",
+            "canonical_bson": "0800000006610000",
+            "canonical_extjson": "{\"a\" : {\"$undefined\" : true}}",
+            "converted_bson": "080000000A610000",
+            "converted_extjson": "{\"a\" : null}"
+        }
+    ]
+}
diff --git a/src/tests/spec/mod.rs b/src/tests/spec/mod.rs
new file mode 100644
index 0000000..36ff825
--- /dev/null
+++ b/src/tests/spec/mod.rs
@@ -0,0 +1,51 @@
+mod corpus;
+
+use std::{
+    any::type_name,
+    ffi::OsStr,
+    fs::{self, File},
+    path::PathBuf,
+};
+
+use crate::RawDocumentBuf;
+use serde::de::DeserializeOwned;
+
+pub(crate) fn run_spec_test<T, F>(spec: &[&str], run_test_file: F)
+where
+    F: Fn(T),
+    T: DeserializeOwned,
+{
+    let base_path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "src", "tests", "spec", "json"]
+        .iter()
+        .chain(spec.iter())
+        .collect();
+
+    for entry in fs::read_dir(&base_path)
+        .unwrap_or_else(|e| panic!("Failed to read directory at {:?}: {}", base_path, e))
+    {
+        let path = entry.unwrap().path();
+        if path.extension() != Some(OsStr::new("json")) {
+            continue;
+        }
+
+        let file = File::open(&path)
+            .unwrap_or_else(|e| panic!("Failed to open file at {:?}: {}", path, e));
+
+        let test_bson: RawDocumentBuf = serde_json::from_reader(file).unwrap_or_else(|e| {
+            panic!(
+                "Failed to deserialize test JSON to BSON in {:?}: {}",
+                path, e
+            )
+        });
+        let test: T = crate::from_slice(test_bson.as_bytes()).unwrap_or_else(|e| {
+            panic!(
+                "Failed to deserialize test BSON to {} in {:?}: {}",
+                type_name::<T>(),
+                path,
+                e
+            )
+        });
+
+        run_test_file(test)
+    }
+}
