diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/db/pipeline/expression_test.cpp | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/db/pipeline/expression_test.cpp')
| -rw-r--r-- | src/mongo/db/pipeline/expression_test.cpp | 433 |
1 files changed, 42 insertions, 391 deletions
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp index 645dcacdb68..fd6f1c3490e 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -44,7 +44,6 @@ #include "mongo/db/pipeline/expression.h" #include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" -#include "mongo/db/query/query_shape/serialization_options.h" #include "mongo/dbtests/dbtests.h" #include "mongo/idl/server_parameter_test_util.h" #include "mongo/logv2/log.h" @@ -124,7 +123,7 @@ static BSONObj toBson(const Value& value) { /** Convert Expression to BSON. */ static BSONObj expressionToBson(const intrusive_ptr<Expression>& expression) { - return BSON("" << expression->serialize()).firstElement().embeddedObject().getOwned(); + return BSON("" << expression->serialize(false)).firstElement().embeddedObject().getOwned(); } /** Convert Document to BSON. */ @@ -170,41 +169,6 @@ void parseAndVerifyResults( ASSERT_VALUE_EQ(expr->evaluate({}, &expCtx.variables), expected); } -/** - * Generates a random double with a variable number of decimal places between 1 and 15. - */ -double randomDouble() { - // Create a random number generator engine. - std::random_device rd; - std::mt19937 gen(rd()); - - // Create a distribution and generate a double between -1 and 1. - std::uniform_real_distribution<double> dis(-1.0, 1.0); - double randomValue = dis(gen); - - std::uniform_int_distribution<int> multiplier(0, 15); - int shift = multiplier(gen); - double factor = std::pow(10.0, shift); - - // Multiply the random number by the factor to set the decimal places - double result = randomValue * factor; - return result; -} - -/** - * Verifies that a double can correctly convert to a string and round-trip back to the original - * double. - */ -void verifyStringDoubleConvertRoundtripsCorrectly(double doubleToConvert) { - Value doubleConvertedToString = evaluateExpression("$toString", {doubleToConvert}); - ASSERT_EQ(doubleConvertedToString.getType(), BSONType::String); - - Value stringConvertedToDouble = evaluateExpression("$toDouble", {doubleConvertedToString}); - ASSERT_EQ(stringConvertedToDouble.getType(), BSONType::NumberDouble); - - // Verify the conversion round-trips correctly. - ASSERT_VALUE_EQ(stringConvertedToDouble, Value(doubleToConvert)); -} /* ------------------------- ExpressionArrayToObject -------------------------- */ @@ -710,7 +674,7 @@ public: private: static BSONObj toBsonObj(const intrusive_ptr<Expression>& expression) { - return BSON("field" << expression->serialize()); + return BSON("field" << expression->serialize(false)); } }; @@ -729,7 +693,7 @@ public: private: static BSONArray toBsonArray(const intrusive_ptr<Expression>& expression) { BSONArrayBuilder bab; - bab << expression->serialize(); + bab << expression->serialize(false); return bab.arr(); } }; @@ -805,7 +769,7 @@ public: private: static BSONObj toBsonObj(const intrusive_ptr<Expression>& expression) { - return BSON("field" << expression->serialize()); + return BSON("field" << expression->serialize(false)); } }; @@ -822,7 +786,7 @@ public: private: static BSONObj toBsonArray(const intrusive_ptr<Expression>& expression) { BSONArrayBuilder bab; - bab << expression->serialize(); + bab << expression->serialize(false); return bab.obj(); } }; @@ -840,26 +804,7 @@ TEST(ExpressionConstantTest, ConstantOfValueMissingSerializesToRemoveSystemVar) intrusive_ptr<Expression> expression = ExpressionConstant::create(&expCtx, Value()); ASSERT_BSONOBJ_BINARY_EQ(BSON("field" << "$$REMOVE"), - BSON("field" << expression->serialize())); -} - -TEST(ExpressionConstantTest, ConstantRedaction) { - SerializationOptions options; - options.literalPolicy = LiteralSerializationPolicy::kToDebugTypeString; - - // Test that a constant is replaced. - auto expCtx = ExpressionContextForTest{}; - intrusive_ptr<Expression> expression = ExpressionConstant::create(&expCtx, Value("my_ssn"_sd)); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({"field":"?string"})", - BSON("field" << expression->serialize(options))); - - auto expressionBSON = BSON("$and" << BSON_ARRAY(BSON("$gt" << BSON_ARRAY("$foo" << 5)) - << BSON("$lt" << BSON_ARRAY("$foo" << 10)))); - expression = Expression::parseExpression(&expCtx, expressionBSON, expCtx.variablesParseState); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({"field":{"$and":[{"$gt":["$foo","?number"]},{"$lt":["$foo","?number"]}]}})", - BSON("field" << expression->serialize(options))); + BSON("field" << expression->serialize(false))); } } // namespace Constant @@ -1176,7 +1121,7 @@ TEST(ExpressionSwitch, ExpressionSwitchWithAllConstantFalsesAndNoDefaultErrors) ASSERT_THROWS_CODE(switchExp->optimize(), AssertionException, 40069); } -TEST(ExpressionSwitch, ExpressionSwitchWithZeroAsConstantFalseAndNoDefaultErrors) { +TEST(ExpressionSwitch, ExpressionSwitchWithZeroAsConstantFalsesAndNoDefaulErrors) { auto expCtx = ExpressionContextForTest{}; VariablesParseState vps = expCtx.variablesParseState; @@ -1288,62 +1233,6 @@ TEST(ExpressionSwitch, ExpressionSwitchWithNoConstantsShouldStayTheSame) { ASSERT_BSONOBJ_BINARY_EQ(switchQ, expressionToBson(optimizedStaySame)); } -// This test was designed to provide coverage for SERVER-70190, a bug in which optimizing a $switch -// expression could leave its children vector in a bad state. By walking the tree after optimizing -// we make sure that the expected children are found. -TEST(ExpressionSwitch, CaseEliminationShouldLeaveTreeInWalkableState) { - auto expCtx = ExpressionContextForTest{}; - VariablesParseState vps = expCtx.variablesParseState; - - BSONObj switchQ = fromjson(R"( - {$switch: { - branches: [ - {case: false, then: {$const: 0}}, - {case: "$z", then: {$const: 1}}, - {case: "$y", then: {$const: 3}}, - {case: true, then: {$const: 4}}, - {case: "$a", then: {$const: 5}}, - {case: "$b", then: {$const: 6}}, - {case: "$c", then: {$const: 7}} - ], - default: {$const: 8} - }} - )"); - auto switchExp = ExpressionSwitch::parse(&expCtx, switchQ.firstElement(), vps); - auto optimizedExpr = switchExp->optimize(); - - BSONObj optimizedQ = fromjson(R"( - {$switch: { - branches: [ - {case: "$z", then: {$const: 1}}, - {case: "$y", then: {$const: 3}} - ], - default: {$const: 4} - }} - )"); - - ASSERT_BSONOBJ_BINARY_EQ(optimizedQ, expressionToBson(optimizedExpr)); - - // Make sure that the expression tree appears as expected when the children are traversed using - // a for-each loop. - int childNum = 0; - int numConstants = 0; - for (auto&& child : optimizedExpr->getChildren()) { - // Children 0 and 2 are field path expressions, whereas 1, 3, and 4 are constants. - auto constExpr = dynamic_cast<ExpressionConstant*>(child.get()); - if (constExpr) { - ASSERT_VALUE_EQ(constExpr->getValue(), Value{childNum}); - ++numConstants; - } else { - ASSERT(dynamic_cast<ExpressionFieldPath*>(child.get())); - } - ++childNum; - } - // We should have seen 5 children total, 3 of which are constants. - ASSERT_EQ(childNum, 5); - ASSERT_EQ(numConstants, 3); -} - TEST(ExpressionArray, ExpressionArrayShouldOptimizeSubExpressionToExpressionConstant) { auto expCtx = ExpressionContextForTest{}; VariablesParseState vps = expCtx.variablesParseState; @@ -1602,7 +1491,7 @@ TEST(ParseExpression, ShouldRecognizeConstExpression) { auto resultExpression = parseExpression(BSON("$const" << 5)); auto constExpression = dynamic_cast<ExpressionConstant*>(resultExpression.get()); ASSERT_TRUE(constExpression); - ASSERT_VALUE_EQ(constExpression->serialize(), Value(Document{{"$const", 5}})); + ASSERT_VALUE_EQ(constExpression->serialize(false), Value(Document{{"$const", 5}})); } TEST(ParseExpression, ShouldRejectUnknownExpression) { @@ -1636,14 +1525,15 @@ TEST(ParseExpression, ShouldParseExpressionWithMultipleArguments) { ASSERT_TRUE(strCaseCmpExpression); vector<Value> arguments = {Value(Document{{"$const", "foo"_sd}}), Value(Document{{"$const", "FOO"_sd}})}; - ASSERT_VALUE_EQ(strCaseCmpExpression->serialize(), Value(Document{{"$strcasecmp", arguments}})); + ASSERT_VALUE_EQ(strCaseCmpExpression->serialize(false), + Value(Document{{"$strcasecmp", arguments}})); } TEST(ParseExpression, ShouldParseExpressionWithNoArguments) { auto resultExpression = parseExpression(BSON("$and" << BSONArray())); auto andExpression = dynamic_cast<ExpressionAnd*>(resultExpression.get()); ASSERT_TRUE(andExpression); - ASSERT_VALUE_EQ(andExpression->serialize(), Value(Document{{"$and", vector<Value>{}}})); + ASSERT_VALUE_EQ(andExpression->serialize(false), Value(Document{{"$and", vector<Value>{}}})); } TEST(ParseExpression, ShouldParseExpressionWithOneArgument) { @@ -1651,7 +1541,7 @@ TEST(ParseExpression, ShouldParseExpressionWithOneArgument) { auto andExpression = dynamic_cast<ExpressionAnd*>(resultExpression.get()); ASSERT_TRUE(andExpression); vector<Value> arguments = {Value(Document{{"$const", 1}})}; - ASSERT_VALUE_EQ(andExpression->serialize(), Value(Document{{"$and", arguments}})); + ASSERT_VALUE_EQ(andExpression->serialize(false), Value(Document{{"$and", arguments}})); } TEST(ParseExpression, ShouldAcceptArgumentWithoutArrayForVariadicExpressions) { @@ -1659,7 +1549,7 @@ TEST(ParseExpression, ShouldAcceptArgumentWithoutArrayForVariadicExpressions) { auto andExpression = dynamic_cast<ExpressionAnd*>(resultExpression.get()); ASSERT_TRUE(andExpression); vector<Value> arguments = {Value(Document{{"$const", 1}})}; - ASSERT_VALUE_EQ(andExpression->serialize(), Value(Document{{"$and", arguments}})); + ASSERT_VALUE_EQ(andExpression->serialize(false), Value(Document{{"$and", arguments}})); } TEST(ParseExpression, ShouldAcceptArgumentWithoutArrayAsSingleArgument) { @@ -1667,7 +1557,7 @@ TEST(ParseExpression, ShouldAcceptArgumentWithoutArrayAsSingleArgument) { auto notExpression = dynamic_cast<ExpressionNot*>(resultExpression.get()); ASSERT_TRUE(notExpression); vector<Value> arguments = {Value(Document{{"$const", 1}})}; - ASSERT_VALUE_EQ(notExpression->serialize(), Value(Document{{"$not", arguments}})); + ASSERT_VALUE_EQ(notExpression->serialize(false), Value(Document{{"$not", arguments}})); } TEST(ParseExpression, ShouldAcceptObjectAsSingleArgument) { @@ -1675,7 +1565,7 @@ TEST(ParseExpression, ShouldAcceptObjectAsSingleArgument) { auto andExpression = dynamic_cast<ExpressionAnd*>(resultExpression.get()); ASSERT_TRUE(andExpression); vector<Value> arguments = {Value(Document{{"$const", 1}})}; - ASSERT_VALUE_EQ(andExpression->serialize(), Value(Document{{"$and", arguments}})); + ASSERT_VALUE_EQ(andExpression->serialize(false), Value(Document{{"$and", arguments}})); } TEST(ParseExpression, ShouldAcceptObjectInsideArrayAsSingleArgument) { @@ -1683,7 +1573,7 @@ TEST(ParseExpression, ShouldAcceptObjectInsideArrayAsSingleArgument) { auto andExpression = dynamic_cast<ExpressionAnd*>(resultExpression.get()); ASSERT_TRUE(andExpression); vector<Value> arguments = {Value(Document{{"$const", 1}})}; - ASSERT_VALUE_EQ(andExpression->serialize(), Value(Document{{"$and", arguments}})); + ASSERT_VALUE_EQ(andExpression->serialize(false), Value(Document{{"$and", arguments}})); } } // namespace Expression @@ -1709,7 +1599,7 @@ TEST(ParseOperand, ShouldRecognizeFieldPath) { << "$field")); auto fieldPathExpression = dynamic_cast<ExpressionFieldPath*>(resultExpression.get()); ASSERT_TRUE(fieldPathExpression); - ASSERT_VALUE_EQ(fieldPathExpression->serialize(), Value("$field"_sd)); + ASSERT_VALUE_EQ(fieldPathExpression->serialize(false), Value("$field"_sd)); } TEST(ParseOperand, ShouldRecognizeStringLiteral) { @@ -1717,7 +1607,7 @@ TEST(ParseOperand, ShouldRecognizeStringLiteral) { << "foo")); auto constantExpression = dynamic_cast<ExpressionConstant*>(resultExpression.get()); ASSERT_TRUE(constantExpression); - ASSERT_VALUE_EQ(constantExpression->serialize(), Value(Document{{"$const", "foo"_sd}})); + ASSERT_VALUE_EQ(constantExpression->serialize(false), Value(Document{{"$const", "foo"_sd}})); } TEST(ParseOperand, ShouldRecognizeNestedArray) { @@ -1727,21 +1617,21 @@ TEST(ParseOperand, ShouldRecognizeNestedArray) { ASSERT_TRUE(arrayExpression); vector<Value> expectedSerializedArray = {Value(Document{{"$const", "foo"_sd}}), Value("$field"_sd)}; - ASSERT_VALUE_EQ(arrayExpression->serialize(), Value(expectedSerializedArray)); + ASSERT_VALUE_EQ(arrayExpression->serialize(false), Value(expectedSerializedArray)); } TEST(ParseOperand, ShouldRecognizeNumberLiteral) { auto resultExpression = parseOperand(BSON("" << 5)); auto constantExpression = dynamic_cast<ExpressionConstant*>(resultExpression.get()); ASSERT_TRUE(constantExpression); - ASSERT_VALUE_EQ(constantExpression->serialize(), Value(Document{{"$const", 5}})); + ASSERT_VALUE_EQ(constantExpression->serialize(false), Value(Document{{"$const", 5}})); } TEST(ParseOperand, ShouldRecognizeNestedExpression) { auto resultExpression = parseOperand(BSON("" << BSON("$and" << BSONArray()))); auto andExpression = dynamic_cast<ExpressionAnd*>(resultExpression.get()); ASSERT_TRUE(andExpression); - ASSERT_VALUE_EQ(andExpression->serialize(), Value(Document{{"$and", vector<Value>{}}})); + ASSERT_VALUE_EQ(andExpression->serialize(false), Value(Document{{"$and", vector<Value>{}}})); } } // namespace Operand @@ -1782,7 +1672,7 @@ public: if (ValueComparator().evaluate(result != expected)) { string errMsg = str::stream() << "for expression " << field.first.toString() << " with argument " - << args.toString() << " full tree: " << expr->serialize().toString() + << args.toString() << " full tree: " << expr->serialize(false).toString() << " expected: " << expected.toString() << " but got: " << result.toString(); FAIL(errMsg); @@ -2594,7 +2484,7 @@ TEST(BuiltinRemoveVariableTest, RemoveSerializesCorrectly) { auto expression = ExpressionFieldPath::parse(&expCtx, "$$REMOVE", vps); ASSERT_BSONOBJ_EQ(BSON("foo" << "$$REMOVE"), - BSON("foo" << expression->serialize())); + BSON("foo" << expression->serialize(false))); } TEST(BuiltinRemoveVariableTest, RemoveSerializesCorrectlyWithTrailingPath) { @@ -2603,7 +2493,7 @@ TEST(BuiltinRemoveVariableTest, RemoveSerializesCorrectlyWithTrailingPath) { auto expression = ExpressionFieldPath::parse(&expCtx, "$$REMOVE.a.b", vps); ASSERT_BSONOBJ_EQ(BSON("foo" << "$$REMOVE.a.b"), - BSON("foo" << expression->serialize())); + BSON("foo" << expression->serialize(false))); } TEST(BuiltinRemoveVariableTest, RemoveSerializesCorrectlyAfterOptimization) { @@ -2614,7 +2504,7 @@ TEST(BuiltinRemoveVariableTest, RemoveSerializesCorrectlyAfterOptimization) { ASSERT(dynamic_cast<ExpressionConstant*>(optimizedExpression.get())); ASSERT_BSONOBJ_EQ(BSON("foo" << "$$REMOVE"), - BSON("foo" << optimizedExpression->serialize())); + BSON("foo" << optimizedExpression->serialize(false))); } } // namespace BuiltinRemoveVariable @@ -2832,7 +2722,7 @@ public: if (ValueComparator().evaluate(result != expected)) { string errMsg = str::stream() << "for expression " << field.first.toString() << " with argument " - << args.toString() << " full tree: " << expr->serialize().toString() + << args.toString() << " full tree: " << expr->serialize(false).toString() << " expected: " << expected.toString() << " but got: " << result.toString(); FAIL(errMsg); @@ -3215,18 +3105,6 @@ TEST(ExpressionMetaTest, ExpressionMetaSearchScoreDetails) { Value val = expressionMeta->evaluate(doc.freeze(), &expCtx.variables); ASSERT_DOCUMENT_EQ(val.getDocument(), Document(details)); } - -TEST(ExpressionMetaTest, ExpressionMetaVectorSearchScore) { - auto expCtx = ExpressionContextForTest{}; - BSONObj expr = fromjson("{$meta: \"vectorSearchScore\"}"); - auto expressionMeta = - ExpressionMeta::parse(&expCtx, expr.firstElement(), expCtx.variablesParseState); - - MutableDocument doc; - doc.metadata().setVectorSearchScore(1.23); - Value val = expressionMeta->evaluate(doc.freeze(), &expCtx.variables); - ASSERT_EQ(val.getDouble(), 1.23); -} } // namespace expression_meta_test namespace ExpressionRegexTest { @@ -3523,7 +3401,7 @@ TEST(ExpressionRandom, Basic) { intrusive_ptr<Expression> expression = Expression::parseExpression(&expCtx, fromjson("{ $rand: {} }"), vps); - const std::string& serialized = expression->serialize().getDocument().toString(); + const std::string& serialized = expression->serialize(false).getDocument().toString(); ASSERT_EQ("{$rand: {}}", serialized); const auto randFn = [&expression, &expCtx]() -> double { @@ -3660,18 +3538,11 @@ TEST(ExpressionGetFieldTest, GetFieldSerializesStringArgumentCorrectly) { VariablesParseState vps = expCtx.variablesParseState; BSONObj expr = fromjson("{$meta: \"foo\"}"); auto expression = ExpressionGetField::parse(&expCtx, expr.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "ignoredField": { - "$getField": { - "field": { - "$const": "foo" - }, - "input": "$$CURRENT" - } - } - })", - BSON("ignoredField" << expression->serialize())); + ASSERT_BSONOBJ_EQ(BSON("ignoredField" << BSON("$getField" << BSON("field" << BSON("$const" + << "foo") + << "input" + << "$$CURRENT"))), + BSON("ignoredField" << expression->serialize(false))); } TEST(ExpressionGetFieldTest, GetFieldSerializesCorrectly) { @@ -3679,220 +3550,12 @@ TEST(ExpressionGetFieldTest, GetFieldSerializesCorrectly) { VariablesParseState vps = expCtx.variablesParseState; BSONObj expr = fromjson("{$meta: {\"field\": \"foo\", \"input\": {a: 1}}}"); auto expression = ExpressionGetField::parse(&expCtx, expr.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "ignoredField": { - "$getField": { - "field": { - "$const": "foo" - }, - "input": { - "a": { - "$const": 1 - } - } - } - } - })", - BSON("ignoredField" << expression->serialize())); -} - -TEST(ExpressionGetFieldTest, GetFieldSerializesAndRedactsCorrectly) { - SerializationOptions options = SerializationOptions::kDebugShapeAndMarkIdentifiers_FOR_TEST; - auto expCtx = ExpressionContextForTest{}; - VariablesParseState vps = expCtx.variablesParseState; - - BSONObj expressionBSON = BSON("$getField" << BSON("field" - << "a" - << "input" - << "$b")); - - auto expression = ExpressionGetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({"field":{"$getField":{"field":"HASH<a>","input":"$HASH<b>"}}})", - BSON("field" << expression->serialize(options))); - - // Test the shorthand syntax. - expressionBSON = BSON("$getField" - << "a"); - - expression = ExpressionGetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({"field":{"$getField":{"field":"HASH<a>","input":"$$CURRENT"}}})", - BSON("field" << expression->serialize(options))); - - // Test a field with '.' characters. - expressionBSON = BSON("$getField" - << "a.b.c"); - - expression = ExpressionGetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$getField": { - "field": "HASH<a>.HASH<b>.HASH<c>", - "input": "$$CURRENT" - } - } - })", - BSON("field" << expression->serialize(options))); - - // Test a field with a '$' character. - expressionBSON = BSON("$getField" - << "a.$b.c"); - - expression = ExpressionGetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$getField": { - "field": "HASH<a>.HASH<$b>.HASH<c>", - "input": "$$CURRENT" - } - } - })", - BSON("field" << expression->serialize(options))); - - // Test a field with a trailing '.' character (invalid FieldPath). - expressionBSON = BSON("$getField" - << "a.b.c."); - - expression = ExpressionGetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$getField": { - "field": "HASH<invalidFieldPathPlaceholder>", - "input": "$$CURRENT" - } - } - })", - BSON("field" << expression->serialize(options))); -} - -TEST(ExpressionSetFieldTest, SetFieldRedactsCorrectly) { - SerializationOptions options = SerializationOptions::kDebugShapeAndMarkIdentifiers_FOR_TEST; - auto expCtx = ExpressionContextForTest{}; - VariablesParseState vps = expCtx.variablesParseState; - - // Test that a set field redacts properly. - BSONObj expressionBSON = BSON("$setField" << BSON("field" - << "a" - << "input" - << "$b" - << "value" - << "$c")); - auto expression = ExpressionSetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$setField": { - "field": "HASH<a>", - "input": "$HASH<b>", - "value": "$HASH<c>" - } - } - })", - BSON("field" << expression->serialize(options))); - - // Object as input. - expressionBSON = BSON("$setField" << BSON("field" - << "a" - << "input" << BSON("a" << true) << "value" << 10)); - expression = ExpressionSetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$setField": { - "field": "HASH<a>", - "input": "?object", - "value": "?number" - } - } - })", - BSON("field" << expression->serialize(options))); - - // Nested object as input. - expressionBSON = - BSON("$setField" << BSON("field" - << "a" - << "input" << BSON("a" << BSON("b" << 5)) << "value" << 10)); - expression = ExpressionSetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$setField": { - "field": "HASH<a>", - "input": "?object", - "value": "?number" - } - } - })", - BSON("field" << expression->serialize(options))); - - // Object with field path in input. - expressionBSON = BSON("$setField" << BSON("field" - << "a" - << "input" - << BSON("a" - << "$field") - << "value" << 10)); - expression = ExpressionSetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$setField": { - "field": "HASH<a>", - "input": { - "HASH<a>": "$HASH<field>" - }, - "value": "?number" - } - } - })", - BSON("field" << expression->serialize(options))); - - // Object with field path in value. - expressionBSON = BSON("$setField" << BSON("field" - << "a" - << "input" - << BSON("a" - << "b") - << "value" - << BSON("c" - << "$d"))); - expression = ExpressionSetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$setField": { - "field": "HASH<a>", - "input": "?object", - "value": { - "HASH<c>": "$HASH<d>" - } - } - } - })", - BSON("field" << expression->serialize(options))); - - // Array as input. - expressionBSON = BSON("$setField" << BSON("field" - << "a" - << "input" << BSON("a" << BSON_ARRAY(3 << 4 << 5)) - << "value" << 10)); - expression = ExpressionSetField::parse(&expCtx, expressionBSON.firstElement(), vps); - ASSERT_BSONOBJ_EQ_AUTO( // NOLINT - R"({ - "field": { - "$setField": { - "field": "HASH<a>", - "input": "?object", - "value": "?number" - } - } - })", - BSON("field" << expression->serialize(options))); + ASSERT_BSONOBJ_EQ( + BSON("ignoredField" << BSON( + "$getField" << BSON("field" << BSON("$const" + << "foo") + << "input" << BSON("a" << BSON("$const" << 1))))), + BSON("ignoredField" << expression->serialize(false))); } TEST(ExpressionSetFieldTest, SetFieldSerializesCorrectly) { @@ -3906,7 +3569,7 @@ TEST(ExpressionSetFieldTest, SetFieldSerializesCorrectly) { << "foo") << "input" << BSON("a" << BSON("$const" << 1)) << "value" << BSON("$const" << 24)))), - BSON("ignoredField" << expression->serialize())); + BSON("ignoredField" << expression->serialize(false))); } TEST(ExpressionIfNullTest, OptimizedExpressionIfNullShouldRemoveNullConstant) { @@ -3926,7 +3589,7 @@ TEST(ExpressionIfNullTest, auto expr = fromjson("{$ifNull: [null, \"$a\"]}"); auto exprIfNull = ExpressionIfNull::parse(&expCtx, expr.firstElement(), vps); auto optimizedNullRemoved = exprIfNull->optimize(); - ASSERT_VALUE_EQ(optimizedNullRemoved->serialize(), Value("$a"_sd)); + ASSERT_VALUE_EQ(optimizedNullRemoved->serialize(false), Value("$a"_sd)); } TEST(ExpressionIfNullTest, OptimizedExpressionIfNullShouldRemoveAllNullConstantsButLast) { @@ -4258,7 +3921,7 @@ TEST(ExpressionFLETest, TestBinData_RoundTrip) { ASSERT_VALUE_EQ(exprFle->evaluate({}, &expCtx.variables), Value(true)); // Verify it round trips - auto value = exprFle->serialize(); + auto value = exprFle->serialize(false); auto roundTripExpr = fromjson(R"({$_internalFleEq: { field: { @@ -4283,22 +3946,10 @@ TEST(ExpressionFLETest, TestBinData_RoundTrip) { "subType": "6" } } - } })"); + } })"); ASSERT_BSONOBJ_EQ(value.getDocument().toBson(), roundTripExpr); } -/** - * Test case for round-trip conversion of random double using $convert. - * - * Generates 1000 random doubles and verifies they can be correctly converted to string values and - * back to double. - */ -TEST(ExpressionConvert, StringToDouble) { - for (int i = 0; i < 1000; ++i) { - verifyStringDoubleConvertRoundtripsCorrectly(randomDouble()); - } -} - } // namespace ExpressionTests |
