From 88731a55c3dfd97b38ce0360f53b5b2674209754 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 27 Jun 2023 15:54:46 +0200 Subject: [PATCH] PHPLIB-1137: Reject PackedArrays when expecting documents (#1117) * Refactor data providers With this refactoring, data providers become more concise; each data entry also gets a distinct name making for easier identification of failing tests * PHPLIB-1137: Prohibit PackedArray objects where documents are required * Refactor validity check for bulk update argument * Fix invalid data providers * Ensure unique data set names in createOptionDataProvider * Move invalid update values data provider to operation tests * Introduce new exception factory for expected document type --- psalm-baseline.xml | 81 ++++-------- src/Command/ListCollections.php | 7 +- src/Command/ListDatabases.php | 6 +- src/Exception/InvalidArgumentException.php | 11 ++ src/GridFS/WritableStream.php | 7 +- src/Model/ChangeStreamIterator.php | 9 +- src/Model/IndexInput.php | 7 +- src/Operation/Aggregate.php | 9 +- src/Operation/BulkWrite.php | 32 ++--- src/Operation/Count.php | 9 +- src/Operation/CountDocuments.php | 6 +- src/Operation/CreateCollection.php | 34 ++--- src/Operation/CreateEncryptedCollection.php | 5 +- src/Operation/DatabaseCommand.php | 6 +- src/Operation/Delete.php | 13 +- src/Operation/Distinct.php | 9 +- src/Operation/DropEncryptedCollection.php | 7 +- src/Operation/Find.php | 33 ++--- src/Operation/FindAndModify.php | 21 +-- src/Operation/FindOneAndDelete.php | 11 +- src/Operation/FindOneAndReplace.php | 15 +-- src/Operation/FindOneAndUpdate.php | 9 +- src/Operation/InsertMany.php | 7 +- src/Operation/InsertOne.php | 7 +- src/Operation/MapReduce.php | 17 +-- src/Operation/ReplaceOne.php | 7 +- src/Operation/Update.php | 13 +- src/Operation/Watch.php | 9 +- src/functions.php | 25 +++- tests/Collection/CollectionFunctionalTest.php | 27 +--- tests/Command/ListCollectionsTest.php | 27 +--- tests/Command/ListDatabasesTest.php | 30 +---- tests/Database/DatabaseFunctionalTest.php | 25 +--- tests/FunctionsTest.php | 12 +- tests/GridFS/BucketFunctionalTest.php | 40 ++---- tests/GridFS/WritableStreamFunctionalTest.php | 20 +-- tests/Model/ChangeStreamIteratorTest.php | 3 +- tests/Operation/AggregateTest.php | 85 +++--------- tests/Operation/BulkWriteTest.php | 65 ++++----- tests/Operation/CountDocumentsTest.php | 50 ++----- tests/Operation/CountTest.php | 50 ++----- tests/Operation/CreateCollectionTest.php | 115 ++++------------ .../CreateEncryptedCollectionTest.php | 10 +- tests/Operation/CreateIndexesTest.php | 28 ++-- tests/Operation/DatabaseCommandTest.php | 20 +-- tests/Operation/DeleteTest.php | 22 +-- tests/Operation/DistinctTest.php | 35 ++--- tests/Operation/DropCollectionTest.php | 20 +-- tests/Operation/DropDatabaseTest.php | 20 +-- .../Operation/DropEncryptedCollectionTest.php | 10 +- tests/Operation/DropIndexesTest.php | 25 +--- .../Operation/EstimatedDocumentCountTest.php | 25 +--- tests/Operation/ExplainTest.php | 25 +--- tests/Operation/FindAndModifyTest.php | 75 +++-------- tests/Operation/FindOneAndDeleteTest.php | 10 +- tests/Operation/FindOneAndReplaceTest.php | 17 +-- tests/Operation/FindOneAndUpdateTest.php | 15 +-- tests/Operation/FindTest.php | 125 ++++-------------- tests/Operation/InsertManyTest.php | 25 +--- tests/Operation/InsertOneTest.php | 20 +-- tests/Operation/ListIndexesTest.php | 15 +-- tests/Operation/MapReduceTest.php | 80 +++-------- tests/Operation/ModifyCollectionTest.php | 20 +-- tests/Operation/RenameCollectionTest.php | 25 +--- tests/Operation/ReplaceOneTest.php | 2 +- tests/Operation/TestCase.php | 10 ++ tests/Operation/UpdateTest.php | 45 ++----- tests/Operation/WatchTest.php | 61 ++------- tests/TestCase.php | 89 ++++++++++++- 69 files changed, 633 insertions(+), 1222 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 778b248ae..c7aecbc8b 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -196,10 +196,6 @@ - - ! is_array($document) && ! is_object($document) - isset($initialResumeToken) && ! is_array($initialResumeToken) && ! is_object($initialResumeToken) - $reply->cursor->nextBatch $this->current() @@ -276,8 +272,9 @@ - + $fieldName + $index['key'] $fieldName @@ -328,11 +325,13 @@ $args[1] $args[2] - + $args[0] $args[0] $args[0] $args[0] + $args[0] + $args[1] $args[1] $args[1] $args[1] @@ -395,9 +394,6 @@ - - ! is_array($filter) && ! is_object($filter) - $cmd[$option] $cmd['hint'] @@ -410,11 +406,6 @@ isInTransaction - - - ! is_array($filter) && ! is_object($filter) - - $options['pipeline'] @@ -427,7 +418,8 @@ - + + $options['encryptedFields'] $this->options['encryptedFields'] @@ -446,9 +438,6 @@ - - ! is_array($command) && ! is_object($command) - $this->options['typeMap'] @@ -458,9 +447,6 @@ - - ! is_array($filter) && ! is_object($filter) - $this->options['writeConcern'] @@ -476,9 +462,6 @@ - - ! is_array($filter) && ! is_object($filter) - $this->options['typeMap'] @@ -516,6 +499,11 @@ $options['writeConcern'] + + + $options['encryptedFields'] + + $this->options['typeMap'] @@ -540,9 +528,6 @@ - - ! is_array($filter) && ! is_object($filter) - $this->options['typeMap'] @@ -583,32 +568,30 @@ - - ! is_array($filter) && ! is_object($filter) - + + $options['fields'] + - - ! is_array($filter) && ! is_object($filter) - ! is_array($replacement) && ! is_object($replacement) - + + $options['fields'] + $options['returnDocument'] - - ! is_array($filter) && ! is_object($filter) + ! is_array($update) && ! is_object($update) + + $options['fields'] + $options['returnDocument'] - - ! is_array($document) && ! is_object($document) - $insertedIds[$i] $options[$option] @@ -621,9 +604,6 @@ - - ! is_array($document) && ! is_object($document) - $insertedId $options[$option] @@ -692,14 +672,8 @@ isInTransaction - - - ! is_array($replacement) && ! is_object($replacement) - - - - ! is_array($filter) && ! is_object($filter) + ! is_array($update) && ! is_object($update) @@ -767,11 +741,11 @@ - - ! is_array($document) && ! is_object($document) + is_array($document) - + + $stage $wireVersionForWriteStageOnSecondary @@ -784,8 +758,9 @@ $typeMap['fieldPaths'][$fieldPath] $typeMap['fieldPaths'][substr($fieldPath, 0, -2)] - + $element[$key] + $stage $type $typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath] $typeMap['fieldPaths'][$fieldPath] diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index a970aeb07..7b6e84489 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -25,10 +25,9 @@ use MongoDB\Model\CachingIterator; use MongoDB\Operation\Executable; -use function is_array; use function is_bool; use function is_integer; -use function is_object; +use function MongoDB\is_document; /** * Wrapper for the listCollections command. @@ -79,8 +78,8 @@ public function __construct(string $databaseName, array $options = []) throw InvalidArgumentException::invalidType('"authorizedCollections" option', $options['authorizedCollections'], 'boolean'); } - if (isset($options['filter']) && ! is_array($options['filter']) && ! is_object($options['filter'])) { - throw InvalidArgumentException::invalidType('"filter" option', $options['filter'], 'array or object'); + if (isset($options['filter']) && ! is_document($options['filter'])) { + throw InvalidArgumentException::expectedDocumentType('"filter" option', $options['filter']); } if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index 4dabc6ed2..94e1f8750 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -29,7 +29,7 @@ use function is_array; use function is_bool; use function is_integer; -use function is_object; +use function MongoDB\is_document; /** * Wrapper for the ListDatabases command. @@ -76,8 +76,8 @@ public function __construct(array $options = []) throw InvalidArgumentException::invalidType('"authorizedDatabases" option', $options['authorizedDatabases'], 'boolean'); } - if (isset($options['filter']) && ! is_array($options['filter']) && ! is_object($options['filter'])) { - throw InvalidArgumentException::invalidType('"filter" option', $options['filter'], ['array', 'object']); + if (isset($options['filter']) && ! is_document($options['filter'])) { + throw InvalidArgumentException::expectedDocumentType('"filter" option', $options['filter']); } if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 890eb6c16..85ab352d7 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -29,6 +29,17 @@ class InvalidArgumentException extends DriverInvalidArgumentException implements Exception { + /** + * Thrown when an argument or option is expected to be a document. + * + * @param string $name Name of the argument or option + * @param mixed $value Actual value (used to derive the type) + */ + public static function expectedDocumentType(string $name, $value): self + { + return new self(sprintf('Expected %s to have type "document" (array or object) but found "%s"', $name, get_debug_type($value))); + } + /** * Thrown when an argument or option has an invalid type. * diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php index 2228244d5..981ce5312 100644 --- a/src/GridFS/WritableStream.php +++ b/src/GridFS/WritableStream.php @@ -28,11 +28,10 @@ use function hash_final; use function hash_init; use function hash_update; -use function is_array; use function is_bool; use function is_integer; -use function is_object; use function is_string; +use function MongoDB\is_document; use function MongoDB\is_string_array; use function sprintf; use function strlen; @@ -130,8 +129,8 @@ public function __construct(CollectionWrapper $collectionWrapper, string $filena throw InvalidArgumentException::invalidType('"contentType" option', $options['contentType'], 'string'); } - if (isset($options['metadata']) && ! is_array($options['metadata']) && ! is_object($options['metadata'])) { - throw InvalidArgumentException::invalidType('"metadata" option', $options['metadata'], 'array or object'); + if (isset($options['metadata']) && ! is_document($options['metadata'])) { + throw InvalidArgumentException::expectedDocumentType('"metadata" option', $options['metadata']); } $this->chunkSize = $options['chunkSizeBytes']; diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index 23dc33aa9..c34e07d4e 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -36,6 +36,7 @@ use function is_object; use function MongoDB\Driver\Monitoring\addSubscriber; use function MongoDB\Driver\Monitoring\removeSubscriber; +use function MongoDB\is_document; /** * ChangeStreamIterator wraps a change stream's tailable cursor. @@ -75,8 +76,8 @@ class ChangeStreamIterator extends IteratorIterator implements CommandSubscriber */ public function __construct(Cursor $cursor, int $firstBatchSize, $initialResumeToken, ?object $postBatchResumeToken) { - if (isset($initialResumeToken) && ! is_array($initialResumeToken) && ! is_object($initialResumeToken)) { - throw InvalidArgumentException::invalidType('$initialResumeToken', $initialResumeToken, 'array or object'); + if (isset($initialResumeToken) && ! is_document($initialResumeToken)) { + throw InvalidArgumentException::expectedDocumentType('$initialResumeToken', $initialResumeToken); } parent::__construct($cursor); @@ -234,8 +235,8 @@ public function valid(): bool */ private function extractResumeToken($document) { - if (! is_array($document) && ! is_object($document)) { - throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); + if (! is_document($document)) { + throw InvalidArgumentException::expectedDocumentType('$document', $document); } if ($document instanceof Serializable) { diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php index 310251fc9..b95fbfc1f 100644 --- a/src/Model/IndexInput.php +++ b/src/Model/IndexInput.php @@ -20,12 +20,11 @@ use MongoDB\BSON\Serializable; use MongoDB\Exception\InvalidArgumentException; -use function is_array; use function is_float; use function is_int; -use function is_object; use function is_string; use function MongoDB\document_to_array; +use function MongoDB\is_document; use function sprintf; /** @@ -53,8 +52,8 @@ public function __construct(array $index) throw new InvalidArgumentException('Required "key" document is missing from index specification'); } - if (! is_array($index['key']) && ! is_object($index['key'])) { - throw InvalidArgumentException::invalidType('"key" option', $index['key'], 'array or object'); + if (! is_document($index['key'])) { + throw InvalidArgumentException::expectedDocumentType('"key" option', $index['key']); } foreach ($index['key'] as $fieldName => $order) { diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 4d6c5867c..1916f8141 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -38,6 +38,7 @@ use function is_object; use function is_string; use function MongoDB\create_field_path_type_map; +use function MongoDB\is_document; use function MongoDB\is_last_pipeline_operator_write; use function MongoDB\is_pipeline; @@ -155,8 +156,8 @@ public function __construct(string $databaseName, ?string $collectionName, array throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['explain']) && ! is_bool($options['explain'])) { @@ -167,8 +168,8 @@ public function __construct(string $databaseName, ?string $collectionName, array throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], 'string or array or object'); } - if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { - throw InvalidArgumentException::invalidType('"let" option', $options['let'], ['array', 'object']); + if (isset($options['let']) && ! is_document($options['let'])) { + throw InvalidArgumentException::expectedDocumentType('"let" option', $options['let']); } if (isset($options['maxAwaitTimeMS']) && ! is_integer($options['maxAwaitTimeMS'])) { diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index e104d5d73..0f5153489 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -32,8 +32,8 @@ use function current; use function is_array; use function is_bool; -use function is_object; use function key; +use function MongoDB\is_document; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; use function sprintf; @@ -153,8 +153,8 @@ public function __construct(string $databaseName, string $collectionName, array throw new InvalidArgumentException(sprintf('Missing first argument for $operations[%d]["%s"]', $i, $type)); } - if (! is_array($args[0]) && ! is_object($args[0])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][0]', $i, $type), $args[0], 'array or object'); + if (! is_document($args[0])) { + throw InvalidArgumentException::expectedDocumentType(sprintf('$operations[%d]["%s"][0]', $i, $type), $args[0]); } switch ($type) { @@ -173,8 +173,8 @@ public function __construct(string $databaseName, string $collectionName, array $args[1]['limit'] = ($type === self::DELETE_ONE ? 1 : 0); - if (isset($args[1]['collation']) && ! is_array($args[1]['collation']) && ! is_object($args[1]['collation'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]["collation"]', $i, $type), $args[1]['collation'], 'array or object'); + if (isset($args[1]['collation']) && ! is_document($args[1]['collation'])) { + throw InvalidArgumentException::expectedDocumentType(sprintf('$operations[%d]["%s"][1]["collation"]', $i, $type), $args[1]['collation']); } $operations[$i][$type][1] = $args[1]; @@ -186,8 +186,8 @@ public function __construct(string $databaseName, string $collectionName, array throw new InvalidArgumentException(sprintf('Missing second argument for $operations[%d]["%s"]', $i, $type)); } - if (! is_array($args[1]) && ! is_object($args[1])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object'); + if (! is_document($args[1])) { + throw InvalidArgumentException::expectedDocumentType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1]); } // Treat empty arrays as replacement documents for BC @@ -214,8 +214,8 @@ public function __construct(string $databaseName, string $collectionName, array $args[2]['multi'] = false; $args[2] += ['upsert' => false]; - if (isset($args[2]['collation']) && ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); + if (isset($args[2]['collation']) && ! is_document($args[2]['collation'])) { + throw InvalidArgumentException::expectedDocumentType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation']); } if (! is_bool($args[2]['upsert'])) { @@ -232,11 +232,7 @@ public function __construct(string $databaseName, string $collectionName, array throw new InvalidArgumentException(sprintf('Missing second argument for $operations[%d]["%s"]', $i, $type)); } - if (! is_array($args[1]) && ! is_object($args[1])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object'); - } - - if (! is_first_key_operator($args[1]) && ! is_pipeline($args[1])) { + if ((! is_document($args[1]) || ! is_first_key_operator($args[1])) && ! is_pipeline($args[1])) { throw new InvalidArgumentException(sprintf('Expected update operator(s) or non-empty pipeline for $operations[%d]["%s"][1]', $i, $type)); } @@ -255,8 +251,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["arrayFilters"]', $i, $type), $args[2]['arrayFilters'], 'array'); } - if (isset($args[2]['collation']) && ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); + if (isset($args[2]['collation']) && ! is_document($args[2]['collation'])) { + throw InvalidArgumentException::expectedDocumentType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation']); } if (! is_bool($args[2]['upsert'])) { @@ -290,8 +286,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } - if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { - throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + if (isset($options['let']) && ! is_document($options['let'])) { + throw InvalidArgumentException::expectedDocumentType('"let" option', $options['let']); } if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 175ab87a9..b42050ae3 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -33,6 +33,7 @@ use function is_integer; use function is_object; use function is_string; +use function MongoDB\is_document; /** * Operation for the count command. @@ -91,12 +92,12 @@ class Count implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter = [], array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index d83a6bd6e..ecb0e135d 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -28,10 +28,10 @@ use function assert; use function count; use function current; -use function is_array; use function is_float; use function is_integer; use function is_object; +use function MongoDB\is_document; /** * Operation for obtaining an exact count of documents in a collection @@ -96,8 +96,8 @@ class CountDocuments implements Executable */ public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } if (isset($options['limit']) && ! is_integer($options['limit'])) { diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index eff5ab955..795542fea 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -28,8 +28,8 @@ use function is_array; use function is_bool; use function is_integer; -use function is_object; use function is_string; +use function MongoDB\is_document; use function MongoDB\is_pipeline; use function trigger_error; @@ -152,20 +152,20 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"capped" option', $options['capped'], 'boolean'); } - if (isset($options['changeStreamPreAndPostImages']) && ! is_array($options['changeStreamPreAndPostImages']) && ! is_object($options['changeStreamPreAndPostImages'])) { - throw InvalidArgumentException::invalidType('"changeStreamPreAndPostImages" option', $options['changeStreamPreAndPostImages'], 'array or object'); + if (isset($options['changeStreamPreAndPostImages']) && ! is_document($options['changeStreamPreAndPostImages'])) { + throw InvalidArgumentException::expectedDocumentType('"changeStreamPreAndPostImages" option', $options['changeStreamPreAndPostImages']); } - if (isset($options['clusteredIndex']) && ! is_array($options['clusteredIndex']) && ! is_object($options['clusteredIndex'])) { - throw InvalidArgumentException::invalidType('"clusteredIndex" option', $options['clusteredIndex'], 'array or object'); + if (isset($options['clusteredIndex']) && ! is_document($options['clusteredIndex'])) { + throw InvalidArgumentException::expectedDocumentType('"clusteredIndex" option', $options['clusteredIndex']); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } - if (isset($options['encryptedFields']) && ! is_array($options['encryptedFields']) && ! is_object($options['encryptedFields'])) { - throw InvalidArgumentException::invalidType('"encryptedFields" option', $options['encryptedFields'], 'array or object'); + if (isset($options['encryptedFields']) && ! is_document($options['encryptedFields'])) { + throw InvalidArgumentException::expectedDocumentType('"encryptedFields" option', $options['encryptedFields']); } if (isset($options['expireAfterSeconds']) && ! is_integer($options['expireAfterSeconds'])) { @@ -176,8 +176,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"flags" option', $options['flags'], 'integer'); } - if (isset($options['indexOptionDefaults']) && ! is_array($options['indexOptionDefaults']) && ! is_object($options['indexOptionDefaults'])) { - throw InvalidArgumentException::invalidType('"indexOptionDefaults" option', $options['indexOptionDefaults'], 'array or object'); + if (isset($options['indexOptionDefaults']) && ! is_document($options['indexOptionDefaults'])) { + throw InvalidArgumentException::expectedDocumentType('"indexOptionDefaults" option', $options['indexOptionDefaults']); } if (isset($options['max']) && ! is_integer($options['max'])) { @@ -200,12 +200,12 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"size" option', $options['size'], 'integer'); } - if (isset($options['storageEngine']) && ! is_array($options['storageEngine']) && ! is_object($options['storageEngine'])) { - throw InvalidArgumentException::invalidType('"storageEngine" option', $options['storageEngine'], 'array or object'); + if (isset($options['storageEngine']) && ! is_document($options['storageEngine'])) { + throw InvalidArgumentException::expectedDocumentType('"storageEngine" option', $options['storageEngine']); } - if (isset($options['timeseries']) && ! is_array($options['timeseries']) && ! is_object($options['timeseries'])) { - throw InvalidArgumentException::invalidType('"timeseries" option', $options['timeseries'], ['array', 'object']); + if (isset($options['timeseries']) && ! is_document($options['timeseries'])) { + throw InvalidArgumentException::expectedDocumentType('"timeseries" option', $options['timeseries']); } if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { @@ -220,8 +220,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"validationLevel" option', $options['validationLevel'], 'string'); } - if (isset($options['validator']) && ! is_array($options['validator']) && ! is_object($options['validator'])) { - throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object'); + if (isset($options['validator']) && ! is_document($options['validator'])) { + throw InvalidArgumentException::expectedDocumentType('"validator" option', $options['validator']); } if (isset($options['viewOn']) && ! is_string($options['viewOn'])) { diff --git a/src/Operation/CreateEncryptedCollection.php b/src/Operation/CreateEncryptedCollection.php index bc08b321b..aced1321f 100644 --- a/src/Operation/CreateEncryptedCollection.php +++ b/src/Operation/CreateEncryptedCollection.php @@ -30,6 +30,7 @@ use function is_array; use function is_object; use function MongoDB\document_to_array; +use function MongoDB\is_document; use function MongoDB\server_supports_feature; /** @@ -82,8 +83,8 @@ public function __construct(string $databaseName, string $collectionName, array throw new InvalidArgumentException('"encryptedFields" option is required'); } - if (! is_array($options['encryptedFields']) && ! is_object($options['encryptedFields'])) { - throw InvalidArgumentException::invalidType('"encryptedFields" option', $options['encryptedFields'], ['array', 'object']); + if (! is_document($options['encryptedFields'])) { + throw InvalidArgumentException::expectedDocumentType('"encryptedFields" option', $options['encryptedFields']); } $this->createCollection = new CreateCollection($databaseName, $collectionName, $options); diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php index 7c989ae07..39e5a9928 100644 --- a/src/Operation/DatabaseCommand.php +++ b/src/Operation/DatabaseCommand.php @@ -25,7 +25,7 @@ use MongoDB\Exception\InvalidArgumentException; use function is_array; -use function is_object; +use function MongoDB\is_document; /** * Operation for executing a database command. @@ -66,8 +66,8 @@ class DatabaseCommand implements Executable */ public function __construct(string $databaseName, $command, array $options = []) { - if (! is_array($command) && ! is_object($command)) { - throw InvalidArgumentException::invalidType('$command', $command, 'array or object'); + if (! is_document($command)) { + throw InvalidArgumentException::expectedDocumentType('$command', $command); } if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 5f3318012..99bad4ebf 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -29,6 +29,7 @@ use function is_array; use function is_object; use function is_string; +use function MongoDB\is_document; use function MongoDB\is_write_concern_acknowledged; use function MongoDB\server_supports_feature; @@ -98,16 +99,16 @@ class Delete implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter, int $limit, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } if ($limit !== 0 && $limit !== 1) { throw new InvalidArgumentException('$limit must be 0 or 1'); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { @@ -122,8 +123,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } - if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { - throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + if (isset($options['let']) && ! is_document($options['let'])) { + throw InvalidArgumentException::expectedDocumentType('"let" option', $options['let']); } if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 87fd7c597..5c8863fbc 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -32,6 +32,7 @@ use function is_integer; use function is_object; use function MongoDB\create_field_path_type_map; +use function MongoDB\is_document; /** * Operation for the distinct command. @@ -87,12 +88,12 @@ class Distinct implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, string $fieldName, $filter = [], array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { diff --git a/src/Operation/DropEncryptedCollection.php b/src/Operation/DropEncryptedCollection.php index 027b14bfa..6bcdf06d5 100644 --- a/src/Operation/DropEncryptedCollection.php +++ b/src/Operation/DropEncryptedCollection.php @@ -21,9 +21,8 @@ use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; -use function is_array; -use function is_object; use function MongoDB\document_to_array; +use function MongoDB\is_document; /** * Drop an encrypted collection. @@ -68,8 +67,8 @@ public function __construct(string $databaseName, string $collectionName, array throw new InvalidArgumentException('"encryptedFields" option is required'); } - if (! is_array($options['encryptedFields']) && ! is_object($options['encryptedFields'])) { - throw InvalidArgumentException::invalidType('"encryptedFields" option', $options['encryptedFields'], ['array', 'object']); + if (! is_document($options['encryptedFields'])) { + throw InvalidArgumentException::expectedDocumentType('"encryptedFields" option', $options['encryptedFields']); } /** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */ diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 8725d37e8..d3ec85f1a 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -33,6 +33,7 @@ use function is_object; use function is_string; use function MongoDB\document_to_array; +use function MongoDB\is_document; use function trigger_error; use const E_USER_DEPRECATED; @@ -162,8 +163,8 @@ class Find implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } if (isset($options['allowDiskUse']) && ! is_bool($options['allowDiskUse'])) { @@ -178,8 +179,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"batchSize" option', $options['batchSize'], 'integer'); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['cursorType'])) { @@ -204,8 +205,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer'); } - if (isset($options['max']) && ! is_array($options['max']) && ! is_object($options['max'])) { - throw InvalidArgumentException::invalidType('"max" option', $options['max'], 'array or object'); + if (isset($options['max']) && ! is_document($options['max'])) { + throw InvalidArgumentException::expectedDocumentType('"max" option', $options['max']); } if (isset($options['maxAwaitTimeMS']) && ! is_integer($options['maxAwaitTimeMS'])) { @@ -220,12 +221,12 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } - if (isset($options['min']) && ! is_array($options['min']) && ! is_object($options['min'])) { - throw InvalidArgumentException::invalidType('"min" option', $options['min'], 'array or object'); + if (isset($options['min']) && ! is_document($options['min'])) { + throw InvalidArgumentException::expectedDocumentType('"min" option', $options['min']); } - if (isset($options['modifiers']) && ! is_array($options['modifiers']) && ! is_object($options['modifiers'])) { - throw InvalidArgumentException::invalidType('"modifiers" option', $options['modifiers'], 'array or object'); + if (isset($options['modifiers']) && ! is_document($options['modifiers'])) { + throw InvalidArgumentException::expectedDocumentType('"modifiers" option', $options['modifiers']); } if (isset($options['noCursorTimeout']) && ! is_bool($options['noCursorTimeout'])) { @@ -236,8 +237,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"oplogReplay" option', $options['oplogReplay'], 'boolean'); } - if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { - throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); + if (isset($options['projection']) && ! is_document($options['projection'])) { + throw InvalidArgumentException::expectedDocumentType('"projection" option', $options['projection']); } if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { @@ -268,16 +269,16 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"snapshot" option', $options['snapshot'], 'boolean'); } - if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) { - throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object'); + if (isset($options['sort']) && ! is_document($options['sort'])) { + throw InvalidArgumentException::expectedDocumentType('"sort" option', $options['sort']); } if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); } - if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { - throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + if (isset($options['let']) && ! is_document($options['let'])) { + throw InvalidArgumentException::expectedDocumentType('"let" option', $options['let']); } if (isset($options['readConcern']) && $options['readConcern']->isDefault()) { diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index b8f9ce99a..8a08e9b4d 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -34,6 +34,7 @@ use function is_object; use function is_string; use function MongoDB\create_field_path_type_map; +use function MongoDB\is_document; use function MongoDB\is_pipeline; use function MongoDB\is_write_concern_acknowledged; use function MongoDB\server_supports_feature; @@ -139,12 +140,12 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } - if (isset($options['fields']) && ! is_array($options['fields']) && ! is_object($options['fields'])) { - throw InvalidArgumentException::invalidType('"fields" option', $options['fields'], 'array or object'); + if (isset($options['fields']) && ! is_document($options['fields'])) { + throw InvalidArgumentException::expectedDocumentType('"fields" option', $options['fields']); } if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { @@ -159,8 +160,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"new" option', $options['new'], 'boolean'); } - if (isset($options['query']) && ! is_array($options['query']) && ! is_object($options['query'])) { - throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object'); + if (isset($options['query']) && ! is_document($options['query'])) { + throw InvalidArgumentException::expectedDocumentType('"query" option', $options['query']); } if (! is_bool($options['remove'])) { @@ -171,8 +172,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); } - if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) { - throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object'); + if (isset($options['sort']) && ! is_document($options['sort'])) { + throw InvalidArgumentException::expectedDocumentType('"sort" option', $options['sort']); } if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { @@ -191,8 +192,8 @@ public function __construct(string $databaseName, string $collectionName, array throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); } - if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { - throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + if (isset($options['let']) && ! is_document($options['let'])) { + throw InvalidArgumentException::expectedDocumentType('"let" option', $options['let']); } if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 362d04346..d37523003 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -22,8 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; -use function is_array; -use function is_object; +use function MongoDB\is_document; /** * Operation for deleting a document with the findAndModify command. @@ -82,12 +81,12 @@ class FindOneAndDelete implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } - if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { - throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); + if (isset($options['projection']) && ! is_document($options['projection'])) { + throw InvalidArgumentException::expectedDocumentType('"projection" option', $options['projection']); } if (isset($options['projection'])) { diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 5ec774e47..ca1c96c79 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -23,9 +23,8 @@ use MongoDB\Exception\UnsupportedException; use function array_key_exists; -use function is_array; use function is_integer; -use function is_object; +use function MongoDB\is_document; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; @@ -102,12 +101,12 @@ class FindOneAndReplace implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter, $replacement, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } - if (! is_array($replacement) && ! is_object($replacement)) { - throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object'); + if (! is_document($replacement)) { + throw InvalidArgumentException::expectedDocumentType('$replacement', $replacement); } // Treat empty arrays as replacement documents for BC @@ -123,8 +122,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw new InvalidArgumentException('$replacement is an update pipeline'); } - if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { - throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); + if (isset($options['projection']) && ! is_document($options['projection'])) { + throw InvalidArgumentException::expectedDocumentType('"projection" option', $options['projection']); } if (array_key_exists('returnDocument', $options) && ! is_integer($options['returnDocument'])) { diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index 5df15076a..711d7389b 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -26,6 +26,7 @@ use function is_array; use function is_integer; use function is_object; +use function MongoDB\is_document; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; @@ -105,8 +106,8 @@ class FindOneAndUpdate implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter, $update, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } if (! is_array($update) && ! is_object($update)) { @@ -117,8 +118,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw new InvalidArgumentException('Expected update operator(s) or non-empty pipeline for $update'); } - if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { - throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); + if (isset($options['projection']) && ! is_document($options['projection'])) { + throw InvalidArgumentException::expectedDocumentType('"projection" option', $options['projection']); } if (array_key_exists('returnDocument', $options) && ! is_integer($options['returnDocument'])) { diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index a257d069c..8fe782c29 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -27,9 +27,8 @@ use MongoDB\InsertManyResult; use function array_is_list; -use function is_array; use function is_bool; -use function is_object; +use function MongoDB\is_document; use function sprintf; /** @@ -90,8 +89,8 @@ public function __construct(string $databaseName, string $collectionName, array } foreach ($documents as $i => $document) { - if (! is_array($document) && ! is_object($document)) { - throw InvalidArgumentException::invalidType(sprintf('$documents[%d]', $i), $document, 'array or object'); + if (! is_document($document)) { + throw InvalidArgumentException::expectedDocumentType(sprintf('$documents[%d]', $i), $document); } } diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index 0d32530e6..727bb503c 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -26,9 +26,8 @@ use MongoDB\Exception\UnsupportedException; use MongoDB\InsertOneResult; -use function is_array; use function is_bool; -use function is_object; +use function MongoDB\is_document; /** * Operation for inserting a single document with the insert command. @@ -74,8 +73,8 @@ class InsertOne implements Executable */ public function __construct(string $databaseName, string $collectionName, $document, array $options = []) { - if (! is_array($document) && ! is_object($document)) { - throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); + if (! is_document($document)) { + throw InvalidArgumentException::expectedDocumentType('$document', $document); } if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index 58d11938f..b08b2ebb9 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -41,6 +41,7 @@ use function is_string; use function MongoDB\create_field_path_type_map; use function MongoDB\document_to_array; +use function MongoDB\is_document; use function MongoDB\is_mapreduce_output_inline; use function trigger_error; @@ -169,8 +170,8 @@ public function __construct(string $databaseName, string $collectionName, Javasc throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['finalize']) && ! $options['finalize'] instanceof JavascriptInterface) { @@ -189,8 +190,8 @@ public function __construct(string $databaseName, string $collectionName, Javasc throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } - if (isset($options['query']) && ! is_array($options['query']) && ! is_object($options['query'])) { - throw InvalidArgumentException::invalidType('"query" option', $options['query'], 'array or object'); + if (isset($options['query']) && ! is_document($options['query'])) { + throw InvalidArgumentException::expectedDocumentType('"query" option', $options['query']); } if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { @@ -201,16 +202,16 @@ public function __construct(string $databaseName, string $collectionName, Javasc throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class); } - if (isset($options['scope']) && ! is_array($options['scope']) && ! is_object($options['scope'])) { - throw InvalidArgumentException::invalidType('"scope" option', $options['scope'], 'array or object'); + if (isset($options['scope']) && ! is_document($options['scope'])) { + throw InvalidArgumentException::expectedDocumentType('"scope" option', $options['scope']); } if (isset($options['session']) && ! $options['session'] instanceof Session) { throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); } - if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) { - throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object'); + if (isset($options['sort']) && ! is_document($options['sort'])) { + throw InvalidArgumentException::expectedDocumentType('"sort" option', $options['sort']); } if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index a2b641aa8..7b09f7985 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -23,8 +23,7 @@ use MongoDB\Exception\UnsupportedException; use MongoDB\UpdateResult; -use function is_array; -use function is_object; +use function MongoDB\is_document; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; @@ -81,8 +80,8 @@ class ReplaceOne implements Executable */ public function __construct(string $databaseName, string $collectionName, $filter, $replacement, array $options = []) { - if (! is_array($replacement) && ! is_object($replacement)) { - throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object'); + if (! is_document($replacement)) { + throw InvalidArgumentException::expectedDocumentType('$replacement', $replacement); } // Treat empty arrays as replacement documents for BC diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 64f71d4ed..84e8a45c9 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -30,6 +30,7 @@ use function is_bool; use function is_object; use function is_string; +use function MongoDB\is_document; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; use function MongoDB\is_write_concern_acknowledged; @@ -113,8 +114,8 @@ class Update implements Executable, Explainable */ public function __construct(string $databaseName, string $collectionName, $filter, $update, array $options = []) { - if (! is_array($filter) && ! is_object($filter)) { - throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); + if (! is_document($filter)) { + throw InvalidArgumentException::expectedDocumentType('$filter', $filter); } if (! is_array($update) && ! is_object($update)) { @@ -134,8 +135,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); } - if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { - throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); + if (isset($options['collation']) && ! is_document($options['collation'])) { + throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { @@ -162,8 +163,8 @@ public function __construct(string $databaseName, string $collectionName, $filte throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } - if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { - throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + if (isset($options['let']) && ! is_document($options['let'])) { + throw InvalidArgumentException::expectedDocumentType('"let" option', $options['let']); } if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index df230a72f..9eaa7f246 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -44,6 +44,7 @@ use function is_string; use function MongoDB\Driver\Monitoring\addSubscriber; use function MongoDB\Driver\Monitoring\removeSubscriber; +use function MongoDB\is_document; use function MongoDB\select_server; use function MongoDB\server_supports_feature; @@ -222,12 +223,12 @@ public function __construct(Manager $manager, ?string $databaseName, ?string $co throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class); } - if (isset($options['resumeAfter']) && ! is_array($options['resumeAfter']) && ! is_object($options['resumeAfter'])) { - throw InvalidArgumentException::invalidType('"resumeAfter" option', $options['resumeAfter'], 'array or object'); + if (isset($options['resumeAfter']) && ! is_document($options['resumeAfter'])) { + throw InvalidArgumentException::expectedDocumentType('"resumeAfter" option', $options['resumeAfter']); } - if (isset($options['startAfter']) && ! is_array($options['startAfter']) && ! is_object($options['startAfter'])) { - throw InvalidArgumentException::invalidType('"startAfter" option', $options['startAfter'], 'array or object'); + if (isset($options['startAfter']) && ! is_document($options['startAfter'])) { + throw InvalidArgumentException::expectedDocumentType('"startAfter" option', $options['startAfter']); } if (isset($options['startAtOperationTime']) && ! $options['startAtOperationTime'] instanceof TimestampInterface) { diff --git a/src/functions.php b/src/functions.php index 81e4359b4..4acec021c 100644 --- a/src/functions.php +++ b/src/functions.php @@ -87,8 +87,8 @@ function all_servers_support_write_stage_on_secondary(array $servers): bool */ function apply_type_map_to_document($document, array $typeMap) { - if (! is_array($document) && ! is_object($document)) { - throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); + if (! is_document($document)) { + throw InvalidArgumentException::expectedDocumentType('$document', $document); } return toPHP(fromPHP($document), $typeMap); @@ -133,7 +133,7 @@ function document_to_array($document): array } if (! is_array($document)) { - throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); + throw InvalidArgumentException::expectedDocumentType('$document', $document); } return $document; @@ -186,6 +186,19 @@ function get_encrypted_fields_from_server(string $databaseName, string $collecti return null; } +/** + * Returns whether a given value is a valid document. + * + * This method returns true for any array or object, but specifically excludes + * BSON PackedArray instances + * + * @param mixed $document + */ +function is_document($document): bool +{ + return is_array($document) || (is_object($document) && ! $document instanceof PackedArray); +} + /** * Return whether the first key in the document starts with a "$" character. * @@ -200,6 +213,10 @@ function get_encrypted_fields_from_server(string $databaseName, string $collecti */ function is_first_key_operator($document): bool { + if ($document instanceof PackedArray) { + return false; + } + $document = document_to_array($document); $firstKey = array_key_first($document); @@ -266,7 +283,7 @@ function is_pipeline($pipeline, bool $allowEmpty = false): bool } foreach ($pipeline as $stage) { - if (! is_array($stage) && ! is_object($stage)) { + if (! is_document($stage)) { return false; } diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 24c5903b9..4a8b5bf6b 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -61,27 +61,14 @@ public function testConstructorOptionTypeChecks(array $options): void new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $options); } - public function provideInvalidConstructorOptions() + public function provideInvalidConstructorOptions(): array { - $options = []; - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testGetManager(): void diff --git a/tests/Command/ListCollectionsTest.php b/tests/Command/ListCollectionsTest.php index 3cc5aa5e8..78c90afa6 100644 --- a/tests/Command/ListCollectionsTest.php +++ b/tests/Command/ListCollectionsTest.php @@ -15,26 +15,13 @@ public function testConstructorOptionTypeChecks(array $options): void new ListCollections($this->getDatabaseName(), $options); } - public function provideInvalidConstructorOptions() + public function provideInvalidConstructorOptions(): array { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['authorizedCollections' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['filter' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'authorizedCollections' => $this->getInvalidBooleanValues(), + 'filter' => $this->getInvalidDocumentValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'session' => $this->getInvalidSessionValues(), + ]); } } diff --git a/tests/Command/ListDatabasesTest.php b/tests/Command/ListDatabasesTest.php index 90a5513f1..92de68afd 100644 --- a/tests/Command/ListDatabasesTest.php +++ b/tests/Command/ListDatabasesTest.php @@ -17,28 +17,12 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['authorizedDatabases' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['filter' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['nameOnly' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'authorizedDatabases' => $this->getInvalidBooleanValues(), + 'filter' => $this->getInvalidDocumentValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'nameOnly' => $this->getInvalidBooleanValues(), + 'session' => $this->getInvalidSessionValues(), + ]); } } diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index d1f74025c..0022df7a1 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -46,25 +46,12 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testGetManager(): void diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index 86fe31deb..c07f81535 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -112,14 +112,20 @@ public function provideDocumentsAndExpectedArrays(): array ]; } - /** @dataProvider provideInvalidDocumentValues */ + /** @dataProvider provideInvalidDocumentValuesForChecks */ public function testDocumentToArrayArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Expected $document to have type "array or object"'); + $this->expectExceptionMessage('Expected $document to have type "document" (array or object)'); document_to_array($document); } + public function provideInvalidDocumentValuesForChecks(): array + { + // PackedArray is intentionally left out, as document_to_array is used to convert aggregation pipelines + return $this->wrapValuesForDataProvider([123, 3.14, 'foo', true]); + } + public function provideDocumentCasts(): array { // phpcs:disable SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing @@ -145,7 +151,7 @@ public function testIsFirstKeyOperator(callable $cast): void $this->assertFalse(is_first_key_operator($cast(['foo']))); } - /** @dataProvider provideInvalidDocumentValues */ + /** @dataProvider provideInvalidDocumentValuesForChecks */ public function testIsFirstKeyOperatorArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 27a22ff90..8e4f6518f 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -66,37 +66,15 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidStringValues(true) as $value) { - $options[][] = ['bucketName' => $value]; - } - - foreach ($this->getInvalidIntegerValues(true) as $value) { - $options[][] = ['chunkSizeBytes' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['disableMD5' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'bucketName' => $this->getInvalidStringValues(true), + 'chunkSizeBytes' => $this->getInvalidIntegerValues(true), + 'disableMD5' => $this->getInvalidBooleanValues(true), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive(): void diff --git a/tests/GridFS/WritableStreamFunctionalTest.php b/tests/GridFS/WritableStreamFunctionalTest.php index 6a11f64d4..ea6902d26 100644 --- a/tests/GridFS/WritableStreamFunctionalTest.php +++ b/tests/GridFS/WritableStreamFunctionalTest.php @@ -42,21 +42,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidIntegerValues(true) as $value) { - $options[][] = ['chunkSizeBytes' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['disableMD5' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['metadata' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'chunkSizeBytes' => $this->getInvalidIntegerValues(true), + 'disableMD5' => $this->getInvalidBooleanValues(true), + 'metadata' => $this->getInvalidDocumentValues(), + ]); } public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive(): void diff --git a/tests/Model/ChangeStreamIteratorTest.php b/tests/Model/ChangeStreamIteratorTest.php index c0001d6d7..053b1609d 100644 --- a/tests/Model/ChangeStreamIteratorTest.php +++ b/tests/Model/ChangeStreamIteratorTest.php @@ -16,7 +16,6 @@ use MongoDB\Tests\FunctionalTestCase; use TypeError; -use function array_merge; use function sprintf; class ChangeStreamIteratorTest extends FunctionalTestCase @@ -67,7 +66,7 @@ public function testPostBatchResumeTokenArgumentTypeCheck($postBatchResumeToken) public function provideInvalidObjectValues() { - return $this->wrapValuesForDataProvider(array_merge($this->getInvalidDocumentValues(), [[]])); + return $this->wrapValuesForDataProvider([123, 3.14, 'foo', true, []]); } public function testPostBatchResumeTokenIsReturnedForLastElementInFirstBatch(): void diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php index f72fc5a22..e7d148db1 100644 --- a/tests/Operation/AggregateTest.php +++ b/tests/Operation/AggregateTest.php @@ -26,69 +26,23 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['allowDiskUse' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['batchSize' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidHintValues() as $value) { - $options[][] = ['hint' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['let' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['explain' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxAwaitTimeMS' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['useCursor' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'allowDiskUse' => $this->getInvalidBooleanValues(), + 'batchSize' => $this->getInvalidIntegerValues(), + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'hint' => $this->getInvalidHintValues(), + 'let' => $this->getInvalidDocumentValues(), + 'explain' => $this->getInvalidBooleanValues(), + 'maxAwaitTimeMS' => $this->getInvalidIntegerValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'useCursor' => $this->getInvalidBooleanValues(true), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testConstructorBatchSizeOptionRequiresUseCursor(): void @@ -103,11 +57,6 @@ public function testConstructorBatchSizeOptionRequiresUseCursor(): void ); } - private function getInvalidHintValues() - { - return [123, 3.14, true]; - } - public function testExplainableCommandDocument(): void { $options = [ diff --git a/tests/Operation/BulkWriteTest.php b/tests/Operation/BulkWriteTest.php index 444178cf7..18941b455 100644 --- a/tests/Operation/BulkWriteTest.php +++ b/tests/Operation/BulkWriteTest.php @@ -57,7 +57,7 @@ public function testInsertOneDocumentArgumentMissing(): void public function testInsertOneDocumentArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["insertOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["insertOne"\]\[0\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::INSERT_ONE => [$document]], ]); @@ -76,7 +76,7 @@ public function testDeleteManyFilterArgumentMissing(): void public function testDeleteManyFilterArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteMany"\]\[0\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteMany"\]\[0\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::DELETE_MANY => [$document]], ]); @@ -86,7 +86,7 @@ public function testDeleteManyFilterArgumentTypeCheck($document): void public function testDeleteManyCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteMany"\]\[1\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteMany"\]\[1\]\["collation"\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::DELETE_MANY => [['x' => 1], ['collation' => $collation]]], ]); @@ -110,7 +110,7 @@ public function testDeleteOneFilterArgumentMissing(): void public function testDeleteOneFilterArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteOne"\]\[0\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::DELETE_ONE => [$document]], ]); @@ -120,7 +120,7 @@ public function testDeleteOneFilterArgumentTypeCheck($document): void public function testDeleteOneCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteOne"\]\[1\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteOne"\]\[1\]\["collation"\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::DELETE_ONE => [['x' => 1], ['collation' => $collation]]], ]); @@ -139,7 +139,7 @@ public function testReplaceOneFilterArgumentMissing(): void public function testReplaceOneFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[0\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::REPLACE_ONE => [$filter, ['y' => 1]]], ]); @@ -169,7 +169,7 @@ public function testReplaceOneReplacementArgumentMissing(): void public function testReplaceOneReplacementArgumentTypeCheck($replacement): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[1\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[1\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::REPLACE_ONE => [['x' => 1], $replacement]], ]); @@ -192,7 +192,7 @@ public function testReplaceOneReplacementArgumentProhibitsUpdateDocument($replac public function testReplaceOneReplacementArgumentProhibitsUpdatePipeline($replacement): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$operations[0]["replaceOne"][1] is an update pipeline'); + $this->expectExceptionMessageMatches('#(\$operations\[0\]\["replaceOne"\]\[1\] is an update pipeline)|(\$operations\[0\]\["replaceOne"\]\[1\] to have type "document" \(array or object\))#'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::REPLACE_ONE => [['x' => 1], $replacement]], ]); @@ -202,7 +202,7 @@ public function testReplaceOneReplacementArgumentProhibitsUpdatePipeline($replac public function testReplaceOneCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[2\]\["collation"\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::REPLACE_ONE => [['x' => 1], ['y' => 1], ['collation' => $collation]]], ]); @@ -212,7 +212,7 @@ public function testReplaceOneCollationOptionTypeCheck($collation): void public function testReplaceOneUpsertOptionTypeCheck($upsert): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[2\]\["upsert"\] to have type "boolean" but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::REPLACE_ONE => [['x' => 1], ['y' => 1], ['upsert' => $upsert]]], ]); @@ -236,7 +236,7 @@ public function testUpdateManyFilterArgumentMissing(): void public function testUpdateManyFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[0\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[0\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_MANY => [$filter, ['$set' => ['x' => 1]]]], ]); @@ -267,7 +267,7 @@ public function testUpdateManyUpdateArgumentMissing(): void public function testUpdateManyUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[1\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $operations[0]["updateMany"][1]'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_MANY => [['x' => 1], $update]], ]); @@ -290,7 +290,7 @@ public function testUpdateManyUpdateArgumentProhibitsReplacementDocumentOrEmptyP public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["arrayFilters"\] to have type "array" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["arrayFilters"\] to have type "array" but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_MANY => [['x' => 1], ['$set' => ['x' => 1]], ['arrayFilters' => $arrayFilters]]], ]); @@ -300,7 +300,7 @@ public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void public function testUpdateManyCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["collation"\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_MANY => [['x' => 1], ['$set' => ['x' => 1]], ['collation' => $collation]]], ]); @@ -310,7 +310,7 @@ public function testUpdateManyCollationOptionTypeCheck($collation): void public function testUpdateManyUpsertOptionTypeCheck($upsert): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["upsert"\] to have type "boolean" but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_MANY => [['x' => 1], ['$set' => ['x' => 1]], ['upsert' => $upsert]]], ]); @@ -341,7 +341,7 @@ public function testUpdateOneFilterArgumentMissing(): void public function testUpdateOneFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[0\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_ONE => [$filter, ['$set' => ['x' => 1]]]], ]); @@ -360,7 +360,7 @@ public function testUpdateOneUpdateArgumentMissing(): void public function testUpdateOneUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[1\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $operations[0]["updateOne"][1]'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_ONE => [['x' => 1], $update]], ]); @@ -383,7 +383,7 @@ public function testUpdateOneUpdateArgumentProhibitsReplacementDocumentOrEmptyPi public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["arrayFilters"\] to have type "array" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["arrayFilters"\] to have type "array" but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_ONE => [['x' => 1], ['$set' => ['x' => 1]], ['arrayFilters' => $arrayFilters]]], ]); @@ -393,7 +393,7 @@ public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters): void public function testUpdateOneCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["collation"\] to have type "document" \(array or object\) but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_ONE => [['x' => 1], ['$set' => ['x' => 1]], ['collation' => $collation]]], ]); @@ -403,7 +403,7 @@ public function testUpdateOneCollationOptionTypeCheck($collation): void public function testUpdateOneUpsertOptionTypeCheck($upsert): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["upsert"\] to have type "boolean" but found ".+"/'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [ [BulkWrite::UPDATE_ONE => [['x' => 1], ['$set' => ['x' => 1]], ['upsert' => $upsert]]], ]); @@ -423,24 +423,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['ordered' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'ordered' => $this->getInvalidBooleanValues(true), + 'session' => $this->getInvalidSessionValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/CountDocumentsTest.php b/tests/Operation/CountDocumentsTest.php index 3fcb9003a..a7a048be1 100644 --- a/tests/Operation/CountDocumentsTest.php +++ b/tests/Operation/CountDocumentsTest.php @@ -23,45 +23,15 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidHintValues() as $value) { - $options[][] = ['hint' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['limit' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['skip' => $value]; - } - - return $options; - } - - private function getInvalidHintValues() - { - return [123, 3.14, true]; + return $this->createOptionDataProvider([ + 'collation' => $this->getInvalidDocumentValues(), + 'hint' => $this->getInvalidHintValues(), + 'limit' => $this->getInvalidIntegerValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + 'skip' => $this->getInvalidIntegerValues(), + ]); } } diff --git a/tests/Operation/CountTest.php b/tests/Operation/CountTest.php index 5259a9d44..7a26341f6 100644 --- a/tests/Operation/CountTest.php +++ b/tests/Operation/CountTest.php @@ -24,46 +24,16 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidHintValues() as $value) { - $options[][] = ['hint' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['limit' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['skip' => $value]; - } - - return $options; - } - - private function getInvalidHintValues() - { - return [123, 3.14, true]; + return $this->createOptionDataProvider([ + 'collation' => $this->getInvalidDocumentValues(), + 'hint' => $this->getInvalidHintValues(), + 'limit' => $this->getInvalidIntegerValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + 'skip' => $this->getInvalidIntegerValues(), + ]); } public function testExplainableCommandDocument(): void diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index dab0140f9..956fa6ed7 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -23,97 +23,30 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['autoIndexId' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['capped' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['changeStreamPreAndPostImages' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['clusteredIndex' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['encryptedFields' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['expireAfterSeconds' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['flags' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['indexOptionDefaults' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['max' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['pipeline' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['size' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['storageEngine' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['timeseries' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['validationAction' => $value]; - } - - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['validationLevel' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['validator' => $value]; - } - - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['viewOn' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'autoIndexId' => $this->getInvalidBooleanValues(), + 'capped' => $this->getInvalidBooleanValues(), + 'changeStreamPreAndPostImages' => $this->getInvalidDocumentValues(), + 'clusteredIndex' => $this->getInvalidDocumentValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'encryptedFields' => $this->getInvalidDocumentValues(), + 'expireAfterSeconds' => $this->getInvalidIntegerValues(), + 'flags' => $this->getInvalidIntegerValues(), + 'indexOptionDefaults' => $this->getInvalidDocumentValues(), + 'max' => $this->getInvalidIntegerValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'pipeline' => $this->getInvalidArrayValues(), + 'session' => $this->getInvalidSessionValues(), + 'size' => $this->getInvalidIntegerValues(), + 'storageEngine' => $this->getInvalidDocumentValues(), + 'timeseries' => $this->getInvalidDocumentValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'validationAction' => $this->getInvalidStringValues(), + 'validationLevel' => $this->getInvalidStringValues(), + 'validator' => $this->getInvalidDocumentValues(), + 'viewOn' => $this->getInvalidStringValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testAutoIndexIdOptionIsDeprecated(): void diff --git a/tests/Operation/CreateEncryptedCollectionTest.php b/tests/Operation/CreateEncryptedCollectionTest.php index 49d3f9c56..c3c22f5e3 100644 --- a/tests/Operation/CreateEncryptedCollectionTest.php +++ b/tests/Operation/CreateEncryptedCollectionTest.php @@ -6,8 +6,6 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Operation\CreateEncryptedCollection; -use function get_debug_type; - class CreateEncryptedCollectionTest extends TestCase { /** @dataProvider provideInvalidConstructorOptions */ @@ -23,10 +21,8 @@ public function provideInvalidConstructorOptions(): Generator [], ]; - foreach ($this->getInvalidDocumentValues() as $value) { - yield 'encryptedFields type: ' . get_debug_type($value) => [ - ['encryptedFields' => $value], - ]; - } + yield from $this->createOptionDataProvider([ + 'encryptedFields' => $this->getInvalidDocumentValues(), + ]); } } diff --git a/tests/Operation/CreateIndexesTest.php b/tests/Operation/CreateIndexesTest.php index 74c386f30..0ece84f43 100644 --- a/tests/Operation/CreateIndexesTest.php +++ b/tests/Operation/CreateIndexesTest.php @@ -27,25 +27,13 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ([3.14, true, [], new stdClass()] as $value) { - $options[][] = ['commitQuorum' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + // commitQuorum is int|string, for which no helper exists + 'commitQuorum' => ['float' => 3.14, 'bool' => true, 'array' => [], 'object' => new stdClass()], + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'session' => $this->getInvalidSessionValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testConstructorRequiresAtLeastOneIndex(): void @@ -79,7 +67,7 @@ public function testConstructorRequiresIndexSpecificationKey(): void public function testConstructorRequiresIndexSpecificationKeyToBeADocument($key): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Expected "key" option to have type "array or object"'); + $this->expectExceptionMessage('Expected "key" option to have type "document" (array or object)'); new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => $key]]); } diff --git a/tests/Operation/DatabaseCommandTest.php b/tests/Operation/DatabaseCommandTest.php index 29df6bd07..c592aa5e4 100644 --- a/tests/Operation/DatabaseCommandTest.php +++ b/tests/Operation/DatabaseCommandTest.php @@ -23,20 +23,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + ]); } } diff --git a/tests/Operation/DeleteTest.php b/tests/Operation/DeleteTest.php index 90b9cae52..143e7bb16 100644 --- a/tests/Operation/DeleteTest.php +++ b/tests/Operation/DeleteTest.php @@ -50,21 +50,13 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'collation' => $this->getInvalidDocumentValues(), + 'hint' => $this->getInvalidHintValues(), + 'let' => $this->getInvalidDocumentValues(), + 'session' => $this->getInvalidSessionValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testExplainableCommandDocument(): void diff --git a/tests/Operation/DistinctTest.php b/tests/Operation/DistinctTest.php index 9ece08fa5..f04d244ca 100644 --- a/tests/Operation/DistinctTest.php +++ b/tests/Operation/DistinctTest.php @@ -25,33 +25,14 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'collation' => $this->getInvalidDocumentValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + ]); } public function testExplainableCommandDocument(): void diff --git a/tests/Operation/DropCollectionTest.php b/tests/Operation/DropCollectionTest.php index cde87ae44..eb3ddf76d 100644 --- a/tests/Operation/DropCollectionTest.php +++ b/tests/Operation/DropCollectionTest.php @@ -16,20 +16,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/DropDatabaseTest.php b/tests/Operation/DropDatabaseTest.php index fd3a527fd..04a5c763f 100644 --- a/tests/Operation/DropDatabaseTest.php +++ b/tests/Operation/DropDatabaseTest.php @@ -16,20 +16,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/DropEncryptedCollectionTest.php b/tests/Operation/DropEncryptedCollectionTest.php index 31a559efc..4cb0a2401 100644 --- a/tests/Operation/DropEncryptedCollectionTest.php +++ b/tests/Operation/DropEncryptedCollectionTest.php @@ -6,8 +6,6 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Operation\DropEncryptedCollection; -use function get_debug_type; - class DropEncryptedCollectionTest extends TestCase { /** @dataProvider provideInvalidConstructorOptions */ @@ -23,10 +21,8 @@ public function provideInvalidConstructorOptions(): Generator [], ]; - foreach ($this->getInvalidDocumentValues() as $value) { - yield 'encryptedFields type: ' . get_debug_type($value) => [ - ['encryptedFields' => $value], - ]; - } + yield from $this->createOptionDataProvider([ + 'encryptedFields' => $this->getInvalidDocumentValues(), + ]); } } diff --git a/tests/Operation/DropIndexesTest.php b/tests/Operation/DropIndexesTest.php index 03da89f84..5fc021071 100644 --- a/tests/Operation/DropIndexesTest.php +++ b/tests/Operation/DropIndexesTest.php @@ -22,24 +22,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/EstimatedDocumentCountTest.php b/tests/Operation/EstimatedDocumentCountTest.php index 485cb263e..bf090c50d 100644 --- a/tests/Operation/EstimatedDocumentCountTest.php +++ b/tests/Operation/EstimatedDocumentCountTest.php @@ -16,24 +16,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + ]); } } diff --git a/tests/Operation/ExplainTest.php b/tests/Operation/ExplainTest.php index a77f39129..3b202de03 100644 --- a/tests/Operation/ExplainTest.php +++ b/tests/Operation/ExplainTest.php @@ -18,24 +18,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['verbosity' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'verbosity' => $this->getInvalidStringValues(), + ]); } } diff --git a/tests/Operation/FindAndModifyTest.php b/tests/Operation/FindAndModifyTest.php index a0738bb12..f2de657c4 100644 --- a/tests/Operation/FindAndModifyTest.php +++ b/tests/Operation/FindAndModifyTest.php @@ -17,65 +17,22 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['arrayFilters' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['fields' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['new' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['query' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['remove' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['sort' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['update' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['upsert' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'arrayFilters' => $this->getInvalidArrayValues(), + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'fields' => $this->getInvalidDocumentValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'new' => $this->getInvalidBooleanValues(), + 'query' => $this->getInvalidDocumentValues(), + 'remove' => $this->getInvalidBooleanValues(), + 'session' => $this->getInvalidSessionValues(), + 'sort' => $this->getInvalidDocumentValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'update' => $this->getInvalidUpdateValues(), + 'upsert' => $this->getInvalidBooleanValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } public function testConstructorUpdateAndRemoveOptionsAreMutuallyExclusive(): void diff --git a/tests/Operation/FindOneAndDeleteTest.php b/tests/Operation/FindOneAndDeleteTest.php index e63062ace..042c3a279 100644 --- a/tests/Operation/FindOneAndDeleteTest.php +++ b/tests/Operation/FindOneAndDeleteTest.php @@ -24,13 +24,9 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['projection' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'projection' => $this->getInvalidDocumentValues(), + ]); } public function testExplainableCommandDocument(): void diff --git a/tests/Operation/FindOneAndReplaceTest.php b/tests/Operation/FindOneAndReplaceTest.php index 743098e4f..73951596d 100644 --- a/tests/Operation/FindOneAndReplaceTest.php +++ b/tests/Operation/FindOneAndReplaceTest.php @@ -46,7 +46,7 @@ public function testConstructorReplacementArgumentProhibitsUpdateDocument($repla public function testConstructorReplacementArgumentProhibitsUpdatePipeline($replacement): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$replacement is an update pipeline'); + $this->expectExceptionMessageMatches('#(\$replacement is an update pipeline)|(Expected \$replacement to have type "document" \(array or object\))#'); new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement); } @@ -59,17 +59,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['projection' => $value]; - } - - foreach ($this->getInvalidIntegerValues(true) as $value) { - $options[][] = ['returnDocument' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'projection' => $this->getInvalidDocumentValues(), + 'returnDocument' => $this->getInvalidIntegerValues(true), + ]); } /** @dataProvider provideInvalidConstructorReturnDocumentOptions */ diff --git a/tests/Operation/FindOneAndUpdateTest.php b/tests/Operation/FindOneAndUpdateTest.php index d174b73f3..99d49128a 100644 --- a/tests/Operation/FindOneAndUpdateTest.php +++ b/tests/Operation/FindOneAndUpdateTest.php @@ -42,17 +42,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['projection' => $value]; - } - - foreach ($this->getInvalidIntegerValues(true) as $value) { - $options[][] = ['returnDocument' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'projection' => $this->getInvalidDocumentValues(), + 'returnDocument' => $this->getInvalidIntegerValues(), + ]); } /** @dataProvider provideInvalidConstructorReturnDocumentOptions */ diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php index 1da7d23fa..3a24ed3ee 100644 --- a/tests/Operation/FindTest.php +++ b/tests/Operation/FindTest.php @@ -25,101 +25,31 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['allowPartialResults' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['batchSize' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['cursorType' => $value]; - } - - foreach ($this->getInvalidHintValues() as $value) { - $options[][] = ['hint' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['limit' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['max' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxAwaitTimeMS' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxScan' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['min' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['modifiers' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['oplogReplay' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['projection' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['returnKey' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['showRecordId' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['skip' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['snapshot' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['sort' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'allowPartialResults' => $this->getInvalidBooleanValues(), + 'batchSize' => $this->getInvalidIntegerValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'cursorType' => $this->getInvalidIntegerValues(), + 'hint' => $this->getInvalidHintValues(), + 'limit' => $this->getInvalidIntegerValues(), + 'max' => $this->getInvalidDocumentValues(), + 'maxAwaitTimeMS' => $this->getInvalidIntegerValues(), + 'maxScan' => $this->getInvalidIntegerValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'min' => $this->getInvalidDocumentValues(), + 'modifiers' => $this->getInvalidDocumentValues(), + 'oplogReplay' => $this->getInvalidBooleanValues(), + 'projection' => $this->getInvalidDocumentValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'returnKey' => $this->getInvalidBooleanValues(), + 'session' => $this->getInvalidSessionValues(), + 'showRecordId' => $this->getInvalidBooleanValues(), + 'skip' => $this->getInvalidIntegerValues(), + 'snapshot' => $this->getInvalidBooleanValues(), + 'sort' => $this->getInvalidDocumentValues(), + 'typeMap' => $this->getInvalidArrayValues(), + ]); } public function testSnapshotOptionIsDeprecated(): void @@ -140,11 +70,6 @@ public function testMaxScanOptionIsDeprecated(): void }); } - private function getInvalidHintValues() - { - return [123, 3.14, true]; - } - /** @dataProvider provideInvalidConstructorCursorTypeOptions */ public function testConstructorCursorTypeOption($cursorType): void { diff --git a/tests/Operation/InsertManyTest.php b/tests/Operation/InsertManyTest.php index 67d91418e..c3edec535 100644 --- a/tests/Operation/InsertManyTest.php +++ b/tests/Operation/InsertManyTest.php @@ -38,24 +38,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['ordered' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'ordered' => $this->getInvalidBooleanValues(true), + 'session' => $this->getInvalidSessionValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/InsertOneTest.php b/tests/Operation/InsertOneTest.php index c51faea85..17fde0343 100644 --- a/tests/Operation/InsertOneTest.php +++ b/tests/Operation/InsertOneTest.php @@ -23,20 +23,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'session' => $this->getInvalidSessionValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/ListIndexesTest.php b/tests/Operation/ListIndexesTest.php index aa3b75e7a..7edda8ef3 100644 --- a/tests/Operation/ListIndexesTest.php +++ b/tests/Operation/ListIndexesTest.php @@ -16,16 +16,9 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'session' => $this->getInvalidSessionValues(), + ]); } } diff --git a/tests/Operation/MapReduceTest.php b/tests/Operation/MapReduceTest.php index 2f155aa84..04b7a58d0 100644 --- a/tests/Operation/MapReduceTest.php +++ b/tests/Operation/MapReduceTest.php @@ -65,69 +65,23 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidJavascriptValues() as $value) { - $options[][] = ['finalize' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['jsMode' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['limit' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxTimeMS' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['query' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues() as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['scope' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['sort' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['verbose' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'finalize' => $this->getInvalidJavascriptValues(), + 'jsMode' => $this->getInvalidBooleanValues(), + 'limit' => $this->getInvalidIntegerValues(), + 'maxTimeMS' => $this->getInvalidIntegerValues(), + 'query' => $this->getInvalidDocumentValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(), + 'scope' => $this->getInvalidDocumentValues(), + 'session' => $this->getInvalidSessionValues(), + 'sort' => $this->getInvalidDocumentValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'verbose' => $this->getInvalidBooleanValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } private function getInvalidJavascriptValues() diff --git a/tests/Operation/ModifyCollectionTest.php b/tests/Operation/ModifyCollectionTest.php index 4fcda8b72..dfa8d2584 100644 --- a/tests/Operation/ModifyCollectionTest.php +++ b/tests/Operation/ModifyCollectionTest.php @@ -23,20 +23,10 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/RenameCollectionTest.php b/tests/Operation/RenameCollectionTest.php index e13402147..ceabceaa4 100644 --- a/tests/Operation/RenameCollectionTest.php +++ b/tests/Operation/RenameCollectionTest.php @@ -22,24 +22,11 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['dropTarget' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'dropTarget' => $this->getInvalidBooleanValues(), + 'session' => $this->getInvalidSessionValues(), + 'typeMap' => $this->getInvalidArrayValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } } diff --git a/tests/Operation/ReplaceOneTest.php b/tests/Operation/ReplaceOneTest.php index fd057921e..1290f90df 100644 --- a/tests/Operation/ReplaceOneTest.php +++ b/tests/Operation/ReplaceOneTest.php @@ -45,7 +45,7 @@ public function testConstructorReplacementArgumentProhibitsUpdateDocument($repla public function testConstructorReplacementArgumentProhibitsUpdatePipeline($replacement): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$replacement is an update pipeline'); + $this->expectExceptionMessageMatches('#(\$replacement is an update pipeline)|(Expected \$replacement to have type "document" \(array or object\))#'); new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); } } diff --git a/tests/Operation/TestCase.php b/tests/Operation/TestCase.php index 684899ec5..386468ce2 100644 --- a/tests/Operation/TestCase.php +++ b/tests/Operation/TestCase.php @@ -74,4 +74,14 @@ public function provideEmptyUpdatePipelinesExcludingArray(): array 'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])], ]; } + + public function provideInvalidUpdateValues(): array + { + return $this->wrapValuesForDataProvider($this->getInvalidUpdateValues()); + } + + protected function getInvalidUpdateValues(): array + { + return [123, 3.14, 'foo', true]; + } } diff --git a/tests/Operation/UpdateTest.php b/tests/Operation/UpdateTest.php index de9fcbadd..85d00ef88 100644 --- a/tests/Operation/UpdateTest.php +++ b/tests/Operation/UpdateTest.php @@ -12,11 +12,11 @@ class UpdateTest extends TestCase public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Expected \$filter to have type "array or object" but found "[\w ]+"/'); + $this->expectExceptionMessageMatches('/Expected \$filter to have type "document" \(array or object\) but found ".+"/'); new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]); } - /** @dataProvider provideInvalidDocumentValues */ + /** @dataProvider provideInvalidUpdateValues */ public function testConstructorUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); @@ -33,37 +33,16 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['arrayFilters' => $value]; - } - - foreach ($this->getInvalidBooleanValues() as $value) { - $options[][] = ['bypassDocumentValidation' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['multi' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidBooleanValues(true) as $value) { - $options[][] = ['upsert' => $value]; - } - - foreach ($this->getInvalidWriteConcernValues() as $value) { - $options[][] = ['writeConcern' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'arrayFilters' => $this->getInvalidArrayValues(), + 'bypassDocumentValidation' => $this->getInvalidBooleanValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'hint' => $this->getInvalidHintValues(), + 'multi' => $this->getInvalidBooleanValues(), + 'session' => $this->getInvalidSessionValues(), + 'upsert' => $this->getInvalidBooleanValues(), + 'writeConcern' => $this->getInvalidWriteConcernValues(), + ]); } /** diff --git a/tests/Operation/WatchTest.php b/tests/Operation/WatchTest.php index 5c07d8d18..1a9e5fa0e 100644 --- a/tests/Operation/WatchTest.php +++ b/tests/Operation/WatchTest.php @@ -40,53 +40,20 @@ public function testConstructorOptionTypeChecks(array $options): void public function provideInvalidConstructorOptions() { - $options = []; - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['batchSize' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['collation' => $value]; - } - - foreach ($this->getInvalidStringValues(true) as $value) { - $options[][] = ['fullDocument' => $value]; - } - - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['fullDocumentBeforeChange' => $value]; - } - - foreach ($this->getInvalidIntegerValues() as $value) { - $options[][] = ['maxAwaitTimeMS' => $value]; - } - - foreach ($this->getInvalidReadConcernValues() as $value) { - $options[][] = ['readConcern' => $value]; - } - - foreach ($this->getInvalidReadPreferenceValues(true) as $value) { - $options[][] = ['readPreference' => $value]; - } - - foreach ($this->getInvalidDocumentValues() as $value) { - $options[][] = ['resumeAfter' => $value]; - } - - foreach ($this->getInvalidSessionValues() as $value) { - $options[][] = ['session' => $value]; - } - - foreach ($this->getInvalidTimestampValues() as $value) { - $options[][] = ['startAtOperationTime' => $value]; - } - - foreach ($this->getInvalidArrayValues() as $value) { - $options[][] = ['typeMap' => $value]; - } - - return $options; + return $this->createOptionDataProvider([ + 'batchSize' => $this->getInvalidIntegerValues(), + 'collation' => $this->getInvalidDocumentValues(), + 'fullDocument' => $this->getInvalidStringValues(true), + 'fullDocumentBeforeChange' => $this->getInvalidStringValues(), + 'maxAwaitTimeMS' => $this->getInvalidIntegerValues(), + 'readConcern' => $this->getInvalidReadConcernValues(), + 'readPreference' => $this->getInvalidReadPreferenceValues(true), + 'resumeAfter' => $this->getInvalidDocumentValues(), + 'session' => $this->getInvalidSessionValues(), + 'startAfter' => $this->getInvalidDocumentValues(), + 'startAtOperationTime' => $this->getInvalidTimestampValues(), + 'typeMap' => $this->getInvalidArrayValues(), + ]); } private function getInvalidTimestampValues() diff --git a/tests/TestCase.php b/tests/TestCase.php index 91e1244de..dd8d94094 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests; use InvalidArgumentException; +use MongoDB\BSON\PackedArray; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; @@ -17,9 +18,11 @@ use function array_merge; use function array_values; use function call_user_func; +use function get_debug_type; use function getenv; use function hash; use function is_array; +use function is_int; use function is_object; use function is_string; use function iterator_to_array; @@ -154,6 +157,24 @@ protected function assertDeprecated(callable $execution): void $this->assertCount(1, $errors); } + protected function createOptionDataProvider(array $options): array + { + $data = []; + + foreach ($options as $option => $values) { + foreach ($values as $key => $value) { + $dataKey = $option . '_' . $key; + if (is_int($key)) { + $dataKey .= '_' . get_debug_type($value); + } + + $data[$dataKey] = [[$option => $value]]; + } + } + + return $data; + } + /** * Return the test collection name. */ @@ -193,8 +214,15 @@ protected function getInvalidBooleanValues(bool $includeNull = false): array */ protected function getInvalidDocumentValues(bool $includeNull = false): array { - // Note: PackedArray is intentionally omitted here (see: PHPLIB-1137) - return array_merge([123, 3.14, 'foo', true], $includeNull ? [null] : []); + return array_merge([123, 3.14, 'foo', true, PackedArray::fromPHP([])], $includeNull ? [null] : []); + } + + /** + * Return a list of invalid hint values. + */ + protected function getInvalidHintValues() + { + return [123, 3.14, true]; } /** @@ -210,7 +238,19 @@ protected function getInvalidIntegerValues(bool $includeNull = false): array */ protected function getInvalidReadConcernValues(bool $includeNull = false): array { - return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadPreference(ReadPreference::PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []); + return array_merge( + [ + 123, + 3.14, + 'foo', + true, + [], + new stdClass(), + new ReadPreference(ReadPreference::PRIMARY), + new WriteConcern(1), + ], + $includeNull ? ['null' => null] : [] + ); } /** @@ -218,7 +258,19 @@ protected function getInvalidReadConcernValues(bool $includeNull = false): array */ protected function getInvalidReadPreferenceValues(bool $includeNull = false): array { - return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new WriteConcern(1)], $includeNull ? [null] : []); + return array_merge( + [ + 123, + 3.14, + 'foo', + true, + [], + new stdClass(), + new ReadConcern(), + new WriteConcern(1), + ], + $includeNull ? ['null' => null] : [] + ); } /** @@ -226,7 +278,20 @@ protected function getInvalidReadPreferenceValues(bool $includeNull = false): ar */ protected function getInvalidSessionValues(bool $includeNull = false): array { - return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []); + return array_merge( + [ + 123, + 3.14, + 'foo', + true, + [], + new stdClass(), + new ReadConcern(), + new ReadPreference(ReadPreference::PRIMARY), + new WriteConcern(1), + ], + $includeNull ? ['null' => null] : [] + ); } /** @@ -242,7 +307,19 @@ protected function getInvalidStringValues(bool $includeNull = false): array */ protected function getInvalidWriteConcernValues(bool $includeNull = false): array { - return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::PRIMARY)], $includeNull ? [null] : []); + return array_merge( + [ + 123, + 3.14, + 'foo', + true, + [], + new stdClass(), + new ReadConcern(), + new ReadPreference(ReadPreference::PRIMARY), + ], + $includeNull ? ['null' => null] : [] + ); } /**