diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs index 0b57ad3aa01..ae45c85f6a1 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs @@ -68,6 +68,22 @@ public BsonDocument(BsonElement element) Add(element); } + /// + /// Initializes a new instance of the BsonDocument by coping elements from another BsonDocument. + /// + /// The document whose elements will be copied + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public BsonDocument(BsonDocument document) + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + + _allowDuplicateNames = document.AllowDuplicateNames; + AddRange(document); + } + /// /// Initializes a new instance of the BsonDocument class and adds new elements from a dictionary of key/value pairs. /// @@ -733,7 +749,7 @@ public virtual void Clear() /// A shallow clone of the document. public override BsonValue Clone() { - BsonDocument clone = new BsonDocument(); + BsonDocument clone = new BsonDocument() { AllowDuplicateNames = AllowDuplicateNames }; foreach (BsonElement element in _elements) { clone.Add(element.Clone()); @@ -745,7 +761,7 @@ public override BsonValue Clone() /// Compares this document to another document. /// /// The other document. - /// A 32-bit signed integer that indicates whether this document is less than, equal to, or greather than the other. + /// A 32-bit signed integer that indicates whether this document is less than, equal to, or greater than the other. public virtual int CompareTo(BsonDocument rhs) { if (rhs == null) { return 1; } @@ -776,7 +792,7 @@ public virtual int CompareTo(BsonDocument rhs) /// Compares the BsonDocument to another BsonValue. /// /// The other BsonValue. - /// A 32-bit signed integer that indicates whether this BsonDocument is less than, equal to, or greather than the other BsonValue. + /// A 32-bit signed integer that indicates whether this BsonDocument is less than, equal to, or greater than the other BsonValue. public override int CompareTo(BsonValue other) { if (other == null) { return 1; } @@ -818,7 +834,7 @@ public virtual bool ContainsValue(BsonValue value) /// A deep clone of the document. public override BsonValue DeepClone() { - BsonDocument clone = new BsonDocument(); + BsonDocument clone = new BsonDocument() { AllowDuplicateNames = AllowDuplicateNames }; foreach (BsonElement element in _elements) { clone.Add(element.DeepClone()); diff --git a/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentTests.cs b/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentTests.cs index 9489c93a7e6..bf73ded3e68 100644 --- a/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentTests.cs +++ b/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentTests.cs @@ -137,6 +137,21 @@ public void TestClone() var clone = (BsonDocument)document.Clone(); Assert.Equal(clone, document); Assert.Same(clone["d"], document["d"]); + Assert.False(clone.AllowDuplicateNames); + } + + [Fact] + public void TestClone_with_duplicate_elements() + { + var document = new BsonDocument(allowDuplicateNames: true) + { + { "d", new BsonDocument("x", 1) }, + { "d", new BsonDocument("x", 2) }, + }; + + var clone = (BsonDocument)document.Clone(); + clone.Should().Be(document); + clone.AllowDuplicateNames.Should().BeTrue(); } [Fact] @@ -153,6 +168,7 @@ public void TestConstructorElement() { var element = new BsonElement("x", 1); var document = new BsonDocument(element); + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -168,6 +184,7 @@ public void TestConstructorElements() new BsonElement("y", 2) }; var document = new BsonDocument((IEnumerable)elements); + Assert.False(document.AllowDuplicateNames); Assert.Equal(2, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(2, document["y"].AsInt32); @@ -184,6 +201,7 @@ public void TestConstructorElementsDocument() { var originalDocument = new BsonDocument { { "x", 1 }, { "y", 2 } }; var document = new BsonDocument(originalDocument); + Assert.False(document.AllowDuplicateNames); Assert.Equal(2, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(2, document["y"].AsInt32); @@ -195,6 +213,20 @@ public void TestConstructorElementsDocument() Assert.Same(originalDocument.GetElement("y").Value, document.GetElement("y").Value); } + [Fact] + public void TestConstructorElementsDocumentDuplicateNames() + { + var documentA = new BsonDocument(allowDuplicateNames: true) + { + { "x", 1 }, + { "x", 2 }, + }; + var documentB = new BsonDocument(documentA); + + documentB.AllowDuplicateNames.Should().BeTrue(); + documentB.Elements.ShouldAllBeEquivalentTo(documentA.Elements); + } + [Fact] public void TestConstructorElementsParams() { @@ -203,6 +235,8 @@ public void TestConstructorElementsParams() #pragma warning disable 618 var document = new BsonDocument(element1, element2); #pragma warning restore + Assert.False(document.AllowDuplicateNames); + Assert.Equal(2, document.ElementCount); Assert.Equal(2, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(2, document["y"].AsInt32); @@ -219,6 +253,7 @@ public void TestConstructorDictionaryGeneric() { var dictionary = new Dictionary { { "x", 1 } }; var document = new BsonDocument(dictionary); + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -233,6 +268,7 @@ public void TestConstructorDictionaryGenericWithKeys() #pragma warning disable 618 var document = new BsonDocument(dictionary, keys); #pragma warning restore + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -244,6 +280,7 @@ public void TestConstructorIDictionary() { var hashtable = (IDictionary)new Hashtable { { "x", 1 } }; var document = new BsonDocument(hashtable); + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -255,6 +292,7 @@ public void TestConstructorIDictionaryGeneric() { var dictionary = (IDictionary)new Dictionary { { "x", 1 } }; var document = new BsonDocument(dictionary); + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -269,6 +307,7 @@ public void TestConstructorIDictionaryGenericWithKeys() #pragma warning disable 618 var document = new BsonDocument(dictionary, keys); #pragma warning restore + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -283,6 +322,7 @@ public void TestConstructorIDictionaryWithKeys() #pragma warning disable 618 var document = new BsonDocument(hashtable, keys); #pragma warning restore + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -293,6 +333,7 @@ public void TestConstructorIDictionaryWithKeys() public void TestConstructorNameValue() { var document = new BsonDocument("x", 1); + Assert.False(document.AllowDuplicateNames); Assert.Equal(1, document.ElementCount); Assert.Equal(1, document["x"].AsInt32); Assert.Equal(true, document.Contains("x")); @@ -374,6 +415,25 @@ public void TestDeepClone() var clone = (BsonDocument)document.DeepClone(); Assert.Equal(clone, document); Assert.NotSame(clone["d"], document["d"]); + Assert.False(((BsonDocument)document["d"]).AllowDuplicateNames); + } + + [Fact] + public void TestDeepClone_with_duplicate_elements() + { + var documentWithDuplicateElements = new BsonDocument(allowDuplicateNames: true) + { + { "x", 1 }, + { "x", 2 } + }; + + var document = new BsonDocument("d", documentWithDuplicateElements); + var clone = (BsonDocument)document.DeepClone(); + var clonedNestedDocument = (BsonDocument)clone["d"]; + + clonedNestedDocument.Should().NotBeSameAs((BsonDocument)document["d"]); + clonedNestedDocument.Elements.ShouldAllBeEquivalentTo(documentWithDuplicateElements.Elements); + clonedNestedDocument.AllowDuplicateNames.Should().BeTrue(); } [Fact]