PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/MongoDB.Bson.Tests/IO/JsonWriterTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 758 lines | 681 code | 63 blank | 14 comment | 18 complexity | 0b7d74bee09e5b167d832a7f884b757c MD5 | raw file
Possible License(s): Apache-2.0
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Text;
  20. using FluentAssertions;
  21. using MongoDB.Bson.IO;
  22. using MongoDB.Bson.Serialization;
  23. using MongoDB.Bson.TestHelpers;
  24. using MongoDB.Bson.TestHelpers.XunitExtensions;
  25. using Xunit;
  26. namespace MongoDB.Bson.Tests.IO
  27. {
  28. public class JsonWriterTests
  29. {
  30. private class TestData<T>
  31. {
  32. public T Value;
  33. public string Expected;
  34. public TestData(T value, string expected)
  35. {
  36. this.Value = value;
  37. this.Expected = expected;
  38. }
  39. }
  40. [Theory]
  41. [ParameterAttributeData]
  42. public void JsonWriter_should_support_writing_multiple_documents(
  43. [Range(0, 3)]
  44. int numberOfDocuments,
  45. [Values("", " ", "\r\n")]
  46. string documentSeparator)
  47. {
  48. var document = new BsonDocument("x", 1);
  49. var json = document.ToJson();
  50. var expectedResult = Enumerable.Repeat(json, numberOfDocuments).Aggregate("", (a, j) => a + j + documentSeparator);
  51. using (var stringWriter = new StringWriter())
  52. using (var jsonWriter = new JsonWriter(stringWriter))
  53. {
  54. for (var n = 0; n < numberOfDocuments; n++)
  55. {
  56. jsonWriter.WriteStartDocument();
  57. jsonWriter.WriteName("x");
  58. jsonWriter.WriteInt32(1);
  59. jsonWriter.WriteEndDocument();
  60. jsonWriter.BaseTextWriter.Write(documentSeparator);
  61. }
  62. var result = stringWriter.ToString();
  63. result.Should().Be(expectedResult);
  64. }
  65. }
  66. [Fact]
  67. public void TestEmptyDocument()
  68. {
  69. BsonDocument document = new BsonDocument();
  70. string json = document.ToJson();
  71. string expected = "{ }";
  72. Assert.Equal(expected, json);
  73. }
  74. [Fact]
  75. public void TestSingleString()
  76. {
  77. BsonDocument document = new BsonDocument() { { "abc", "xyz" } };
  78. string json = document.ToJson();
  79. string expected = "{ \"abc\" : \"xyz\" }";
  80. Assert.Equal(expected, json);
  81. }
  82. [Fact]
  83. public void TestIndentedEmptyDocument()
  84. {
  85. BsonDocument document = new BsonDocument();
  86. var settings = new JsonWriterSettings { Indent = true };
  87. string json = document.ToJson(settings);
  88. string expected = "{ }";
  89. Assert.Equal(expected, json);
  90. }
  91. [Fact]
  92. public void TestIndentedOneElement()
  93. {
  94. BsonDocument document = new BsonDocument() { { "name", "value" } };
  95. var settings = new JsonWriterSettings { Indent = true };
  96. string json = document.ToJson(settings);
  97. string expected = "{\r\n \"name\" : \"value\"\r\n}";
  98. Assert.Equal(expected, json);
  99. }
  100. [Fact]
  101. public void TestIndentedTwoElements()
  102. {
  103. BsonDocument document = new BsonDocument() { { "a", "x" }, { "b", "y" } };
  104. var settings = new JsonWriterSettings { Indent = true };
  105. string json = document.ToJson(settings);
  106. string expected = "{\r\n \"a\" : \"x\",\r\n \"b\" : \"y\"\r\n}";
  107. Assert.Equal(expected, json);
  108. }
  109. [Fact]
  110. public void TestDecimal128Shell()
  111. {
  112. var tests = new TestData<Decimal128>[]
  113. {
  114. new TestData<Decimal128>(Decimal128.Parse("0"), "NumberDecimal(\"0\")"),
  115. new TestData<Decimal128>(Decimal128.Parse("0.0"), "NumberDecimal(\"0.0\")"),
  116. new TestData<Decimal128>(Decimal128.Parse("0.0005"), "NumberDecimal(\"0.0005\")"),
  117. new TestData<Decimal128>(Decimal128.Parse("0.5"), "NumberDecimal(\"0.5\")"),
  118. new TestData<Decimal128>(Decimal128.Parse("1.0"), "NumberDecimal(\"1.0\")"),
  119. new TestData<Decimal128>(Decimal128.Parse("1.5"), "NumberDecimal(\"1.5\")"),
  120. new TestData<Decimal128>(Decimal128.Parse("1.5E+40"), "NumberDecimal(\"1.5E+40\")"),
  121. new TestData<Decimal128>(Decimal128.Parse("1.5E-40"), "NumberDecimal(\"1.5E-40\")"),
  122. new TestData<Decimal128>(Decimal128.Parse("1234567890.1234568E+123"), "NumberDecimal(\"1.2345678901234568E+132\")"),
  123. new TestData<Decimal128>(Decimal128.Parse("NaN"), "NumberDecimal(\"NaN\")"),
  124. new TestData<Decimal128>(Decimal128.Parse("-Infinity"), "NumberDecimal(\"-Infinity\")"),
  125. new TestData<Decimal128>(Decimal128.Parse("Infinity"), "NumberDecimal(\"Infinity\")")
  126. };
  127. foreach (var test in tests)
  128. {
  129. var json = new BsonDecimal128(test.Value).ToJson();
  130. Assert.Equal(test.Expected, json);
  131. Assert.Equal(test.Value, BsonSerializer.Deserialize<Decimal128>(json));
  132. }
  133. }
  134. [Fact]
  135. public void TestDecimal128Strict()
  136. {
  137. var tests = new TestData<Decimal128>[]
  138. {
  139. new TestData<Decimal128>(Decimal128.Parse("0"), "{ \"$numberDecimal\" : \"0\" }"),
  140. new TestData<Decimal128>(Decimal128.Parse("0.0"), "{ \"$numberDecimal\" : \"0.0\" }"),
  141. new TestData<Decimal128>(Decimal128.Parse("0.0005"), "{ \"$numberDecimal\" : \"0.0005\" }"),
  142. new TestData<Decimal128>(Decimal128.Parse("0.5"), "{ \"$numberDecimal\" : \"0.5\" }"),
  143. new TestData<Decimal128>(Decimal128.Parse("1.0"), "{ \"$numberDecimal\" : \"1.0\" }"),
  144. new TestData<Decimal128>(Decimal128.Parse("1.5"), "{ \"$numberDecimal\" : \"1.5\" }"),
  145. new TestData<Decimal128>(Decimal128.Parse("1.5E+40"), "{ \"$numberDecimal\" : \"1.5E+40\" }"),
  146. new TestData<Decimal128>(Decimal128.Parse("1.5E-40"), "{ \"$numberDecimal\" : \"1.5E-40\" }"),
  147. new TestData<Decimal128>(Decimal128.Parse("1234567890.1234568E+123"), "{ \"$numberDecimal\" : \"1.2345678901234568E+132\" }"),
  148. new TestData<Decimal128>(Decimal128.Parse("NaN"), "{ \"$numberDecimal\" : \"NaN\" }"),
  149. new TestData<Decimal128>(Decimal128.Parse("-Infinity"), "{ \"$numberDecimal\" : \"-Infinity\" }"),
  150. new TestData<Decimal128>(Decimal128.Parse("Infinity"), "{ \"$numberDecimal\" : \"Infinity\" }")
  151. };
  152. foreach (var test in tests)
  153. {
  154. #pragma warning disable 618
  155. var json = new BsonDecimal128(test.Value).ToJson(new JsonWriterSettings { OutputMode = JsonOutputMode.Strict });
  156. #pragma warning restore 618
  157. Assert.Equal(test.Expected, json);
  158. Assert.Equal(test.Value, BsonSerializer.Deserialize<Decimal128>(json));
  159. }
  160. }
  161. [Fact]
  162. public void TestDouble()
  163. {
  164. var tests = new TestData<double>[]
  165. {
  166. new TestData<double>(0.0, "0.0"),
  167. new TestData<double>(0.0005, "0.00050000000000000001"),
  168. new TestData<double>(0.5, "0.5"),
  169. new TestData<double>(1.0, "1.0"),
  170. new TestData<double>(1.5, "1.5"),
  171. new TestData<double>(1.5E+40, "1.5000000000000001E+40"),
  172. new TestData<double>(1.5E-40, "1.5000000000000001E-40"),
  173. new TestData<double>(1234567890.1234568E+123, "1.2345678901234568E+132"),
  174. new TestData<double>(double.Epsilon, "4.9406564584124654E-324"),
  175. new TestData<double>(double.MaxValue, "1.7976931348623157E+308"),
  176. new TestData<double>(double.MinValue, "-1.7976931348623157E+308"),
  177. new TestData<double>(-0.0005, "-0.00050000000000000001"),
  178. new TestData<double>(-0.5, "-0.5"),
  179. new TestData<double>(-1.0, "-1.0"),
  180. new TestData<double>(-1.5, "-1.5"),
  181. new TestData<double>(-1.5E+40, "-1.5000000000000001E+40"),
  182. new TestData<double>(-1.5E-40, "-1.5000000000000001E-40"),
  183. new TestData<double>(-1234567890.1234568E+123, "-1.2345678901234568E+132"),
  184. new TestData<double>(-double.Epsilon, "-4.9406564584124654E-324"),
  185. new TestData<double>(double.NaN, "NaN"),
  186. new TestData<double>(double.NegativeInfinity, "-Infinity"),
  187. new TestData<double>(double.PositiveInfinity, "Infinity")
  188. };
  189. foreach (var test in tests)
  190. {
  191. var json = test.Value.ToJson();
  192. Assert.Equal(test.Expected, json);
  193. Assert.Equal(test.Value, BsonSerializer.Deserialize<double>(json));
  194. }
  195. }
  196. [SkippableFact]
  197. public void TestDoubleRoundTripOn64BitProcess()
  198. {
  199. RequireProcess.Check().Bits(64);
  200. var value = 0.6822871999174; // see: https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx#RFormatString
  201. var json = value.ToJson();
  202. var rehydrated = BsonSerializer.Deserialize<double>(json);
  203. rehydrated.Should().Be(value);
  204. }
  205. [Fact]
  206. public void TestInt64Shell()
  207. {
  208. var tests = new TestData<long>[]
  209. {
  210. new TestData<long>(long.MinValue, "NumberLong(\"-9223372036854775808\")"),
  211. new TestData<long>(int.MinValue - 1L, "NumberLong(\"-2147483649\")"),
  212. new TestData<long>(int.MinValue, "NumberLong(-2147483648)"),
  213. new TestData<long>(0, "NumberLong(0)"),
  214. new TestData<long>(int.MaxValue, "NumberLong(2147483647)"),
  215. new TestData<long>(int.MaxValue + 1L, "NumberLong(\"2147483648\")"),
  216. new TestData<long>(long.MaxValue, "NumberLong(\"9223372036854775807\")")
  217. };
  218. foreach (var test in tests)
  219. {
  220. var json = test.Value.ToJson();
  221. Assert.Equal(test.Expected, json);
  222. Assert.Equal(test.Value, BsonSerializer.Deserialize<long>(json));
  223. }
  224. }
  225. [Fact]
  226. public void TestInt64Strict()
  227. {
  228. var tests = new TestData<long>[]
  229. {
  230. new TestData<long>(long.MinValue, "-9223372036854775808"),
  231. new TestData<long>(int.MinValue - 1L, "-2147483649"),
  232. new TestData<long>(int.MinValue, "-2147483648"),
  233. new TestData<long>(0, "0"),
  234. new TestData<long>(int.MaxValue, "2147483647"),
  235. new TestData<long>(int.MaxValue + 1L, "2147483648"),
  236. new TestData<long>(long.MaxValue, "9223372036854775807")
  237. };
  238. #pragma warning disable 618
  239. var jsonSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
  240. #pragma warning restore 618
  241. foreach (var test in tests)
  242. {
  243. var json = test.Value.ToJson(jsonSettings);
  244. Assert.Equal(test.Expected, json);
  245. Assert.Equal(test.Value, BsonSerializer.Deserialize<long>(json));
  246. }
  247. }
  248. [Fact]
  249. public void TestEmbeddedDocument()
  250. {
  251. BsonDocument document = new BsonDocument
  252. {
  253. { "doc", new BsonDocument { { "a", 1 }, { "b", 2 } } }
  254. };
  255. string json = document.ToJson();
  256. string expected = "{ \"doc\" : { \"a\" : 1, \"b\" : 2 } }";
  257. Assert.Equal(expected, json);
  258. }
  259. [Fact]
  260. public void TestIndentedEmbeddedDocument()
  261. {
  262. BsonDocument document = new BsonDocument
  263. {
  264. { "doc", new BsonDocument { { "a", 1 }, { "b", 2 } } }
  265. };
  266. var settings = new JsonWriterSettings { Indent = true };
  267. string json = document.ToJson(settings);
  268. string expected = "{\r\n \"doc\" : {\r\n \"a\" : 1,\r\n \"b\" : 2\r\n }\r\n}";
  269. Assert.Equal(expected, json);
  270. }
  271. [Fact]
  272. public void TestArray()
  273. {
  274. BsonDocument document = new BsonDocument
  275. {
  276. { "array", new BsonArray { 1, 2, 3 } }
  277. };
  278. string json = document.ToJson();
  279. string expected = "{ \"array\" : [1, 2, 3] }";
  280. Assert.Equal(expected, json);
  281. }
  282. [Theory]
  283. [ParameterAttributeData]
  284. [ResetGuidModeAfterTest]
  285. public void TestBinaryShell(
  286. [ClassValues(typeof(GuidModeValues))] GuidMode mode)
  287. {
  288. mode.Set();
  289. #pragma warning disable 618
  290. var guid = Guid.Parse("00112233-4455-6677-8899-aabbccddeeff");
  291. var tests = new List<TestData<BsonBinaryData>>
  292. {
  293. new TestData<BsonBinaryData>(new byte[] { }, "new BinData(0, \"\")"),
  294. new TestData<BsonBinaryData>(new byte[] { 1 }, "new BinData(0, \"AQ==\")"),
  295. new TestData<BsonBinaryData>(new byte[] { 1, 2 }, "new BinData(0, \"AQI=\")"),
  296. new TestData<BsonBinaryData>(new byte[] { 1, 2, 3 }, "new BinData(0, \"AQID\")")
  297. };
  298. if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2 && BsonDefaults.GuidRepresentation != GuidRepresentation.Unspecified)
  299. {
  300. string expectedGuidJson;
  301. switch (BsonDefaults.GuidRepresentation)
  302. {
  303. case GuidRepresentation.CSharpLegacy: expectedGuidJson = "CSUUID(\"00112233-4455-6677-8899-aabbccddeeff\")"; break;
  304. case GuidRepresentation.JavaLegacy: expectedGuidJson = "JUUID(\"00112233-4455-6677-8899-aabbccddeeff\")"; break;
  305. case GuidRepresentation.PythonLegacy: expectedGuidJson = "PYUUID(\"00112233-4455-6677-8899-aabbccddeeff\")"; break;
  306. case GuidRepresentation.Standard: expectedGuidJson = "UUID(\"00112233-4455-6677-8899-aabbccddeeff\")"; break;
  307. default: throw new Exception("Invalid GuidRepresentation.");
  308. }
  309. tests.Add(new TestData<BsonBinaryData>(guid, expectedGuidJson));
  310. }
  311. foreach (var test in tests)
  312. {
  313. var json = test.Value.ToJson(new JsonWriterSettings());
  314. Assert.Equal(test.Expected, json);
  315. Assert.Equal(test.Value, BsonSerializer.Deserialize<BsonBinaryData>(json));
  316. }
  317. #pragma warning restore 618
  318. }
  319. [Theory]
  320. [ParameterAttributeData]
  321. [ResetGuidModeAfterTest]
  322. public void TestBinaryStrict(
  323. [ClassValues(typeof(GuidModeValues))] GuidMode mode)
  324. {
  325. mode.Set();
  326. #pragma warning disable 618
  327. var guid = Guid.Parse("00112233-4455-6677-8899-aabbccddeeff");
  328. var tests = new List<TestData<BsonBinaryData>>
  329. {
  330. new TestData<BsonBinaryData>(new byte[] { }, "{ \"$binary\" : \"\", \"$type\" : \"00\" }"),
  331. new TestData<BsonBinaryData>(new byte[] { 1 }, "{ \"$binary\" : \"AQ==\", \"$type\" : \"00\" }"),
  332. new TestData<BsonBinaryData>(new byte[] { 1, 2 }, "{ \"$binary\" : \"AQI=\", \"$type\" : \"00\" }"),
  333. new TestData<BsonBinaryData>(new byte[] { 1, 2, 3 }, "{ \"$binary\" : \"AQID\", \"$type\" : \"00\" }")
  334. };
  335. if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2 && BsonDefaults.GuidRepresentation != GuidRepresentation.Unspecified)
  336. {
  337. byte[] expectedBytes;
  338. string expectedSubType;
  339. switch (BsonDefaults.GuidRepresentation)
  340. {
  341. case GuidRepresentation.CSharpLegacy:
  342. case GuidRepresentation.JavaLegacy:
  343. case GuidRepresentation.PythonLegacy:
  344. expectedBytes = GuidConverter.ToBytes(guid, BsonDefaults.GuidRepresentation);
  345. expectedSubType = "03";
  346. break;
  347. case GuidRepresentation.Standard:
  348. expectedBytes = GuidConverter.ToBytes(guid, GuidRepresentation.Standard);
  349. expectedSubType = "04";
  350. break;
  351. default: throw new Exception("Invalid GuidRepresentation.");
  352. }
  353. var expectedBase64 = Convert.ToBase64String(expectedBytes);
  354. var expectedGuidJson = $"{{ \"$binary\" : \"{expectedBase64}\", \"$type\" : \"{expectedSubType}\" }}";
  355. tests.Add(new TestData<BsonBinaryData>(guid, expectedGuidJson));
  356. }
  357. var jsonSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
  358. foreach (var test in tests)
  359. {
  360. var json = test.Value.ToJson(jsonSettings);
  361. Assert.Equal(test.Expected, json);
  362. Assert.Equal(test.Value, BsonSerializer.Deserialize<BsonBinaryData>(new JsonReader(json, new JsonReaderSettings())));
  363. }
  364. #pragma warning restore 618
  365. }
  366. [Fact]
  367. public void TestDateTimeShell()
  368. {
  369. var utcNow = DateTime.UtcNow;
  370. var utcNowTruncated = utcNow.AddTicks(-(utcNow.Ticks % 10000));
  371. var isoDate = string.Format("ISODate(\"{0}\")", utcNowTruncated.ToString("yyyy-MM-ddTHH:mm:ss.FFFZ"));
  372. var tests = new TestData<BsonDateTime>[]
  373. {
  374. new TestData<BsonDateTime>(new BsonDateTime(long.MinValue), "new Date(-9223372036854775808)"),
  375. new TestData<BsonDateTime>(new BsonDateTime(0), "ISODate(\"1970-01-01T00:00:00Z\")"),
  376. new TestData<BsonDateTime>(new BsonDateTime(long.MaxValue), "new Date(9223372036854775807)"),
  377. new TestData<BsonDateTime>(new BsonDateTime(DateTime.MinValue), "ISODate(\"0001-01-01T00:00:00Z\")"),
  378. new TestData<BsonDateTime>(new BsonDateTime(BsonConstants.UnixEpoch), "ISODate(\"1970-01-01T00:00:00Z\")"),
  379. new TestData<BsonDateTime>(new BsonDateTime(utcNowTruncated), isoDate),
  380. new TestData<BsonDateTime>(new BsonDateTime(DateTime.MaxValue), "ISODate(\"9999-12-31T23:59:59.999Z\")"),
  381. };
  382. foreach (var test in tests)
  383. {
  384. var json = test.Value.ToJson();
  385. Assert.Equal(test.Expected, json);
  386. Assert.Equal(test.Value, BsonSerializer.Deserialize<BsonDateTime>(json));
  387. }
  388. }
  389. [Fact]
  390. public void TestDateTimeStrict()
  391. {
  392. var utcNow = DateTime.UtcNow;
  393. var utcNowTruncated = utcNow.AddTicks(-(utcNow.Ticks % 10000));
  394. var ms = BsonUtils.ToMillisecondsSinceEpoch(utcNowTruncated);
  395. var strictDate = string.Format("{{ \"$date\" : {0} }}", ms);
  396. var tests = new TestData<BsonDateTime>[]
  397. {
  398. new TestData<BsonDateTime>(new BsonDateTime(long.MinValue), "{ \"$date\" : -9223372036854775808 }"),
  399. new TestData<BsonDateTime>(new BsonDateTime(0), "{ \"$date\" : 0 }"),
  400. new TestData<BsonDateTime>(new BsonDateTime(long.MaxValue), "{ \"$date\" : 9223372036854775807 }"),
  401. new TestData<BsonDateTime>(new BsonDateTime(DateTime.MinValue), "{ \"$date\" : -62135596800000 }"),
  402. new TestData<BsonDateTime>(new BsonDateTime(BsonConstants.UnixEpoch), "{ \"$date\" : 0 }"),
  403. new TestData<BsonDateTime>(new BsonDateTime(utcNowTruncated), strictDate),
  404. new TestData<BsonDateTime>(new BsonDateTime(DateTime.MaxValue), "{ \"$date\" : 253402300799999 }"),
  405. };
  406. #pragma warning disable 618
  407. var jsonSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
  408. #pragma warning restore 618
  409. foreach (var test in tests)
  410. {
  411. var json = test.Value.ToJson(jsonSettings);
  412. Assert.Equal(test.Expected, json);
  413. Assert.Equal(test.Value, BsonSerializer.Deserialize<BsonDateTime>(json));
  414. }
  415. }
  416. [Fact]
  417. public void TestJavaScript()
  418. {
  419. var document = new BsonDocument
  420. {
  421. { "f", new BsonJavaScript("function f() { return 1; }") }
  422. };
  423. string expected = "{ \"f\" : { \"$code\" : \"function f() { return 1; }\" } }";
  424. string actual = document.ToJson();
  425. Assert.Equal(expected, actual);
  426. }
  427. [Fact]
  428. public void TestJavaScriptWithScope()
  429. {
  430. var document = new BsonDocument
  431. {
  432. { "f", new BsonJavaScriptWithScope("function f() { return n; }", new BsonDocument("n", 1)) }
  433. };
  434. string expected = "{ \"f\" : { \"$code\" : \"function f() { return n; }\", \"$scope\" : { \"n\" : 1 } } }";
  435. string actual = document.ToJson();
  436. Assert.Equal(expected, actual);
  437. }
  438. [Theory]
  439. [ParameterAttributeData]
  440. [ResetGuidModeAfterTest]
  441. public void TestGuid(
  442. [ClassValues(typeof(GuidModeValues))] GuidMode mode)
  443. {
  444. mode.Set();
  445. #pragma warning disable 618, 1062
  446. if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2 && BsonDefaults.GuidRepresentation == GuidRepresentation.Unspecified ||
  447. BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V3)
  448. {
  449. var exception = Record.Exception(() => new BsonDocument("guid", new Guid("00112233445566778899aabbccddeeff")));
  450. exception.Should().BeOfType<InvalidOperationException>();
  451. }
  452. else
  453. {
  454. var document = new BsonDocument
  455. {
  456. { "guid", new Guid("00112233445566778899aabbccddeeff") }
  457. };
  458. string expected;
  459. var guidRepresentation = BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2 ? BsonDefaults.GuidRepresentation : GuidRepresentation.Unspecified;
  460. switch (guidRepresentation)
  461. {
  462. case GuidRepresentation.CSharpLegacy: expected = "{ \"guid\" : CSUUID(\"00112233-4455-6677-8899-aabbccddeeff\") }"; break;
  463. case GuidRepresentation.JavaLegacy: expected = "{ \"guid\" : JUUID(\"00112233-4455-6677-8899-aabbccddeeff\") }"; break;
  464. case GuidRepresentation.PythonLegacy: expected = "{ \"guid\" : PYUUID(\"00112233-4455-6677-8899-aabbccddeeff\") }"; break;
  465. case GuidRepresentation.Standard: expected = "{ \"guid\" : UUID(\"00112233-4455-6677-8899-aabbccddeeff\") }"; break;
  466. default: throw new Exception("Unexpected GuidRepresentation.");
  467. }
  468. string actual = document.ToJson(new JsonWriterSettings());
  469. Assert.Equal(expected, actual);
  470. }
  471. #pragma warning restore 618, 1062
  472. }
  473. [Fact]
  474. public void TestMaxKey()
  475. {
  476. var document = new BsonDocument
  477. {
  478. { "maxkey", BsonMaxKey.Value }
  479. };
  480. string expected = "{ \"maxkey\" : MaxKey }";
  481. string actual = document.ToJson();
  482. Assert.Equal(expected, actual);
  483. }
  484. [Fact]
  485. public void TestMinKey()
  486. {
  487. var document = new BsonDocument
  488. {
  489. { "minkey", BsonMinKey.Value }
  490. };
  491. string expected = "{ \"minkey\" : MinKey }";
  492. string actual = document.ToJson();
  493. Assert.Equal(expected, actual);
  494. }
  495. [Fact]
  496. public void TestNull()
  497. {
  498. var document = new BsonDocument
  499. {
  500. { "null", BsonNull.Value }
  501. };
  502. string expected = "{ \"null\" : null }";
  503. string actual = document.ToJson();
  504. Assert.Equal(expected, actual);
  505. }
  506. [Fact]
  507. public void TestObjectIdShell()
  508. {
  509. var objectId = new ObjectId("4d0ce088e447ad08b4721a37");
  510. var json = objectId.ToJson();
  511. var expected = "ObjectId(\"4d0ce088e447ad08b4721a37\")";
  512. Assert.Equal(expected, json);
  513. Assert.Equal(objectId, BsonSerializer.Deserialize<ObjectId>(json));
  514. }
  515. [Fact]
  516. public void TestObjectIdStrict()
  517. {
  518. var objectId = new ObjectId("4d0ce088e447ad08b4721a37");
  519. #pragma warning disable 618
  520. var jsonSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
  521. #pragma warning restore 618
  522. var json = objectId.ToJson(jsonSettings);
  523. var expected = "{ \"$oid\" : \"4d0ce088e447ad08b4721a37\" }";
  524. Assert.Equal(expected, json);
  525. Assert.Equal(objectId, BsonSerializer.Deserialize<ObjectId>(json));
  526. }
  527. [Fact]
  528. public void TestRegularExpressionShell()
  529. {
  530. var tests = new TestData<BsonRegularExpression>[]
  531. {
  532. new TestData<BsonRegularExpression>(new BsonRegularExpression(""), "/(?:)/"),
  533. new TestData<BsonRegularExpression>(new BsonRegularExpression("a"), "/a/"),
  534. new TestData<BsonRegularExpression>(new BsonRegularExpression("a/b"), "/a\\/b/"),
  535. new TestData<BsonRegularExpression>(new BsonRegularExpression("a\\b"), "/a\\b/"),
  536. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "i"), "/a/i"),
  537. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "m"), "/a/m"),
  538. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "x"), "/a/x"),
  539. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "s"), "/a/s"),
  540. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "imxs"), "/a/imsx"),
  541. };
  542. foreach (var test in tests)
  543. {
  544. var json = test.Value.ToJson();
  545. Assert.Equal(test.Expected, json);
  546. Assert.Equal(test.Value, BsonSerializer.Deserialize<BsonRegularExpression>(json));
  547. }
  548. }
  549. [Fact]
  550. public void TestRegularExpressionStrict()
  551. {
  552. var tests = new TestData<BsonRegularExpression>[]
  553. {
  554. new TestData<BsonRegularExpression>(new BsonRegularExpression(""), "{ \"$regex\" : \"\", \"$options\" : \"\" }"),
  555. new TestData<BsonRegularExpression>(new BsonRegularExpression("a"), "{ \"$regex\" : \"a\", \"$options\" : \"\" }"),
  556. new TestData<BsonRegularExpression>(new BsonRegularExpression("a/b"), "{ \"$regex\" : \"a/b\", \"$options\" : \"\" }"),
  557. new TestData<BsonRegularExpression>(new BsonRegularExpression("a\\b"), "{ \"$regex\" : \"a\\\\b\", \"$options\" : \"\" }"),
  558. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "i"), "{ \"$regex\" : \"a\", \"$options\" : \"i\" }"),
  559. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "m"), "{ \"$regex\" : \"a\", \"$options\" : \"m\" }"),
  560. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "x"), "{ \"$regex\" : \"a\", \"$options\" : \"x\" }"),
  561. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "s"), "{ \"$regex\" : \"a\", \"$options\" : \"s\" }"),
  562. new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "imxs"), "{ \"$regex\" : \"a\", \"$options\" : \"imsx\" }"),
  563. };
  564. #pragma warning disable 618
  565. var jsonSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
  566. #pragma warning restore 618
  567. foreach (var test in tests)
  568. {
  569. var json = test.Value.ToJson(jsonSettings);
  570. Assert.Equal(test.Expected, json);
  571. Assert.Equal(test.Value, BsonSerializer.Deserialize<BsonRegularExpression>(json));
  572. }
  573. }
  574. [Fact]
  575. public void TestString()
  576. {
  577. var tests = new TestData<string>[]
  578. {
  579. new TestData<string>(null, "null"),
  580. new TestData<string>("", "\"\""),
  581. new TestData<string>(" ", "\" \""),
  582. new TestData<string>("a", "\"a\""),
  583. new TestData<string>("ab", "\"ab\""),
  584. new TestData<string>("abc", "\"abc\""),
  585. new TestData<string>("abc\0def", "\"abc\\u0000def\""),
  586. new TestData<string>("\'", "\"'\""),
  587. new TestData<string>("\"", "\"\\\"\""),
  588. new TestData<string>("\0", "\"\\u0000\""),
  589. new TestData<string>("\a", "\"\\u0007\""),
  590. new TestData<string>("\b", "\"\\b\""),
  591. new TestData<string>("\f", "\"\\f\""),
  592. new TestData<string>("\n", "\"\\n\""),
  593. new TestData<string>("\r", "\"\\r\""),
  594. new TestData<string>("\t", "\"\\t\""),
  595. new TestData<string>("\v", "\"\\u000b\""),
  596. new TestData<string>("\u0080", "\"\\u0080\""),
  597. new TestData<string>("\u0080\u0081", "\"\\u0080\\u0081\""),
  598. new TestData<string>("\u0080\u0081\u0082", "\"\\u0080\\u0081\\u0082\"")
  599. };
  600. foreach (var test in tests)
  601. {
  602. var json = test.Value.ToJson();
  603. Assert.Equal(test.Expected, json);
  604. Assert.Equal(test.Value, BsonSerializer.Deserialize<string>(json));
  605. }
  606. }
  607. [Fact]
  608. public void TestSymbol()
  609. {
  610. var document = new BsonDocument
  611. {
  612. { "symbol", BsonSymbolTable.Lookup("name") }
  613. };
  614. string expected = "{ \"symbol\" : { \"$symbol\" : \"name\" } }";
  615. string actual = document.ToJson();
  616. Assert.Equal(expected, actual);
  617. }
  618. [Fact]
  619. public void TestTimestamp()
  620. {
  621. var document = new BsonDocument
  622. {
  623. { "timestamp", new BsonTimestamp(1, 2) }
  624. };
  625. string expected = "{ \"timestamp\" : Timestamp(1, 2) }";
  626. string actual = document.ToJson();
  627. Assert.Equal(expected, actual);
  628. }
  629. [Fact]
  630. public void TestUndefined()
  631. {
  632. var document = new BsonDocument
  633. {
  634. { "undefined", BsonUndefined.Value }
  635. };
  636. string expected = "{ \"undefined\" : undefined }";
  637. string actual = document.ToJson();
  638. Assert.Equal(expected, actual);
  639. }
  640. [Fact]
  641. public void TestUtf16BigEndian()
  642. {
  643. var encoding = new UnicodeEncoding(true, true, true);
  644. using (var memoryStream = new MemoryStream())
  645. {
  646. using (var streamWriter = new StreamWriter(memoryStream, encoding))
  647. using (var jsonWriter = new JsonWriter(streamWriter, JsonWriterSettings.Defaults))
  648. {
  649. var document = new BsonDocument("x", 1);
  650. BsonSerializer.Serialize(jsonWriter, document);
  651. }
  652. var bytes = memoryStream.ToArray();
  653. var bom = new byte[] { 0xfe, 0xff };
  654. var expected = bom.Concat(encoding.GetBytes("{ \"x\" : 1 }")).ToArray();
  655. Assert.Equal(expected, bytes);
  656. }
  657. }
  658. [Fact]
  659. public void TestUtf16LittleEndian()
  660. {
  661. var encoding = new UnicodeEncoding(false, true, true);
  662. using (var memoryStream = new MemoryStream())
  663. {
  664. using (var streamWriter = new StreamWriter(memoryStream, encoding))
  665. using (var jsonWriter = new JsonWriter(streamWriter, JsonWriterSettings.Defaults))
  666. {
  667. var document = new BsonDocument("x", 1);
  668. BsonSerializer.Serialize(jsonWriter, document);
  669. }
  670. var bytes = memoryStream.ToArray();
  671. var bom = new byte[] { 0xff, 0xfe };
  672. var expected = bom.Concat(encoding.GetBytes("{ \"x\" : 1 }")).ToArray();
  673. Assert.Equal(expected, bytes);
  674. }
  675. }
  676. [Fact]
  677. public void TestUtf8()
  678. {
  679. var encoding = new UTF8Encoding(true, true); // emit UTF8 identifier
  680. using (var memoryStream = new MemoryStream())
  681. {
  682. using (var streamWriter = new StreamWriter(memoryStream, encoding))
  683. using (var jsonWriter = new JsonWriter(streamWriter, JsonWriterSettings.Defaults))
  684. {
  685. var document = new BsonDocument("x", 1);
  686. BsonSerializer.Serialize(jsonWriter, document);
  687. }
  688. var bytes = memoryStream.ToArray();
  689. var bom = new byte[] { 0xef, 0xbb, 0xbf };
  690. var expected = bom.Concat(encoding.GetBytes("{ \"x\" : 1 }")).ToArray();
  691. Assert.Equal(expected, bytes);
  692. }
  693. }
  694. }
  695. }