|
18 | 18 | import sys
|
19 | 19 | sys.path[0:0] = [""]
|
20 | 20 |
|
| 21 | +from bson import encode, decode |
21 | 22 | from bson.dbref import DBRef
|
22 | 23 | from bson.objectid import ObjectId
|
23 | 24 | from test import unittest
|
@@ -131,5 +132,108 @@ def test_dbref_hash(self):
|
131 | 132 |
|
132 | 133 | self.assertNotEqual(hash(dbref_1a), hash(dbref_2a))
|
133 | 134 |
|
| 135 | + |
| 136 | +# https://github.com/mongodb/specifications/blob/master/source/dbref.rst#test-plan |
| 137 | +class TestDBRefSpec(unittest.TestCase): |
| 138 | + def test_decoding_1_2_3(self): |
| 139 | + for doc in [ |
| 140 | + # 1, Valid documents MUST be decoded to a DBRef: |
| 141 | + {"$ref": "coll0", "$id": ObjectId("60a6fe9a54f4180c86309efa")}, |
| 142 | + {"$ref": "coll0", "$id": 1}, |
| 143 | + {"$ref": "coll0", "$id": None}, |
| 144 | + {"$ref": "coll0", "$id": 1, "$db": "db0"}, |
| 145 | + # 2, Valid documents with extra fields: |
| 146 | + {"$ref": "coll0", "$id": 1, "$db": "db0", "foo": "bar"}, |
| 147 | + {"$ref": "coll0", "$id": 1, "foo": True, "bar": False}, |
| 148 | + {"$ref": "coll0", "$id": 1, "meta": {"foo": 1, "bar": 2}}, |
| 149 | + {"$ref": "coll0", "$id": 1, "$foo": "bar"}, |
| 150 | + {"$ref": "coll0", "$id": 1, "foo.bar": 0}, |
| 151 | + # 3, Valid documents with out of order fields: |
| 152 | + {"$id": 1, "$ref": "coll0"}, |
| 153 | + {"$db": "db0", "$ref": "coll0", "$id": 1}, |
| 154 | + {"foo": 1, "$id": 1, "$ref": "coll0"}, |
| 155 | + {"foo": 1, "$ref": "coll0", "$id": 1, "$db": "db0"}, |
| 156 | + {"foo": 1, "$ref": "coll0", "$id": 1, "$db": "db0", "bar": 1}, |
| 157 | + ]: |
| 158 | + with self.subTest(doc=doc): |
| 159 | + decoded = decode(encode({'dbref': doc})) |
| 160 | + dbref = decoded['dbref'] |
| 161 | + self.assertIsInstance(dbref, DBRef) |
| 162 | + self.assertEqual(dbref.collection, doc['$ref']) |
| 163 | + self.assertEqual(dbref.id, doc['$id']) |
| 164 | + self.assertEqual(dbref.database, doc.get('$db')) |
| 165 | + for extra in set(doc.keys()) - {"$ref", "$id", "$db"}: |
| 166 | + self.assertEqual(getattr(dbref, extra), doc[extra]) |
| 167 | + |
| 168 | + def test_decoding_4_5(self): |
| 169 | + for doc in [ |
| 170 | + # 4, Documents missing required fields MUST NOT be decoded to a |
| 171 | + # DBRef: |
| 172 | + {"$ref": "coll0"}, |
| 173 | + {"$id": ObjectId("60a6fe9a54f4180c86309efa")}, |
| 174 | + {"$db": "db0"}, |
| 175 | + # 5, Documents with invalid types for $ref or $db MUST NOT be |
| 176 | + # decoded to a DBRef |
| 177 | + {"$ref": True, "$id": 1}, |
| 178 | + {"$ref": "coll0", "$id": 1, "$db": 1}, |
| 179 | + ]: |
| 180 | + with self.subTest(doc=doc): |
| 181 | + decoded = decode(encode({'dbref': doc})) |
| 182 | + dbref = decoded['dbref'] |
| 183 | + self.assertIsInstance(dbref, dict) |
| 184 | + |
| 185 | + def test_encoding_1_2(self): |
| 186 | + for doc in [ |
| 187 | + # 1, Encoding DBRefs with basic fields: |
| 188 | + {"$ref": "coll0", "$id": ObjectId("60a6fe9a54f4180c86309efa")}, |
| 189 | + {"$ref": "coll0", "$id": 1}, |
| 190 | + {"$ref": "coll0", "$id": None}, |
| 191 | + {"$ref": "coll0", "$id": 1, "$db": "db0"}, |
| 192 | + # 2, Encoding DBRefs with extra, optional fields: |
| 193 | + {"$ref": "coll0", "$id": 1, "$db": "db0", "foo": "bar"}, |
| 194 | + {"$ref": "coll0", "$id": 1, "foo": True, "bar": False}, |
| 195 | + {"$ref": "coll0", "$id": 1, "meta": {"foo": 1, "bar": 2}}, |
| 196 | + {"$ref": "coll0", "$id": 1, "$foo": "bar"}, |
| 197 | + {"$ref": "coll0", "$id": 1, "foo.bar": 0}, |
| 198 | + ]: |
| 199 | + with self.subTest(doc=doc): |
| 200 | + # Decode the test input to a DBRef via a BSON roundtrip. |
| 201 | + encoded_doc = encode({'dbref': doc}) |
| 202 | + decoded = decode(encoded_doc) |
| 203 | + dbref = decoded['dbref'] |
| 204 | + self.assertIsInstance(dbref, DBRef) |
| 205 | + # Encode the DBRef. |
| 206 | + encoded_dbref = encode(decoded) |
| 207 | + self.assertEqual(encoded_dbref, encoded_doc) |
| 208 | + # Ensure extra fields are present. |
| 209 | + for extra in set(doc.keys()) - {"$ref", "$id", "$db"}: |
| 210 | + self.assertEqual(getattr(dbref, extra), doc[extra]) |
| 211 | + |
| 212 | + def test_encoding_3(self): |
| 213 | + for doc in [ |
| 214 | + # 3, Encoding DBRefs re-orders any out of order fields during |
| 215 | + # decoding: |
| 216 | + {"$id": 1, "$ref": "coll0"}, |
| 217 | + {"$db": "db0", "$ref": "coll0", "$id": 1}, |
| 218 | + {"foo": 1, "$id": 1, "$ref": "coll0"}, |
| 219 | + {"foo": 1, "$ref": "coll0", "$id": 1, "$db": "db0"}, |
| 220 | + {"foo": 1, "$ref": "coll0", "$id": 1, "$db": "db0", "bar": 1}, |
| 221 | + ]: |
| 222 | + with self.subTest(doc=doc): |
| 223 | + # Decode the test input to a DBRef via a BSON roundtrip. |
| 224 | + encoded_doc = encode({'dbref': doc}) |
| 225 | + decoded = decode(encoded_doc) |
| 226 | + dbref = decoded['dbref'] |
| 227 | + self.assertIsInstance(dbref, DBRef) |
| 228 | + # Encode the DBRef. |
| 229 | + encoded_dbref = encode(decoded) |
| 230 | + # BSON does not match because DBRef fields are reordered. |
| 231 | + self.assertNotEqual(encoded_dbref, encoded_doc) |
| 232 | + self.assertEqual(decode(encoded_dbref), decode(encoded_doc)) |
| 233 | + # Ensure extra fields are present. |
| 234 | + for extra in set(doc.keys()) - {"$ref", "$id", "$db"}: |
| 235 | + self.assertEqual(getattr(dbref, extra), doc[extra]) |
| 236 | + |
| 237 | + |
134 | 238 | if __name__ == "__main__":
|
135 | 239 | unittest.main()
|
0 commit comments