diff options
Diffstat (limited to 'src/mongo/db/query/collation')
-rw-r--r-- | src/mongo/db/query/collation/collator_factory_icu.cpp | 38 | ||||
-rw-r--r-- | src/mongo/db/query/collation/collator_factory_icu_test.cpp | 125 |
2 files changed, 163 insertions, 0 deletions
diff --git a/src/mongo/db/query/collation/collator_factory_icu.cpp b/src/mongo/db/query/collation/collator_factory_icu.cpp index a7f0ba911e0..85b51c0423b 100644 --- a/src/mongo/db/query/collation/collator_factory_icu.cpp +++ b/src/mongo/db/query/collation/collator_factory_icu.cpp @@ -661,6 +661,39 @@ Status validateLocaleID(const BSONObj& spec, return Status::OK(); } +// Returns a non-OK status if 'spec' contains any invalid combinations of options. +Status validateCollationSpec(const CollationSpec& spec) { + // The backwards option specifically means backwards secondary weighting, and therefore only + // affects the secondary comparison level. It has no effect at strength 1. + if (spec.backwards && spec.strength == CollationSpec::StrengthType::kPrimary) { + return {ErrorCodes::BadValue, + str::stream() << "'" << CollationSpec::kBackwardsField << "' is invalid with '" + << CollationSpec::kStrengthField + << "' of " + << static_cast<int>(CollationSpec::StrengthType::kPrimary) + << " in: " + << spec.toBSON()}; + } + + // The caseFirst option only affects tertiary level or caseLevel comparisons. It will have no + // affect if caseLevel is off and strength is 1 or 2. + if (spec.caseFirst != CollationSpec::CaseFirstType::kOff && !spec.caseLevel && + (spec.strength == CollationSpec::StrengthType::kPrimary || + spec.strength == CollationSpec::StrengthType::kSecondary)) { + return {ErrorCodes::BadValue, + str::stream() << "'" << CollationSpec::kCaseFirstField << "' is invalid unless '" + << CollationSpec::kCaseLevelField + << "' is on or '" + << CollationSpec::kStrengthField + << "' is greater than " + << static_cast<int>(CollationSpec::StrengthType::kSecondary) + << " in: " + << spec.toBSON()}; + } + + return Status::OK(); +} + } // namespace StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryICU::makeFromBSON( @@ -716,6 +749,11 @@ StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryICU::makeFromBSON( return parsedSpec.getStatus(); } + auto validateSpecStatus = validateCollationSpec(parsedSpec.getValue()); + if (!validateSpecStatus.isOK()) { + return validateSpecStatus; + } + auto mongoCollator = stdx::make_unique<CollatorInterfaceICU>(std::move(parsedSpec.getValue()), std::move(icuCollator)); return {std::move(mongoCollator)}; diff --git a/src/mongo/db/query/collation/collator_factory_icu_test.cpp b/src/mongo/db/query/collation/collator_factory_icu_test.cpp index e35512a8a79..2ce271a568f 100644 --- a/src/mongo/db/query/collation/collator_factory_icu_test.cpp +++ b/src/mongo/db/query/collation/collator_factory_icu_test.cpp @@ -1063,6 +1063,131 @@ TEST(CollatorFactoryICUTest, FactoryMadeCollatorComparisonKeysCorrectEnUS) { ASSERT_LT(comparisonKeyABB.getKeyData().compare(comparisonKeyBA.getKeyData()), 0); } +TEST(CollatorFactoryICUTest, BackwardsTrueWithStrengthOneFails) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "backwards" + << true + << "strength" + << 1)); + ASSERT_NOT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, BackwardsTrueWithStrengthTwoSucceeds) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "backwards" + << true + << "strength" + << 2)); + ASSERT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstLowerWithStrengthThreeSucceeds) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "lower" + << "strength" + << 3)); + ASSERT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstUpperWithStrengthThreeSucceeds) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "upper" + << "strength" + << 3)); + ASSERT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstLowerWithCaseLevelSucceeds) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "lower" + << "caseLevel" + << true + << "strength" + << 1)); + ASSERT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstUpperWithCaseLevelSucceeds) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "upper" + << "caseLevel" + << true + << "strength" + << 1)); + ASSERT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstOffWithStrengthOneSucceeds) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "off" + << "strength" + << 1)); + ASSERT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstLowerWithStrengthOneFails) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "lower" + << "strength" + << 1)); + ASSERT_NOT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstLowerWithStrengthTwoFails) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "lower" + << "strength" + << 2)); + ASSERT_NOT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstUpperWithStrengthOneFails) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "upper" + << "strength" + << 1)); + ASSERT_NOT_OK(collator.getStatus()); +} + +TEST(CollatorFactoryICUTest, CaseFirstUpperWithStrengthTwoFails) { + CollatorFactoryICU factory; + auto collator = factory.makeFromBSON(BSON("locale" + << "en_US" + << "caseFirst" + << "upper" + << "strength" + << 2)); + ASSERT_NOT_OK(collator.getStatus()); +} + TEST(CollatorFactoryICUTest, FactoryInitializationSucceedsWithArabicLocale) { CollatorFactoryICU factory; ASSERT_OK(factory |