Browse Source

Implemented CSHARP-260. Modified JsonReader to support additional ways of representing regular expressions.

pull/63/head
rstam 14 years ago
parent
commit
0a1371cfef
  1. 56
      Bson/IO/JsonReader.cs
  2. 3
      Bson/IO/JsonScanner.cs
  3. 10
      Bson/IO/JsonWriter.cs
  4. 1
      BsonUnitTests/BsonUnitTests.csproj
  5. 4
      BsonUnitTests/DefaultSerializer/Serializers/BsonValueSerializerTests.cs
  6. 12
      BsonUnitTests/IO/BsonDocumentWriterTests.cs
  7. 8
      BsonUnitTests/IO/JsonReaderTests.cs
  8. 4
      BsonUnitTests/IO/JsonScannerTests.cs
  9. 10
      BsonUnitTests/IO/JsonWriterTests.cs
  10. 114
      BsonUnitTests/Jira/CSharp260Tests.cs
  11. 2
      BsonUnitTests/ObjectModel/BsonValueIConvertibleTests.cs

56
Bson/IO/JsonReader.cs

@ -221,6 +221,10 @@ namespace MongoDB.Bson.IO {
currentBsonType = BsonType.ObjectId;
currentValue = ParseObjectIdShell();
break;
case "RegExp":
currentBsonType = BsonType.RegularExpression;
currentValue = ParseRegularExpressionConstructor();
break;
case "new":
currentBsonType = ParseNew(out currentValue);
break;
@ -793,7 +797,7 @@ namespace MongoDB.Bson.IO {
case "$maxkey": currentValue = ParseMaxKey(); return BsonType.MaxKey;
case "$minkey": currentValue = ParseMinKey(); return BsonType.MinKey;
case "$oid": currentValue = ParseObjectIdStrict(); return BsonType.ObjectId;
case "$regex": currentValue = ParseRegularExpression(); return BsonType.RegularExpression;
case "$regex": currentValue = ParseRegularExpressionStrict(); return BsonType.RegularExpression;
case "$symbol": currentValue = ParseSymbol(); return BsonType.Symbol;
case "$timestamp": currentValue = ParseTimestamp(); return BsonType.Timestamp;
}
@ -840,6 +844,9 @@ namespace MongoDB.Bson.IO {
case "ObjectId":
value = ParseObjectIdShell();
return BsonType.ObjectId;
case "RegExp":
value = ParseRegularExpressionConstructor();
return BsonType.RegularExpression;
default:
var message = string.Format("JSON reader expected a type name but found '{0}'.", typeToken.Lexeme);
throw new FileFormatException(message);
@ -884,23 +891,52 @@ namespace MongoDB.Bson.IO {
return BsonObjectId.Create(valueToken.StringValue);
}
private BsonValue ParseRegularExpression() {
VerifyToken(":");
private BsonValue ParseRegularExpressionConstructor() {
VerifyToken("(");
var patternToken = PopToken();
if (patternToken.Type != JsonTokenType.String) {
var message = string.Format("JSON reader expected a string but found '{0}'.", patternToken.Lexeme);
throw new FileFormatException(message);
}
VerifyToken(",");
VerifyString("$options");
var options = "";
var commaToken = PopToken();
if (commaToken.Lexeme == ",") {
var optionsToken = PopToken();
if (optionsToken.Type != JsonTokenType.String) {
var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
throw new FileFormatException(message);
}
options = optionsToken.StringValue;
} else {
PushToken(commaToken);
}
VerifyToken(")");
return BsonRegularExpression.Create(patternToken.StringValue, options);
}
private BsonValue ParseRegularExpressionStrict() {
VerifyToken(":");
var optionsToken = PopToken();
if (optionsToken.Type != JsonTokenType.String) {
var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
var patternToken = PopToken();
if (patternToken.Type != JsonTokenType.String) {
var message = string.Format("JSON reader expected a string but found '{0}'.", patternToken.Lexeme);
throw new FileFormatException(message);
}
var options = "";
var commaToken = PopToken();
if (commaToken.Lexeme == ",") {
VerifyString("$options");
VerifyToken(":");
var optionsToken = PopToken();
if (optionsToken.Type != JsonTokenType.String) {
var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
throw new FileFormatException(message);
}
options = optionsToken.StringValue;
} else {
PushToken(commaToken);
}
VerifyToken("}");
return BsonRegularExpression.Create(patternToken.StringValue, optionsToken.StringValue);
return BsonRegularExpression.Create(patternToken.StringValue, options);
}
private BsonValue ParseSymbol() {
@ -954,7 +990,7 @@ namespace MongoDB.Bson.IO {
string expectedString
) {
var token = PopToken();
if (token.Type != JsonTokenType.String || token.StringValue != expectedString) {
if ((token.Type != JsonTokenType.String && token.Type != JsonTokenType.UnquotedString) || token.StringValue != expectedString) {
var message = string.Format("JSON reader expected '{0}' but found '{1}'.", expectedString, token.StringValue);
throw new FileFormatException(message);
}

3
Bson/IO/JsonScanner.cs

@ -326,9 +326,10 @@ namespace MongoDB.Bson.IO {
break;
case RegularExpressionState.InOptions:
switch (c) {
case 'g':
case 'i':
case 'm':
case 'x':
case 's':
state = RegularExpressionState.InOptions;
break;
case ',':

10
Bson/IO/JsonWriter.cs

@ -440,15 +440,7 @@ namespace MongoDB.Bson.IO {
var escaped = (pattern == "") ? "(?:)" : pattern.Replace(@"\", @"\\").Replace("/", @"\/");
textWriter.Write(escaped);
textWriter.Write("/");
foreach (char c in options.ToLower()) {
switch (c) {
case 'g':
case 'i':
case 'm':
textWriter.Write(c);
break;
}
}
textWriter.Write(options);
break;
}

1
BsonUnitTests/BsonUnitTests.csproj

@ -123,6 +123,7 @@
<Compile Include="Jira\CSharp170Tests.cs" />
<Compile Include="Jira\CSharp238Tests.cs" />
<Compile Include="Jira\CSharp239Tests.cs" />
<Compile Include="Jira\CSharp260Tests.cs" />
<Compile Include="Jira\CSharp70Tests.cs" />
<Compile Include="Jira\CSharp71Tests.cs" />
<Compile Include="Jira\CSharp74Tests.cs" />

4
BsonUnitTests/DefaultSerializer/Serializers/BsonValueSerializerTests.cs

@ -1062,9 +1062,9 @@ namespace MongoDB.BsonUnitTests.Serialization {
[Test]
public void TestWithOptions() {
var obj = new TestClass(new BsonRegularExpression("abc", "gim"));
var obj = new TestClass(new BsonRegularExpression("abc", "imxs"));
var json = obj.ToJson();
var expected = "{ 'B' : #, 'V' : # }".Replace("#", "/abc/gim").Replace("'", "\"");
var expected = "{ 'B' : #, 'V' : # }".Replace("#", "/abc/imxs").Replace("'", "\"");
Assert.AreEqual(expected, json);
var bson = obj.ToBson();

12
BsonUnitTests/IO/BsonDocumentWriterTests.cs

@ -1040,12 +1040,12 @@ namespace MongoDB.BsonUnitTests.IO {
var document = new BsonDocument();
using (var writer = BsonWriter.Create(document)) {
writer.WriteStartDocument();
writer.WriteRegularExpression("a", "p", "g");
writer.WriteRegularExpression("b", "q", "i");
writer.WriteRegularExpression("a", "p", "i");
writer.WriteRegularExpression("b", "q", "m");
writer.WriteEndDocument();
}
var json = document.ToJson();
var expected = "{ 'a' : /p/g, 'b' : /q/i }".Replace("'", "\""); ;
var expected = "{ 'a' : /p/i, 'b' : /q/m }".Replace("'", "\""); ;
Assert.AreEqual(expected, json);
}
@ -1055,13 +1055,13 @@ namespace MongoDB.BsonUnitTests.IO {
using (var writer = BsonWriter.Create(document)) {
writer.WriteStartDocument();
writer.WriteStartDocument("nested");
writer.WriteRegularExpression("a", "p", "g");
writer.WriteRegularExpression("b", "q", "i");
writer.WriteRegularExpression("a", "p", "i");
writer.WriteRegularExpression("b", "q", "m");
writer.WriteEndDocument();
writer.WriteEndDocument();
}
var json = document.ToJson();
var expected = "{ 'nested' : { 'a' : /p/g, 'b' : /q/i } }".Replace("'", "\"");
var expected = "{ 'nested' : { 'a' : /p/i, 'b' : /q/m } }".Replace("'", "\"");
Assert.AreEqual(expected, json);
}

8
BsonUnitTests/IO/JsonReaderTests.cs

@ -497,13 +497,13 @@ namespace MongoDB.BsonUnitTests.IO {
[Test]
public void TestRegularExpressionShell() {
var json = "/pattern/gim";
var json = "/pattern/imxs";
using (bsonReader = BsonReader.Create(json)) {
Assert.AreEqual(BsonType.RegularExpression, bsonReader.ReadBsonType());
string pattern, options;
bsonReader.ReadRegularExpression(out pattern, out options);
Assert.AreEqual("pattern", pattern);
Assert.AreEqual("gim", options);
Assert.AreEqual("imxs", options);
Assert.AreEqual(BsonReaderState.Done, bsonReader.State);
}
Assert.AreEqual(json, BsonSerializer.Deserialize<BsonRegularExpression>(new StringReader(json)).ToJson());
@ -511,13 +511,13 @@ namespace MongoDB.BsonUnitTests.IO {
[Test]
public void TestRegularExpressionStrict() {
var json = "{ \"$regex\" : \"pattern\", \"$options\" : \"gim\" }";
var json = "{ \"$regex\" : \"pattern\", \"$options\" : \"imxs\" }";
using (bsonReader = BsonReader.Create(json)) {
Assert.AreEqual(BsonType.RegularExpression, bsonReader.ReadBsonType());
string pattern, options;
bsonReader.ReadRegularExpression(out pattern, out options);
Assert.AreEqual("pattern", pattern);
Assert.AreEqual("gim", options);
Assert.AreEqual("imxs", options);
Assert.AreEqual(BsonReaderState.Done, bsonReader.State);
}
var settings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };

4
BsonUnitTests/IO/JsonScannerTests.cs

@ -398,11 +398,11 @@ namespace MongoDB.BsonUnitTests.IO {
[Test]
public void TestRegularExpressionPatternAndOptions() {
var json = "\t /pattern/gim,";
var json = "\t /pattern/imxs,";
var buffer = new JsonBuffer(json);
var token = JsonScanner.GetNextToken(buffer);
Assert.AreEqual(JsonTokenType.RegularExpression, token.Type);
Assert.AreEqual("/pattern/gim", token.Lexeme);
Assert.AreEqual("/pattern/imxs", token.Lexeme);
Assert.AreEqual(',', buffer.Read());
}
}

10
BsonUnitTests/IO/JsonWriterTests.cs

@ -370,10 +370,11 @@ namespace MongoDB.BsonUnitTests.IO {
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a"), "/a/"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a/b"), "/a\\/b/"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a\\b"), "/a\\\\b/"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "g"), "/a/g"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "i"), "/a/i"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "m"), "/a/m"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "gim"), "/a/gim"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "x"), "/a/x"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "s"), "/a/s"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "imxs"), "/a/imxs"),
};
foreach (var test in tests) {
var json = test.Value.ToJson();
@ -390,10 +391,11 @@ namespace MongoDB.BsonUnitTests.IO {
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a"), "{ \"$regex\" : \"a\", \"$options\" : \"\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a/b"), "{ \"$regex\" : \"a/b\", \"$options\" : \"\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a\\b"), "{ \"$regex\" : \"a\\\\b\", \"$options\" : \"\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "g"), "{ \"$regex\" : \"a\", \"$options\" : \"g\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "i"), "{ \"$regex\" : \"a\", \"$options\" : \"i\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "m"), "{ \"$regex\" : \"a\", \"$options\" : \"m\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "gim"), "{ \"$regex\" : \"a\", \"$options\" : \"gim\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "x"), "{ \"$regex\" : \"a\", \"$options\" : \"x\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "s"), "{ \"$regex\" : \"a\", \"$options\" : \"s\" }"),
new TestData<BsonRegularExpression>(BsonRegularExpression.Create("a", "imxs"), "{ \"$regex\" : \"a\", \"$options\" : \"imxs\" }"),
};
var jsonSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
foreach (var test in tests) {

114
BsonUnitTests/Jira/CSharp260Tests.cs

@ -0,0 +1,114 @@
/* Copyright 2010-2011 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using NUnit.Framework;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
namespace MongoDB.BsonUnitTests.Jira.CSharp260 {
[TestFixture]
public class CSharp260Tests {
[Test]
public void TestConstantPattern() {
var json = "{ rx : /abc/ }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("", rx.Options);
}
[Test]
public void TestConstantPatternWithOptions() {
var json = "{ rx : /abc/imxs }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("imxs", rx.Options);
}
[Test]
public void TestNewRegExpPattern() {
var json = "{ rx : new RegExp('abc') }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("", rx.Options);
}
[Test]
public void TestNewRegExpPatternWithOptions() {
var json = "{ rx : new RegExp('abc', 'imxs') }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("imxs", rx.Options);
}
[Test]
public void TestRegExpPattern() {
var json = "{ rx : RegExp('abc') }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("", rx.Options);
}
[Test]
public void TestRegExpPatternWithOptions() {
var json = "{ rx : RegExp('abc', 'imxs') }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("imxs", rx.Options);
}
[Test]
public void TestStrictPattern() {
var json = "{ rx : { $regex : 'abc' } }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("", rx.Options);
}
[Test]
public void TestStrictPatternWithOptions() {
var json = "{ rx : { $regex : 'abc', $options : 'imxs' } }";
var document = BsonDocument.Parse(json);
Assert.AreEqual(BsonType.RegularExpression, document["rx"].BsonType);
var rx = document["rx"].AsBsonRegularExpression;
Assert.AreEqual("abc", rx.Pattern);
Assert.AreEqual("imxs", rx.Options);
}
}
}

2
BsonUnitTests/ObjectModel/BsonValueIConvertibleTests.cs

@ -310,7 +310,7 @@ namespace MongoDB.BsonUnitTests {
[Test]
public void TestBsonRegularExpression() {
var value = BsonRegularExpression.Create("pattern", "gim");
var value = BsonRegularExpression.Create("pattern", "imxs");
Assert.Throws<InvalidCastException>(() => Convert.ToBoolean(value));
Assert.Throws<InvalidCastException>(() => Convert.ToByte(value));
Assert.Throws<InvalidCastException>(() => Convert.ToChar(value));

Loading…
Cancel
Save