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:
850
tests/spec/positional/first-positional.json
Normal file
850
tests/spec/positional/first-positional.json
Normal file
@@ -0,0 +1,850 @@
|
||||
{
|
||||
"description": "first-positional",
|
||||
"schemaVersion": "1.4",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database0",
|
||||
"client": "client0",
|
||||
"databaseName": "positional-corpus"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 3
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "$ writes the element the filter matched",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 3
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.b": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 7
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ writes only the first match when several elements qualify",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "deleteMany",
|
||||
"arguments": {
|
||||
"filter": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "insertMany",
|
||||
"arguments": {
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 1
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
},
|
||||
{
|
||||
"b": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 1
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.b": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 7
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
},
|
||||
{
|
||||
"b": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ when the filter never touched the array is refused",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"_id": 1
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.b": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isError": true,
|
||||
"errorCode": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 3
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$inc through $",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 3
|
||||
},
|
||||
"update": {
|
||||
"$inc": {
|
||||
"y.$.b": 10
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 13
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ as the leaf replaces the matched element",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 3
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$": {
|
||||
"replaced": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"replaced": true
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ reaching a field below the matched element",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 5
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.c": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 3
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ with the filter matching on a different field of the element",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "deleteMany",
|
||||
"arguments": {
|
||||
"filter": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "insertMany",
|
||||
"arguments": {
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"k": "a",
|
||||
"v": 1
|
||||
},
|
||||
{
|
||||
"k": "b",
|
||||
"v": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.k": "b"
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.v": 9
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"k": "a",
|
||||
"v": 1
|
||||
},
|
||||
{
|
||||
"k": "b",
|
||||
"v": 9
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updateMany with $ writes each document's own match",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateMany",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 1
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.b": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 2,
|
||||
"modifiedCount": 2,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 3
|
||||
},
|
||||
{
|
||||
"b": 7
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 7
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ over an array of scalars",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "deleteMany",
|
||||
"arguments": {
|
||||
"filter": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "insertMany",
|
||||
"arguments": {
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y": 2
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$": 9
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"matchedCount": 1,
|
||||
"modifiedCount": 1,
|
||||
"upsertedCount": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
1,
|
||||
9,
|
||||
3
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ in first position is refused",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 3
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"$": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isError": true,
|
||||
"errorCode": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 3
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ twice in one path is refused",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 5
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.c.$.d": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isError": true,
|
||||
"errorCode": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"y": [
|
||||
{
|
||||
"b": 3
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 2,
|
||||
"y": [
|
||||
{
|
||||
"b": 0
|
||||
},
|
||||
{
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": 3,
|
||||
"y": [
|
||||
{
|
||||
"b": 5,
|
||||
"c": [
|
||||
{
|
||||
"d": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ on an upsert that inserts",
|
||||
"operations": [
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "deleteMany",
|
||||
"arguments": {
|
||||
"filter": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"object": "collection0",
|
||||
"name": "updateOne",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"y.b": 3
|
||||
},
|
||||
"update": {
|
||||
"$set": {
|
||||
"y.$.b": 7
|
||||
}
|
||||
},
|
||||
"upsert": true
|
||||
},
|
||||
"expectError": {
|
||||
"isError": true,
|
||||
"errorCode": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "positional-corpus",
|
||||
"documents": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user