tests/spec: a recorded corpus for the positional operators

M3's gate as named -- "remaining crud coverage; e2e3/e2e4 green" -- cannot
see this work. e2e3 and e2e4 contain zero positional paths, and the pinned
crud corpus covers `$[<identifier>]` only: no `$[]` case, no bare `$` case
anywhere in it. Both stayed green through a bug that replaced an array with
`{"$[i]": {...}}` and answered ok: 1. So M3 brings its own corpus, built the
way M2.5's was: inputs authored in `sources/`, every expectation recorded
from mongod 8.3.7, run through the shared runner with `--suite-dir`.

51 cases across the three spellings. It stands at 15 pass / 36 fail against
the refusal, which is the intended shape -- `expressions.json` was recorded
at 1 pass / 26 fail before the evaluator and is green now. The 15 that pass
are refusals where this server's code already matches; of the 36, 31 are the
constructs answering "not implemented" and 5 are refusals whose code
differs, four of them arrayFilters validation this server cannot do because
it never parses the option.

Every case records its `outcome`, refusals included. That is deliberate and
it is the whole point of the file: a refusal that left the document mangled
is indistinguishable from a clean one in `expectError` alone, and a mangled
document is what this corpus exists to catch.

What recording it settled, none of it guessable, the first contradicting
what the design review assumed:

  - `y.$[i].c.$[i].d`, one identifier reused at two levels, is **accepted**
    -- not a duplicate-identifier error
  - `$[]` over an empty array is a no-op with modifiedCount 0
  - `$[]` over an array with a non-document element is error 28, where every
    other path failure here is 2
  - a positional segment never creates: a missing or non-array path is an
    error, where `$set: {'a.b': 1}` would construct one
  - an upsert gets no special case -- it fails for the same reason
  - `$` writes only the first matching element, and is refused when the query
    never touched the array
  - any of the three in first position is refused, as is `$` twice in a path
  - `arrayFilters` alongside a replacement is ignored rather than refused

A case needing its own documents reseeds through operations rather than
`initialData`, because the format's `initialData` is per file and the runner
seeds it once per test. That keeps one file per operator instead of one file
per document shape.

crud scorecard unchanged at 204/87, aggregation corpus still 70/0.
This commit was merged in pull request #6.
This commit is contained in:
A.Shakhmatov
2026-08-10 19:00:01 +03:00
parent 3c2ac38fd9
commit e5a84c0598
10 changed files with 4554 additions and 2 deletions

View File

@@ -0,0 +1,118 @@
{
"_comment": [
"Inputs only. Expectations are measured -- see record.js.",
"`$[]`, the all-positional operator. The pinned crud corpus contains no",
"`$[]` case at all, which is half of why this directory exists: before",
"the refusal landed, `$[]` overwrote the array it was meant to walk and",
"nothing external would have noticed."
],
"documents": [
{ "_id": 1, "y": [{ "b": 3 }, { "b": 1 }] },
{ "_id": 2, "y": [] },
{ "_id": 3, "y": [{ "c": [{ "d": 1 }, { "d": 2 }] }, { "c": [{ "d": 3 }] }] }
],
"cases": [
{
"description": "every element of the array is written",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 1 },
"update": { "$set": { "y.$[].b": 9 } }
}
},
{
"description": "nested $[] is a cross-product over both levels",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 3 },
"update": { "$set": { "y.$[].c.$[].d": 0 } }
}
},
{
"description": "$[] over an empty array",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 2 },
"update": { "$set": { "y.$[].b": 9 } }
}
},
{
"description": "$inc through $[] adds to every element",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 1 },
"update": { "$inc": { "y.$[].b": 10 } }
}
},
{
"description": "$[] as the leaf over an array of scalars",
"documents": [{ "_id": 1, "y": [1, 2, 3] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[]": 0 } }
}
},
{
"description": "$unset through $[] removes a field from every element",
"documents": [{ "_id": 1, "y": [{ "b": 1, "e": 1 }, { "b": 2, "e": 2 }] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$unset": { "y.$[].e": "" } }
}
},
{
"description": "$[] where an element is not a document",
"documents": [{ "_id": 1, "y": [{ "b": 1 }, 7] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[].b": 9 } }
}
},
{
"description": "updateMany with $[] across every document",
"operation": "updateMany",
"arguments": {
"filter": { "_id": { "$in": [1, 2] } },
"update": { "$set": { "y.$[].b": 9 } }
}
},
{
"description": "$[] where the path does not exist",
"documents": [{ "_id": 1, "z": 1 }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[].b": 9 } }
}
},
{
"description": "$[] where the path is not an array",
"documents": [{ "_id": 1, "y": 5 }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[].b": 9 } }
}
},
{
"description": "$[] in first position is refused",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 1 },
"update": { "$set": { "$[]": 9 } }
}
},
{
"description": "$[] combined with an identifier in one path",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 3 },
"update": { "$set": { "y.$[].c.$[j].d": 0 } },
"arrayFilters": [{ "j.d": 2 }]
}
}
]
}

View File

@@ -0,0 +1,267 @@
{
"_comment": [
"Inputs only. Expectations are measured -- see record.js.",
"`$[<identifier>]` and its arrayFilters. The documents are the pinned",
"corpus's own (updateOne-arrayFilters.json) so the two agree on the data",
"and a disagreement between them is about behaviour, never about setup.",
"Cases that need a different shape carry their own `documents`."
],
"documents": [
{ "_id": 1, "y": [{ "b": 3 }, { "b": 1 }] },
{ "_id": 2, "y": [{ "b": 0 }, { "b": 1 }] },
{ "_id": 3, "y": [{ "b": 5, "c": [{ "d": 2 }, { "d": 1 }] }] }
],
"cases": [
{
"description": "one element matches the filter",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "no element matches the filter",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 4 }]
}
},
{
"description": "every element of the array matches",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": { "$gte": 0 } }]
}
},
{
"description": "updateMany where no document has a matching element",
"operation": "updateMany",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 4 }]
}
},
{
"description": "updateMany where one document has a matching element",
"operation": "updateMany",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "updateMany where several documents match",
"operation": "updateMany",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 1 }]
}
},
{
"description": "two identifiers down a nested path",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 3 },
"update": { "$set": { "y.$[i].c.$[j].d": 0 } },
"arrayFilters": [{ "i.b": 5 }, { "j.d": 2 }]
}
},
{
"description": "the outer identifier matches nothing, so the inner never runs",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 3 },
"update": { "$set": { "y.$[i].c.$[j].d": 0 } },
"arrayFilters": [{ "i.b": 99 }, { "j.d": 2 }]
}
},
{
"description": "findOneAndUpdate returns the document and reports the array",
"operation": "findOneAndUpdate",
"arguments": {
"filter": { "_id": 1 },
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }],
"returnDocument": "after"
}
},
{
"description": "$inc through an identifier adds to the element",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 1 },
"update": { "$inc": { "y.$[i].b": 10 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "$unset through an identifier removes the element's field",
"documents": [{ "_id": 1, "y": [{ "b": 3, "e": 9 }, { "b": 1 }] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$unset": { "y.$[i].e": "" } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "an identifier as the leaf replaces the whole element",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 1 },
"update": { "$set": { "y.$[i]": { "replaced": true } } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "a filter reaching a nested field of the element",
"documents": [{ "_id": 1, "y": [{ "b": { "q": 1 } }, { "b": { "q": 2 } }] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b.q": 0 } },
"arrayFilters": [{ "i.b.q": 2 }]
}
},
{
"description": "an array of scalars, filtered on the identifier itself",
"documents": [{ "_id": 1, "y": [1, 2, 3, 2] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i]": 9 } },
"arrayFilters": [{ "i": 2 }]
}
},
{
"description": "an identifier used twice in one path",
"documents": [{ "_id": 1, "y": [{ "c": [{ "d": 1 }, { "d": 2 }] }] }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].c.$[i].d": 0 } },
"arrayFilters": [{ "i.d": 1 }]
}
},
{
"description": "an identifier naming no array filter is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[k].b": 2 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "an identifier with no arrayFilters at all is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } }
}
},
{
"description": "an array filter the update never uses is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.b": 2 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "two array filters with the same identifier are refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }, { "i.b": 1 }]
}
},
{
"description": "an array filter with no top-level field is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{}]
}
},
{
"description": "an array filter with two top-level fields is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3, "j.b": 1 }]
}
},
{
"description": "an identifier that is not a lowercase alphanumeric name is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[1x].b": 2 } },
"arrayFilters": [{ "1x.b": 3 }]
}
},
{
"description": "an identifier in first position is refused",
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "$[i]": 2 } },
"arrayFilters": [{ "i": 1 }]
}
},
{
"description": "the path's array does not exist",
"documents": [{ "_id": 1, "z": 1 }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "the path names something that is not an array",
"documents": [{ "_id": 1, "y": 5 }],
"operation": "updateOne",
"arguments": {
"filter": {},
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }]
}
},
{
"description": "an upsert gets no special case",
"documents": [],
"operation": "updateOne",
"arguments": {
"filter": { "k": 1 },
"update": { "$set": { "y.$[i].b": 2 } },
"arrayFilters": [{ "i.b": 3 }],
"upsert": true
}
},
{
"description": "arrayFilters alongside a replacement",
"operation": "replaceOne",
"arguments": {
"filter": { "_id": 1 },
"replacement": { "z": 1 },
"arrayFilters": [{ "i.b": 3 }]
}
}
]
}

View File

@@ -0,0 +1,118 @@
{
"_comment": [
"Inputs only. Expectations are measured -- see record.js.",
"`$`, the original positional operator, which writes the *first* element",
"the query matched. It is the one of the three that needs something the",
"document alone does not hold -- which element the filter matched -- so",
"every case here pairs a filter with an update and the pairing is the",
"point. The pinned crud corpus has no `$` case anywhere."
],
"documents": [
{ "_id": 1, "y": [{ "b": 3 }, { "b": 1 }] },
{ "_id": 2, "y": [{ "b": 0 }, { "b": 1 }] },
{ "_id": 3, "y": [{ "b": 5, "c": [{ "d": 2 }] }] }
],
"cases": [
{
"description": "$ writes the element the filter matched",
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 3 },
"update": { "$set": { "y.$.b": 7 } }
}
},
{
"description": "$ writes only the first match when several elements qualify",
"documents": [{ "_id": 1, "y": [{ "b": 1 }, { "b": 1 }, { "b": 2 }] }],
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 1 },
"update": { "$set": { "y.$.b": 7 } }
}
},
{
"description": "$ when the filter never touched the array is refused",
"operation": "updateOne",
"arguments": {
"filter": { "_id": 1 },
"update": { "$set": { "y.$.b": 7 } }
}
},
{
"description": "$inc through $",
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 3 },
"update": { "$inc": { "y.$.b": 10 } }
}
},
{
"description": "$ as the leaf replaces the matched element",
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 3 },
"update": { "$set": { "y.$": { "replaced": true } } }
}
},
{
"description": "$ reaching a field below the matched element",
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 5 },
"update": { "$set": { "y.$.c": [] } }
}
},
{
"description": "$ with the filter matching on a different field of the element",
"documents": [{ "_id": 1, "y": [{ "k": "a", "v": 1 }, { "k": "b", "v": 2 }] }],
"operation": "updateOne",
"arguments": {
"filter": { "y.k": "b" },
"update": { "$set": { "y.$.v": 9 } }
}
},
{
"description": "updateMany with $ writes each document's own match",
"operation": "updateMany",
"arguments": {
"filter": { "y.b": 1 },
"update": { "$set": { "y.$.b": 7 } }
}
},
{
"description": "$ over an array of scalars",
"documents": [{ "_id": 1, "y": [1, 2, 3] }],
"operation": "updateOne",
"arguments": {
"filter": { "y": 2 },
"update": { "$set": { "y.$": 9 } }
}
},
{
"description": "$ in first position is refused",
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 3 },
"update": { "$set": { "$": 7 } }
}
},
{
"description": "$ twice in one path is refused",
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 5 },
"update": { "$set": { "y.$.c.$.d": 0 } }
}
},
{
"description": "$ on an upsert that inserts",
"documents": [],
"operation": "updateOne",
"arguments": {
"filter": { "y.b": 3 },
"update": { "$set": { "y.$.b": 7 } },
"upsert": true
}
}
]
}