Skip to content

Commit 2d20c9b

Browse files
committed
CSHARP-1546: Rephrase invalid BSON type error message.
1 parent a29fb13 commit 2d20c9b

File tree

5 files changed

+261
-21
lines changed

5 files changed

+261
-21
lines changed

src/MongoDB.Bson.Tests/IO/BsonBinaryReaderTests.cs

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2010-2015 MongoDB Inc.
1+
/* Copyright 2010-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -17,10 +17,9 @@
1717
using System.Collections.Generic;
1818
using System.IO;
1919
using System.Linq;
20-
using MongoDB.Bson;
20+
using FluentAssertions;
2121
using MongoDB.Bson.IO;
2222
using MongoDB.Bson.Serialization;
23-
using FluentAssertions;
2423
using NUnit.Framework;
2524

2625
namespace MongoDB.Bson.Tests.IO
@@ -58,6 +57,151 @@ public void BsonBinaryReader_should_support_reading_multiple_documents(
5857
}
5958
}
6059

60+
[Test]
61+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_a()
62+
{
63+
var bytes = new byte[] { 0, 0, 0, 0, 0xf0, 97, 0 };
64+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"a\". Are you using the latest driver version?";
65+
66+
using (var memoryStream = new MemoryStream(bytes))
67+
using (var subject = new BsonBinaryReader(memoryStream))
68+
{
69+
subject.ReadStartDocument();
70+
71+
Action action = () => subject.ReadBsonType();
72+
73+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
74+
}
75+
}
76+
77+
[Test]
78+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_a_0()
79+
{
80+
var bytes = new byte[] { 0, 0, 0, 0, 4, 97, 0, 0, 0, 0, 0, 0xf0, 48, 0 };
81+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"a.0\". Are you using the latest driver version?";
82+
83+
using (var memoryStream = new MemoryStream(bytes))
84+
using (var subject = new BsonBinaryReader(memoryStream))
85+
{
86+
subject.ReadStartDocument();
87+
subject.ReadBsonType();
88+
subject.ReadName();
89+
subject.ReadStartArray();
90+
91+
Action action = () => subject.ReadBsonType();
92+
93+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
94+
}
95+
}
96+
97+
[Test]
98+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_a_0_b()
99+
{
100+
var bytes = new byte[] { 0, 0, 0, 0, 4, 97, 0, 0, 0, 0, 0, 3, 48, 0, 0, 0, 0, 0, 0xf0, 98, 0 };
101+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"a.0.b\". Are you using the latest driver version?";
102+
103+
using (var memoryStream = new MemoryStream(bytes))
104+
using (var subject = new BsonBinaryReader(memoryStream))
105+
{
106+
subject.ReadStartDocument();
107+
subject.ReadBsonType();
108+
subject.ReadName();
109+
subject.ReadStartArray();
110+
subject.ReadBsonType();
111+
subject.ReadStartDocument();
112+
113+
Action action = () => subject.ReadBsonType();
114+
115+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
116+
}
117+
}
118+
119+
[Test]
120+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_a_1()
121+
{
122+
var bytes = new byte[] { 0, 0, 0, 0, 4, 97, 0, 0, 0, 0, 0, 0x10, 48, 0, 0, 0, 0, 0, 0xf0, 49, 0 };
123+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"a.1\". Are you using the latest driver version?";
124+
125+
using (var memoryStream = new MemoryStream(bytes))
126+
using (var subject = new BsonBinaryReader(memoryStream))
127+
{
128+
subject.ReadStartDocument();
129+
subject.ReadBsonType();
130+
subject.ReadName();
131+
subject.ReadStartArray();
132+
subject.ReadBsonType();
133+
subject.ReadInt32();
134+
135+
Action action = () => subject.ReadBsonType();
136+
137+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
138+
}
139+
}
140+
141+
[Test]
142+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_a_1_b()
143+
{
144+
var bytes = new byte[] { 0, 0, 0, 0, 4, 97, 0, 0, 0, 0, 0, 0x10, 48, 0, 0, 0, 0, 0, 3, 49, 0, 0, 0, 0, 0, 0xf0, 98, 0 };
145+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"a.1.b\". Are you using the latest driver version?";
146+
147+
using (var memoryStream = new MemoryStream(bytes))
148+
using (var subject = new BsonBinaryReader(memoryStream))
149+
{
150+
subject.ReadStartDocument();
151+
subject.ReadBsonType();
152+
subject.ReadName();
153+
subject.ReadStartArray();
154+
subject.ReadBsonType();
155+
subject.ReadInt32();
156+
subject.ReadBsonType();
157+
subject.ReadStartDocument();
158+
159+
Action action = () => subject.ReadBsonType();
160+
161+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
162+
}
163+
}
164+
165+
[Test]
166+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_a_b()
167+
{
168+
var bytes = new byte[] { 0, 0, 0, 0, 3, 97, 0, 0, 0, 0, 0, 0xf0, 98, 0 };
169+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"a.b\". Are you using the latest driver version?";
170+
171+
using (var memoryStream = new MemoryStream(bytes))
172+
using (var subject = new BsonBinaryReader(memoryStream))
173+
{
174+
subject.ReadStartDocument();
175+
subject.ReadBsonType();
176+
subject.ReadName();
177+
subject.ReadStartDocument();
178+
179+
Action action = () => subject.ReadBsonType();
180+
181+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
182+
}
183+
}
184+
185+
[Test]
186+
public void ReadBsonType_should_throw_when_bson_type_is_invalid_for_b()
187+
{
188+
var bytes = new byte[] { 0, 0, 0, 0, 0x10, 97, 0, 0, 0, 0, 0, 0xf0, 98, 0 };
189+
var expectedMessage = $"Detected unknown BSON type \"\\xf0\" for fieldname \"b\". Are you using the latest driver version?";
190+
191+
using (var memoryStream = new MemoryStream(bytes))
192+
using (var subject = new BsonBinaryReader(memoryStream))
193+
{
194+
subject.ReadStartDocument();
195+
subject.ReadBsonType();
196+
subject.ReadName();
197+
subject.ReadInt32();
198+
199+
Action action = () => subject.ReadBsonType();
200+
201+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
202+
}
203+
}
204+
61205
[Test]
62206
public void TestHelloWorld()
63207
{

src/MongoDB.Bson.Tests/IO/BsonStreamExtensionsTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2010-2015 MongoDB Inc.
1+
/* Copyright 2010-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -238,7 +238,9 @@ public void ReadBsonType_should_throw_when_value_is_invalid(int n)
238238
{
239239
Action action = () => stream.ReadBsonType();
240240

241-
action.ShouldThrow<FormatException>();
241+
var hexBsonType = string.Format("{0:x2}", n);
242+
var expectedMessage = $"Detected unknown BSON type \"\\x{hexBsonType}\". Are you using the latest driver version?";
243+
action.ShouldThrow<FormatException>().WithMessage(expectedMessage);
242244
}
243245
}
244246

src/MongoDB.Bson/IO/BsonBinaryReader.cs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2010-2015 MongoDB Inc.
1+
/* Copyright 2010-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
1414
*/
1515

1616
using System;
17+
using System.Globalization;
1718
using System.IO;
1819

1920
namespace MongoDB.Bson.IO
@@ -200,7 +201,28 @@ public override BsonType ReadBsonType()
200201
ThrowInvalidState("ReadBsonType", BsonReaderState.Type);
201202
}
202203

203-
CurrentBsonType = _bsonStream.ReadBsonType();
204+
if (_context.ContextType == ContextType.Array)
205+
{
206+
_context.CurrentArrayIndex++;
207+
}
208+
209+
try
210+
{
211+
212+
CurrentBsonType = _bsonStream.ReadBsonType();
213+
}
214+
catch (FormatException ex)
215+
{
216+
if (ex.Message.StartsWith("Detected unknown BSON type"))
217+
{
218+
// insert the element name into the error message
219+
var periodIndex = ex.Message.IndexOf('.');
220+
var dottedElementName = GenerateDottedElementName();
221+
var message = ex.Message.Substring(0, periodIndex) + $" for fieldname \"{dottedElementName}\"" + ex.Message.Substring(periodIndex);
222+
throw new FormatException(message);
223+
}
224+
throw;
225+
}
204226

205227
if (CurrentBsonType == BsonType.EndOfDocument)
206228
{
@@ -455,6 +477,11 @@ public override string ReadName(INameDecoder nameDecoder)
455477
CurrentName = nameDecoder.Decode(_bsonStream, _settings.Encoding);
456478
State = BsonReaderState.Value;
457479

480+
if (_context.ContextType == ContextType.Document)
481+
{
482+
_context.CurrentElementName = CurrentName;
483+
}
484+
458485
return CurrentName;
459486
}
460487

@@ -647,7 +674,13 @@ public override void SkipName()
647674
}
648675

649676
_bsonStream.SkipCString();
677+
CurrentName = "?";
650678
State = BsonReaderState.Value;
679+
680+
if (_context.ContextType == ContextType.Document)
681+
{
682+
_context.CurrentElementName = CurrentName;
683+
}
651684
}
652685

653686
/// <summary>
@@ -710,6 +743,53 @@ protected override void Dispose(bool disposing)
710743
}
711744

712745
// private methods
746+
private string GenerateDottedElementName()
747+
{
748+
string elementName;
749+
if (_context.ContextType == ContextType.Document)
750+
{
751+
try
752+
{
753+
elementName = _bsonStream.ReadCString(Utf8Encodings.Lenient);
754+
}
755+
catch
756+
{
757+
elementName = "?"; // ignore exception
758+
}
759+
}
760+
else if (_context.ContextType == ContextType.Array)
761+
{
762+
elementName = _context.CurrentArrayIndex.ToString(NumberFormatInfo.InvariantInfo);
763+
}
764+
else
765+
{
766+
elementName = "?";
767+
}
768+
769+
return GenerateDottedElementName(_context.ParentContext, elementName);
770+
}
771+
772+
private string GenerateDottedElementName(BsonBinaryReaderContext context, string elementName)
773+
{
774+
if (context.ContextType == ContextType.Document)
775+
{
776+
return GenerateDottedElementName(context.ParentContext, context.CurrentElementName + "." + elementName);
777+
}
778+
else if (context.ContextType == ContextType.Array)
779+
{
780+
var indexElementName = context.CurrentArrayIndex.ToString(NumberFormatInfo.InvariantInfo);
781+
return GenerateDottedElementName(context.ParentContext, indexElementName + "." + elementName);
782+
}
783+
else if (context.ParentContext != null)
784+
{
785+
return GenerateDottedElementName(context.ParentContext, "?." + elementName);
786+
}
787+
else
788+
{
789+
return elementName;
790+
}
791+
}
792+
713793
private BsonReaderState GetNextState()
714794
{
715795
switch (_context.ContextType)

src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2010-2014 MongoDB Inc.
1+
/* Copyright 2010-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -14,17 +14,18 @@
1414
*/
1515

1616
using System;
17-
using System.IO;
1817

1918
namespace MongoDB.Bson.IO
2019
{
2120
internal class BsonBinaryReaderContext
2221
{
2322
// private fields
24-
private BsonBinaryReaderContext _parentContext;
25-
private ContextType _contextType;
26-
private long _startPosition;
27-
private long _size;
23+
private readonly BsonBinaryReaderContext _parentContext;
24+
private readonly ContextType _contextType;
25+
private readonly long _startPosition;
26+
private readonly long _size;
27+
private string _currentElementName;
28+
private int _currentArrayIndex = -1;
2829

2930
// constructors
3031
internal BsonBinaryReaderContext(
@@ -39,12 +40,29 @@ internal BsonBinaryReaderContext(
3940
_size = size;
4041
}
4142

42-
// internal properties
43-
internal ContextType ContextType
43+
// public properties
44+
public ContextType ContextType
4445
{
4546
get { return _contextType; }
4647
}
4748

49+
public int CurrentArrayIndex
50+
{
51+
get { return _currentArrayIndex; }
52+
set { _currentArrayIndex = value; }
53+
}
54+
55+
public string CurrentElementName
56+
{
57+
get { return _currentElementName; }
58+
set { _currentElementName = value; }
59+
}
60+
61+
public BsonBinaryReaderContext ParentContext
62+
{
63+
get { return _parentContext; }
64+
}
65+
4866
// public methods
4967
/// <summary>
5068
/// Creates a clone of the context.

src/MongoDB.Bson/IO/BsonStreamExtensions.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2010-2015 MongoDB Inc.
1+
/* Copyright 2010-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -14,11 +14,7 @@
1414
*/
1515

1616
using System;
17-
using System.Collections.Generic;
1817
using System.IO;
19-
using System.Linq;
20-
using System.Text;
21-
using System.Threading.Tasks;
2218

2319
namespace MongoDB.Bson.IO
2420
{
@@ -128,7 +124,7 @@ public static BsonType ReadBsonType(this BsonStream stream)
128124
}
129125
if (!__validBsonTypes[b])
130126
{
131-
string message = string.Format("Invalid BsonType: {0}.", b);
127+
var message = string.Format("Detected unknown BSON type \"\\x{0:x2}\". Are you using the latest driver version?", b);
132128
throw new FormatException(message);
133129
}
134130
return (BsonType)b;

0 commit comments

Comments
 (0)