PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/MongoDB.Bson.Tests/Serialization/Serializers/ObjectSerializerTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 582 lines | 497 code | 69 blank | 16 comment | 21 complexity | acd81964201d3eb65e194405a0d63ad9 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.Dynamic;
  17. using System.IO;
  18. using System.Linq;
  19. using FluentAssertions;
  20. using MongoDB.Bson.IO;
  21. using MongoDB.Bson.Serialization;
  22. using MongoDB.Bson.Serialization.Conventions;
  23. using MongoDB.Bson.Serialization.Serializers;
  24. using MongoDB.Bson.TestHelpers;
  25. using MongoDB.Bson.TestHelpers.XunitExtensions;
  26. using Moq;
  27. using Xunit;
  28. namespace MongoDB.Bson.Tests.Serialization
  29. {
  30. public class ObjectSerializerTests
  31. {
  32. public class C
  33. {
  34. public object Obj;
  35. }
  36. public class D
  37. {
  38. public object[] Array;
  39. }
  40. [Fact]
  41. public void TestArray()
  42. {
  43. var d = new D
  44. {
  45. Array = new object[]
  46. {
  47. (Decimal128)1.5M,
  48. 1.5,
  49. "abc",
  50. new object(),
  51. true,
  52. BsonConstants.UnixEpoch,
  53. null,
  54. 123,
  55. 123L
  56. }
  57. };
  58. var json = d.ToJson();
  59. var expected = "{ 'Array' : [#A] }";
  60. expected = expected.Replace("#A",
  61. string.Join(", ", new string[]
  62. {
  63. "NumberDecimal('1.5')",
  64. "1.5",
  65. "'abc'",
  66. "{ }",
  67. "true",
  68. "ISODate('1970-01-01T00:00:00Z')",
  69. "null",
  70. "123",
  71. "NumberLong(123)"
  72. }));
  73. expected = expected.Replace("'", "\"");
  74. Assert.Equal(expected, json);
  75. var bson = d.ToBson();
  76. var rehydrated = BsonSerializer.Deserialize<D>(bson);
  77. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  78. }
  79. [Fact]
  80. public void TestBoolean()
  81. {
  82. var c = new C { Obj = true };
  83. var json = c.ToJson();
  84. var expected = "{ 'Obj' : true }".Replace("'", "\"");
  85. Assert.Equal(expected, json);
  86. var bson = c.ToBson();
  87. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  88. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  89. }
  90. [Fact]
  91. public void TestDateTime()
  92. {
  93. var c = new C { Obj = BsonConstants.UnixEpoch };
  94. var json = c.ToJson();
  95. var expected = "{ 'Obj' : ISODate('1970-01-01T00:00:00Z') }".Replace("'", "\"");
  96. Assert.Equal(expected, json);
  97. var bson = c.ToBson();
  98. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  99. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  100. }
  101. [Fact]
  102. public void TestDecimal128()
  103. {
  104. var c = new C { Obj = (Decimal128)1.5M };
  105. var json = c.ToJson();
  106. var expected = "{ 'Obj' : NumberDecimal('1.5') }".Replace("'", "\"");
  107. Assert.Equal(expected, json);
  108. var bson = c.ToBson();
  109. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  110. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  111. }
  112. [Fact]
  113. public void TestDouble()
  114. {
  115. var c = new C { Obj = 1.5 };
  116. var json = c.ToJson();
  117. var expected = "{ 'Obj' : 1.5 }".Replace("'", "\"");
  118. Assert.Equal(expected, json);
  119. var bson = c.ToBson();
  120. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  121. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  122. }
  123. [Fact]
  124. public void TestInt32()
  125. {
  126. var c = new C { Obj = 123 };
  127. var json = c.ToJson();
  128. var expected = "{ 'Obj' : 123 }".Replace("'", "\"");
  129. Assert.Equal(expected, json);
  130. var bson = c.ToBson();
  131. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  132. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  133. }
  134. [Fact]
  135. public void TestInt64()
  136. {
  137. var c = new C { Obj = 123L };
  138. var json = c.ToJson();
  139. var expected = "{ 'Obj' : NumberLong(123) }".Replace("'", "\"");
  140. Assert.Equal(expected, json);
  141. var bson = c.ToBson();
  142. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  143. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  144. }
  145. [Theory]
  146. [InlineData("{ Obj : { _v : \"01020304-0506-0708-090a-0b0c0d0e0f10\" } }")]
  147. public void TestMissingDiscriminator(string json)
  148. {
  149. var result = BsonSerializer.Deserialize<C>(json);
  150. Assert.IsType<ExpandoObject>(result.Obj);
  151. }
  152. [Theory]
  153. [InlineData("{ Obj : { _t : \"System.Guid\" } }")]
  154. public void TestMissingValue(string json)
  155. {
  156. Assert.Throws<FormatException>(() => BsonSerializer.Deserialize<C>(json));
  157. }
  158. [Fact]
  159. public void TestNull()
  160. {
  161. var c = new C { Obj = null };
  162. var json = c.ToJson();
  163. var expected = "{ 'Obj' : null }".Replace("'", "\"");
  164. Assert.Equal(expected, json);
  165. var bson = c.ToBson();
  166. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  167. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  168. }
  169. [Fact]
  170. public void TestObject()
  171. {
  172. var c = new C { Obj = new object() };
  173. var json = c.ToJson();
  174. var expected = "{ 'Obj' : { } }".Replace("'", "\"");
  175. Assert.Equal(expected, json);
  176. var bson = c.ToBson();
  177. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  178. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  179. }
  180. [Theory]
  181. [InlineData("{ Obj : { _t : \"System.Object[]\", _v : [] } }")]
  182. [InlineData("{ Obj : { _v : [], _t : \"System.Object[]\" } }")]
  183. public void TestOrderOfElementsDoesNotMatter(string json)
  184. {
  185. var result = BsonSerializer.Deserialize<C>(json);
  186. Assert.IsType<object[]>(result.Obj);
  187. }
  188. [Theory]
  189. [InlineData("{ Obj : { _t : \"System.Guid\", _v : \"01020304-0506-0708-090a-0b0c0d0e0f10\" } }", "01020304-0506-0708-090a-0b0c0d0e0f10")]
  190. [InlineData("{ Obj : { _v : \"01020304-0506-0708-090a-0b0c0d0e0f10\", _t : \"System.Guid\" } }", "01020304-0506-0708-090a-0b0c0d0e0f10")]
  191. public void TestOrderOfElementsDoesNotMatter_with_Guids(string json, string expectedGuid)
  192. {
  193. var result = BsonSerializer.Deserialize<C>(json);
  194. Assert.Equal(Guid.Parse(expectedGuid), result.Obj);
  195. }
  196. [Fact]
  197. public void TestString()
  198. {
  199. var c = new C { Obj = "abc" };
  200. var json = c.ToJson();
  201. var expected = "{ 'Obj' : 'abc' }".Replace("'", "\"");
  202. Assert.Equal(expected, json);
  203. var bson = c.ToBson();
  204. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  205. Assert.True(bson.SequenceEqual(rehydrated.ToBson()));
  206. }
  207. [Fact]
  208. public void TestUsesDiscriminatorWhenTypeIsNotABsonPrimitive()
  209. {
  210. var c = new C { Obj = new ExpandoObject() };
  211. var json = c.ToJson(configurator: config => config.IsDynamicType = t => false);
  212. #if NET452
  213. var discriminator = "System.Dynamic.ExpandoObject";
  214. #else
  215. var discriminator = typeof(ExpandoObject).AssemblyQualifiedName;
  216. #endif
  217. var expected = ("{ 'Obj' : { '_t' : '" + discriminator + "', '_v' : { } } }").Replace("'", "\"");
  218. Assert.Equal(expected, json);
  219. var bson = c.ToBson(configurator: config => config.IsDynamicType = t => false);
  220. var rehydrated = BsonSerializer.Deserialize<C>(bson);
  221. Assert.True(bson.SequenceEqual(rehydrated.ToBson(configurator: config => config.IsDynamicType = t => false)));
  222. }
  223. [Fact]
  224. public void TestDoesNotUseDiscriminatorForDynamicTypes()
  225. {
  226. // explicitly setting the IsDynamicType and DynamicDocumentSerializer properties
  227. // in case we change the dynamic defaults in BsonDefaults.
  228. var c = new C { Obj = new ExpandoObject() };
  229. var json = c.ToJson(configurator: b => b.IsDynamicType = t => t == typeof(ExpandoObject));
  230. var expected = "{ 'Obj' : { } }".Replace("'", "\"");
  231. Assert.Equal(expected, json);
  232. var bson = c.ToBson(configurator: b => b.IsDynamicType = t => t == typeof(ExpandoObject));
  233. var rehydrated = BsonSerializer.Deserialize<C>(bson, b => b.DynamicDocumentSerializer = BsonSerializer.LookupSerializer<ExpandoObject>());
  234. Assert.True(bson.SequenceEqual(rehydrated.ToBson(configurator: b => b.IsDynamicType = t => t == typeof(ExpandoObject))));
  235. }
  236. [Fact]
  237. public void constructor_should_initialize_instance()
  238. {
  239. var subject = new ObjectSerializer();
  240. subject._discriminatorConvention().Should().Be(BsonSerializer.LookupDiscriminatorConvention(typeof(object)));
  241. subject._guidRepresentation().Should().Be(GuidRepresentation.Unspecified);
  242. }
  243. [Fact]
  244. public void constructor_with_discriminator_convention_should_initialize_instance()
  245. {
  246. var discriminatorConvention = Mock.Of<IDiscriminatorConvention>();
  247. var subject = new ObjectSerializer(discriminatorConvention);
  248. subject._discriminatorConvention().Should().BeSameAs(discriminatorConvention);
  249. subject._guidRepresentation().Should().Be(GuidRepresentation.Unspecified);
  250. }
  251. [Fact]
  252. public void constructor_with_discriminator_convention_should_throw_when_discriminator_convention_is_null()
  253. {
  254. var exception = Record.Exception(() => new ObjectSerializer(null));
  255. var e = exception.Should().BeOfType<ArgumentNullException>().Subject;
  256. e.ParamName.Should().Be("discriminatorConvention");
  257. }
  258. [Theory]
  259. [ParameterAttributeData]
  260. public void constructor_with_discriminator_convention_and_guid_representation_should_initialize_instance(
  261. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.Standard, GuidRepresentation.Unspecified)] GuidRepresentation guidRepresentation)
  262. {
  263. var discriminatorConvention = Mock.Of<IDiscriminatorConvention>();
  264. var subject = new ObjectSerializer(discriminatorConvention, guidRepresentation);
  265. subject._discriminatorConvention().Should().BeSameAs(discriminatorConvention);
  266. subject._guidRepresentation().Should().Be(guidRepresentation);
  267. }
  268. [Fact]
  269. public void constructor_with_discriminator_convention_and_guid_representation_should_throw_when_discriminator_convention_is_null()
  270. {
  271. var exception = Record.Exception(() => new ObjectSerializer(null, GuidRepresentation.Unspecified));
  272. var e = exception.Should().BeOfType<ArgumentNullException>().Subject;
  273. e.ParamName.Should().Be("discriminatorConvention");
  274. }
  275. [SkippableTheory]
  276. [ParameterAttributeData]
  277. [ResetGuidModeAfterTest]
  278. public void Deserialize_binary_data_should_return_expected_result_when_guid_representation_is_unspecified_and_mode_is_v2(
  279. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard, GuidRepresentation.Unspecified)]
  280. GuidRepresentation defaultGuidRepresentation,
  281. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard, GuidRepresentation.Unspecified)]
  282. GuidRepresentation readerGuidRepresentation)
  283. {
  284. #pragma warning disable 618
  285. var expectedGuidRepresentation = readerGuidRepresentation == GuidRepresentation.Unspecified ? defaultGuidRepresentation : readerGuidRepresentation;
  286. if (expectedGuidRepresentation == GuidRepresentation.Unspecified)
  287. {
  288. throw new SkipException("Skipped because expected GuidRepresentation is Unspecified.");
  289. }
  290. BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V2;
  291. BsonDefaults.GuidRepresentation = defaultGuidRepresentation;
  292. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  293. var subject = new ObjectSerializer(discriminatorConvention, GuidRepresentation.Unspecified);
  294. var bytes = new byte[] { 29, 0, 0, 0, 5, 120, 0, 16, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
  295. var subType = GuidConverter.GetSubType(expectedGuidRepresentation);
  296. bytes[11] = (byte)subType;
  297. var readerSettings = new BsonBinaryReaderSettings();
  298. if (readerGuidRepresentation != GuidRepresentation.Unspecified)
  299. {
  300. readerSettings.GuidRepresentation = readerGuidRepresentation;
  301. }
  302. using (var memoryStream = new MemoryStream(bytes))
  303. using (var reader = new BsonBinaryReader(memoryStream, readerSettings))
  304. {
  305. var context = BsonDeserializationContext.CreateRoot(reader);
  306. reader.ReadStartDocument();
  307. reader.ReadName("x");
  308. var result = subject.Deserialize<object>(context);
  309. var guidBytes = bytes.Skip(12).Take(16).ToArray();
  310. var expectedResult = GuidConverter.FromBytes(guidBytes, expectedGuidRepresentation);
  311. result.Should().Be(expectedResult);
  312. }
  313. #pragma warning restore 618
  314. }
  315. [Theory]
  316. [ParameterAttributeData]
  317. [ResetGuidModeAfterTest]
  318. public void Deserialize_binary_data_should_return_expected_result_when_guid_representation_is_specified(
  319. [ClassValues(typeof(GuidModeValues))]
  320. GuidMode mode,
  321. [Values(-1, GuidRepresentation.Unspecified)]
  322. GuidRepresentation readerGuidRepresentation,
  323. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard)]
  324. GuidRepresentation guidRepresentation)
  325. {
  326. #pragma warning disable 618
  327. mode.Set();
  328. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  329. var subject = new ObjectSerializer(discriminatorConvention, guidRepresentation);
  330. var bytes = new byte[] { 29, 0, 0, 0, 5, 120, 0, 16, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
  331. var subType = GuidConverter.GetSubType(guidRepresentation);
  332. bytes[11] = (byte)subType;
  333. var readerSettings = new BsonBinaryReaderSettings();
  334. if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
  335. {
  336. readerSettings.GuidRepresentation = readerGuidRepresentation == (GuidRepresentation)(-1) ? guidRepresentation : GuidRepresentation.Unspecified;
  337. }
  338. using (var memoryStream = new MemoryStream(bytes))
  339. using (var reader = new BsonBinaryReader(memoryStream, readerSettings))
  340. {
  341. var context = BsonDeserializationContext.CreateRoot(reader);
  342. reader.ReadStartDocument();
  343. reader.ReadName("x");
  344. var result = subject.Deserialize<object>(context);
  345. var guidBytes = bytes.Skip(12).Take(16).ToArray();
  346. var expectedResult = GuidConverter.FromBytes(guidBytes, guidRepresentation);
  347. result.Should().Be(expectedResult);
  348. }
  349. #pragma warning restore 618
  350. }
  351. [Fact]
  352. [ResetGuidModeAfterTest]
  353. public void Deserialize_binary_data_should_throw_when_guid_representation_is_unspecified_and_mode_is_v3()
  354. {
  355. #pragma warning disable 618
  356. BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
  357. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  358. var subject = new ObjectSerializer(discriminatorConvention, GuidRepresentation.Unspecified);
  359. var bytes = new byte[] { 29, 0, 0, 0, 5, 120, 0, 16, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
  360. using (var memoryStream = new MemoryStream(bytes))
  361. using (var reader = new BsonBinaryReader(memoryStream))
  362. {
  363. var context = BsonDeserializationContext.CreateRoot(reader);
  364. reader.ReadStartDocument();
  365. reader.ReadName("x");
  366. var exception = Record.Exception(() => subject.Deserialize<object>(context));
  367. exception.Should().BeOfType<BsonSerializationException>();
  368. }
  369. #pragma warning restore 618
  370. }
  371. [Theory]
  372. [ParameterAttributeData]
  373. [ResetGuidModeAfterTest]
  374. public void Deserialize_binary_data_should_throw_when_guid_representation_is_specified_and_sub_type_is_not_expected_sub_type(
  375. [ClassValues(typeof(GuidModeValues))]
  376. GuidMode mode,
  377. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard)]
  378. GuidRepresentation readerGuidRepresentation,
  379. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard)]
  380. GuidRepresentation guidRepresentation)
  381. {
  382. #pragma warning disable 618
  383. mode.Set();
  384. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  385. var subject = new ObjectSerializer(discriminatorConvention, guidRepresentation);
  386. var bytes = new byte[] { 29, 0, 0, 0, 5, 120, 0, 16, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
  387. var incorrectSubType = guidRepresentation == GuidRepresentation.Standard ? BsonBinarySubType.UuidLegacy : BsonBinarySubType.UuidStandard;
  388. bytes[11] = (byte)incorrectSubType;
  389. var readerSettings = new BsonBinaryReaderSettings();
  390. if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
  391. {
  392. readerSettings.GuidRepresentation = readerGuidRepresentation;
  393. }
  394. using (var memoryStream = new MemoryStream(bytes))
  395. using (var reader = new BsonBinaryReader(memoryStream, readerSettings))
  396. {
  397. var context = BsonDeserializationContext.CreateRoot(reader);
  398. reader.ReadStartDocument();
  399. reader.ReadName("x");
  400. var exception = Record.Exception(() => subject.Deserialize<object>(context));
  401. exception.Should().BeOfType<FormatException>();
  402. }
  403. #pragma warning restore 618
  404. }
  405. [SkippableTheory]
  406. [ParameterAttributeData]
  407. [ResetGuidModeAfterTest]
  408. public void Serialize_guid_should_have_expected_result_when_guid_representation_is_unspecified_and_mode_is_v2(
  409. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard, GuidRepresentation.Unspecified)]
  410. GuidRepresentation defaultGuidRepresentation,
  411. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard, GuidRepresentation.Unspecified)]
  412. GuidRepresentation writerGuidRepresentation)
  413. {
  414. #pragma warning disable 618
  415. var expectedGuidRepresentation = writerGuidRepresentation != GuidRepresentation.Unspecified ? writerGuidRepresentation : defaultGuidRepresentation;
  416. if (expectedGuidRepresentation == GuidRepresentation.Unspecified)
  417. {
  418. throw new SkipException("Test skipped because expectedGuidRepresentation is Unspecified.");
  419. }
  420. BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V2;
  421. BsonDefaults.GuidRepresentation = defaultGuidRepresentation;
  422. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  423. var subject = new ObjectSerializer(discriminatorConvention, GuidRepresentation.Unspecified);
  424. var writerSettings = new BsonBinaryWriterSettings();
  425. if (writerGuidRepresentation != GuidRepresentation.Unspecified)
  426. {
  427. writerSettings.GuidRepresentation = writerGuidRepresentation;
  428. }
  429. using (var memoryStream = new MemoryStream())
  430. using (var writer = new BsonBinaryWriter(memoryStream, writerSettings))
  431. {
  432. var context = BsonSerializationContext.CreateRoot(writer);
  433. var guid = Guid.Parse("01020304-0506-0708-090a-0b0c0d0e0f10");
  434. writer.WriteStartDocument();
  435. writer.WriteName("x");
  436. subject.Serialize(context, guid);
  437. writer.WriteEndDocument();
  438. var bytes = memoryStream.ToArray();
  439. var expectedBytes = new byte[] { 29, 0, 0, 0, 5, 120, 0, 16, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
  440. var expectedSubType = GuidConverter.GetSubType(expectedGuidRepresentation);
  441. var expectedGuidBytes = GuidConverter.ToBytes(guid, expectedGuidRepresentation);
  442. expectedBytes[11] = (byte)expectedSubType;
  443. Array.Copy(expectedGuidBytes, 0, expectedBytes, 12, 16);
  444. bytes.Should().Equal(expectedBytes);
  445. }
  446. #pragma warning restore 618
  447. }
  448. [Theory]
  449. [ParameterAttributeData]
  450. [ResetGuidModeAfterTest]
  451. public void Serialize_guid_should_have_expected_result_when_guid_representation_is_specified(
  452. [ClassValues(typeof(GuidModeValues))]
  453. GuidMode mode,
  454. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard, GuidRepresentation.Unspecified)]
  455. GuidRepresentation writerGuidRepresentation,
  456. [Values(GuidRepresentation.CSharpLegacy, GuidRepresentation.JavaLegacy, GuidRepresentation.PythonLegacy, GuidRepresentation.Standard)]
  457. GuidRepresentation guidRepresentation)
  458. {
  459. #pragma warning disable 618
  460. mode.Set();
  461. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  462. var subject = new ObjectSerializer(discriminatorConvention, guidRepresentation);
  463. var writerSettings = new BsonBinaryWriterSettings();
  464. if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
  465. {
  466. writerSettings.GuidRepresentation = writerGuidRepresentation;
  467. }
  468. using (var memoryStream = new MemoryStream())
  469. using (var writer = new BsonBinaryWriter(memoryStream, writerSettings))
  470. {
  471. var context = BsonSerializationContext.CreateRoot(writer);
  472. var guid = Guid.Parse("01020304-0506-0708-090a-0b0c0d0e0f10");
  473. writer.WriteStartDocument();
  474. writer.WriteName("x");
  475. subject.Serialize(context, guid);
  476. writer.WriteEndDocument();
  477. var bytes = memoryStream.ToArray();
  478. var expectedBytes = new byte[] { 29, 0, 0, 0, 5, 120, 0, 16, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
  479. var expectedSubType = GuidConverter.GetSubType(guidRepresentation);
  480. var expectedGuidBytes = GuidConverter.ToBytes(guid, guidRepresentation);
  481. expectedBytes[11] = (byte)expectedSubType;
  482. Array.Copy(expectedGuidBytes, 0, expectedBytes, 12, 16);
  483. bytes.Should().Equal(expectedBytes);
  484. }
  485. #pragma warning restore 618
  486. }
  487. [Fact]
  488. [ResetGuidModeAfterTest]
  489. public void Serialize_guid_should_throw_when_guid_representation_is_unspecified_and_mode_is_v3()
  490. {
  491. #pragma warning disable 618
  492. BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
  493. var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
  494. var subject = new ObjectSerializer(discriminatorConvention, GuidRepresentation.Unspecified);
  495. using (var memoryStream = new MemoryStream())
  496. using (var writer = new BsonBinaryWriter(memoryStream))
  497. {
  498. var context = BsonSerializationContext.CreateRoot(writer);
  499. var guid = Guid.Parse("01020304-0506-0708-090a-0b0c0d0e0f10");
  500. writer.WriteStartDocument();
  501. writer.WriteName("x");
  502. var exception = Record.Exception(() => subject.Serialize(context, guid));
  503. exception.Should().BeOfType<BsonSerializationException>();
  504. }
  505. #pragma warning restore 618
  506. }
  507. }
  508. internal static class ObjectSerializerReflector
  509. {
  510. public static IDiscriminatorConvention _discriminatorConvention(this ObjectSerializer obj) => (IDiscriminatorConvention)Reflector.GetFieldValue(obj, nameof(_discriminatorConvention));
  511. public static GuidRepresentation _guidRepresentation(this ObjectSerializer obj) => (GuidRepresentation)Reflector.GetFieldValue(obj, nameof(_guidRepresentation));
  512. }
  513. }