diff --git a/Firestore/phpunit-conformance.xml.dist b/Firestore/phpunit-conformance.xml.dist deleted file mode 100644 index 236f6e8796f4..000000000000 --- a/Firestore/phpunit-conformance.xml.dist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - tests/Conformance - - - - - src - - src/V[!a-zA-Z]* - - - - diff --git a/Firestore/src/DocumentReference.php b/Firestore/src/DocumentReference.php index 58b4f2fa1dd9..4d49b6bf5729 100644 --- a/Firestore/src/DocumentReference.php +++ b/Firestore/src/DocumentReference.php @@ -245,6 +245,11 @@ public function set(array $fields, array $options = []) * as a dot-delimited string (i.e. `foo.bar`), or an instance of * {@see Google\Cloud\Firestore\FieldPath}. Nested arrays are not allowed. * + * Please note that conflicting paths will result in an exception. Paths + * conflict when one path indicates a location nested within another path. + * For instance, path `a.b` cannot be set directly if path `a` is also + * provided. + * * Example: * ``` * $document->update([ @@ -281,9 +286,14 @@ public function set(array $fields, array $options = []) * @codingStandardsIgnoreStart * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit * - * @param array[] $data A list of arrays of form `[FieldPath|string $path, mixed $value]`. + * @param array[] $data A list of arrays of form + * `[FieldPath|string $path, mixed $value]`. * @param array $options Configuration options * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.WriteResult) + * @throws \InvalidArgumentException If data is given in an invalid format + * or is empty. + * @throws \InvalidArgumentException If any field paths are empty. + * @throws \InvalidArgumentException If field paths conflict. * @codingStandardsIgnoreEnd */ public function update(array $data, array $options = []) diff --git a/Firestore/src/FieldPath.php b/Firestore/src/FieldPath.php index 5fb42c6e078a..fc06b426eccd 100644 --- a/Firestore/src/FieldPath.php +++ b/Firestore/src/FieldPath.php @@ -30,16 +30,103 @@ */ class FieldPath { + const SPECIAL_CHARS = '/^[^*~\/[\]]+$/'; + const UNESCAPED_FIELD_NAME = '/^[_a-zA-Z][_a-zA-Z0-9]*$/'; + + /** + * @var array + */ private $fieldNames; /** * @param array $fieldNames A list of field names. + * @throws \InvalidArgumentException If an empty path element is provided. */ public function __construct(array $fieldNames) { + foreach ($fieldNames as $field) { + // falsey is good enough unless the field is actually `0`. + if (!$field && $field !== 0) { + throw new \InvalidArgumentException(sprintf( + 'Field paths cannot contain empty path elements. Given path was `%s`.', + implode('.', $fieldNames) + )); + } + } + $this->fieldNames = $fieldNames; } + /** + * Create a FieldPath from a string path. + * + * Example: + * ``` + * use Google\Cloud\Firestore\FieldPath; + * + * $path = FieldPath::fromString('path.to.field'); + * ``` + * + * @param string $path The field path string. + * @param bool $splitPath If false, the input path will not be split on `.`. + * **Defaults to** `true`. + * @return FieldPath + * @throws \InvalidArgumentException If an invalid path is provided. + */ + public static function fromString($path, $splitPath = true) + { + self::validateString($path); + + $parts = $splitPath + ? explode('.', $path) + : [$path]; + + return new self($parts); + } + + /** + * Get a new FieldPath with the given path part appended to the current + * path. + * + * Example: + * ``` + * $child = $path->child('element'); + * ``` + * + * @param string $part The child path part. + * @return FieldPath + * @throws \InvalidArgumentException If an empty path element is provided. + */ + public function child($part) + { + $fieldNames = $this->fieldNames; + $fieldNames[] = $part; + + return new static($fieldNames); + } + + /** + * Get the current path as a string, with special characters escaped. + * + * Example: + * ``` + * $string = $path->pathString(); + * ``` + * + * @return string + */ + public function pathString() + { + $out = []; + foreach ($this->fieldNames as $part) { + $out[] = $this->escapePathPart($part); + } + + $fieldPath = implode('.', $out); + + return $fieldPath; + } + /** * Get the path elements. * @@ -52,14 +139,52 @@ public function path() } /** - * Create a FieldPath from a string path. + * Cast the path to a string. * - * @param string $path - * @return FieldPath + * @return string * @access private */ - public static function fromString($path) + public function __toString() { - return new self(explode('.', $path)); + return $this->pathString(); + } + + /** + * Test a field path component, checking for any special characters, + * and escaping as required. + * + * @param string $part The raw field path component. + * @return string + */ + private function escapePathPart($part) + { + // If no special characters are found, return the input unchanged. + if (preg_match(self::UNESCAPED_FIELD_NAME, $part)) { + return $part; + } + + // If the string is already wrapped in backticks, return as-is. + if (substr($part, 0, 1) === '`' && substr($part, -1) === '`' && strlen($part) > 1) { + return $part; + } + + return '`' . str_replace('`', '\\`', str_replace('\\', '\\\\', $part)) . '`'; + } + + /** + * Check if a given string field path is valid. + * + * @param string $fieldPath + * @throws \InvalidArgumentException + */ + private static function validateString($fieldPath) + { + if (strpos($fieldPath, '..')) { + throw new \InvalidArgumentException('Paths cannot contain `..`.'); + } + + if (strpos($fieldPath, '.') === 0 || strpos(strrev($fieldPath), '.') === 0) { + throw new \InvalidArgumentException('Paths cannot begin or end with `.`.'); + } } } diff --git a/Firestore/src/FieldValue.php b/Firestore/src/FieldValue.php index fe83d4233a02..3bbb25748618 100644 --- a/Firestore/src/FieldValue.php +++ b/Firestore/src/FieldValue.php @@ -94,9 +94,20 @@ public static function serverTimestamp() */ public static function isSentinelValue($value) { - return in_array($value, [ + return in_array($value, self::sentinelValues(), true); + } + + /** + * Get a list of sentinel values. + * + * @return array + * @access private + */ + public static function sentinelValues() + { + return [ self::deleteField(), self::serverTimestamp() - ]); + ]; } } diff --git a/Firestore/src/Query.php b/Firestore/src/Query.php index 12db6740edc5..7a60dc6c8497 100644 --- a/Firestore/src/Query.php +++ b/Firestore/src/Query.php @@ -76,7 +76,9 @@ class Query '<=' => self::OP_LESS_THAN_OR_EQUAL, '>' => self::OP_GREATER_THAN, '>=' => self::OP_GREATER_THAN_OR_EQUAL, - '=' => self::OP_EQUAL + '=' => self::OP_EQUAL, + '==' => self::OP_EQUAL, + '===' => self::OP_EQUAL, ]; private $allowedDirections = [ @@ -236,8 +238,12 @@ public function select(array $fieldPaths) { $fields = []; foreach ($fieldPaths as $field) { + if (!($field instanceof FieldPath)) { + $field = FieldPath::fromString($field); + } + $fields[] = [ - 'fieldPath' => $this->valueMapper->escapeFieldPath($field) + 'fieldPath' => $field->pathString() ]; } @@ -282,7 +288,11 @@ public function where($fieldPath, $operator, $value) )); } - $escapedFieldPath = $this->valueMapper->escapeFieldPath($fieldPath); + if (!($fieldPath instanceof FieldPath)) { + $fieldPath = FieldPath::fromString($fieldPath); + } + + $escapedPathString = $fieldPath->pathString(); $operator = array_key_exists($operator, $this->shortOperators) ? $this->shortOperators[$operator] @@ -307,7 +317,7 @@ public function where($fieldPath, $operator, $value) $filter = [ 'unaryFilter' => [ 'field' => [ - 'fieldPath' => $escapedFieldPath + 'fieldPath' => $escapedPathString ], 'op' => $unaryOperator ] @@ -316,7 +326,7 @@ public function where($fieldPath, $operator, $value) $filter = [ 'fieldFilter' => [ 'field' => [ - 'fieldPath' => $escapedFieldPath, + 'fieldPath' => $escapedPathString, ], 'op' => $operator, 'value' => $this->valueMapper->encodeValue($value) @@ -373,11 +383,15 @@ public function orderBy($fieldPath, $direction = self::DIR_ASCENDING) ); } + if (!($fieldPath instanceof FieldPath)) { + $fieldPath = FieldPath::fromString($fieldPath); + } + return $this->newQuery([ 'orderBy' => [ [ 'field' => [ - 'fieldPath' => $this->valueMapper->escapeFieldPath($fieldPath) + 'fieldPath' => $fieldPath->pathString() ], 'direction' => $direction ] diff --git a/Firestore/src/SnapshotTrait.php b/Firestore/src/SnapshotTrait.php index 69c9a9df670d..8855f411d295 100644 --- a/Firestore/src/SnapshotTrait.php +++ b/Firestore/src/SnapshotTrait.php @@ -236,9 +236,11 @@ private function getDocumentReference( // manually construct a document path. $hasSpecialChars = preg_match('/[!@#$%^&*(),.?":{}|<>]/', $name) === 1; + //@codeCoverageIgnoreStart if (!$hasSpecialChars) { throw $e; } + //@codeCoverageIgnoreEnd $base = $this->databaseName($projectId, $database); $name = $base .'/documents/'. $name; diff --git a/Firestore/src/Transaction.php b/Firestore/src/Transaction.php index bd6f253f96a4..65f031585758 100644 --- a/Firestore/src/Transaction.php +++ b/Firestore/src/Transaction.php @@ -267,6 +267,11 @@ public function set(DocumentReference $document, array $fields, array $options = * as a dot-delimited string (i.e. `foo.bar`), or an instance of * {@see Google\Cloud\Firestore\FieldPath}. Nested arrays are not allowed. * + * Please note that conflicting paths will result in an exception. Paths + * conflict when one path indicates a location nested within another path. + * For instance, path `a.b` cannot be set directly if path `a` is also + * provided. + * * Example: * ``` * $transaction->update($document, [ @@ -300,12 +305,15 @@ public function set(DocumentReference $document, array $fields, array $options = * ]); * ``` * - * @codingStandardsIgnoreStart * @param DocumentReference $document The document to modify or replace. - * @param array[] $data A list of arrays of form `[FieldPath|string $path, mixed $value]`. + * @param array[] $data A list of arrays of form + * `[FieldPath|string $path, mixed $value]`. * @param array $options Configuration options * @return Transaction - * @codingStandardsIgnoreEnd + * @throws \InvalidArgumentException If data is given in an invalid format + * or is empty. + * @throws \InvalidArgumentException If any field paths are empty. + * @throws \InvalidArgumentException If field paths conflict. */ public function update(DocumentReference $document, array $data, array $options = []) { diff --git a/Firestore/src/ValueMapper.php b/Firestore/src/ValueMapper.php index 68aa95d41371..82506fe9b4fb 100644 --- a/Firestore/src/ValueMapper.php +++ b/Firestore/src/ValueMapper.php @@ -30,6 +30,8 @@ /** * Normalizes values between Google Cloud PHP and Cloud Firestore. + * + * @internal */ class ValueMapper { @@ -102,155 +104,6 @@ public function encodeValues(array $fields) return $output; } - /** - * Escape a field path and return it as a string. - * - * @param string|FieldPath $fieldPath - * @return string - * @throws \InvalidArgumentException If the path is a string, and is invalid. - */ - public function escapeFieldPath($fieldPath) - { - if ($fieldPath instanceof FieldPath) { - $parts = $fieldPath->path(); - - $out = []; - foreach ($parts as $part) { - $out[] = $this->escapePathPart($part); - } - - $fieldPath = implode('.', $out); - } else { - if (!preg_match(self::VALID_FIELD_PATH, $fieldPath)) { - throw new \InvalidArgumentException('Paths cannot be empty and must not contain `*~/[]\`.'); - } - } - - $this->validateFieldPath($fieldPath); - return $fieldPath; - } - - /** - * Create a list of fields paths from field data. - * - * The return value of this method does not include the field values. It - * merely provides a list of field paths which were included in the input. - * - * @param array $fields A list of fields to map as paths. - * @param string $parentPath The parent path (used internally). - * @return array - */ - public function encodeFieldPaths(array $fields, $parentPath = '') - { - $output = []; - - foreach ($fields as $key => $val) { - $key = $this->escapePathPart($key); - - if (is_array($val) && $this->isAssoc($val)) { - $nestedParentPath = $parentPath - ? $parentPath . '.' . $key - : $key; - - $output = array_merge($output, $this->encodeFieldPaths($val, $nestedParentPath)); - } else { - $output[] = $parentPath - ? $parentPath . '.' . $key - : $key; - } - } - - return $output; - } - - /** - * Accepts a list of field paths and a list of values, and constructs - * a nested array of fields and values. - * - * @param FieldPath[] $paths The field paths. - * @param array $values The field values. - * @return array - * @todo less recursion - */ - public function buildDocumentFromPathsAndValues(array $paths, array $values) - { - $this->validateBatch($paths, FieldPath::class); - - $output = []; - - foreach ($paths as $pathIndex => $path) { - $keys = $path->path(); - $num = count($keys); - - $val = $values[$pathIndex]; - foreach (array_reverse($keys) as $index => $key) { - if ($num >= $index+1) { - $val = [ - $key => $val - ]; - } - } - - $output = $this->arrayMergeRecursive($output, $val); - } - - return $output; - } - - /** - * Search an array for sentinel values, returning the array of fields with - * sentinels removed, and a list of delete and server timestamp value field - * paths. - * - * @param array $fields The input field data. - * @return array `[$fields, $timestamps, $deletes]` - */ - public function findSentinels(array $fields) - { - $timestamps = []; - $deletes = []; - $fields = $this->removeSentinel($fields, $timestamps, $deletes); - - return [$fields, $timestamps, $deletes]; - } - - /** - * Recurse through fields and find and remove sentinel values. - * - * @param array $fields The input field data. - * @param array $timestamps The timestamps field paths. (reference) - * @param array $deletes the deletes field paths. (reference) - * @param string $path The current field path. - * @return array - */ - private function removeSentinel(array $fields, array &$timestamps, array &$deletes, $path = '') - { - if ($path !== '') { - $path .= '.'; - } - - foreach ($fields as $key => $value) { - $currPath = $path . (string) $this->escapePathPart($key); - if (is_array($value)) { - $fields[$key] = $this->removeSentinel($value, $timestamps, $deletes, $currPath); - } else { - if ($value === FieldValue::deleteField() || $value === FieldValue::serverTimestamp()) { - if ($value === FieldValue::deleteField()) { - $deletes[] = $currPath; - } - - if ($value === FieldValue::serverTimestamp()) { - $timestamps[] = $currPath; - } - - unset($fields[$key]); - } - } - } - - return $fields; - } - /** * Convert a Firestore value to a Google Cloud PHP value. * @@ -479,35 +332,4 @@ private function encodeArrayValue(array $value) return ['arrayValue' => ['values' => $out]]; } - - /** - * Test a field path component, checking for any special characters, - * and escaping as required. - * - * @param string $part The raw field path component. - * @return string - */ - private function escapePathPart($part) - { - return preg_match(self::UNESCAPED_FIELD_NAME, $part) - ? $part - : '`' . str_replace('`', '\\`', str_replace('\\', '\\\\', $part)) . '`'; - } - - /** - * Check if a given string field path is valid. - * - * @param string $fieldPath - * @throws \InvalidArgumentException - */ - private function validateFieldPath($fieldPath) - { - if (strpos($fieldPath, '..')) { - throw new \InvalidArgumentException('Paths cannot contain `..`.'); - } - - if (strpos($fieldPath, '.') === 0 || strpos(strrev($fieldPath), '.') === 0) { - throw new \InvalidArgumentException('Paths cannot begin or end with `.`.'); - } - } } diff --git a/Firestore/src/WriteBatch.php b/Firestore/src/WriteBatch.php index 1ce0ecfa81a7..a7a875843594 100644 --- a/Firestore/src/WriteBatch.php +++ b/Firestore/src/WriteBatch.php @@ -116,20 +116,31 @@ public function __construct(ConnectionInterface $connection, $valueMapper, $data * field paths are NOT supported by this method. * @param array $options Configuration options * @return WriteBatch - * @throws \InvalidArgumentException If delete field sentinels are found in the fields list. + * @throws \InvalidArgumentException If `FieldValue::deleteField()` is found in the fields list. + * @throws \InvalidArgumentException If `FieldValue::serverTimestamp()` is found in an array value. */ public function create($document, array $fields, array $options = []) { + // Record whether the document is empty before any filtering. $emptyDocument = count($fields) === 0; - list($fields, $timestamps, $deletes) = $this->valueMapper->findSentinels($fields); + list ($fields, $sentinels, $flags) = $this->filterFields($fields); - if (!empty($deletes)) { + if ($sentinels[FieldValue::deleteField()]) { throw new \InvalidArgumentException('Cannot delete fields when creating a document.'); } + if ($flags['timestampInArray']) { + throw new \InvalidArgumentException( + 'Server Timestamps cannot be used anywhere within a non-associative array value.' + ); + } + + // Cannot create a document that already exists! $precondition = ['exists' => false]; + // Enqueue an update operation if an empty document was provided, + // or if there are still fields after filtering. $transformOptions = []; if (!empty($fields) || $emptyDocument) { $this->writes[] = $this->createDatabaseWrite(self::TYPE_UPDATE, $document, [ @@ -137,13 +148,21 @@ public function create($document, array $fields, array $options = []) 'precondition' => $precondition ] + $options); } else { + // If no UPDATE mutation is enqueued, we need the precondition applied + // to the transform mutation. $transformOptions = [ 'precondition' => $precondition ]; } - // Setting values to the server timestamp is implemented as a document tranformation. - $this->updateTransforms($document, $timestamps, $transformOptions); + // Some sentinel values (at the time of writing server timestamps) + // are implemented using TRANSFORM mutations rather than being embedded + // in the normal update. + $this->updateTransforms( + $document, + $sentinels, + $transformOptions + ); return $this; } @@ -151,7 +170,8 @@ public function create($document, array $fields, array $options = []) /** * Enqueue a set mutation. * - * Replaces all fields in a Firestore document. + * Unless `$options['merge']` is set to `true, this method replaces all + * fields in a Firestore document. * * Example: * ``` @@ -177,29 +197,64 @@ public function create($document, array $fields, array $options = []) * } * @return WriteBatch * @codingStandardsIgnoreEnd - * @throws \InvalidArgumentException If the fields list is empty when `$options.merge` is `true`. + * @throws \InvalidArgumentException If `FieldValue::deleteField()` is found in the document when `$options.merge` + * is not `true`. + * @throws \InvalidArgumentException If `FieldValue::serverTimestamp()` is found in an array value. */ public function set($document, array $fields, array $options = []) { $merge = $this->pluck('merge', $options, false) ?: false; - if ($merge && empty($fields)) { - throw new \InvalidArgumentException('Fields list cannot be empty when merging fields.'); + // Record whether the document is empty before any filtering. + $emptyDocument = count($fields) === 0; + + list ($fields, $sentinels, $flags) = $this->filterFields($fields); + + if (!$merge && $sentinels[FieldValue::deleteField()]) { + throw new \InvalidArgumentException('Delete cannot appear in data unless `$options[\'merge\']` is set.'); } - list($fields, $timestamps) = $this->valueMapper->findSentinels($fields); + if ($flags['timestampInArray']) { + throw new \InvalidArgumentException( + 'Server Timestamps cannot be used anywhere within a non-associative array value.' + ); + } - if ($fields) { - $write = array_filter([ + $hasOnlyTimestamps = count($fields) === 0 + && !$emptyDocument + && $sentinels[FieldValue::serverTimestamp()] + && !$sentinels[FieldValue::deleteField()]; + + // Enqueue a write if any of the following conditions are met + // - if there are still fields remaining after sentinels were removed + // - if the user provided an empty set to begin with + // - if the user provided only server timestamp sentinel values AND did not specify merge behavior + // - if the user provided only delete sentinel field values. + $shouldEnqueueUpdate = $fields + || $emptyDocument + || ($hasOnlyTimestamps && !$merge) + || $sentinels[FieldValue::deleteField()]; + + if ($shouldEnqueueUpdate) { + $write = [ 'fields' => $this->valueMapper->encodeValues($fields), - 'updateMask' => $merge ? $this->valueMapper->encodeFieldPaths($fields) : null - ]); + ]; + + if ($merge) { + $deletes = $sentinels[FieldValue::deleteField()]; - $this->writes[] = $this->createDatabaseWrite(self::TYPE_UPDATE, $document, $write); + $write['updateMask'] = $this->pathsToStrings( + array_merge($this->encodeFieldPaths($fields), $deletes) + ); + } + + $this->writes[] = $this->createDatabaseWrite(self::TYPE_UPDATE, $document, $write, $options); } - // Setting values to the server timestamp is implemented as a document tranformation. - $this->updateTransforms($document, $timestamps); + // Some sentinel values (at the time of writing server timestamps) + // are implemented using TRANSFORM mutations rather than being embedded + // in the normal update. + $this->updateTransforms($document, $sentinels, $options); return $this; } @@ -219,6 +274,11 @@ public function set($document, array $fields, array $options = []) * as a dot-delimited string (i.e. `foo.bar`), or an instance of * {@see Google\Cloud\Firestore\FieldPath}. Nested arrays are not allowed. * + * Please note that conflicting paths will result in an exception. Paths + * conflict when one path indicates a location nested within another path. + * For instance, path `a.b` cannot be set directly if path `a` is also + * provided. + * * Example: * ``` * $batch->update($documentName, [ @@ -256,11 +316,14 @@ public function set($document, array $fields, array $options = []) * as a string document name, or DocumentReference object. Please * note that DocumentReferences will be used only for the document * name. Field data must be provided in the `$data` argument. - * @param array[] $data A list of arrays of form `[FieldPath|string $path, mixed $value]`. + * @param array[] $data A list of arrays of form + * `[FieldPath|string $path, mixed $value]`. * @param array $options Configuration options * @return WriteBatch - * @throws \InvalidArgumentException If data is given in an invalid format or is empty. + * @throws \InvalidArgumentException If data is given in an invalid format + * or is empty. * @throws \InvalidArgumentException If any field paths are empty. + * @throws \InvalidArgumentException If field paths conflict. */ public function update($document, array $data, array $options = []) { @@ -268,18 +331,10 @@ public function update($document, array $data, array $options = []) throw new \InvalidArgumentException( 'Field data must be provided as a list of arrays of form `[string|FieldPath $path, mixed $value]`.' ); - } elseif (!$data) { - throw new \InvalidArgumentException( - 'Field data cannot be empty.' - ); } - $options += [ - 'precondition' => ['exists' => true] - ]; - $paths = []; - $values = []; + $fields = []; foreach ($data as $field) { $this->arrayHasKeys($field, ['path', 'value']); @@ -293,42 +348,91 @@ public function update($document, array $data, array $options = []) $paths[] = $path; - $values[] = $field['value']; + $keys = $path->path(); + $num = count($keys); + + // Construct a nested array to represent a nested field path. + // For instance, `a.b.c` = 'foo' will become + // `['a' => ['b' => ['c' => 'foo']]]` + $val = $field['value']; + foreach (array_reverse($keys) as $index => $key) { + if ($num >= $index + 1) { + $val = [ + $key => $val + ]; + } + } + + $fields = $this->arrayMergeRecursive($fields, $val); } - $fields = $this->valueMapper->buildDocumentFromPathsAndValues($paths, $values); + if (count(array_unique($paths)) !== count($paths)) { + throw new \InvalidArgumentException('Duplicate field paths are not allowed.'); + } + + // Record whether the document is empty before any filtering. + $emptyDocument = count($fields) === 0; - list($fields, $timestamps, $deletes) = $this->valueMapper->findSentinels($fields); + list ($fields, $sentinels, $flags) = $this->filterFields($fields); - $transformOptions = []; + // to conform to specification. + if (isset($options['precondition']['exists'])) { + throw new \InvalidArgumentException('Exists preconditions are not supported by this method.'); + } + + if ($flags['timestampInArray']) { + throw new \InvalidArgumentException( + 'Server Timestamps cannot be used anywhere within a non-associative array value.' + ); + } // We only want to enqueue an update write if there are non-sentinel fields // OR no timestamp sentinels are found. // We MUST always enqueue at least one write, so if there are no fields // and no timestamp sentinels, we can assume an empty write is intended // and enqueue an empty UPDATE operation. - if ($fields || !$timestamps || $deletes) { - // encode field paths as strings and remove server timestamp sentinels. - $updateMask = []; - array_walk($paths, function ($path) use (&$updateMask, $timestamps) { - $path = $this->valueMapper->escapeFieldPath($path); - if (!in_array($path, $timestamps)) { - $updateMask[] = $path; - } - }); + $shouldEnqueueUpdate = $fields + || !$sentinels[FieldValue::serverTimestamp()] + || $sentinels[FieldValue::deleteField()]; - $this->writes[] = $this->createDatabaseWrite(self::TYPE_UPDATE, $document, [ + if ($shouldEnqueueUpdate) { + $write = [ 'fields' => $this->valueMapper->encodeValues($fields), - 'updateMask' => array_unique(array_merge($updateMask, $deletes)) - ] + $options); - } else { - $transformOptions = [ - 'precondition' => $options['precondition'] ]; + + $deletes = $sentinels[FieldValue::deleteField()]; + $timestamps = $sentinels[FieldValue::serverTimestamp()]; + + // Add deletes to the list of paths + $mask = array_merge($paths, $deletes); + $mask = array_unique($this->pathsToStrings($mask)); + + // Check the update mask for prefix paths. + // This needs to happen before we remove server timestamp sentinels. + $this->checkPrefixes($mask); + + // remove timestamps from the mask. + // since we constructed the input mask before removing sentinels, + // we'll need to run through and pull them out now. + $mask = array_filter($mask, function ($item) use ($timestamps) { + return !in_array($item, $timestamps); + }); + + $write['updateMask'] = $mask; + + $this->writes[] = $this->createDatabaseWrite( + self::TYPE_UPDATE, + $document, + $write + $this->formatPrecondition($options, true) + ); + } else { + // If no update write is enqueued, preconditions must be applied to + // a transform. + $options = $this->formatPrecondition($options, true); } // Setting values to the server timestamp is implemented as a document tranformation. - $this->updateTransforms($document, $timestamps, $transformOptions); + $this->updateTransforms($document, $sentinels, $options); return $this; } @@ -350,6 +454,7 @@ public function update($document, array $data, array $options = []) */ public function delete($document, array $options = []) { + $options = $this->formatPrecondition($options); $this->writes[] = $this->createDatabaseWrite(self::TYPE_DELETE, $document, $options); return $this; @@ -422,21 +527,32 @@ public function rollback(array $options = []) ] + $options); } + /** + * Check if the WriteBatch has any writes enqueued. + * + * @return bool + * @access private + */ + public function isEmpty() + { + return ! (bool) $this->writes; + } + /** * Enqueue transforms for sentinels found in UPDATE calls. * * @param DocumentReference|string $document The document to target, either * as a string document name, or DocumentReference object. - * @param array $timestamps + * @param array $sentinels * @param array $options * @return void */ - private function updateTransforms($document, array $timestamps, array $options = []) + private function updateTransforms($document, array $sentinels, array $options = []) { $transforms = []; - foreach ($timestamps as $timestamp) { + foreach ($sentinels[FieldValue::serverTimestamp()] as $timestamp) { $transforms[] = [ - 'fieldPath' => $timestamp, + 'fieldPath' => $timestamp->pathString(), 'setToServerValue' => self::REQUEST_TIME ]; } @@ -469,7 +585,7 @@ private function updateTransforms($document, array $timestamps, array $options = private function createDatabaseWrite($type, $document, array $options = []) { $mask = $this->pluck('updateMask', $options, false); - if ($mask) { + if ($mask !== null) { sort($mask); $mask = ['fieldPaths' => $mask]; } @@ -478,7 +594,7 @@ private function createDatabaseWrite($type, $document, array $options = []) ? $document->name() : $document; - return array_filter([ + return $this->arrayFilterRemoveNull([ 'updateMask' => $mask, 'currentDocument' => $this->validatePrecondition($options), ]) + $this->createDatabaseWriteOperation($type, $document, $options); @@ -495,7 +611,9 @@ private function createDatabaseWrite($type, $document, array $options = []) */ private function validatePrecondition(array &$options) { - $precondition = $this->pluck('precondition', $options, false); + $precondition = isset($options['precondition']) + ? $options['precondition'] + : null; if (!$precondition) { return; @@ -508,7 +626,7 @@ private function validatePrecondition(array &$options) if (isset($precondition['updateTime'])) { if (!($precondition['updateTime'] instanceof Timestamp)) { throw new \InvalidArgumentException( - 'Precondition Update Time must be an instance of Google\\Cloud\\Core\\Timestamp' + 'Precondition Update Time must be an instance of `Google\\Cloud\\Core\\Timestamp`' ); } @@ -567,13 +685,188 @@ private function createDatabaseWriteOperation($type, $document, array $options = } /** - * Check if the WriteBatch has any writes enqueued. + * Filter fields, removing sentinel values from the field list and recording + * their location. * + * @param array $fields The fields input + * @return array An array containing the output fields at position 0 and the + * sentinels list at position 1. + */ + private function filterFields(array $fields) + { + // initialize the sentinels list with empty arrays. + $sentinels = []; + foreach (FieldValue::sentinelValues() as $sentinel) { + $sentinels[$sentinel] = []; + } + + // Track useful information here to keep complexity low elsewhere. + $flags = [ + 'timestampInArray' => false + ]; + + $filterSentinels = function ( + array $fields, + FieldPath $path = null, + $inArray = false + ) use ( + &$sentinels, + &$filterSentinels, + &$flags + ) { + if (!$path) { + $path = new FieldPath([]); + } + + foreach ($fields as $key => $value) { + $currentPath = $path->child($key); + if (is_array($value)) { + // If a sentinel appears in or descends from an array, we need to track that. + $inArray = $inArray + ? $inArray + : !$this->isAssoc($value); + + $fields[$key] = $filterSentinels($value, $currentPath, $inArray); + if (empty($fields[$key])) { + unset($fields[$key]); + } + } else { + if (FieldValue::isSentinelValue($value)) { + $sentinels[$value][] = $currentPath; + if ($value === FieldValue::serverTimestamp() && $inArray) { + $flags['timestampInArray'] = true; + } + + unset($fields[$key]); + } + } + } + + return $fields; + }; + + $fields = $filterSentinels($fields); + + return [$fields, $sentinels, $flags]; + } + + /** + * Check list of FieldPaths for prefix paths and throw exception. + * + * @param string[] $paths + * @throws \InvalidArgumentException If prefix paths are found. + */ + private function checkPrefixes(array $paths) + { + sort($paths); + + for ($i = 1; $i < count($paths); $i++) { + if ($this->isPrefix($paths[$i-1], $paths[$i])) { + throw new \InvalidArgumentException(sprintf( + 'Field path conflict detected for field path `%s`. ' . + 'Conflicts occur when a field path descends from another ' . + 'path. For instance `a.b` is not allowed when `a` is also ' . + 'provided.', + $paths[$i-1] + )); + } + } + } + + /** + * Compare two field paths to determine whether one is a prefix of the other. + * + * @param string $prefix The prefix path. + * @param string $suffix The suffix path. * @return bool - * @access private */ - public function isEmpty() + private function isPrefix($prefix, $suffix) { - return ! (bool) $this->writes; + $prefix = explode('.', $prefix); + $suffix = explode('.', $suffix); + + return count($prefix) < count($suffix) + && $prefix === array_slice($suffix, 0, count($prefix)); + } + + /** + * Correctly formats a precondition for a write. + * + * @param array $options Configuration options input. + * @param bool $mustExist If true, the precondition will always include at + * least `exists=true` precondition. **Defaults to** `false`. + * @return array Modified configuration options. + */ + private function formatPrecondition(array $options, $mustExist = false) + { + if (!isset($options['precondition']) && !$mustExist) { + return $options; + } + + $precondition = isset($options['precondition']) + ? $options['precondition'] + : []; + + if (isset($precondition['updateTime'])) { + return $options; + } + + if ($mustExist) { + $precondition['exists'] = true; + } + + $options['precondition'] = $precondition; + + return $options; + } + + /** + * Create a list of fields paths from field data. + * + * The return value of this method does not include the field values. It + * merely provides a list of field paths which were included in the input. + * + * @param array $fields A list of fields to map as paths. + * @param FieldPath|null $path The parent path (used internally). + * @return FieldPath[] + */ + private function encodeFieldPaths(array $fields, $path = null) + { + $output = []; + + if (!$path) { + $path = new FieldPath([]); + } + + foreach ($fields as $key => $val) { + $currentPath = $path->child($key); + + if (is_array($val) && $this->isAssoc($val)) { + $output = array_merge( + $output, + $this->encodeFieldPaths($val, $currentPath) + ); + } else { + $output[] = $currentPath; + } + } + + return $output; + } + + /** + * Convert a set of {@see Google\Cloud\Firestore\FieldPath} objects to strings. + * + * @param FieldPath[] $paths The input paths. + * @return string[] + */ + private function pathsToStrings(array $paths) + { + $out = []; + foreach ($paths as $path) { + $out[] = $path->pathString(); + } + + return $out; } } diff --git a/Firestore/tests/Conformance/Clause.php b/Firestore/tests/Conformance/Clause.php new file mode 100644 index 000000000000..62a3d2f05714 --- /dev/null +++ b/Firestore/tests/Conformance/Clause.php @@ -0,0 +1,230 @@ +tests.Clause + */ +class Clause extends \Google\Protobuf\Internal\Message +{ + protected $clause; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field .tests.Select select = 1; + * @return \Google\Cloud\Firestore\Tests\Conformance\Select + */ + public function getSelect() + { + return $this->readOneof(1); + } + + /** + * Generated from protobuf field .tests.Select select = 1; + * @param \Google\Cloud\Firestore\Tests\Conformance\Select $var + * @return $this + */ + public function setSelect($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\Select::class); + $this->writeOneof(1, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.Where where = 2; + * @return \Google\Cloud\Firestore\Tests\Conformance\Where + */ + public function getWhere() + { + return $this->readOneof(2); + } + + /** + * Generated from protobuf field .tests.Where where = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\Where $var + * @return $this + */ + public function setWhere($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\Where::class); + $this->writeOneof(2, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.OrderBy order_by = 3; + * @return \Google\Cloud\Firestore\Tests\Conformance\OrderBy + */ + public function getOrderBy() + { + return $this->readOneof(3); + } + + /** + * Generated from protobuf field .tests.OrderBy order_by = 3; + * @param \Google\Cloud\Firestore\Tests\Conformance\OrderBy $var + * @return $this + */ + public function setOrderBy($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\OrderBy::class); + $this->writeOneof(3, $var); + + return $this; + } + + /** + * Generated from protobuf field int32 offset = 4; + * @return int + */ + public function getOffset() + { + return $this->readOneof(4); + } + + /** + * Generated from protobuf field int32 offset = 4; + * @param int $var + * @return $this + */ + public function setOffset($var) + { + GPBUtil::checkInt32($var); + $this->writeOneof(4, $var); + + return $this; + } + + /** + * Generated from protobuf field int32 limit = 5; + * @return int + */ + public function getLimit() + { + return $this->readOneof(5); + } + + /** + * Generated from protobuf field int32 limit = 5; + * @param int $var + * @return $this + */ + public function setLimit($var) + { + GPBUtil::checkInt32($var); + $this->writeOneof(5, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.Cursor start_at = 6; + * @return \Google\Cloud\Firestore\Tests\Conformance\Cursor + */ + public function getStartAt() + { + return $this->readOneof(6); + } + + /** + * Generated from protobuf field .tests.Cursor start_at = 6; + * @param \Google\Cloud\Firestore\Tests\Conformance\Cursor $var + * @return $this + */ + public function setStartAt($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\Cursor::class); + $this->writeOneof(6, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.Cursor start_after = 7; + * @return \Google\Cloud\Firestore\Tests\Conformance\Cursor + */ + public function getStartAfter() + { + return $this->readOneof(7); + } + + /** + * Generated from protobuf field .tests.Cursor start_after = 7; + * @param \Google\Cloud\Firestore\Tests\Conformance\Cursor $var + * @return $this + */ + public function setStartAfter($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\Cursor::class); + $this->writeOneof(7, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.Cursor end_at = 8; + * @return \Google\Cloud\Firestore\Tests\Conformance\Cursor + */ + public function getEndAt() + { + return $this->readOneof(8); + } + + /** + * Generated from protobuf field .tests.Cursor end_at = 8; + * @param \Google\Cloud\Firestore\Tests\Conformance\Cursor $var + * @return $this + */ + public function setEndAt($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\Cursor::class); + $this->writeOneof(8, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.Cursor end_before = 9; + * @return \Google\Cloud\Firestore\Tests\Conformance\Cursor + */ + public function getEndBefore() + { + return $this->readOneof(9); + } + + /** + * Generated from protobuf field .tests.Cursor end_before = 9; + * @param \Google\Cloud\Firestore\Tests\Conformance\Cursor $var + * @return $this + */ + public function setEndBefore($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\Cursor::class); + $this->writeOneof(9, $var); + + return $this; + } + + /** + * @return string + */ + public function getClause() + { + return $this->whichOneof("clause"); + } + +} + diff --git a/Firestore/tests/conformance-fixtures/Tests/CreateTest.php b/Firestore/tests/Conformance/CreateTest.php similarity index 65% rename from Firestore/tests/conformance-fixtures/Tests/CreateTest.php rename to Firestore/tests/Conformance/CreateTest.php index f0747e86c236..9bba0d810644 100644 --- a/Firestore/tests/conformance-fixtures/Tests/CreateTest.php +++ b/Firestore/tests/Conformance/CreateTest.php @@ -2,68 +2,57 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
  * Call to DocumentRef.Create.
- * 
* - * Protobuf type tests.CreateTest + * Generated from protobuf message tests.CreateTest */ class CreateTest extends \Google\Protobuf\Internal\Message { /** - *
      * The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; */ private $doc_ref_path = ''; /** - *
      * The data passed to Create, as JSON. The strings "Delete" and "ServerTimestamp"
      * denote the two special sentinel values. Values that could be interpreted as integers
      * (i.e. digit strings) should be treated as integers.
-     * 
* - * string json_data = 2; + * Generated from protobuf field string json_data = 2; */ private $json_data = ''; /** - *
      * The request that the call should generate.
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 3; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 3; */ private $request = null; /** - *
      * If true, the call should result in an error without generating a request.
      * If this is true, request should not be set.
-     * 
* - * bool is_error = 4; + * Generated from protobuf field bool is_error = 4; */ private $is_error = false; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - *
      * The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @return string */ public function getDocRefPath() { @@ -71,26 +60,27 @@ public function getDocRefPath() } /** - *
      * The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @param string $var + * @return $this */ public function setDocRefPath($var) { GPBUtil::checkString($var, True); $this->doc_ref_path = $var; + + return $this; } /** - *
      * The data passed to Create, as JSON. The strings "Delete" and "ServerTimestamp"
      * denote the two special sentinel values. Values that could be interpreted as integers
      * (i.e. digit strings) should be treated as integers.
-     * 
* - * string json_data = 2; + * Generated from protobuf field string json_data = 2; + * @return string */ public function getJsonData() { @@ -98,26 +88,27 @@ public function getJsonData() } /** - *
      * The data passed to Create, as JSON. The strings "Delete" and "ServerTimestamp"
      * denote the two special sentinel values. Values that could be interpreted as integers
      * (i.e. digit strings) should be treated as integers.
-     * 
* - * string json_data = 2; + * Generated from protobuf field string json_data = 2; + * @param string $var + * @return $this */ public function setJsonData($var) { GPBUtil::checkString($var, True); $this->json_data = $var; + + return $this; } /** - *
      * The request that the call should generate.
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 3; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 3; + * @return \Google\Cloud\Firestore\V1beta1\CommitRequest */ public function getRequest() { @@ -125,25 +116,26 @@ public function getRequest() } /** - *
      * The request that the call should generate.
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 3; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 3; + * @param \Google\Cloud\Firestore\V1beta1\CommitRequest $var + * @return $this */ - public function setRequest(&$var) + public function setRequest($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\CommitRequest::class); $this->request = $var; + + return $this; } /** - *
      * If true, the call should result in an error without generating a request.
      * If this is true, request should not be set.
-     * 
* - * bool is_error = 4; + * Generated from protobuf field bool is_error = 4; + * @return bool */ public function getIsError() { @@ -151,17 +143,19 @@ public function getIsError() } /** - *
      * If true, the call should result in an error without generating a request.
      * If this is true, request should not be set.
-     * 
* - * bool is_error = 4; + * Generated from protobuf field bool is_error = 4; + * @param bool $var + * @return $this */ public function setIsError($var) { GPBUtil::checkBool($var); $this->is_error = $var; + + return $this; } } diff --git a/Firestore/tests/Conformance/Cursor.php b/Firestore/tests/Conformance/Cursor.php new file mode 100644 index 000000000000..d0de7b06fb37 --- /dev/null +++ b/Firestore/tests/Conformance/Cursor.php @@ -0,0 +1,81 @@ +tests.Cursor + */ +class Cursor extends \Google\Protobuf\Internal\Message +{ + /** + * one of: + * + * Generated from protobuf field .tests.DocSnapshot doc_snapshot = 1; + */ + private $doc_snapshot = null; + /** + * Generated from protobuf field repeated string json_values = 2; + */ + private $json_values; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * one of: + * + * Generated from protobuf field .tests.DocSnapshot doc_snapshot = 1; + * @return \Google\Cloud\Firestore\Tests\Conformance\DocSnapshot + */ + public function getDocSnapshot() + { + return $this->doc_snapshot; + } + + /** + * one of: + * + * Generated from protobuf field .tests.DocSnapshot doc_snapshot = 1; + * @param \Google\Cloud\Firestore\Tests\Conformance\DocSnapshot $var + * @return $this + */ + public function setDocSnapshot($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\DocSnapshot::class); + $this->doc_snapshot = $var; + + return $this; + } + + /** + * Generated from protobuf field repeated string json_values = 2; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getJsonValues() + { + return $this->json_values; + } + + /** + * Generated from protobuf field repeated string json_values = 2; + * @param string[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setJsonValues($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING); + $this->json_values = $arr; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/DeleteTest.php b/Firestore/tests/Conformance/DeleteTest.php new file mode 100644 index 000000000000..a789ab545e90 --- /dev/null +++ b/Firestore/tests/Conformance/DeleteTest.php @@ -0,0 +1,147 @@ +tests.DeleteTest + */ +class DeleteTest extends \Google\Protobuf\Internal\Message +{ + /** + * path of doc + * + * Generated from protobuf field string doc_ref_path = 1; + */ + private $doc_ref_path = ''; + /** + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + */ + private $precondition = null; + /** + * expected rquest + * + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 3; + */ + private $request = null; + /** + * call signals an error + * + * Generated from protobuf field bool is_error = 4; + */ + private $is_error = false; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * path of doc + * + * Generated from protobuf field string doc_ref_path = 1; + * @return string + */ + public function getDocRefPath() + { + return $this->doc_ref_path; + } + + /** + * path of doc + * + * Generated from protobuf field string doc_ref_path = 1; + * @param string $var + * @return $this + */ + public function setDocRefPath($var) + { + GPBUtil::checkString($var, True); + $this->doc_ref_path = $var; + + return $this; + } + + /** + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + * @return \Google\Cloud\Firestore\V1beta1\Precondition + */ + public function getPrecondition() + { + return $this->precondition; + } + + /** + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + * @param \Google\Cloud\Firestore\V1beta1\Precondition $var + * @return $this + */ + public function setPrecondition($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\Precondition::class); + $this->precondition = $var; + + return $this; + } + + /** + * expected rquest + * + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 3; + * @return \Google\Cloud\Firestore\V1beta1\CommitRequest + */ + public function getRequest() + { + return $this->request; + } + + /** + * expected rquest + * + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 3; + * @param \Google\Cloud\Firestore\V1beta1\CommitRequest $var + * @return $this + */ + public function setRequest($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\CommitRequest::class); + $this->request = $var; + + return $this; + } + + /** + * call signals an error + * + * Generated from protobuf field bool is_error = 4; + * @return bool + */ + public function getIsError() + { + return $this->is_error; + } + + /** + * call signals an error + * + * Generated from protobuf field bool is_error = 4; + * @param bool $var + * @return $this + */ + public function setIsError($var) + { + GPBUtil::checkBool($var); + $this->is_error = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/DocChange.php b/Firestore/tests/Conformance/DocChange.php new file mode 100644 index 000000000000..fb924eb875b8 --- /dev/null +++ b/Firestore/tests/Conformance/DocChange.php @@ -0,0 +1,127 @@ +tests.DocChange + */ +class DocChange extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field .tests.DocChange.Kind kind = 1; + */ + private $kind = 0; + /** + * Generated from protobuf field .google.firestore.v1beta1.Document doc = 2; + */ + private $doc = null; + /** + * Generated from protobuf field int32 old_index = 3; + */ + private $old_index = 0; + /** + * Generated from protobuf field int32 new_index = 4; + */ + private $new_index = 0; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field .tests.DocChange.Kind kind = 1; + * @return int + */ + public function getKind() + { + return $this->kind; + } + + /** + * Generated from protobuf field .tests.DocChange.Kind kind = 1; + * @param int $var + * @return $this + */ + public function setKind($var) + { + GPBUtil::checkEnum($var, \Google\Cloud\Firestore\Tests\Conformance\DocChange_Kind::class); + $this->kind = $var; + + return $this; + } + + /** + * Generated from protobuf field .google.firestore.v1beta1.Document doc = 2; + * @return \Google\Cloud\Firestore\V1beta1\Document + */ + public function getDoc() + { + return $this->doc; + } + + /** + * Generated from protobuf field .google.firestore.v1beta1.Document doc = 2; + * @param \Google\Cloud\Firestore\V1beta1\Document $var + * @return $this + */ + public function setDoc($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\Document::class); + $this->doc = $var; + + return $this; + } + + /** + * Generated from protobuf field int32 old_index = 3; + * @return int + */ + public function getOldIndex() + { + return $this->old_index; + } + + /** + * Generated from protobuf field int32 old_index = 3; + * @param int $var + * @return $this + */ + public function setOldIndex($var) + { + GPBUtil::checkInt32($var); + $this->old_index = $var; + + return $this; + } + + /** + * Generated from protobuf field int32 new_index = 4; + * @return int + */ + public function getNewIndex() + { + return $this->new_index; + } + + /** + * Generated from protobuf field int32 new_index = 4; + * @param int $var + * @return $this + */ + public function setNewIndex($var) + { + GPBUtil::checkInt32($var); + $this->new_index = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/DocChange_Kind.php b/Firestore/tests/Conformance/DocChange_Kind.php new file mode 100644 index 000000000000..5843ef5ea56f --- /dev/null +++ b/Firestore/tests/Conformance/DocChange_Kind.php @@ -0,0 +1,29 @@ +Tests\DocChange\Kind + */ +class DocChange_Kind +{ + /** + * Generated from protobuf enum KIND_UNSPECIFIED = 0; + */ + const KIND_UNSPECIFIED = 0; + /** + * Generated from protobuf enum ADDED = 1; + */ + const ADDED = 1; + /** + * Generated from protobuf enum REMOVED = 2; + */ + const REMOVED = 2; + /** + * Generated from protobuf enum MODIFIED = 3; + */ + const MODIFIED = 3; +} + diff --git a/Firestore/tests/Conformance/DocSnapshot.php b/Firestore/tests/Conformance/DocSnapshot.php new file mode 100644 index 000000000000..e43ad5d19a02 --- /dev/null +++ b/Firestore/tests/Conformance/DocSnapshot.php @@ -0,0 +1,75 @@ +tests.DocSnapshot + */ +class DocSnapshot extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field string path = 1; + */ + private $path = ''; + /** + * Generated from protobuf field string json_data = 2; + */ + private $json_data = ''; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field string path = 1; + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * Generated from protobuf field string path = 1; + * @param string $var + * @return $this + */ + public function setPath($var) + { + GPBUtil::checkString($var, True); + $this->path = $var; + + return $this; + } + + /** + * Generated from protobuf field string json_data = 2; + * @return string + */ + public function getJsonData() + { + return $this->json_data; + } + + /** + * Generated from protobuf field string json_data = 2; + * @param string $var + * @return $this + */ + public function setJsonData($var) + { + GPBUtil::checkString($var, True); + $this->json_data = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/conformance-fixtures/Tests/FieldPath.php b/Firestore/tests/Conformance/FieldPath.php similarity index 50% rename from Firestore/tests/conformance-fixtures/Tests/FieldPath.php rename to Firestore/tests/Conformance/FieldPath.php index 0e29e2560860..91da0b2def3c 100644 --- a/Firestore/tests/conformance-fixtures/Tests/FieldPath.php +++ b/Firestore/tests/Conformance/FieldPath.php @@ -2,33 +2,30 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
- * A field path.
- * 
- * - * Protobuf type tests.FieldPath + * Generated from protobuf message tests.FieldPath */ class FieldPath extends \Google\Protobuf\Internal\Message { /** - * repeated string field = 1; + * Generated from protobuf field repeated string field = 1; */ private $field; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - * repeated string field = 1; + * Generated from protobuf field repeated string field = 1; + * @return \Google\Protobuf\Internal\RepeatedField */ public function getField() { @@ -36,12 +33,16 @@ public function getField() } /** - * repeated string field = 1; + * Generated from protobuf field repeated string field = 1; + * @param string[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this */ - public function setField(&$var) + public function setField($var) { $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING); $this->field = $arr; + + return $this; } } diff --git a/Firestore/tests/Conformance/FirestoreTest.php b/Firestore/tests/Conformance/FirestoreTest.php deleted file mode 100644 index 146cae0d0e31..000000000000 --- a/Firestore/tests/Conformance/FirestoreTest.php +++ /dev/null @@ -1,393 +0,0 @@ -client = TestHelpers::stub(FirestoreClient::class, [ - [ - 'projectId' => 'projectID' - ] - ]); - $this->connection = $this->prophesize(ConnectionInterface::class); - } - - /** - * @dataProvider cases - */ - public function testConformance($description, $type, array $test) - { - if (in_array($description, $this->skipped)) { - $this->markTestSkipped('manually skipped '. $description); - return; - } - - switch ($type) { - case 'get': - $method = 'runGet'; - break; - - case 'create': - $method = 'runCreate'; - break; - - case 'set': - $method = 'runSet'; - break; - - case 'update': - $method = 'runUpdate'; - break; - - case 'updatePaths': - $method = 'runUpdatePaths'; - break; - - case 'delete': - $method = 'runDelete'; - break; - - default: - throw \Exception('Invalid test type '. $type); - break; - } - - return $this->$method($test); - } - - private function runGet($test) - { - $this->connection->batchGetDocuments(Argument::withEntry('documents', [$test['request']['name']])) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([[]])); - $this->client->___setProperty('connection', $this->connection->reveal()); - - $this->client->document($this->relativeName($test['docRefPath']))->snapshot(); - } - - private function runCreate($test) - { - if (isset($test['request'])) { - $request = $test['request']; - if (isset($request['transaction']) && !$request['transaction']) { - unset($request['transaction']); - } - - $this->connection->commit($request) - ->shouldBeCalled()->willReturn([]); - $this->client->___setProperty('connection', $this->connection->reveal()); - } - - $hasError = false; - try { - $this->client->document($this->relativeName($test['docRefPath'])) - ->create($this->generateFields($test['jsonData'])); - } catch (\Exception $e) { - if ($e instanceof UnexpectedCallException) { - throw $e; - } - - $hasError = true; - } - - if (isset($test['isError']) && $test['isError']) { - $this->assertTrue($hasError); - } - } - - private function runSet($test) - { - if (isset($test['request'])) { - $request = $test['request']; - if (isset($request['transaction']) && !$request['transaction']) { - unset($request['transaction']); - } - - $this->connection->commit(new ArrayHasSameValuesToken($request)) - ->shouldBeCalled()->willReturn([]); - $this->client->___setProperty('connection', $this->connection->reveal()); - } - - $hasError = false; - try { - $options = []; - if (isset($test['option']['all']) && $test['option']['all']) { - $options = ['merge' => true]; - } - - $this->client->document($this->relativeName($test['docRefPath'])) - ->set($this->generateFields($test['jsonData']), $options); - } catch (\Exception $e) { - if ($e instanceof UnexpectedCallException) { - throw $e; - } - - $hasError = true; - } - - if (isset($test['isError']) && $test['isError']) { - $this->assertTrue($hasError); - } - } - - private function runUpdate($test) - { - if (isset($test['request'])) { - $request = $test['request']; - if (isset($request['transaction']) && !$request['transaction']) { - unset($request['transaction']); - } - - $this->connection->commit(new ArrayHasSameValuesToken($request)) - ->shouldBeCalled()->willReturn([]); - $this->client->___setProperty('connection', $this->connection->reveal()); - } - - $fields = []; - foreach ($this->generateFields($test['jsonData']) as $key => $val) { - $fields[] = ['path' => $key, 'value' => $val]; - } - - $options = $this->formatOptions($test); - - $hasError = false; - try { - $this->client->document($this->relativeName($test['docRefPath'])) - ->update($fields, $options); - } catch (\Exception $e) { - if ($e instanceof UnexpectedCallException) { - throw $e; - } - - $hasError = true; - } - - if (isset($test['isError']) && $test['isError']) { - $this->assertTrue($hasError); - } elseif (isset($e)) { - throw $e; - } - } - - private function runUpdatePaths($test) - { - if (isset($test['request'])) { - $request = $test['request']; - if (isset($request['transaction']) && !$request['transaction']) { - unset($request['transaction']); - } - - if (!isset($test['isError']) || !$test['isError']) { - $this->connection->commit(new ArrayHasSameValuesToken($request)) - ->shouldBeCalled()->willReturn([]); - } - - $this->client->___setProperty('connection', $this->connection->reveal()); - } - - $data = []; - foreach ($test['fieldPaths'] as $key => $val) { - $data[] = [ - 'path' => new FieldPath($val['field']), - 'value' => $this->injectSentinel(json_decode($test['jsonValues'][$key], true)) - ]; - } - - $options = $this->formatOptions($test); - - $hasError = false; - try { - $this->client->document($this->relativeName($test['docRefPath'])) - ->update($data, $options); - } catch (\Exception $e) { - if ($e instanceof UnexpectedCallException) { - throw $e; - } - - $hasError = true; - } - - if (isset($test['isError']) && $test['isError']) { - $this->assertTrue($hasError); - } - } - - private function runDelete($test) - { - if (isset($test['request'])) { - $request = $test['request']; - if (isset($request['transaction']) && !$request['transaction']) { - unset($request['transaction']); - } - - $this->connection->commit($request) - ->shouldBeCalled()->willReturn([]); - $this->client->___setProperty('connection', $this->connection->reveal()); - } - - $options = $this->formatOptions($test); - - $hasError = false; - try { - $this->client->document($this->relativeName($test['docRefPath'])) - ->delete($options); - } catch (\Exception $e) { - if ($e instanceof UnexpectedCallException) { - throw $e; - } - - $hasError = true; - } - - if (isset($test['isError']) && $test['isError']) { - $this->assertTrue($hasError); - } - } - - private function formatOptions(array $test) - { - $options = []; - if (isset($test['precondition'])) { - if (isset($test['precondition']['exists'])) { - $options['precondition'] = ['exists' => $test['precondition']['exists']]; - } - - if (isset($test['precondition']['updateTime'])) { - $test['precondition']['updateTime'] += ['seconds' => 0, 'nanos' => 0]; - - $options['precondition'] = [ - 'updateTime' => new Timestamp( - \DateTime::createFromFormat('U', (string) $test['precondition']['updateTime']['seconds']), - $test['precondition']['updateTime']['nanos'] - ) - ]; - } - } - - return $options; - } - - private function generateFields($data) - { - $fields = json_decode($data, true); - return $this->injectSentinels($fields); - } - - private function injectSentinels(array $fields) - { - foreach ($fields as $name => &$value) { - $value = $this->injectSentinel($value); - } - - return $fields; - } - - private function injectSentinel($value) - { - if (is_array($value)) { - $value = $this->injectSentinels($value); - } - - if ($value === 'Delete') { - $value = FieldValue::deleteField(); - } - - if ($value === 'ServerTimestamp') { - $value = FieldValue::serverTimestamp(); - } - - return $value; - } - - public function cases() - { - $types = ['get', 'create', 'set', 'update', 'updatePaths', 'delete']; - - $serializer = new Serializer; - $bytes = (new Client)->get(self::TEST_FILE)->getBody(); - - $index = 0; - $len = strlen($bytes); - $protos = []; - while ($index < $len) { - list($proto, $index) = $this->loadProto($bytes, $index); - $case = $serializer->encodeMessage($proto); - - $type = array_values(array_intersect($types, array_keys($case)))[0]; - - $protos[] = [$case['description'], $type, $case[$type]]; - } - - return $protos; - } - - private static function loadProto($bytes, $index) - { - list($num, $index) = \VarInt::decode($bytes, $index); - $binProto = substr($bytes, $index, $num); - $testProto = new \Tests\Test(); - $testProto->mergeFromString($binProto); - return [$testProto, $index + $num]; - } -} diff --git a/Firestore/tests/Conformance/FirestoreTestGpb.php b/Firestore/tests/Conformance/FirestoreTestGpb.php new file mode 100644 index 000000000000..24f898d12d53 --- /dev/null +++ b/Firestore/tests/Conformance/FirestoreTestGpb.php @@ -0,0 +1,128 @@ +internalAddGeneratedFile(hex2bin( + "0aa7170a0a746573742e70726f746f120574657374731a27676f6f676c65" . + "2f6669726573746f72652f763162657461312f646f63756d656e742e7072" . + "6f746f1a28676f6f676c652f6669726573746f72652f763162657461312f" . + "6669726573746f72652e70726f746f1a24676f6f676c652f666972657374" . + "6f72652f763162657461312f71756572792e70726f746f1a1f676f6f676c" . + "652f70726f746f6275662f74696d657374616d702e70726f746f22270a09" . + "546573745375697465121a0a05746573747318012003280b320b2e746573" . + "74732e5465737422c8020a045465737412130a0b6465736372697074696f" . + "6e180120012809121d0a0367657418022001280b320e2e74657374732e47" . + "657454657374480012230a0663726561746518032001280b32112e746573" . + "74732e437265617465546573744800121d0a0373657418042001280b320e" . + "2e74657374732e53657454657374480012230a0675706461746518052001" . + "280b32112e74657374732e557064617465546573744800122e0a0c757064" . + "6174655f706174687318062001280b32162e74657374732e557064617465" . + "506174687354657374480012230a0664656c65746518072001280b32112e" . + "74657374732e44656c65746554657374480012210a057175657279180820" . + "01280b32102e74657374732e517565727954657374480012230a066c6973" . + "74656e18092001280b32112e74657374732e4c697374656e546573744800" . + "42060a0474657374225e0a074765745465737412140a0c646f635f726566" . + "5f70617468180120012809123d0a077265717565737418022001280b322c" . + "2e676f6f676c652e6669726573746f72652e763162657461312e47657444" . + "6f63756d656e74526571756573742281010a0a4372656174655465737412" . + "140a0c646f635f7265665f7061746818012001280912110a096a736f6e5f" . + "6461746118022001280912380a077265717565737418032001280b32272e" . + "676f6f676c652e6669726573746f72652e763162657461312e436f6d6d69" . + "745265717565737412100a0869735f6572726f7218042001280822a0010a" . + "075365745465737412140a0c646f635f7265665f70617468180120012809" . + "12200a066f7074696f6e18022001280b32102e74657374732e5365744f70" . + "74696f6e12110a096a736f6e5f6461746118032001280912380a07726571" . + "7565737418042001280b32272e676f6f676c652e6669726573746f72652e" . + "763162657461312e436f6d6d69745265717565737412100a0869735f6572" . + "726f7218052001280822bf010a0a5570646174655465737412140a0c646f" . + "635f7265665f70617468180120012809123c0a0c707265636f6e64697469" . + "6f6e18022001280b32262e676f6f676c652e6669726573746f72652e7631" . + "62657461312e507265636f6e646974696f6e12110a096a736f6e5f646174" . + "6118032001280912380a077265717565737418042001280b32272e676f6f" . + "676c652e6669726573746f72652e763162657461312e436f6d6d69745265" . + "717565737412100a0869735f6572726f7218052001280822ed010a0f5570" . + "6461746550617468735465737412140a0c646f635f7265665f7061746818" . + "0120012809123c0a0c707265636f6e646974696f6e18022001280b32262e" . + "676f6f676c652e6669726573746f72652e763162657461312e507265636f" . + "6e646974696f6e12250a0b6669656c645f706174687318032003280b3210" . + "2e74657374732e4669656c645061746812130a0b6a736f6e5f76616c7565" . + "7318042003280912380a077265717565737418052001280b32272e676f6f" . + "676c652e6669726573746f72652e763162657461312e436f6d6d69745265" . + "717565737412100a0869735f6572726f7218062001280822ac010a0a4465" . + "6c6574655465737412140a0c646f635f7265665f70617468180120012809" . + "123c0a0c707265636f6e646974696f6e18022001280b32262e676f6f676c" . + "652e6669726573746f72652e763162657461312e507265636f6e64697469" . + "6f6e12380a077265717565737418032001280b32272e676f6f676c652e66" . + "69726573746f72652e763162657461312e436f6d6d697452657175657374" . + "12100a0869735f6572726f72180420012808223a0a095365744f7074696f" . + "6e120b0a03616c6c18012001280812200a066669656c647318022003280b" . + "32102e74657374732e4669656c6450617468228a010a0951756572795465" . + "737412110a09636f6c6c5f70617468180120012809121e0a07636c617573" . + "657318022003280b320d2e74657374732e436c6175736512380a05717565" . + "727918032001280b32292e676f6f676c652e6669726573746f72652e7631" . + "62657461312e53747275637475726564517565727912100a0869735f6572" . + "726f7218042001280822a8020a06436c61757365121f0a0673656c656374" . + "18012001280b320d2e74657374732e53656c6563744800121d0a05776865" . + "726518022001280b320c2e74657374732e5768657265480012220a086f72" . + "6465725f627918032001280b320e2e74657374732e4f7264657242794800" . + "12100a066f66667365741804200128054800120f0a056c696d6974180520" . + "012805480012210a0873746172745f617418062001280b320d2e74657374" . + "732e437572736f72480012240a0b73746172745f61667465721807200128" . + "0b320d2e74657374732e437572736f724800121f0a06656e645f61741808" . + "2001280b320d2e74657374732e437572736f72480012230a0a656e645f62" . + "65666f726518092001280b320d2e74657374732e437572736f7248004208" . + "0a06636c61757365222a0a0653656c65637412200a066669656c64731801" . + "2003280b32102e74657374732e4669656c645061746822470a0557686572" . + "65121e0a047061746818012001280b32102e74657374732e4669656c6450" . + "617468120a0a026f7018022001280912120a0a6a736f6e5f76616c756518" . + "0320012809223c0a074f726465724279121e0a047061746818012001280b" . + "32102e74657374732e4669656c645061746812110a09646972656374696f" . + "6e18022001280922470a06437572736f7212280a0c646f635f736e617073" . + "686f7418012001280b32122e74657374732e446f63536e617073686f7412" . + "130a0b6a736f6e5f76616c756573180220032809222e0a0b446f63536e61" . + "7073686f74120c0a047061746818012001280912110a096a736f6e5f6461" . + "7461180220012809221a0a094669656c6450617468120d0a056669656c64" . + "180120032809227f0a0a4c697374656e54657374123b0a09726573706f6e" . + "73657318012003280b32282e676f6f676c652e6669726573746f72652e76" . + "3162657461312e4c697374656e526573706f6e736512220a09736e617073" . + "686f747318022003280b320f2e74657374732e536e617073686f7412100a" . + "0869735f6572726f72180320012808228e010a08536e617073686f741230" . + "0a04646f637318012003280b32222e676f6f676c652e6669726573746f72" . + "652e763162657461312e446f63756d656e7412210a076368616e67657318" . + "022003280b32102e74657374732e446f634368616e6765122d0a09726561" . + "645f74696d6518032001280b321a2e676f6f676c652e70726f746f627566" . + "2e54696d657374616d7022cb010a09446f634368616e676512230a046b69" . + "6e6418012001280e32152e74657374732e446f634368616e67652e4b696e" . + "64122f0a03646f6318022001280b32222e676f6f676c652e666972657374" . + "6f72652e763162657461312e446f63756d656e7412110a096f6c645f696e" . + "64657818032001280512110a096e65775f696e6465781804200128052242" . + "0a044b696e6412140a104b494e445f554e53504543494649454410001209" . + "0a0541444445441001120b0a0752454d4f5645441002120c0a084d4f4449" . + "46494544100342780a26636f6d2e676f6f676c652e636c6f75642e666972" . + "6573746f72652e636f6e666f726d616e6365aa0222476f6f676c652e436c" . + "6f75642e4669726573746f72652e54657374732e50726f746fca0228476f" . + "6f676c655c436c6f75645c4669726573746f72655c54657374735c436f6e" . + "666f726d616e6365620670726f746f33" + )); + + static::$is_initialized = true; + } +} + diff --git a/Firestore/tests/conformance-fixtures/Tests/GetTest.php b/Firestore/tests/Conformance/GetTest.php similarity index 58% rename from Firestore/tests/conformance-fixtures/Tests/GetTest.php rename to Firestore/tests/Conformance/GetTest.php index 8d78dea154ed..0d41d22ceb0a 100644 --- a/Firestore/tests/conformance-fixtures/Tests/GetTest.php +++ b/Firestore/tests/Conformance/GetTest.php @@ -2,49 +2,42 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
  * Call to the DocumentRef.Get method.
- * 
* - * Protobuf type tests.GetTest + * Generated from protobuf message tests.GetTest */ class GetTest extends \Google\Protobuf\Internal\Message { /** - *
      * The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; */ private $doc_ref_path = ''; /** - *
      * The request that the call should send to the Firestore service.
-     * 
* - * .google.firestore.v1beta1.GetDocumentRequest request = 2; + * Generated from protobuf field .google.firestore.v1beta1.GetDocumentRequest request = 2; */ private $request = null; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - *
      * The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @return string */ public function getDocRefPath() { @@ -52,24 +45,25 @@ public function getDocRefPath() } /** - *
      * The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d"
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @param string $var + * @return $this */ public function setDocRefPath($var) { GPBUtil::checkString($var, True); $this->doc_ref_path = $var; + + return $this; } /** - *
      * The request that the call should send to the Firestore service.
-     * 
* - * .google.firestore.v1beta1.GetDocumentRequest request = 2; + * Generated from protobuf field .google.firestore.v1beta1.GetDocumentRequest request = 2; + * @return \Google\Cloud\Firestore\V1beta1\GetDocumentRequest */ public function getRequest() { @@ -77,16 +71,18 @@ public function getRequest() } /** - *
      * The request that the call should send to the Firestore service.
-     * 
* - * .google.firestore.v1beta1.GetDocumentRequest request = 2; + * Generated from protobuf field .google.firestore.v1beta1.GetDocumentRequest request = 2; + * @param \Google\Cloud\Firestore\V1beta1\GetDocumentRequest $var + * @return $this */ - public function setRequest(&$var) + public function setRequest($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\GetDocumentRequest::class); $this->request = $var; + + return $this; } } diff --git a/Firestore/tests/Conformance/ListenTest.php b/Firestore/tests/Conformance/ListenTest.php new file mode 100644 index 000000000000..09fdd8dcecb2 --- /dev/null +++ b/Firestore/tests/Conformance/ListenTest.php @@ -0,0 +1,111 @@ +tests.ListenTest + */ +class ListenTest extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field repeated .google.firestore.v1beta1.ListenResponse responses = 1; + */ + private $responses; + /** + * Generated from protobuf field repeated .tests.Snapshot snapshots = 2; + */ + private $snapshots; + /** + * Generated from protobuf field bool is_error = 3; + */ + private $is_error = false; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field repeated .google.firestore.v1beta1.ListenResponse responses = 1; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getResponses() + { + return $this->responses; + } + + /** + * Generated from protobuf field repeated .google.firestore.v1beta1.ListenResponse responses = 1; + * @param \Google\Cloud\Firestore\V1beta1\ListenResponse[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setResponses($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\V1beta1\ListenResponse::class); + $this->responses = $arr; + + return $this; + } + + /** + * Generated from protobuf field repeated .tests.Snapshot snapshots = 2; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getSnapshots() + { + return $this->snapshots; + } + + /** + * Generated from protobuf field repeated .tests.Snapshot snapshots = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\Snapshot[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setSnapshots($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\Snapshot::class); + $this->snapshots = $arr; + + return $this; + } + + /** + * Generated from protobuf field bool is_error = 3; + * @return bool + */ + public function getIsError() + { + return $this->is_error; + } + + /** + * Generated from protobuf field bool is_error = 3; + * @param bool $var + * @return $this + */ + public function setIsError($var) + { + GPBUtil::checkBool($var); + $this->is_error = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/OrderBy.php b/Firestore/tests/Conformance/OrderBy.php new file mode 100644 index 000000000000..aa2c27942e4f --- /dev/null +++ b/Firestore/tests/Conformance/OrderBy.php @@ -0,0 +1,81 @@ +tests.OrderBy + */ +class OrderBy extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field .tests.FieldPath path = 1; + */ + private $path = null; + /** + * "asc" or "desc" + * + * Generated from protobuf field string direction = 2; + */ + private $direction = ''; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field .tests.FieldPath path = 1; + * @return \Google\Cloud\Firestore\Tests\Conformance\FieldPath + */ + public function getPath() + { + return $this->path; + } + + /** + * Generated from protobuf field .tests.FieldPath path = 1; + * @param \Google\Cloud\Firestore\Tests\Conformance\FieldPath $var + * @return $this + */ + public function setPath($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\FieldPath::class); + $this->path = $var; + + return $this; + } + + /** + * "asc" or "desc" + * + * Generated from protobuf field string direction = 2; + * @return string + */ + public function getDirection() + { + return $this->direction; + } + + /** + * "asc" or "desc" + * + * Generated from protobuf field string direction = 2; + * @param string $var + * @return $this + */ + public function setDirection($var) + { + GPBUtil::checkString($var, True); + $this->direction = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/QueryTest.php b/Firestore/tests/Conformance/QueryTest.php new file mode 100644 index 000000000000..7aa20bdec745 --- /dev/null +++ b/Firestore/tests/Conformance/QueryTest.php @@ -0,0 +1,133 @@ +tests.QueryTest + */ +class QueryTest extends \Google\Protobuf\Internal\Message +{ + /** + * path of collection, e.g. "projects/projectID/databases/(default)/documents/C" + * + * Generated from protobuf field string coll_path = 1; + */ + private $coll_path = ''; + /** + * Generated from protobuf field repeated .tests.Clause clauses = 2; + */ + private $clauses; + /** + * Generated from protobuf field .google.firestore.v1beta1.StructuredQuery query = 3; + */ + private $query = null; + /** + * Generated from protobuf field bool is_error = 4; + */ + private $is_error = false; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * path of collection, e.g. "projects/projectID/databases/(default)/documents/C" + * + * Generated from protobuf field string coll_path = 1; + * @return string + */ + public function getCollPath() + { + return $this->coll_path; + } + + /** + * path of collection, e.g. "projects/projectID/databases/(default)/documents/C" + * + * Generated from protobuf field string coll_path = 1; + * @param string $var + * @return $this + */ + public function setCollPath($var) + { + GPBUtil::checkString($var, True); + $this->coll_path = $var; + + return $this; + } + + /** + * Generated from protobuf field repeated .tests.Clause clauses = 2; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getClauses() + { + return $this->clauses; + } + + /** + * Generated from protobuf field repeated .tests.Clause clauses = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\Clause[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setClauses($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\Clause::class); + $this->clauses = $arr; + + return $this; + } + + /** + * Generated from protobuf field .google.firestore.v1beta1.StructuredQuery query = 3; + * @return \Google\Cloud\Firestore\V1beta1\StructuredQuery + */ + public function getQuery() + { + return $this->query; + } + + /** + * Generated from protobuf field .google.firestore.v1beta1.StructuredQuery query = 3; + * @param \Google\Cloud\Firestore\V1beta1\StructuredQuery $var + * @return $this + */ + public function setQuery($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\StructuredQuery::class); + $this->query = $var; + + return $this; + } + + /** + * Generated from protobuf field bool is_error = 4; + * @return bool + */ + public function getIsError() + { + return $this->is_error; + } + + /** + * Generated from protobuf field bool is_error = 4; + * @param bool $var + * @return $this + */ + public function setIsError($var) + { + GPBUtil::checkBool($var); + $this->is_error = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/Select.php b/Firestore/tests/Conformance/Select.php new file mode 100644 index 000000000000..5f357c1d40c6 --- /dev/null +++ b/Firestore/tests/Conformance/Select.php @@ -0,0 +1,49 @@ +tests.Select + */ +class Select extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field repeated .tests.FieldPath fields = 1; + */ + private $fields; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field repeated .tests.FieldPath fields = 1; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getFields() + { + return $this->fields; + } + + /** + * Generated from protobuf field repeated .tests.FieldPath fields = 1; + * @param \Google\Cloud\Firestore\Tests\Conformance\FieldPath[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setFields($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\FieldPath::class); + $this->fields = $arr; + + return $this; + } + +} + diff --git a/Firestore/tests/conformance-fixtures/Tests/SetOption.php b/Firestore/tests/Conformance/SetOption.php similarity index 53% rename from Firestore/tests/conformance-fixtures/Tests/SetOption.php rename to Firestore/tests/Conformance/SetOption.php index 4df89dbde184..2f7fb0edb22a 100644 --- a/Firestore/tests/conformance-fixtures/Tests/SetOption.php +++ b/Firestore/tests/Conformance/SetOption.php @@ -2,49 +2,42 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
  * An option to the DocumentRef.Set call.
- * 
* - * Protobuf type tests.SetOption + * Generated from protobuf message tests.SetOption */ class SetOption extends \Google\Protobuf\Internal\Message { /** - *
      * if true, merge all fields ("fields" is ignored).
-     * 
* - * bool all = 1; + * Generated from protobuf field bool all = 1; */ private $all = false; /** - *
      * field paths for a Merge option
-     * 
* - * repeated .tests.FieldPath fields = 2; + * Generated from protobuf field repeated .tests.FieldPath fields = 2; */ private $fields; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - *
      * if true, merge all fields ("fields" is ignored).
-     * 
* - * bool all = 1; + * Generated from protobuf field bool all = 1; + * @return bool */ public function getAll() { @@ -52,24 +45,25 @@ public function getAll() } /** - *
      * if true, merge all fields ("fields" is ignored).
-     * 
* - * bool all = 1; + * Generated from protobuf field bool all = 1; + * @param bool $var + * @return $this */ public function setAll($var) { GPBUtil::checkBool($var); $this->all = $var; + + return $this; } /** - *
      * field paths for a Merge option
-     * 
* - * repeated .tests.FieldPath fields = 2; + * Generated from protobuf field repeated .tests.FieldPath fields = 2; + * @return \Google\Protobuf\Internal\RepeatedField */ public function getFields() { @@ -77,16 +71,18 @@ public function getFields() } /** - *
      * field paths for a Merge option
-     * 
* - * repeated .tests.FieldPath fields = 2; + * Generated from protobuf field repeated .tests.FieldPath fields = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\FieldPath[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this */ - public function setFields(&$var) + public function setFields($var) { - $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Tests\FieldPath::class); + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\FieldPath::class); $this->fields = $arr; + + return $this; } } diff --git a/Firestore/tests/conformance-fixtures/Tests/SetTest.php b/Firestore/tests/Conformance/SetTest.php similarity index 51% rename from Firestore/tests/conformance-fixtures/Tests/SetTest.php rename to Firestore/tests/Conformance/SetTest.php index ba2a560d549f..258dbf1a9c96 100644 --- a/Firestore/tests/conformance-fixtures/Tests/SetTest.php +++ b/Firestore/tests/Conformance/SetTest.php @@ -2,73 +2,60 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
  * A call to DocumentRef.Set.
- * 
* - * Protobuf type tests.SetTest + * Generated from protobuf message tests.SetTest */ class SetTest extends \Google\Protobuf\Internal\Message { /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; */ private $doc_ref_path = ''; /** - *
      * option to the Set call, if any
-     * 
* - * .tests.SetOption option = 2; + * Generated from protobuf field .tests.SetOption option = 2; */ private $option = null; /** - *
      * data (see CreateTest.json_data)
-     * 
* - * string json_data = 3; + * Generated from protobuf field string json_data = 3; */ private $json_data = ''; /** - *
      * expected request
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 4; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 4; */ private $request = null; /** - *
      * call signals an error
-     * 
* - * bool is_error = 5; + * Generated from protobuf field bool is_error = 5; */ private $is_error = false; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @return string */ public function getDocRefPath() { @@ -76,24 +63,25 @@ public function getDocRefPath() } /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @param string $var + * @return $this */ public function setDocRefPath($var) { GPBUtil::checkString($var, True); $this->doc_ref_path = $var; + + return $this; } /** - *
      * option to the Set call, if any
-     * 
* - * .tests.SetOption option = 2; + * Generated from protobuf field .tests.SetOption option = 2; + * @return \Google\Cloud\Firestore\Tests\Conformance\SetOption */ public function getOption() { @@ -101,24 +89,25 @@ public function getOption() } /** - *
      * option to the Set call, if any
-     * 
* - * .tests.SetOption option = 2; + * Generated from protobuf field .tests.SetOption option = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\SetOption $var + * @return $this */ - public function setOption(&$var) + public function setOption($var) { - GPBUtil::checkMessage($var, \Tests\SetOption::class); + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\SetOption::class); $this->option = $var; + + return $this; } /** - *
      * data (see CreateTest.json_data)
-     * 
* - * string json_data = 3; + * Generated from protobuf field string json_data = 3; + * @return string */ public function getJsonData() { @@ -126,24 +115,25 @@ public function getJsonData() } /** - *
      * data (see CreateTest.json_data)
-     * 
* - * string json_data = 3; + * Generated from protobuf field string json_data = 3; + * @param string $var + * @return $this */ public function setJsonData($var) { GPBUtil::checkString($var, True); $this->json_data = $var; + + return $this; } /** - *
      * expected request
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 4; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 4; + * @return \Google\Cloud\Firestore\V1beta1\CommitRequest */ public function getRequest() { @@ -151,24 +141,25 @@ public function getRequest() } /** - *
      * expected request
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 4; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 4; + * @param \Google\Cloud\Firestore\V1beta1\CommitRequest $var + * @return $this */ - public function setRequest(&$var) + public function setRequest($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\CommitRequest::class); $this->request = $var; + + return $this; } /** - *
      * call signals an error
-     * 
* - * bool is_error = 5; + * Generated from protobuf field bool is_error = 5; + * @return bool */ public function getIsError() { @@ -176,16 +167,18 @@ public function getIsError() } /** - *
      * call signals an error
-     * 
* - * bool is_error = 5; + * Generated from protobuf field bool is_error = 5; + * @param bool $var + * @return $this */ public function setIsError($var) { GPBUtil::checkBool($var); $this->is_error = $var; + + return $this; } } diff --git a/Firestore/tests/Conformance/Snapshot.php b/Firestore/tests/Conformance/Snapshot.php new file mode 100644 index 000000000000..24da8c5d42b7 --- /dev/null +++ b/Firestore/tests/Conformance/Snapshot.php @@ -0,0 +1,101 @@ +tests.Snapshot + */ +class Snapshot extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field repeated .google.firestore.v1beta1.Document docs = 1; + */ + private $docs; + /** + * Generated from protobuf field repeated .tests.DocChange changes = 2; + */ + private $changes; + /** + * Generated from protobuf field .google.protobuf.Timestamp read_time = 3; + */ + private $read_time = null; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field repeated .google.firestore.v1beta1.Document docs = 1; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getDocs() + { + return $this->docs; + } + + /** + * Generated from protobuf field repeated .google.firestore.v1beta1.Document docs = 1; + * @param \Google\Cloud\Firestore\V1beta1\Document[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setDocs($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\V1beta1\Document::class); + $this->docs = $arr; + + return $this; + } + + /** + * Generated from protobuf field repeated .tests.DocChange changes = 2; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getChanges() + { + return $this->changes; + } + + /** + * Generated from protobuf field repeated .tests.DocChange changes = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\DocChange[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setChanges($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\DocChange::class); + $this->changes = $arr; + + return $this; + } + + /** + * Generated from protobuf field .google.protobuf.Timestamp read_time = 3; + * @return \Google\Protobuf\Timestamp + */ + public function getReadTime() + { + return $this->read_time; + } + + /** + * Generated from protobuf field .google.protobuf.Timestamp read_time = 3; + * @param \Google\Protobuf\Timestamp $var + * @return $this + */ + public function setReadTime($var) + { + GPBUtil::checkMessage($var, \Google\Protobuf\Timestamp::class); + $this->read_time = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/Test.php b/Firestore/tests/Conformance/Test.php new file mode 100644 index 000000000000..342355b06fc2 --- /dev/null +++ b/Firestore/tests/Conformance/Test.php @@ -0,0 +1,242 @@ +tests.Test + */ +class Test extends \Google\Protobuf\Internal\Message +{ + /** + * short description of the test + * + * Generated from protobuf field string description = 1; + */ + private $description = ''; + protected $test; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * short description of the test + * + * Generated from protobuf field string description = 1; + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * short description of the test + * + * Generated from protobuf field string description = 1; + * @param string $var + * @return $this + */ + public function setDescription($var) + { + GPBUtil::checkString($var, True); + $this->description = $var; + + return $this; + } + + /** + * Generated from protobuf field .tests.GetTest get = 2; + * @return \Google\Cloud\Firestore\Tests\Conformance\GetTest + */ + public function getGet() + { + return $this->readOneof(2); + } + + /** + * Generated from protobuf field .tests.GetTest get = 2; + * @param \Google\Cloud\Firestore\Tests\Conformance\GetTest $var + * @return $this + */ + public function setGet($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\GetTest::class); + $this->writeOneof(2, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.CreateTest create = 3; + * @return \Google\Cloud\Firestore\Tests\Conformance\CreateTest + */ + public function getCreate() + { + return $this->readOneof(3); + } + + /** + * Generated from protobuf field .tests.CreateTest create = 3; + * @param \Google\Cloud\Firestore\Tests\Conformance\CreateTest $var + * @return $this + */ + public function setCreate($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\CreateTest::class); + $this->writeOneof(3, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.SetTest set = 4; + * @return \Google\Cloud\Firestore\Tests\Conformance\SetTest + */ + public function getSet() + { + return $this->readOneof(4); + } + + /** + * Generated from protobuf field .tests.SetTest set = 4; + * @param \Google\Cloud\Firestore\Tests\Conformance\SetTest $var + * @return $this + */ + public function setSet($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\SetTest::class); + $this->writeOneof(4, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.UpdateTest update = 5; + * @return \Google\Cloud\Firestore\Tests\Conformance\UpdateTest + */ + public function getUpdate() + { + return $this->readOneof(5); + } + + /** + * Generated from protobuf field .tests.UpdateTest update = 5; + * @param \Google\Cloud\Firestore\Tests\Conformance\UpdateTest $var + * @return $this + */ + public function setUpdate($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\UpdateTest::class); + $this->writeOneof(5, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.UpdatePathsTest update_paths = 6; + * @return \Google\Cloud\Firestore\Tests\Conformance\UpdatePathsTest + */ + public function getUpdatePaths() + { + return $this->readOneof(6); + } + + /** + * Generated from protobuf field .tests.UpdatePathsTest update_paths = 6; + * @param \Google\Cloud\Firestore\Tests\Conformance\UpdatePathsTest $var + * @return $this + */ + public function setUpdatePaths($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\UpdatePathsTest::class); + $this->writeOneof(6, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.DeleteTest delete = 7; + * @return \Google\Cloud\Firestore\Tests\Conformance\DeleteTest + */ + public function getDelete() + { + return $this->readOneof(7); + } + + /** + * Generated from protobuf field .tests.DeleteTest delete = 7; + * @param \Google\Cloud\Firestore\Tests\Conformance\DeleteTest $var + * @return $this + */ + public function setDelete($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\DeleteTest::class); + $this->writeOneof(7, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.QueryTest query = 8; + * @return \Google\Cloud\Firestore\Tests\Conformance\QueryTest + */ + public function getQuery() + { + return $this->readOneof(8); + } + + /** + * Generated from protobuf field .tests.QueryTest query = 8; + * @param \Google\Cloud\Firestore\Tests\Conformance\QueryTest $var + * @return $this + */ + public function setQuery($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\QueryTest::class); + $this->writeOneof(8, $var); + + return $this; + } + + /** + * Generated from protobuf field .tests.ListenTest listen = 9; + * @return \Google\Cloud\Firestore\Tests\Conformance\ListenTest + */ + public function getListen() + { + return $this->readOneof(9); + } + + /** + * Generated from protobuf field .tests.ListenTest listen = 9; + * @param \Google\Cloud\Firestore\Tests\Conformance\ListenTest $var + * @return $this + */ + public function setListen($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\ListenTest::class); + $this->writeOneof(9, $var); + + return $this; + } + + /** + * @return string + */ + public function getTest() + { + return $this->whichOneof("test"); + } + +} + diff --git a/Firestore/tests/Conformance/TestSuite.php b/Firestore/tests/Conformance/TestSuite.php new file mode 100644 index 000000000000..d01752dbb1c9 --- /dev/null +++ b/Firestore/tests/Conformance/TestSuite.php @@ -0,0 +1,51 @@ +tests.TestSuite + */ +class TestSuite extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field repeated .tests.Test tests = 1; + */ + private $tests; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field repeated .tests.Test tests = 1; + * @return \Google\Protobuf\Internal\RepeatedField + */ + public function getTests() + { + return $this->tests; + } + + /** + * Generated from protobuf field repeated .tests.Test tests = 1; + * @param \Google\Cloud\Firestore\Tests\Conformance\Test[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this + */ + public function setTests($var) + { + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\Test::class); + $this->tests = $arr; + + return $this; + } + +} + diff --git a/Firestore/tests/conformance-fixtures/Tests/UpdatePathsTest.php b/Firestore/tests/Conformance/UpdatePathsTest.php similarity index 50% rename from Firestore/tests/conformance-fixtures/Tests/UpdatePathsTest.php rename to Firestore/tests/Conformance/UpdatePathsTest.php index 2d3d82e8fe09..ab3a44c9329f 100644 --- a/Firestore/tests/conformance-fixtures/Tests/UpdatePathsTest.php +++ b/Firestore/tests/Conformance/UpdatePathsTest.php @@ -2,82 +2,67 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
  * A call to the form of DocumentRef.Update that represents the data as a list
  * of field paths and their values.
- * 
* - * Protobuf type tests.UpdatePathsTest + * Generated from protobuf message tests.UpdatePathsTest */ class UpdatePathsTest extends \Google\Protobuf\Internal\Message { /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; */ private $doc_ref_path = ''; /** - *
      * precondition in call, if any
-     * 
* - * .google.firestore.v1beta1.Precondition precondition = 2; + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; */ private $precondition = null; /** - *
      * parallel sequences: field_paths[i] corresponds to json_values[i]
-     * 
* - * repeated .tests.FieldPath field_paths = 3; + * Generated from protobuf field repeated .tests.FieldPath field_paths = 3; */ private $field_paths; /** - *
      * the argument values, as JSON
-     * 
* - * repeated string json_values = 4; + * Generated from protobuf field repeated string json_values = 4; */ private $json_values; /** - *
      * expected rquest
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 5; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 5; */ private $request = null; /** - *
      * call signals an error
-     * 
* - * bool is_error = 6; + * Generated from protobuf field bool is_error = 6; */ private $is_error = false; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @return string */ public function getDocRefPath() { @@ -85,24 +70,25 @@ public function getDocRefPath() } /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @param string $var + * @return $this */ public function setDocRefPath($var) { GPBUtil::checkString($var, True); $this->doc_ref_path = $var; + + return $this; } /** - *
      * precondition in call, if any
-     * 
* - * .google.firestore.v1beta1.Precondition precondition = 2; + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + * @return \Google\Cloud\Firestore\V1beta1\Precondition */ public function getPrecondition() { @@ -110,24 +96,25 @@ public function getPrecondition() } /** - *
      * precondition in call, if any
-     * 
* - * .google.firestore.v1beta1.Precondition precondition = 2; + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + * @param \Google\Cloud\Firestore\V1beta1\Precondition $var + * @return $this */ - public function setPrecondition(&$var) + public function setPrecondition($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\Precondition::class); $this->precondition = $var; + + return $this; } /** - *
      * parallel sequences: field_paths[i] corresponds to json_values[i]
-     * 
* - * repeated .tests.FieldPath field_paths = 3; + * Generated from protobuf field repeated .tests.FieldPath field_paths = 3; + * @return \Google\Protobuf\Internal\RepeatedField */ public function getFieldPaths() { @@ -135,24 +122,25 @@ public function getFieldPaths() } /** - *
      * parallel sequences: field_paths[i] corresponds to json_values[i]
-     * 
* - * repeated .tests.FieldPath field_paths = 3; + * Generated from protobuf field repeated .tests.FieldPath field_paths = 3; + * @param \Google\Cloud\Firestore\Tests\Conformance\FieldPath[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this */ - public function setFieldPaths(&$var) + public function setFieldPaths($var) { - $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Tests\FieldPath::class); + $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Google\Cloud\Firestore\Tests\Conformance\FieldPath::class); $this->field_paths = $arr; + + return $this; } /** - *
      * the argument values, as JSON
-     * 
* - * repeated string json_values = 4; + * Generated from protobuf field repeated string json_values = 4; + * @return \Google\Protobuf\Internal\RepeatedField */ public function getJsonValues() { @@ -160,24 +148,25 @@ public function getJsonValues() } /** - *
      * the argument values, as JSON
-     * 
* - * repeated string json_values = 4; + * Generated from protobuf field repeated string json_values = 4; + * @param string[]|\Google\Protobuf\Internal\RepeatedField $var + * @return $this */ - public function setJsonValues(&$var) + public function setJsonValues($var) { $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING); $this->json_values = $arr; + + return $this; } /** - *
      * expected rquest
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 5; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 5; + * @return \Google\Cloud\Firestore\V1beta1\CommitRequest */ public function getRequest() { @@ -185,24 +174,25 @@ public function getRequest() } /** - *
      * expected rquest
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 5; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 5; + * @param \Google\Cloud\Firestore\V1beta1\CommitRequest $var + * @return $this */ - public function setRequest(&$var) + public function setRequest($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\CommitRequest::class); $this->request = $var; + + return $this; } /** - *
      * call signals an error
-     * 
* - * bool is_error = 6; + * Generated from protobuf field bool is_error = 6; + * @return bool */ public function getIsError() { @@ -210,16 +200,18 @@ public function getIsError() } /** - *
      * call signals an error
-     * 
* - * bool is_error = 6; + * Generated from protobuf field bool is_error = 6; + * @param bool $var + * @return $this */ public function setIsError($var) { GPBUtil::checkBool($var); $this->is_error = $var; + + return $this; } } diff --git a/Firestore/tests/conformance-fixtures/Tests/UpdateTest.php b/Firestore/tests/Conformance/UpdateTest.php similarity index 53% rename from Firestore/tests/conformance-fixtures/Tests/UpdateTest.php rename to Firestore/tests/Conformance/UpdateTest.php index db3cf9147327..18fc2bef5007 100644 --- a/Firestore/tests/conformance-fixtures/Tests/UpdateTest.php +++ b/Firestore/tests/Conformance/UpdateTest.php @@ -2,74 +2,61 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: test.proto -namespace Tests; +namespace Google\Cloud\Firestore\Tests\Conformance; use Google\Protobuf\Internal\GPBType; use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\GPBUtil; /** - *
  * A call to the form of DocumentRef.Update that represents the data as a map
  * or dictionary.
- * 
* - * Protobuf type tests.UpdateTest + * Generated from protobuf message tests.UpdateTest */ class UpdateTest extends \Google\Protobuf\Internal\Message { /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; */ private $doc_ref_path = ''; /** - *
      * precondition in call, if any
-     * 
* - * .google.firestore.v1beta1.Precondition precondition = 2; + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; */ private $precondition = null; /** - *
      * data (see CreateTest.json_data)
-     * 
* - * string json_data = 3; + * Generated from protobuf field string json_data = 3; */ private $json_data = ''; /** - *
      * expected request
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 4; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 4; */ private $request = null; /** - *
      * call signals an error
-     * 
* - * bool is_error = 5; + * Generated from protobuf field bool is_error = 5; */ private $is_error = false; public function __construct() { - \GPBMetadata\Test::initOnce(); + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); parent::__construct(); } /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @return string */ public function getDocRefPath() { @@ -77,24 +64,25 @@ public function getDocRefPath() } /** - *
      * path of doc
-     * 
* - * string doc_ref_path = 1; + * Generated from protobuf field string doc_ref_path = 1; + * @param string $var + * @return $this */ public function setDocRefPath($var) { GPBUtil::checkString($var, True); $this->doc_ref_path = $var; + + return $this; } /** - *
      * precondition in call, if any
-     * 
* - * .google.firestore.v1beta1.Precondition precondition = 2; + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + * @return \Google\Cloud\Firestore\V1beta1\Precondition */ public function getPrecondition() { @@ -102,24 +90,25 @@ public function getPrecondition() } /** - *
      * precondition in call, if any
-     * 
* - * .google.firestore.v1beta1.Precondition precondition = 2; + * Generated from protobuf field .google.firestore.v1beta1.Precondition precondition = 2; + * @param \Google\Cloud\Firestore\V1beta1\Precondition $var + * @return $this */ - public function setPrecondition(&$var) + public function setPrecondition($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\Precondition::class); $this->precondition = $var; + + return $this; } /** - *
      * data (see CreateTest.json_data)
-     * 
* - * string json_data = 3; + * Generated from protobuf field string json_data = 3; + * @return string */ public function getJsonData() { @@ -127,24 +116,25 @@ public function getJsonData() } /** - *
      * data (see CreateTest.json_data)
-     * 
* - * string json_data = 3; + * Generated from protobuf field string json_data = 3; + * @param string $var + * @return $this */ public function setJsonData($var) { GPBUtil::checkString($var, True); $this->json_data = $var; + + return $this; } /** - *
      * expected request
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 4; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 4; + * @return \Google\Cloud\Firestore\V1beta1\CommitRequest */ public function getRequest() { @@ -152,24 +142,25 @@ public function getRequest() } /** - *
      * expected request
-     * 
* - * .google.firestore.v1beta1.CommitRequest request = 4; + * Generated from protobuf field .google.firestore.v1beta1.CommitRequest request = 4; + * @param \Google\Cloud\Firestore\V1beta1\CommitRequest $var + * @return $this */ - public function setRequest(&$var) + public function setRequest($var) { GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\CommitRequest::class); $this->request = $var; + + return $this; } /** - *
      * call signals an error
-     * 
* - * bool is_error = 5; + * Generated from protobuf field bool is_error = 5; + * @return bool */ public function getIsError() { @@ -177,16 +168,18 @@ public function getIsError() } /** - *
      * call signals an error
-     * 
* - * bool is_error = 5; + * Generated from protobuf field bool is_error = 5; + * @param bool $var + * @return $this */ public function setIsError($var) { GPBUtil::checkBool($var); $this->is_error = $var; + + return $this; } } diff --git a/Firestore/tests/Conformance/Where.php b/Firestore/tests/Conformance/Where.php new file mode 100644 index 000000000000..77853ee27853 --- /dev/null +++ b/Firestore/tests/Conformance/Where.php @@ -0,0 +1,101 @@ +tests.Where + */ +class Where extends \Google\Protobuf\Internal\Message +{ + /** + * Generated from protobuf field .tests.FieldPath path = 1; + */ + private $path = null; + /** + * Generated from protobuf field string op = 2; + */ + private $op = ''; + /** + * Generated from protobuf field string json_value = 3; + */ + private $json_value = ''; + + public function __construct() { + \Google\Cloud\Firestore\Tests\Conformance\FirestoreTestGpb::initOnce(); + parent::__construct(); + } + + /** + * Generated from protobuf field .tests.FieldPath path = 1; + * @return \Google\Cloud\Firestore\Tests\Conformance\FieldPath + */ + public function getPath() + { + return $this->path; + } + + /** + * Generated from protobuf field .tests.FieldPath path = 1; + * @param \Google\Cloud\Firestore\Tests\Conformance\FieldPath $var + * @return $this + */ + public function setPath($var) + { + GPBUtil::checkMessage($var, \Google\Cloud\Firestore\Tests\Conformance\FieldPath::class); + $this->path = $var; + + return $this; + } + + /** + * Generated from protobuf field string op = 2; + * @return string + */ + public function getOp() + { + return $this->op; + } + + /** + * Generated from protobuf field string op = 2; + * @param string $var + * @return $this + */ + public function setOp($var) + { + GPBUtil::checkString($var, True); + $this->op = $var; + + return $this; + } + + /** + * Generated from protobuf field string json_value = 3; + * @return string + */ + public function getJsonValue() + { + return $this->json_value; + } + + /** + * Generated from protobuf field string json_value = 3; + * @param string $var + * @return $this + */ + public function setJsonValue($var) + { + GPBUtil::checkString($var, True); + $this->json_value = $var; + + return $this; + } + +} + diff --git a/Firestore/tests/Conformance/bootstrap.php b/Firestore/tests/Conformance/bootstrap.php index 19d4b20353dd..58bf1f9a34ff 100644 --- a/Firestore/tests/Conformance/bootstrap.php +++ b/Firestore/tests/Conformance/bootstrap.php @@ -1,3 +1,4 @@ fieldPath = new FieldPath([]); + } + public function testClass() { $this->checkAndSkipGrpcTests(); @@ -37,4 +44,29 @@ public function testClass() $res = $snippet->invoke('path'); $this->assertInstanceOf(FieldPath::class, $res->returnVal()); } + + public function testFromString() + { + $snippet = $this->snippetFromMethod(FieldPath::class, 'fromString'); + $res = $snippet->invoke('path'); + $this->assertInstanceOf(FieldPath::class, $res->returnVal()); + } + + public function testChild() + { + $snippet = $this->snippetFromMethod(FieldPath::class, 'child'); + $snippet->addLocal('path', $this->fieldPath); + $res = $snippet->invoke('child'); + + $this->assertCount(1, $res->returnVal()->path()); + } + + public function testPathString() + { + $snippet = $this->snippetFromMethod(FieldPath::class, 'pathString'); + $snippet->addLocal('path', $this->fieldPath->child('foo')); + $res = $snippet->invoke('string'); + + $this->assertEquals('foo', $res->returnVal()); + } } diff --git a/Firestore/tests/Unit/ConformanceTest.php b/Firestore/tests/Unit/ConformanceTest.php new file mode 100644 index 000000000000..f8038685c41b --- /dev/null +++ b/Firestore/tests/Unit/ConformanceTest.php @@ -0,0 +1,498 @@ +checkAndSkipGrpcTests(); + + $this->client = TestHelpers::stub(FirestoreClient::class, [ + [ + 'projectId' => 'projectID' + ] + ]); + + $this->connection = $this->prophesize(ConnectionInterface::class); + } + + /** + * @dataProvider cases + * @group firestore-conformance-get + */ + public function testGet($test) + { + $this->connection->batchGetDocuments(Argument::withEntry('documents', [$test['request']['name']])) + ->shouldBeCalled() + ->willReturn(new \ArrayIterator([[]])); + $this->client->___setProperty('connection', $this->connection->reveal()); + + $this->client->document($this->relativeName($test['docRefPath']))->snapshot(); + } + + /** + * @dataProvider cases + * @group firestore-conformance-create + */ + public function testCreate($test) + { + $this->setupCommitRequest($test, function ($test) { + $request = $test['request']; + if (isset($request['transaction']) && !$request['transaction']) { + unset($request['transaction']); + } + + $this->connection->commit(new ArrayHasSameValuesToken($request)) + ->shouldBeCalled()->willReturn([]); + }); + + $this->executeAndHandleError($test, function ($test) { + $this->client->document($this->relativeName($test['docRefPath'])) + ->create($this->generateFields($test['jsonData'])); + }); + } + + /** + * @dataProvider cases + * @group firestore-conformance-set + */ + public function testSet($test) + { + $this->setupCommitRequest($test, function ($test) { + $request = $test['request']; + if (isset($request['transaction']) && !$request['transaction']) { + unset($request['transaction']); + } + + $this->connection->commit(new ArrayHasSameValuesToken($request)) + ->shouldBeCalled()->willReturn([]); + }); + + $this->client->___setProperty('connection', $this->connection->reveal()); + + $this->executeAndHandleError($test, function ($test) { + $options = []; + if (isset($test['option']['all']) && $test['option']['all']) { + $options = ['merge' => true]; + } + + $this->client->document($this->relativeName($test['docRefPath'])) + ->set($this->generateFields($test['jsonData']), $options); + }); + } + + /** + * @dataProvider cases + * @group firestore-conformance-updatepaths + */ + public function testUpdatePaths($test) + { + $this->setupCommitRequest($test, function ($test) { + $request = $test['request']; + if (isset($request['transaction']) && !$request['transaction']) { + unset($request['transaction']); + } + + $this->connection->commit(new ArrayHasSameValuesToken($request)) + ->shouldBeCalled()->willReturn([]); + }); + + $this->executeAndHandleError($test, function ($test) { + $fields = []; + foreach ($test['fieldPaths'] as $key => $val) { + $fields[] = [ + 'path' => new FieldPath($val['field']), + 'value' => $this->injectSentinel(json_decode($test['jsonValues'][$key], true)) + ]; + } + + $options = $this->formatOptions($test); + + $this->client->document($this->relativeName($test['docRefPath'])) + ->update($fields, $options); + }); + } + + /** + * @dataProvider cases + * @group firestore-conformance-delete + */ + public function testDelete($test) + { + $this->setupCommitRequest($test, function ($test) { + $request = $test['request']; + if (isset($request['transaction']) && !$request['transaction']) { + unset($request['transaction']); + } + + $this->connection->commit(new ArrayHasSameValuesToken($request)) + ->shouldBeCalled()->willReturn([]); + }); + + $options = $this->formatOptions($test); + + $this->executeAndHandleError($test, function ($test) use ($options) { + $this->client->document($this->relativeName($test['docRefPath'])) + ->delete($options); + }); + } + + /** + * @dataProvider cases + * @group firestore-conformance-query + */ + public function testQuery($test) + { + $query = isset($test['query']) + ? $test['query'] + : []; + if (isset($query['from'][0]['allDescendants']) && !$query['from'][0]['allDescendants']) { + unset($query['from'][0]['allDescendants']); + } + + $times = (isset($test['isError']) && $test['isError']) ? 0 : 1; + $this->connection->runQuery(new ArrayHasSameValuesToken([ + 'parent' => $this->parentPath($test['collPath']), + 'structuredQuery' => $query, + 'retries' => 0 + ]))->shouldBeCalledTimes($times)->willReturn(new \ArrayIterator([])); + + $this->client->___setProperty('connection', $this->connection->reveal()); + + $query = $this->client->collection($this->relativeName($test['collPath'])); + + $this->executeAndHandleError($test, function ($test) use ($query) { + foreach ($test['clauses'] as $clause) { + $name = array_keys($clause)[0]; + switch ($name) { + case 'select': + $fields = []; + foreach ($clause['select']['fields'] as $field) { + $fields[] = $field['field'][0]; + } + + $query = $query->select($fields); + break; + + case 'where': + $path = count($clause['where']['path']['field']) === 1 + ? $clause['where']['path']['field'][0] + : new FieldPath($clause['where']['path']['field']); + + $query = $query->where( + $path, + $clause['where']['op'], + $this->injectWhere($this->injectSentinel(json_decode($clause['where']['jsonValue'], true))) + ); + break; + + case 'offset': + $query = $query->offset($clause['offset']); + break; + + case 'limit': + $query = $query->limit($clause['limit']); + break; + + case 'orderBy': + $path = count($clause['orderBy']['path']['field']) === 1 + ? $clause['orderBy']['path']['field'][0] + : new FieldPath($clause['orderBy']['path']['field']); + + $query = $query->orderBy( + $path, + $clause['orderBy']['direction'] + ); + break; + + case 'startAt': + case 'startAfter': + case 'endBefore': + case 'endAt': + $values = []; + if (isset($clause[$name]['jsonValues'])) { + foreach ($clause[$name]['jsonValues'] as $value) { + $values[] = $this->injectSentinel(json_decode($value, true)); + } + } + + if (isset($clause[$name]['docSnapshot'])) { + $coll = $this->prophesize(CollectionReference::class); + $coll->name()->willReturn($this->parentPath($clause[$name]['docSnapshot']['path'])); + $ref = $this->prophesize(DocumentReference::class); + $ref->parent()->willReturn($coll->reveal()); + $ref->name()->willReturn($clause[$name]['docSnapshot']['path']); + + $mapper = new ValueMapper( + $this->prophesize(ConnectionInterface::class)->reveal(), + false + ); + + $values = new DocumentSnapshot( + $ref->reveal(), + $mapper, + [], + json_decode($clause[$name]['docSnapshot']['jsonData'], true), + true + ); + } + + $query = $query->$name($values); + break; + + default: + throw new \RuntimeException('clause '. $name .' is not handled'); + } + } + + $query->documents(['maxRetries' => 0]); + }); + } + + private function setupCommitRequest(array $test, callable $call) + { + $test += [ + 'isError' => false + ]; + + if (!$test['isError']) { + $call($test); + } else { + $this->connection->commit(Argument::any()) + ->shouldNotBeCalled()->willReturn([]); + } + + $this->client->___setProperty('connection', $this->connection->reveal()); + } + + private function executeAndHandleError(array $test, callable $executeTest) + { + $hasError = false; + try { + $executeTest($test); + } catch (\Exception $e) { + if ($e instanceof UnexpectedCallException) { + throw $e; + } + + $hasError = $e; + } + + if (isset($test['isError']) && $test['isError']) { + $this->assertTrue((bool) $hasError); + } elseif ($hasError) { + throw $hasError; + } + } + + private function formatOptions(array $test) + { + $options = []; + if (isset($test['precondition'])) { + if (isset($test['precondition']['exists'])) { + $options['precondition'] = ['exists' => $test['precondition']['exists']]; + } + + if (isset($test['precondition']['updateTime'])) { + $test['precondition']['updateTime'] += ['seconds' => 0, 'nanos' => 0]; + + $options['precondition'] = [ + 'updateTime' => new Timestamp( + \DateTime::createFromFormat('U', (string) $test['precondition']['updateTime']['seconds']), + $test['precondition']['updateTime']['nanos'] + ) + ]; + } + } + + return $options; + } + + private function generateFields($data) + { + $fields = json_decode($data, true); + return $this->injectSentinels($fields); + } + + private function injectSentinels(array $fields) + { + foreach ($fields as $name => &$value) { + $value = $this->injectSentinel($value); + } + + return $fields; + } + + private function injectSentinel($value) + { + if (is_array($value)) { + return $this->injectSentinels($value); + } + + if ($value === 'Delete') { + return FieldValue::deleteField(); + } + + if ($value === 'ServerTimestamp') { + return FieldValue::serverTimestamp(); + } + + return $value; + } + + private function injectWhere($value) + { + if ($value === 'NaN') { + return NAN; + } + + return $value; + } + + private function setupCases($suite, array $types, array $excludes) + { + if (self::$cases) { + return self::$cases; + } + + $serializer = new Serializer; + + $str = file_get_contents($suite); + $suite = new TestSuite; + $suite->mergeFromString($str); + + $cases = []; + foreach ($suite->getTests() as $test) { + $case = $serializer->encodeMessage($test); + $matches = array_values(array_intersect($types, array_keys($case))); + if (!$matches) { + if (in_array($case['description'], $excludes)) { + self::$skipped[] = [$case['description']]; + continue; + } + + continue; + } + + $type = $matches[0]; + + if (in_array($case['description'], $excludes)) { + self::$skipped[] = [$case['description']]; + continue; + } + + $cases[] = [ + 'description' => $case['description'], + 'type' => $type, + 'test' => $case[$type] + ]; + } + + self::$cases = $cases; + return $cases; + } + + /** + * Report skipped cases for measurement purposes. + * + * @dataProvider skippedCases + */ + public function testSkipped($desc) + { + $this->markTestSkipped($desc); + } + + public function skippedCases() + { + return self::$skipped; + } + + public function cases($type) + { + if (strpos($type, 'test') === 0) { + $type = lcfirst(str_replace('test', '', $type)); + } + + $suite = __DIR__ . '/../Conformance/proto/'. self::SUITE_FILENAME; + $cases = array_filter( + $this->setupCases($suite, $this->testTypes, $this->excludes), + function ($case) use ($type) { + return $case['type'] === $type; + } + ); + + $res = []; + foreach ($cases as $case) { + $res[$case['description']] = [$case['test'], $case['description']]; + } + + return $res; + } +} diff --git a/Firestore/tests/Unit/FieldPathTest.php b/Firestore/tests/Unit/FieldPathTest.php index 04cb368b094b..592081bcc186 100644 --- a/Firestore/tests/Unit/FieldPathTest.php +++ b/Firestore/tests/Unit/FieldPathTest.php @@ -34,9 +34,63 @@ public function testConstruct() $this->assertEquals($this->pieces, $fieldPath->path()); } + /** + * @expectedException InvalidArgumentException + */ + public function testEmptyElements() + { + new FieldPath(['']); + } + public function testFromString() { $fieldPath = FieldPath::fromString(implode('.', $this->pieces)); $this->assertEquals($this->pieces, $fieldPath->path()); } + + /** + * @dataProvider invalidPaths + * @expectedException InvalidArgumentException + */ + public function testInvalidPaths($path) + { + FieldPath::fromString($path); + } + + public function invalidPaths() + { + return [ + ['hello..world'], + ['.hello.world'], + ['hello.world.'], + ['.hello.world.'], + ]; + } + + /** + * @dataProvider fieldPaths + */ + public function testEscapeFieldPath($expected, $input) + { + if ($input instanceof FieldPath) { + $input = $input->pathString(); + } else { + $input = FieldPath::fromString($input)->pathString(); + } + + $this->assertEquals($expected, $input); + } + + public function fieldPaths() + { + return [ + ['foo.bar', 'foo.bar'], + ['foo.bar.bar.bar.baz.whatever', 'foo.bar.bar.bar.baz.whatever'], + ['this.is.a.bad.`idea!!`', 'this.is.a.bad.idea!!'], + ['manual.escaping.`isn\'t`.wrong', 'manual.escaping.`isn\'t`.wrong'], + ['foo.bar', new FieldPath(['foo', 'bar'])], + ['`hello.world`', new FieldPath(['hello.world'])], + ['get.`$$$$`.do.`things#`', new FieldPath(['get', '$$$$', 'do', 'things#'])] + ]; + } } diff --git a/Firestore/tests/Unit/FirestoreClientTest.php b/Firestore/tests/Unit/FirestoreClientTest.php index ebd19891bd9b..d200ebe4ee74 100644 --- a/Firestore/tests/Unit/FirestoreClientTest.php +++ b/Firestore/tests/Unit/FirestoreClientTest.php @@ -226,6 +226,16 @@ public function testDocuments(array $input, array $names) $this->assertEquals('world', $res[0]['hello']); } + /** + * @expectedException InvalidArgumentException + */ + public function testDocumentsInvalidInputType() + { + $this->client->documents([ + 10 + ]); + } + public function documents() { $b = $this->prophesize(DocumentReference::class); diff --git a/Firestore/tests/Unit/PathTraitTest.php b/Firestore/tests/Unit/PathTraitTest.php index 2b13c868ad4f..03b91819d87e 100644 --- a/Firestore/tests/Unit/PathTraitTest.php +++ b/Firestore/tests/Unit/PathTraitTest.php @@ -80,6 +80,36 @@ public function testDatabaseFromName() ); } + public function testDatabaseIdFromName() + { + $path = sprintf('projects/%s/databases/%s/documents/%s', self::PROJECT, self::DATABASE, self::DOCUMENT); + + $this->assertEquals( + self::DATABASE, + $this->impl->call('databaseIdFromName', [$path]) + ); + } + + public function testDatabaseIdFromNameNull() + { + $this->assertNull($this->impl->call('databaseIdFromName', ['foo bar'])); + } + + public function testProjectIdFromName() + { + $path = sprintf('projects/%s/databases/%s/documents/%s', self::PROJECT, self::DATABASE, self::DOCUMENT); + + $this->assertEquals( + self::PROJECT, + $this->impl->call('projectIdFromName', [$path]) + ); + } + + public function testProjectIdFromNameNull() + { + $this->assertNull($this->impl->call('projectIdFromName', ['foo bar'])); + } + /** * @dataProvider documentsTrue */ diff --git a/Firestore/tests/Unit/QueryTest.php b/Firestore/tests/Unit/QueryTest.php index f5bd49021057..a7f0a9b37622 100644 --- a/Firestore/tests/Unit/QueryTest.php +++ b/Firestore/tests/Unit/QueryTest.php @@ -24,6 +24,7 @@ use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; +use Google\Cloud\Firestore\FieldValue; use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Firestore\Query; use Google\Cloud\Firestore\V1beta1\StructuredQuery_CompositeFilter_Operator; @@ -314,6 +315,15 @@ public function whereOperators() ]; } + /** + * @expectedException InvalidArgumentException + * @dataProvider sentinels + */ + public function testWhereInvalidSentinelValue($sentinel) + { + $this->query->where('foo', '=', $sentinel); + } + /** * @expectedException InvalidArgumentException */ @@ -815,6 +825,15 @@ public function testBuildPositionInvalidCursorType() $this->query->orderBy(Query::DOCUMENT_ID)->startAt([10]); } + /** + * @expectedException InvalidArgumentException + * @dataProvider sentinels + */ + public function testBuildPositionInvalidSentinelValue($sentinel) + { + $this->query->orderBy(Query::DOCUMENT_ID)->startAt([$sentinel]); + } + /** * @expectedException InvalidArgumentException */ @@ -864,4 +883,11 @@ private function queryFrom() { return $this->queryObj['from']; } + + public function sentinels() + { + return array_map(function ($val) { + return [$val]; + }, FieldValue::sentinelValues()); + } } diff --git a/Firestore/tests/Unit/ValueMapperTest.php b/Firestore/tests/Unit/ValueMapperTest.php index b72fd8e34729..81536c555b9b 100644 --- a/Firestore/tests/Unit/ValueMapperTest.php +++ b/Firestore/tests/Unit/ValueMapperTest.php @@ -365,104 +365,4 @@ public function testEncodeValuesInvalidArray() ['a'] ]]); } - - /** - * @dataProvider fieldPaths - */ - public function testEscapeFieldPath($input, $expected) - { - $this->assertEquals($expected, $this->mapper->escapeFieldPath($input)); - } - - public function fieldPaths() - { - return [ - ['foo.bar', 'foo.bar'], - ['foo.bar.bar.bar.baz.whatever', 'foo.bar.bar.bar.baz.whatever'], - ['this.is.a.bad.idea!!', 'this.is.a.bad.idea!!'], - ['manual.escaping.`isn\'t`.wrong', 'manual.escaping.`isn\'t`.wrong'], - [new FieldPath(['foo', 'bar']), 'foo.bar'], - [new FieldPath(['hello.world']), '`hello.world`'], - [new FieldPath(['get', '$$$$', 'do', 'things#']), 'get.`$$$$`.do.`things#`'] - ]; - } - - public function testEncodeFieldPaths() - { - $input = [ - 'users' => [ - 'john' => [ - 'name' => 'John', - 'family' => ['katelynn'] - ], - 'david' => [ - 'name' => 'David', - ] - ] - ]; - - $expected = [ - 'users.john.name', - 'users.john.family', - 'users.david.name' - ]; - - $res = $this->mapper->encodeFieldPaths($input); - $this->assertEquals($expected, $res); - } - - public function testFindSentinels() - { - $input = [ - 'users' => [ - 'john' => [ - 'name' => 'John', - 'family' => FieldValue::deleteField() - ], - 'david' => [ - 'name' => 'David', - 'lastLogin' => FieldValue::serverTimestamp() - ] - ] - ]; - - $expectedFields = $input; - unset($expectedFields['users']['john']['family']); - unset($expectedFields['users']['david']['lastLogin']); - - $timestamps = ['users.david.lastLogin']; - $deletes = ['users.john.family']; - - $res = $this->mapper->findSentinels($input); - - $this->assertEquals([ - $expectedFields, - $timestamps, - $deletes, - ], $res); - } - - /** - * @dataProvider invalidPaths - * @expectedException InvalidArgumentException - */ - public function testValidatePathsInvalidPaths($path) - { - $this->mapper->escapeFieldPath($path); - } - - public function invalidPaths() - { - return [ - ['hello..world'], - ['.hello.world'], - ['hello.world.'], - ['.hello.world.'], - ['hello*'], - ['hello~'], - ['hello/'], - ['hello['], - ['hello]'], - ]; - } } diff --git a/Firestore/tests/Unit/WriteBatchTest.php b/Firestore/tests/Unit/WriteBatchTest.php index 0c079afeb74b..7d597db58dba 100644 --- a/Firestore/tests/Unit/WriteBatchTest.php +++ b/Firestore/tests/Unit/WriteBatchTest.php @@ -233,14 +233,23 @@ public function testSetMerge($name, $ref) public function testSetSentinels($name, $ref) { $this->batch->set($ref, [ - 'hello' => FieldValue::deleteField(), - 'world' => FieldValue::serverTimestamp() + 'world' => FieldValue::serverTimestamp(), + 'foo' => 'bar' ]); $this->commitAndAssert([ 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), 'writes' => [ [ + 'update' => [ + 'name' => $name, + 'fields' => [ + 'foo' => [ + 'stringValue' => 'bar' + ] + ] + ] + ], [ 'transform' => [ 'document' => $name, 'fieldTransforms' => [ @@ -255,6 +264,18 @@ public function testSetSentinels($name, $ref) ]); } + /** + * @dataProvider documents + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Delete cannot appear in data unless `$options['merge']` is set. + */ + public function testSetSentinelsDeleteRequiresMerge($name, $ref) + { + $this->batch->set($ref, [ + 'hello' => FieldValue::DeleteField(), + ]); + } + /** * @dataProvider documents */ @@ -399,14 +420,6 @@ public function testRollbackFailsWithoutTransaction() $this->batch->rollback(); } - /** - * @expectedException InvalidArgumentException - */ - public function testSetEmptyFails() - { - $this->batch->set(self::DOCUMENT, [], ['merge' => true]); - } - /** * @expectedException InvalidArgumentException */ diff --git a/Firestore/tests/conformance-fixtures/GPBMetadata/Test.php b/Firestore/tests/conformance-fixtures/GPBMetadata/Test.php deleted file mode 100644 index ed081a0939fe..000000000000 --- a/Firestore/tests/conformance-fixtures/GPBMetadata/Test.php +++ /dev/null @@ -1,73 +0,0 @@ -internalAddGeneratedFile(hex2bin( - "0a850b0a0a746573742e70726f746f120574657374731a25676f6f676c65" . - "2f6669726573746f72652f763162657461312f636f6d6d6f6e2e70726f74" . - "6f2280020a045465737412130a0b6465736372697074696f6e1801200128" . - "09121d0a0367657418022001280b320e2e74657374732e47657454657374" . - "480012230a0663726561746518032001280b32112e74657374732e437265" . - "617465546573744800121d0a0373657418042001280b320e2e7465737473" . - "2e53657454657374480012230a0675706461746518052001280b32112e74" . - "657374732e557064617465546573744800122e0a0c7570646174655f7061" . - "74687318062001280b32162e74657374732e557064617465506174687354" . - "657374480012230a0664656c65746518072001280b32112e74657374732e" . - "44656c65746554657374480042060a0474657374225e0a07476574546573" . - "7412140a0c646f635f7265665f70617468180120012809123d0a07726571" . - "7565737418022001280b322c2e676f6f676c652e6669726573746f72652e" . - "763162657461312e476574446f63756d656e74526571756573742281010a" . - "0a4372656174655465737412140a0c646f635f7265665f70617468180120" . - "01280912110a096a736f6e5f6461746118022001280912380a0772657175" . - "65737418032001280b32272e676f6f676c652e6669726573746f72652e76" . - "3162657461312e436f6d6d69745265717565737412100a0869735f657272" . - "6f7218042001280822a0010a075365745465737412140a0c646f635f7265" . - "665f7061746818012001280912200a066f7074696f6e18022001280b3210" . - "2e74657374732e5365744f7074696f6e12110a096a736f6e5f6461746118" . - "032001280912380a077265717565737418042001280b32272e676f6f676c" . - "652e6669726573746f72652e763162657461312e436f6d6d697452657175" . - "65737412100a0869735f6572726f7218052001280822bf010a0a55706461" . - "74655465737412140a0c646f635f7265665f70617468180120012809123c" . - "0a0c707265636f6e646974696f6e18022001280b32262e676f6f676c652e" . - "6669726573746f72652e763162657461312e507265636f6e646974696f6e" . - "12110a096a736f6e5f6461746118032001280912380a0772657175657374" . - "18042001280b32272e676f6f676c652e6669726573746f72652e76316265" . - "7461312e436f6d6d69745265717565737412100a0869735f6572726f7218" . - "052001280822ed010a0f55706461746550617468735465737412140a0c64" . - "6f635f7265665f70617468180120012809123c0a0c707265636f6e646974" . - "696f6e18022001280b32262e676f6f676c652e6669726573746f72652e76" . - "3162657461312e507265636f6e646974696f6e12250a0b6669656c645f70" . - "6174687318032003280b32102e74657374732e4669656c64506174681213" . - "0a0b6a736f6e5f76616c75657318042003280912380a0772657175657374" . - "18052001280b32272e676f6f676c652e6669726573746f72652e76316265" . - "7461312e436f6d6d69745265717565737412100a0869735f6572726f7218" . - "062001280822ac010a0a44656c6574655465737412140a0c646f635f7265" . - "665f70617468180120012809123c0a0c707265636f6e646974696f6e1802" . - "2001280b32262e676f6f676c652e6669726573746f72652e763162657461" . - "312e507265636f6e646974696f6e12380a07726571756573741803200128" . - "0b32272e676f6f676c652e6669726573746f72652e763162657461312e43" . - "6f6d6d69745265717565737412100a0869735f6572726f72180420012808" . - "223a0a095365744f7074696f6e120b0a03616c6c18012001280812200a06" . - "6669656c647318022003280b32102e74657374732e4669656c6450617468" . - "221a0a094669656c6450617468120d0a056669656c641801200328096206" . - "70726f746f33" - )); - - static::$is_initialized = true; - } -} - diff --git a/Firestore/tests/conformance-fixtures/Tests/DeleteTest.php b/Firestore/tests/conformance-fixtures/Tests/DeleteTest.php deleted file mode 100644 index 5f08ad47af2e..000000000000 --- a/Firestore/tests/conformance-fixtures/Tests/DeleteTest.php +++ /dev/null @@ -1,147 +0,0 @@ - - * A call to DocmentRef.Delete - * - * - * Protobuf type tests.DeleteTest - */ -class DeleteTest extends \Google\Protobuf\Internal\Message -{ - /** - *
-     * path of doc
-     * 
- * - * string doc_ref_path = 1; - */ - private $doc_ref_path = ''; - /** - * .google.firestore.v1beta1.Precondition precondition = 2; - */ - private $precondition = null; - /** - *
-     * expected rquest
-     * 
- * - * .google.firestore.v1beta1.CommitRequest request = 3; - */ - private $request = null; - /** - *
-     * call signals an error
-     * 
- * - * bool is_error = 4; - */ - private $is_error = false; - - public function __construct() { - \GPBMetadata\Test::initOnce(); - parent::__construct(); - } - - /** - *
-     * path of doc
-     * 
- * - * string doc_ref_path = 1; - */ - public function getDocRefPath() - { - return $this->doc_ref_path; - } - - /** - *
-     * path of doc
-     * 
- * - * string doc_ref_path = 1; - */ - public function setDocRefPath($var) - { - GPBUtil::checkString($var, True); - $this->doc_ref_path = $var; - } - - /** - * .google.firestore.v1beta1.Precondition precondition = 2; - */ - public function getPrecondition() - { - return $this->precondition; - } - - /** - * .google.firestore.v1beta1.Precondition precondition = 2; - */ - public function setPrecondition(&$var) - { - GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\Precondition::class); - $this->precondition = $var; - } - - /** - *
-     * expected rquest
-     * 
- * - * .google.firestore.v1beta1.CommitRequest request = 3; - */ - public function getRequest() - { - return $this->request; - } - - /** - *
-     * expected rquest
-     * 
- * - * .google.firestore.v1beta1.CommitRequest request = 3; - */ - public function setRequest(&$var) - { - GPBUtil::checkMessage($var, \Google\Cloud\Firestore\V1beta1\CommitRequest::class); - $this->request = $var; - } - - /** - *
-     * call signals an error
-     * 
- * - * bool is_error = 4; - */ - public function getIsError() - { - return $this->is_error; - } - - /** - *
-     * call signals an error
-     * 
- * - * bool is_error = 4; - */ - public function setIsError($var) - { - GPBUtil::checkBool($var); - $this->is_error = $var; - } - -} - diff --git a/Firestore/tests/conformance-fixtures/Tests/Test.php b/Firestore/tests/conformance-fixtures/Tests/Test.php deleted file mode 100644 index 0dc58cc32f4e..000000000000 --- a/Firestore/tests/conformance-fixtures/Tests/Test.php +++ /dev/null @@ -1,168 +0,0 @@ - - * A Test describes a single client method call and its expected result. - * - * - * Protobuf type tests.Test - */ -class Test extends \Google\Protobuf\Internal\Message -{ - /** - *
-     * short description of the test
-     * 
- * - * string description = 1; - */ - private $description = ''; - protected $test; - - public function __construct() { - \GPBMetadata\Test::initOnce(); - parent::__construct(); - } - - /** - *
-     * short description of the test
-     * 
- * - * string description = 1; - */ - public function getDescription() - { - return $this->description; - } - - /** - *
-     * short description of the test
-     * 
- * - * string description = 1; - */ - public function setDescription($var) - { - GPBUtil::checkString($var, True); - $this->description = $var; - } - - /** - * .tests.GetTest get = 2; - */ - public function getGet() - { - return $this->readOneof(2); - } - - /** - * .tests.GetTest get = 2; - */ - public function setGet(&$var) - { - GPBUtil::checkMessage($var, \Tests\GetTest::class); - $this->writeOneof(2, $var); - } - - /** - * .tests.CreateTest create = 3; - */ - public function getCreate() - { - return $this->readOneof(3); - } - - /** - * .tests.CreateTest create = 3; - */ - public function setCreate(&$var) - { - GPBUtil::checkMessage($var, \Tests\CreateTest::class); - $this->writeOneof(3, $var); - } - - /** - * .tests.SetTest set = 4; - */ - public function getSet() - { - return $this->readOneof(4); - } - - /** - * .tests.SetTest set = 4; - */ - public function setSet(&$var) - { - GPBUtil::checkMessage($var, \Tests\SetTest::class); - $this->writeOneof(4, $var); - } - - /** - * .tests.UpdateTest update = 5; - */ - public function getUpdate() - { - return $this->readOneof(5); - } - - /** - * .tests.UpdateTest update = 5; - */ - public function setUpdate(&$var) - { - GPBUtil::checkMessage($var, \Tests\UpdateTest::class); - $this->writeOneof(5, $var); - } - - /** - * .tests.UpdatePathsTest update_paths = 6; - */ - public function getUpdatePaths() - { - return $this->readOneof(6); - } - - /** - * .tests.UpdatePathsTest update_paths = 6; - */ - public function setUpdatePaths(&$var) - { - GPBUtil::checkMessage($var, \Tests\UpdatePathsTest::class); - $this->writeOneof(6, $var); - } - - /** - * .tests.DeleteTest delete = 7; - */ - public function getDelete() - { - return $this->readOneof(7); - } - - /** - * .tests.DeleteTest delete = 7; - */ - public function setDelete(&$var) - { - GPBUtil::checkMessage($var, \Tests\DeleteTest::class); - $this->writeOneof(7, $var); - } - - public function getTest() - { - return $this->whichOneof("test"); - } - -} - diff --git a/Firestore/tests/conformance-fixtures/VarInt.php b/Firestore/tests/conformance-fixtures/VarInt.php deleted file mode 100644 index 5b64228f3dd9..000000000000 --- a/Firestore/tests/conformance-fixtures/VarInt.php +++ /dev/null @@ -1,51 +0,0 @@ -> 7; - if ($number) { - $buf .= pack('c', $toWrite | 0x80); - } else { - $buf .= pack('c', $toWrite); - break; - } - } - return $buf; - } - - public static function decode($bytes, $index) - { - $shift = 0; - $result = 0; - while (true) { - $i = unpack('C', substr($bytes, $index, 1))[1]; - $index += 1; - $result = $result | (($i & 0x7f) << $shift); - $shift += 7; - if (!($i & 0x80)) { - break; - } - } - return [$result, $index]; - } -} diff --git a/phpcs-ruleset.xml b/phpcs-ruleset.xml index 2a9958846d2e..dbad3dc6f836 100644 --- a/phpcs-ruleset.xml +++ b/phpcs-ruleset.xml @@ -21,7 +21,7 @@ dev docs */metadata - Firestore/tests/conformance-fixtures + Firestore/tests/Conformance tests/Component/TestComposerInstall.php diff --git a/phpunit-conformance.xml.dist b/phpunit-conformance.xml.dist deleted file mode 100644 index a6e8a9e175d3..000000000000 --- a/phpunit-conformance.xml.dist +++ /dev/null @@ -1,21 +0,0 @@ - - - - - */tests/Conformance - - - - - */src - src - - */src/V[!a-zA-Z]* - */src/*/V[!a-zA-Z]* - */src/*/*/V[!a-zA-Z]* - Core/src/Testing - dev - - - -