Skip to content

Commit a191980

Browse files
committed
JAVA-2376: Enforce alphabetic order on encoding BSON regular expression options
1 parent 709878e commit a191980

File tree

5 files changed

+118
-41
lines changed

5 files changed

+118
-41
lines changed

bson/src/main/org/bson/BsonRegularExpression.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.bson;
1818

19+
import java.util.Arrays;
20+
1921
import static org.bson.assertions.Assertions.notNull;
2022

2123
/**
@@ -36,7 +38,7 @@ public final class BsonRegularExpression extends BsonValue {
3638
*/
3739
public BsonRegularExpression(final String pattern, final String options) {
3840
this.pattern = notNull("pattern", pattern);
39-
this.options = options == null ? "" : options;
41+
this.options = options == null ? "" : sortOptionCharacters(options);
4042
}
4143

4244
/**
@@ -45,7 +47,7 @@ public BsonRegularExpression(final String pattern, final String options) {
4547
* @param pattern the regular expression {@link java.util.regex.Pattern}
4648
*/
4749
public BsonRegularExpression(final String pattern) {
48-
this(pattern, "");
50+
this(pattern, null);
4951
}
5052

5153
@Override
@@ -106,4 +108,10 @@ public String toString() {
106108
+ ", options='" + options + '\''
107109
+ '}';
108110
}
111+
112+
private String sortOptionCharacters(final String options) {
113+
char[] chars = options.toCharArray();
114+
Arrays.sort(chars);
115+
return new String(chars);
116+
}
109117
}
Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
11
{
2-
"description": "Regular Expression type",
3-
"bson_type": "0x0B",
4-
"test_key": "a",
5-
"valid": [
6-
{
7-
"description": "empty regex with no options",
8-
"bson": "0A0000000B6100000000",
9-
"extjson": "{\"a\" : {\"$regex\" : \"\", \"$options\" : \"\"}}"
10-
},
11-
{
12-
"description": "regex without options",
13-
"bson": "0D0000000B6100616263000000",
14-
"extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"\"}}"
15-
},
16-
{
17-
"description": "regex with options",
18-
"bson": "0F0000000B610061626300696D0000",
19-
"extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"im\"}}"
20-
},
21-
{
22-
"description": "regex with slash",
23-
"bson": "110000000B610061622F636400696D0000",
24-
"extjson": "{\"a\" : {\"$regex\" : \"ab/cd\", \"$options\" : \"im\"}}"
25-
}
26-
],
27-
"decodeErrors": [
28-
{
29-
"description": "embedded null in pattern",
30-
"bson": "0F0000000B610061006300696D0000"
31-
},
32-
{
33-
"description": "embedded null in flags",
34-
"bson": "100000000B61006162630069006D0000"
35-
}
36-
]
2+
"description": "Regular Expression type",
3+
"bson_type": "0x0B",
4+
"test_key": "a",
5+
"valid": [
6+
{
7+
"description": "empty regex with no options",
8+
"bson": "0A0000000B6100000000",
9+
"extjson": "{\"a\" : {\"$regex\" : \"\", \"$options\" : \"\"}}"
10+
},
11+
{
12+
"description": "regex without options",
13+
"bson": "0D0000000B6100616263000000",
14+
"extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"\"}}"
15+
},
16+
{
17+
"description": "regex with options",
18+
"bson": "0F0000000B610061626300696D0000",
19+
"extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"im\"}}"
20+
},
21+
{
22+
"description": "regex with slash",
23+
"bson": "110000000B610061622F636400696D0000",
24+
"extjson": "{\"a\" : {\"$regex\" : \"ab/cd\", \"$options\" : \"im\"}}"
25+
},
26+
{
27+
"description": "flags not alphabetized",
28+
"bson": "100000000B6100616263006D69780000",
29+
"canonical_bson": "100000000B610061626300696D780000",
30+
"extjson": "{\"a\" : {\"$regex\" : \"abc\", \"$options\" : \"imx\"}}"
31+
}
32+
],
33+
"decodeErrors": [
34+
{
35+
"description": "embedded null in pattern",
36+
"bson": "0F0000000B610061006300696D0000"
37+
},
38+
{
39+
"description": "embedded null in flags",
40+
"bson": "100000000B61006162630069006D0000"
41+
}
42+
]
3743
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2016 MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.bson
19+
20+
import spock.lang.Specification
21+
22+
class BsonRegularExpressionSpecification extends Specification {
23+
def 'should get type'() {
24+
expect:
25+
new BsonRegularExpression('abc', '').bsonType == BsonType.REGULAR_EXPRESSION
26+
}
27+
28+
def 'should sort options'() {
29+
expect:
30+
new BsonRegularExpression('abc', 'uxsmi').options == 'imsux'
31+
}
32+
33+
def 'should accept invalid options'() {
34+
expect:
35+
new BsonRegularExpression('abc', 'uxsmiw').options == 'imsuwx'
36+
}
37+
38+
def 'should allow null options'() {
39+
expect:
40+
new BsonRegularExpression('abc').options == ''
41+
new BsonRegularExpression('abc', null).options == ''
42+
}
43+
44+
def 'should get regular expression'() {
45+
expect:
46+
new BsonRegularExpression('abc', null).pattern == 'abc'
47+
}
48+
49+
def 'equivalent values should be equal and have same hashcode'() {
50+
given:
51+
def first = new BsonRegularExpression('abc', 'uxsmi')
52+
def second = new BsonRegularExpression('abc', 'imsxu')
53+
54+
expect:
55+
first.equals(second)
56+
first.hashCode() == second.hashCode()
57+
}
58+
59+
def 'should convert to string'() {
60+
expect:
61+
new BsonRegularExpression('abc', 'uxsmi').toString() == 'BsonRegularExpression{pattern=\'abc\', options=\'imsux\'}'
62+
}
63+
}

bson/src/test/unit/org/bson/json/JsonReaderTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ public void testRegularExpressionShell() {
552552
assertEquals(BsonType.REGULAR_EXPRESSION, bsonReader.readBsonType());
553553
BsonRegularExpression regex = bsonReader.readRegularExpression();
554554
assertEquals("pattern", regex.getPattern());
555-
assertEquals("imxs", regex.getOptions());
555+
assertEquals("imsx", regex.getOptions());
556556
assertEquals(AbstractBsonReader.State.DONE, bsonReader.getState());
557557

558558
}
@@ -564,7 +564,7 @@ public void testRegularExpressionStrict() {
564564
assertEquals(BsonType.REGULAR_EXPRESSION, bsonReader.readBsonType());
565565
BsonRegularExpression regex = bsonReader.readRegularExpression();
566566
assertEquals("pattern", regex.getPattern());
567-
assertEquals("imxs", regex.getOptions());
567+
assertEquals("imsx", regex.getOptions());
568568
assertEquals(AbstractBsonReader.State.DONE, bsonReader.getState());
569569
JsonWriterSettings settings = new JsonWriterSettings(JsonMode.STRICT);
570570

bson/src/test/unit/org/bson/json/JsonWriterTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ public void testRegularExpressionShell() {
571571
new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "m"), "/a/m"),
572572
new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "x"), "/a/x"),
573573
new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "s"), "/a/s"),
574-
new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "imxs"), "/a/imxs"));
574+
new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "imxs"), "/a/imsx"));
575575
for (final TestData<BsonRegularExpression> cur : tests) {
576576
stringWriter = new StringWriter();
577577
writer = new JsonWriter(stringWriter, new JsonWriterSettings(JsonMode.SHELL));
@@ -613,7 +613,7 @@ public void testRegularExpressionStrict() {
613613
+ " \"$options\" : \"s\""
614614
+ " }"),
615615
new TestData<BsonRegularExpression>(new BsonRegularExpression("a", "imxs"),
616-
"{ \"$regex\" : \"a\"," + " \"$options\" : \"imxs\" }"));
616+
"{ \"$regex\" : \"a\"," + " \"$options\" : \"imsx\" }"));
617617
for (final TestData<BsonRegularExpression> cur : tests) {
618618
stringWriter = new StringWriter();
619619
writer = new JsonWriter(stringWriter, new JsonWriterSettings(JsonMode.STRICT));

0 commit comments

Comments
 (0)