Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
"""
Tests for $exists argument truthiness.

Tests non-obvious truthy/falsy behavior when non-boolean values are passed
as the $exists argument. Only covers cases where the result is surprising
or where compatible engines are likely to diverge.
"""

import pytest
from bson import Decimal128

from documentdb_tests.compatibility.tests.core.operator.query.utils.query_test_case import (
QueryTestCase,
)
from documentdb_tests.framework.assertions import assertSuccess
from documentdb_tests.framework.executor import execute_command
from documentdb_tests.framework.parametrize import pytest_params
from documentdb_tests.framework.test_constants import (
DECIMAL128_INFINITY,
DECIMAL128_MANY_TRAILING_ZEROS,
DECIMAL128_NAN,
DECIMAL128_NEGATIVE_INFINITY,
DECIMAL128_NEGATIVE_ZERO,
DECIMAL128_TRAILING_ZERO,
DECIMAL128_ZERO,
DOUBLE_NEGATIVE_ZERO,
FLOAT_NAN,
)

DOCS = [{"_id": 1, "a": 1}, {"_id": 2, "b": 2}]
EXISTS_TRUE = [{"_id": 1, "a": 1}]
EXISTS_FALSE = [{"_id": 2, "b": 2}]

ALL_TESTS: list[QueryTestCase] = [
QueryTestCase(
id="true_matches_docs_with_field",
filter={"a": {"$exists": True}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: true matches documents with the field",
),
QueryTestCase(
id="false_matches_docs_without_field",
filter={"a": {"$exists": False}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: false matches documents without the field",
),
QueryTestCase(
id="int_1_as_true",
filter={"a": {"$exists": 1}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: 1 behaves as true",
),
QueryTestCase(
id="int_0_as_false",
filter={"a": {"$exists": 0}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: 0 behaves as false",
),
QueryTestCase(
id="negative_int_as_true",
filter={"a": {"$exists": -1}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: -1 behaves as true (non-zero)",
),
QueryTestCase(
id="negative_zero_double_as_false",
filter={"a": {"$exists": DOUBLE_NEGATIVE_ZERO}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: -0.0 treated as false (zero)",
),
QueryTestCase(
id="decimal128_zero_as_false",
filter={"a": {"$exists": DECIMAL128_ZERO}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: Decimal128('0') behaves as false",
),
QueryTestCase(
id="decimal128_negative_zero_as_false",
filter={"a": {"$exists": DECIMAL128_NEGATIVE_ZERO}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: Decimal128('-0') treated as false (zero)",
),
QueryTestCase(
id="decimal128_infinity_as_true",
filter={"a": {"$exists": DECIMAL128_INFINITY}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: Decimal128('Infinity') behaves as true",
),
QueryTestCase(
id="decimal128_negative_infinity_as_true",
filter={"a": {"$exists": DECIMAL128_NEGATIVE_INFINITY}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: Decimal128('-Infinity') behaves as true",
),
QueryTestCase(
id="decimal128_trailing_zero_as_true",
filter={"a": {"$exists": DECIMAL128_TRAILING_ZERO}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: Decimal128('1.0') behaves as true (non-zero)",
),
QueryTestCase(
id="decimal128_many_trailing_zeros_as_true",
filter={"a": {"$exists": DECIMAL128_MANY_TRAILING_ZEROS}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: Decimal128 with many trailing zeros behaves as true (non-zero)",
),
QueryTestCase(
id="decimal128_zero_trailing_decimals_as_false",
filter={"a": {"$exists": Decimal128("0.00")}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: Decimal128('0.00') treated as false (zero representation)",
),
QueryTestCase(
id="decimal128_zero_exponent_as_false",
filter={"a": {"$exists": Decimal128("0E+10")}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: Decimal128('0E+10') treated as false (zero representation)",
),
QueryTestCase(
id="decimal128_nan_as_true",
filter={"a": {"$exists": DECIMAL128_NAN}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: Decimal128('NaN') behaves as true (truthy)",
),
QueryTestCase(
id="float_nan_as_true",
filter={"a": {"$exists": FLOAT_NAN}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: float('nan') behaves as true (truthy)",
),
QueryTestCase(
id="empty_string_as_true",
filter={"a": {"$exists": ""}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: '' behaves as true (empty string is truthy in BSON)",
),
QueryTestCase(
id="string_false_as_true",
filter={"a": {"$exists": "false"}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: 'false' behaves as true (non-empty string is truthy)",
),
QueryTestCase(
id="empty_array_as_true",
filter={"a": {"$exists": []}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: [] behaves as true (truthy)",
),
QueryTestCase(
id="empty_object_as_true",
filter={"a": {"$exists": {}}},
doc=DOCS,
expected=EXISTS_TRUE,
msg="$exists: {} behaves as true (truthy)",
),
QueryTestCase(
id="null_as_false",
filter={"a": {"$exists": None}},
doc=DOCS,
expected=EXISTS_FALSE,
msg="$exists: None behaves as false",
),
]


@pytest.mark.parametrize("test", pytest_params(ALL_TESTS))
def test_exists_argument_handling(collection, test):
"""Parametrized test for $exists argument truthiness."""
collection.insert_many(test.doc)
result = execute_command(collection, {"find": collection.name, "filter": test.filter})
assertSuccess(result, test.expected, ignore_doc_order=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""
Tests for $exists array field behavior, special field names, and multiple fields.

Covers $exists on array fields, $elemMatch with $exists, _id field behavior,
and multiple $exists conditions.
"""

import pytest

from documentdb_tests.compatibility.tests.core.operator.query.utils.query_test_case import (
QueryTestCase,
)
from documentdb_tests.framework.assertions import assertSuccess
from documentdb_tests.framework.executor import execute_command
from documentdb_tests.framework.parametrize import pytest_params

MULTI_DOCS = [
{"_id": 1, "a": 1, "b": 2},
{"_id": 2, "a": 1},
{"_id": 3, "b": 2},
{"_id": 4},
]

ARRAY_TESTS: list[QueryTestCase] = [
QueryTestCase(
id="elemMatch_exists_true",
filter={"a": {"$elemMatch": {"y": {"$exists": True}}}},
doc=[{"_id": 1, "a": [{"x": 1, "y": 2}, {"x": 3}]}],
expected=[{"_id": 1, "a": [{"x": 1, "y": 2}, {"x": 3}]}],
msg="$elemMatch with $exists: true matches element with field",
),
QueryTestCase(
id="elemMatch_exists_false",
filter={"a": {"$elemMatch": {"y": {"$exists": False}}}},
doc=[{"_id": 1, "a": [{"x": 1, "y": 2}, {"x": 3}]}],
expected=[{"_id": 1, "a": [{"x": 1, "y": 2}, {"x": 3}]}],
msg="$elemMatch with $exists: false matches element without field",
),
QueryTestCase(
id="elemMatch_compound",
filter={"a": {"$elemMatch": {"y": {"$exists": True}, "x": {"$gt": 0}}}},
doc=[{"_id": 1, "a": [{"x": 1, "y": 2}, {"x": 3}]}],
expected=[{"_id": 1, "a": [{"x": 1, "y": 2}, {"x": 3}]}],
msg="$elemMatch compound with $exists and $gt",
),
QueryTestCase(
id="dot_notation_nested_fields",
filter={"a.x": {"$exists": True}},
doc=[
{"_id": 1, "a": [{"x": 1}, {"x": 2}, {"y": 3}]},
{"_id": 2, "a": [{"y": 1}, {"y": 2}]},
],
expected=[{"_id": 1, "a": [{"x": 1}, {"x": 2}, {"y": 3}]}],
msg="Dot notation on array elements matches when any has field",
),
]

SPECIAL_FIELD_TESTS: list[QueryTestCase] = [
QueryTestCase(
id="id_always_true",
filter={"_id": {"$exists": True}},
doc=[{"_id": 1}, {"_id": 2}, {"_id": 3}],
expected=[{"_id": 1}, {"_id": 2}, {"_id": 3}],
msg="_id always exists — $exists: true matches all",
),
QueryTestCase(
id="id_false_no_match",
filter={"_id": {"$exists": False}},
doc=[{"_id": 1}, {"_id": 2}, {"_id": 3}],
expected=[],
msg="_id always exists — $exists: false matches none",
),
QueryTestCase(
id="both_exist",
filter={"a": {"$exists": True}, "b": {"$exists": True}},
doc=MULTI_DOCS,
expected=[{"_id": 1, "a": 1, "b": 2}],
msg="Both fields must exist",
),
QueryTestCase(
id="a_exists_b_not",
filter={"a": {"$exists": True}, "b": {"$exists": False}},
doc=MULTI_DOCS,
expected=[{"_id": 2, "a": 1}],
msg="a exists, b does not",
),
QueryTestCase(
id="neither_exists",
filter={"a": {"$exists": False}, "b": {"$exists": False}},
doc=MULTI_DOCS,
expected=[{"_id": 4}],
msg="Neither field exists",
),
]

ALL_TESTS = ARRAY_TESTS + SPECIAL_FIELD_TESTS


@pytest.mark.parametrize("test", pytest_params(ALL_TESTS))
def test_exists_array_and_special_fields(collection, test):
"""Parametrized test for $exists array behavior, special fields, and multiple conditions."""
collection.insert_many(test.doc)
result = execute_command(collection, {"find": collection.name, "filter": test.filter})
assertSuccess(result, test.expected, ignore_doc_order=True)
Loading
Loading