summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/expression_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/expression_test.cpp')
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp433
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