diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..26c5802
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,11 @@
+name: "Continuous Integration"
+
+on:
+ pull_request:
+ push:
+ branches:
+ tags:
+
+jobs:
+ ci:
+ uses: laminas/workflow-continuous-integration/.github/workflows/continuous-integration.yml@1.x
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
deleted file mode 100644
index 999e2ae..0000000
--- a/.github/workflows/php.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: PHP Composer
-
-on:
- push:
- branches: [ master ]
- pull_request:
- branches: [ master ]
-
-jobs:
- build:
-
- runs-on: ubuntu-latest
- strategy:
- matrix:
- php: [7.3, 7.4, 8.0]
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Validate composer.json and composer.lock
- run: composer validate --strict
-
- - name: Cache Composer packages
- id: composer-cache
- uses: actions/cache@v2
- with:
- path: vendor
- key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
- restore-keys: |
- ${{ runner.os }}-php-
-
- - name: Install dependencies
- run: composer install --prefer-dist --no-progress
-
- # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
- # Docs: https://getcomposer.org/doc/articles/scripts.md
-
- - name: Run test suite
- run: composer run test
- env:
- AWS_ACCESS_KEY_ID: key
- AWS_SECRET_ACCESS_KEY: secret
- AWS_SESSION_TOKEN: token
diff --git a/.laminas-ci.json b/.laminas-ci.json
new file mode 100644
index 0000000..089ade8
--- /dev/null
+++ b/.laminas-ci.json
@@ -0,0 +1,13 @@
+{
+ "additional_checks": [
+ {
+ "name": "PHPStan",
+ "job": {
+ "php": "*",
+ "dependencies": "*",
+ "command": "vendor/bin/phpstan analyse"
+ }
+ }
+ ],
+ "stablePHP": "8.0"
+}
diff --git a/composer.json b/composer.json
index 947eeb7..fd71755 100644
--- a/composer.json
+++ b/composer.json
@@ -29,22 +29,17 @@
}
},
"require": {
- "php": "^7.1 || ^8.0",
+ "php": "^8.2",
"ext-json": "*",
- "psr/http-message": "^1.0 || ^2.0 ",
+ "psr/http-message": "^2.0 ",
"psr/http-client": "^1.0",
- "guzzlehttp/guzzle": "^6.3|^7.0.1"
+ "guzzlehttp/guzzle": "^7.0.1"
},
"require-dev": {
- "phpunit/phpunit": "^7.5|^8.0|^9.0",
- "codacy/coverage": "^1.4",
- "aws/aws-sdk-php": "^3.186"
- },
- "conflict": {
- "guzzlehttp/psr7": "< 1.7.0"
- },
- "scripts": {
- "test": "phpunit tests/ --whitelist src/ --coverage-clover build/coverage/xml"
+ "aws/aws-sdk-php": "^3.186",
+ "phpstan/phpstan": "^1.11.4",
+ "squizlabs/php_codesniffer": "3.10.1",
+ "phpunit/phpunit": "^10.5.20"
},
"suggest": {
"aws/aws-sdk-php": "Move this package to require section to use AWS IAM authorization",
diff --git a/examples/mutation_example.php b/examples/mutation_example.php
index ed55af3..ae8b5cc 100644
--- a/examples/mutation_example.php
+++ b/examples/mutation_example.php
@@ -44,4 +44,4 @@
// Reformat the results to an array and get the results of part of the array
$results->reformatResults(true);
-print_r($results->getData()['pokemon']);
\ No newline at end of file
+print_r($results->getData()['pokemon']);
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..73969c8
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,11 @@
+
+
+
+ PHPCS configuration file.
+ src
+
+ */vendor/*
+
+
+
+
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..c77d90f
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,5 @@
+parameters:
+ level: 8
+ paths:
+ - src
+ treatPhpDocTypesAsCertain: false
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..35bea45
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ tests
+
+
+
+
+
diff --git a/src/Auth/AuthInterface.php b/src/Auth/AuthInterface.php
index f2e5637..cd9c48d 100644
--- a/src/Auth/AuthInterface.php
+++ b/src/Auth/AuthInterface.php
@@ -3,13 +3,10 @@
namespace GraphQL\Auth;
use GuzzleHttp\Psr7\Request;
+use Psr\Http\Message\RequestInterface;
interface AuthInterface
{
- /**
- * @param Request $request
- * @param array $options
- * @return Request
- */
- public function run(Request $request, array $options = []): Request;
+ /** @param array $options */
+ public function run(Request $request, array $options = []): RequestInterface;
}
diff --git a/src/Auth/AwsIamAuth.php b/src/Auth/AwsIamAuth.php
deleted file mode 100644
index 2f638a0..0000000
--- a/src/Auth/AwsIamAuth.php
+++ /dev/null
@@ -1,62 +0,0 @@
-getSignature($region)->signRequest(
- $request, $this->getCredentials(),
- self::SERVICE_NAME
- );
- }
-
- /**
- * @param string $region
- * @return SignatureV4
- */
- protected function getSignature(string $region): SignatureV4
- {
- return new SignatureV4(self::SERVICE_NAME, $region);
- }
-
- /**
- * @return Credentials
- */
- protected function getCredentials(): Credentials
- {
- $provider = CredentialProvider::defaultProvider();
- return $provider()->wait();
- }
-}
diff --git a/src/Client.php b/src/Client.php
index 9d8d2dd..9832f95 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -3,7 +3,6 @@
namespace GraphQL;
use GraphQL\Auth\AuthInterface;
-use GraphQL\Auth\HeaderAuth;
use GraphQL\Exception\QueryError;
use GraphQL\Exception\MethodNotSupportedException;
use GraphQL\QueryBuilder\QueryBuilderInterface;
@@ -12,141 +11,98 @@
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Utils;
use Psr\Http\Client\ClientInterface;
-use TypeError;
-/**
- * Class Client
- *
- * @package GraphQL
- */
class Client
{
- /**
- * @var string
- */
- protected $endpointUrl;
+ protected ClientInterface $httpClient;
- /**
- * @var ClientInterface
- */
- protected $httpClient;
+ /** @var array> */
+ protected array $httpHeaders;
- /**
- * @var array
- */
- protected $httpHeaders;
-
- /**
- * @var array
- */
- protected $options;
-
- /**
- * @var string
- */
- protected $requestMethod;
-
- /**
- * @var AuthInterface
- */
- protected $auth;
+ /** @var array */
+ protected array $options;
/**
* Client constructor.
*
- * @param string $endpointUrl
- * @param array $authorizationHeaders
- * @param array $httpOptions
- * @param ClientInterface|null $httpClient
- * @param string $requestMethod
- * @param AuthInterface|null $auth
+ * @param array> $authorizationHeaders
+ * @param array $httpOptions
*/
public function __construct(
- string $endpointUrl,
+ protected string $endpointUrl,
array $authorizationHeaders = [],
array $httpOptions = [],
- ClientInterface $httpClient = null,
- string $requestMethod = 'POST',
- AuthInterface $auth = null
+ ?ClientInterface $httpClient = null,
+ protected string $requestMethod = 'POST',
+ protected ?AuthInterface $auth = null
) {
- $headers = array_merge(
+ $this->httpHeaders = array_merge(
$authorizationHeaders,
$httpOptions['headers'] ?? [],
['Content-Type' => 'application/json']
);
- /**
- * All headers will be set on the request objects explicitly,
- * Guzzle doesn't have to care about them at this point, so to avoid any conflicts
- * we are removing the headers from the options
- */
- unset($httpOptions['headers']);
- $this->options = $httpOptions;
- if ($auth) {
- $this->auth = $auth;
- }
- $this->endpointUrl = $endpointUrl;
- $this->httpClient = $httpClient ?? new GuzzleAdapter(new \GuzzleHttp\Client($httpOptions));
- $this->httpHeaders = $headers;
+ $this->options = array_filter(
+ $httpOptions,
+ fn($k) => $k !== 'headers',
+ ARRAY_FILTER_USE_KEY,
+ );
+
+ $this->httpClient = $httpClient ??
+ new GuzzleAdapter(new \GuzzleHttp\Client($httpOptions));
+
if ($requestMethod !== 'POST') {
throw new MethodNotSupportedException($requestMethod);
}
- $this->requestMethod = $requestMethod;
}
/**
- * @param Query|QueryBuilderInterface $query
- * @param bool $resultsAsArray
- * @param array $variables
- *
- * @return Results
+ * @param array $variables
* @throws QueryError
*/
- public function runQuery($query, bool $resultsAsArray = false, array $variables = []): Results
- {
+ public function runQuery(
+ Query|QueryBuilderInterface $query,
+ bool $resultsAsArray = false,
+ array $variables = []
+ ): Results {
if ($query instanceof QueryBuilderInterface) {
$query = $query->getQuery();
}
- if (!$query instanceof Query) {
- throw new TypeError('Client::runQuery accepts the first argument of type Query or QueryBuilderInterface');
- }
-
return $this->runRawQuery((string) $query, $resultsAsArray, $variables);
}
/**
- * @param string $queryString
- * @param bool $resultsAsArray
- * @param array $variables
- * @param
- *
- * @return Results
+ * @param array $variables
* @throws QueryError
*/
- public function runRawQuery(string $queryString, $resultsAsArray = false, array $variables = []): Results
- {
+ public function runRawQuery(
+ string $queryString,
+ bool $resultsAsArray = false,
+ array $variables = []
+ ): Results {
$request = new Request($this->requestMethod, $this->endpointUrl);
- foreach($this->httpHeaders as $header => $value) {
+ foreach ($this->httpHeaders as $header => $value) {
$request = $request->withHeader($header, $value);
}
// Convert empty variables array to empty json object
- if (empty($variables)) $variables = (object) null;
+ if (empty($variables)) {
+ $variables = (object) null;
+ }
// Set query in the request body
$bodyArray = ['query' => (string) $queryString, 'variables' => $variables];
$request = $request->withBody(Utils::streamFor(json_encode($bodyArray)));
- if ($this->auth) {
+ if (isset($this->auth)) {
$request = $this->auth->run($request, $this->options);
}
// Send api request and get response
try {
$response = $this->httpClient->sendRequest($request);
- }
- catch (ClientException $exception) {
+ } catch (ClientException $exception) {
$response = $exception->getResponse();
// If exception thrown by client is "400 Bad Request ", then it can be treated as a successful API request
diff --git a/src/Exception/ArgumentException.php b/src/Exception/ArgumentException.php
index 6ffe816..994179e 100644
--- a/src/Exception/ArgumentException.php
+++ b/src/Exception/ArgumentException.php
@@ -11,8 +11,8 @@
*/
class ArgumentException extends InvalidArgumentException
{
- public function __construct($message = "")
+ public function __construct(string $message = '')
{
parent::__construct($message);
}
-}
\ No newline at end of file
+}
diff --git a/src/Exception/AwsRegionNotSetException.php b/src/Exception/AwsRegionNotSetException.php
deleted file mode 100644
index 5d396aa..0000000
--- a/src/Exception/AwsRegionNotSetException.php
+++ /dev/null
@@ -1,18 +0,0 @@
- */
+ protected array $errorDetails;
+
+ /** @var array */
protected $data;
- /**
- * @var array
- */
+
+ /** @var array */
protected $errors;
- /**
- * QueryError constructor.
- *
- * @param array $errorDetails
- */
- public function __construct($errorDetails)
+ /** @param array $errorDetails */
+ public function __construct(array $errorDetails)
{
+ $this->errors = $errorDetails['errors'];
$this->errorDetails = $errorDetails['errors'][0];
+
$this->data = [];
if (!empty($errorDetails['data'])) {
$this->data = $errorDetails['data'];
}
- $this->errors = $errorDetails['errors'];
parent::__construct($this->errorDetails['message']);
}
- /**
- * @return array
- */
- public function getErrorDetails()
+ /** @return array */
+ public function getErrorDetails(): array
{
return $this->errorDetails;
}
- /**
- * @return array
- */
- public function getData()
+ /** @return array */
+ public function getData(): array
{
return $this->data;
}
- /**
- * @return array
- */
- public function getErrors()
+ /** @return array */
+ public function getErrors(): array
{
return $this->errors;
}
diff --git a/src/FieldTrait.php b/src/FieldTrait.php
index cec27b9..5dce1b0 100644
--- a/src/FieldTrait.php
+++ b/src/FieldTrait.php
@@ -3,72 +3,72 @@
namespace GraphQL;
use GraphQL\Exception\InvalidSelectionException;
+use GraphQL\QueryBuilder\QueryBuilderInterface;
trait FieldTrait
{
/**
* Stores the selection set desired to get from the query, can include nested queries
*
- * @var array
+ * @var array
*/
- protected $selectionSet;
+ protected array $selectionSet;
/**
- * @param array $selectionSet
- *
- * @return $this
+ * @param array $selectionSet
* @throws InvalidSelectionException
*/
- public function setSelectionSet(array $selectionSet)
+ public function setSelectionSet(array $selectionSet): self
{
- $nonStringsFields = array_filter($selectionSet, function($element) {
- return !is_string($element) && !$element instanceof Query && !$element instanceof InlineFragment;
- });
- if (!empty($nonStringsFields)) {
- throw new InvalidSelectionException(
- 'One or more of the selection fields provided is not of type string or Query'
- );
+ $selectionSet = array_map(
+ fn ($s) => $s instanceof QueryBuilderInterface ?
+ $s->getQuery() :
+ $s,
+ $selectionSet,
+ );
+
+
+ foreach ($selectionSet as $selection) {
+ if (
+ !is_string($selection) &&
+ !$selection instanceof Query &&
+ !$selection instanceof InlineFragment
+ ) {
+ throw new InvalidSelectionException(sprintf(
+ 'Can only set a selection from one of the following: %s',
+ implode(', ', [
+ InlineFragment::class,
+ Query::class,
+ QueryBuilderInterface::class,
+ 'string',
+ ]),
+ ));
+ }
}
$this->selectionSet = $selectionSet;
-
return $this;
}
- /**
- * @return string
- */
protected function constructSelectionSet(): string
{
if (empty($this->selectionSet)) {
return '';
- }
-
- $attributesString = " {" . PHP_EOL;
- $first = true;
- foreach ($this->selectionSet as $attribute) {
-
- // Append empty line at the beginning if it's not the first item on the list
- if ($first) {
- $first = false;
- } else {
- $attributesString .= PHP_EOL;
- }
-
- // If query is included in attributes set as a nested query
- if ($attribute instanceof Query) {
- $attribute->setAsNested();
- }
-
- // Append attribute to returned attributes list
- $attributesString .= $attribute;
}
- $attributesString .= PHP_EOL . "}";
- return $attributesString;
+ return sprintf(' { %s }', implode(' ', array_map(
+ function ($selection) {
+ if ($selection instanceof Query) {
+ $selection->setAsNested();
+ }
+ return $selection;
+ },
+ $this->selectionSet,
+ )));
}
- public function getSelectionSet()
+ /** @return array */
+ public function getSelectionSet(): array
{
return $this->selectionSet;
}
diff --git a/src/InlineFragment.php b/src/InlineFragment.php
index e41f242..8b67fa0 100644
--- a/src/InlineFragment.php
+++ b/src/InlineFragment.php
@@ -3,49 +3,21 @@
namespace GraphQL;
use GraphQL\QueryBuilder\QueryBuilderInterface;
+use Stringable;
-/**
- * Class InlineFragment
- *
- * @package GraphQL
- */
-class InlineFragment extends NestableObject
+class InlineFragment implements Stringable
{
use FieldTrait;
- /**
- * Stores the format for the inline fragment format
- *
- * @var string
- */
protected const FORMAT = '... on %s%s';
- /**
- * @var string
- */
- protected $typeName;
-
- /**
- * @var QueryBuilderInterface|null
- */
- protected $queryBuilder;
-
- /**
- * InlineFragment constructor.
- *
- * @param string $typeName
- * @param QueryBuilderInterface|null $queryBuilder
- */
- public function __construct(string $typeName, ?QueryBuilderInterface $queryBuilder = null)
- {
- $this->typeName = $typeName;
- $this->queryBuilder = $queryBuilder;
+ public function __construct(
+ protected string $typeName,
+ protected ?QueryBuilderInterface $queryBuilder = null,
+ ) {
}
- /**
- *
- */
- public function __toString()
+ public function __toString(): string
{
if ($this->queryBuilder !== null) {
$this->setSelectionSet($this->queryBuilder->getQuery()->getSelectionSet());
@@ -53,14 +25,4 @@ public function __toString()
return sprintf(static::FORMAT, $this->typeName, $this->constructSelectionSet());
}
-
- /**
- * @codeCoverageIgnore
- *
- * @return mixed|void
- */
- protected function setAsNested()
- {
- // TODO: Remove this method, it's purely tech debt
- }
}
diff --git a/src/Mutation.php b/src/Mutation.php
index fc07282..e879643 100644
--- a/src/Mutation.php
+++ b/src/Mutation.php
@@ -2,17 +2,10 @@
namespace GraphQL;
-/**
- * Class Mutation
- *
- * @package GraphQL
- */
class Mutation extends Query
{
/**
* Stores the name of the type of the operation to be executed on the GraphQL server
- *
- * @var string
*/
- protected const OPERATION_TYPE = 'mutation';
-}
\ No newline at end of file
+ protected const OPERATION_TYPE = OperationType::Mutation->value;
+}
diff --git a/src/NestableObject.php b/src/NestableObject.php
deleted file mode 100644
index 0b3e980..0000000
--- a/src/NestableObject.php
+++ /dev/null
@@ -1,19 +0,0 @@
-value;
- /**
- * Stores the object alias
- *
- * @var string
- */
- protected $alias;
+ /** The name of the operation to be run on the server */
+ protected string $operationName = '';
/**
- * Stores the list of variables to be used in the query
+ * The list of variables to be used in the query
*
- * @var array|Variable[]
+ * @var Variable[]
*/
- protected $variables;
+ protected array $variables;
/**
- * Stores the list of arguments used when querying data
+ * The list of arguments used when querying data
*
- * @var array
+ * @var array|scalar|Stringable|BackedEnum>
*/
- protected $arguments;
+ protected array $arguments = [];
/**
- * Private member that's not accessible from outside the class, used internally to deduce if query is nested or not
+ * Private member that's not accessible from outside the class,
+ * used internally to deduce if query is nested or not
*
* @var bool
*/
- protected $isNested;
+ protected bool $isNested = false;
/**
* GQLQueryBuilder constructor.
*
- * @param string $fieldName if no value is provided for the field name an empty query object is assumed
+ * @param string $fieldName if no value is provided, empty query object is assumed
* @param string $alias the alias to use for the query if required
*/
- public function __construct(string $fieldName = '', string $alias = '')
- {
- $this->fieldName = $fieldName;
- $this->alias = $alias;
- $this->operationName = '';
- $this->variables = [];
- $this->arguments = [];
- $this->selectionSet = [];
- $this->isNested = false;
+ public function __construct(
+ protected string $fieldName = '',
+ protected string $alias = ''
+ ) {
}
- /**
- * @return string
- */
public function getFieldName(): string
{
return $this->fieldName;
}
- /**
- * @param string $alias
- *
- * @return Query
- */
- public function setAlias(string $alias)
+ public function setAlias(string $alias): Query
{
$this->alias = $alias;
return $this;
}
- /**
- * @param string $operationName
- *
- * @return Query
- */
- public function setOperationName(string $operationName)
+ public function setOperationName(string $operationName): Query
{
if (!empty($operationName)) {
$this->operationName = " $operationName";
@@ -126,18 +82,15 @@ public function setOperationName(string $operationName)
return $this;
}
- /**
- * @param array $variables
- *
- * @return Query
- */
- public function setVariables(array $variables)
+ /** @param Variable[] $variables */
+ public function setVariables(array $variables): Query
{
- $nonVarElements = array_filter($variables, function($e) {
- return !$e instanceof Variable;
- });
- if (count($nonVarElements) > 0) {
- throw new InvalidVariableException('At least one of the elements of the variables array provided is not an instance of GraphQL\\Variable');
+ foreach ($variables as $variable) {
+ if (!$variable instanceof Variable) {
+ throw new InvalidVariableException(
+ 'All variables must be an instance of GraphQL\\Variable'
+ );
+ }
}
$this->variables = $variables;
@@ -146,24 +99,20 @@ public function setVariables(array $variables)
}
/**
- * Throwing exception when setting the arguments if they are incorrect because we can't throw an exception during
- * the execution of __ToString(), it's a fatal error in PHP
- *
- * @param array $arguments
- *
- * @return Query
- * @throws ArgumentException
+ * @param array|Stringable|BackedEnum> $arguments
+ * @throws ArgumentException for invalid arguments
*/
public function setArguments(array $arguments): Query
{
- // If one of the arguments does not have a name provided, throw an exception
- $nonStringArgs = array_filter(array_keys($arguments), function($element) {
- return !is_string($element);
- });
- if (!empty($nonStringArgs)) {
- throw new ArgumentException(
- 'One or more of the arguments provided for creating the query does not have a key, which represents argument name'
- );
+ foreach ($arguments as $name => $argument) {
+ if (!is_string($name)) {
+ throw new ArgumentException(
+ 'All query arguments require string keys,' .
+ 'these represent the argument name'
+ );
+ }
+
+ $this->validateArgument($argument);
}
$this->arguments = $arguments;
@@ -171,125 +120,97 @@ public function setArguments(array $arguments): Query
return $this;
}
- /**
- * @return array
- */
+ private function validateArgument(mixed $value): void
+ {
+ if (is_array($value)) {
+ foreach ($value as $item) {
+ $this->validateArgument($item);
+ }
+
+ return;
+ }
+
+ if (
+ is_null($value)
+ || is_scalar($value)
+ || $value instanceof Stringable
+ || $value instanceof BackedEnum
+ ) {
+ return;
+ }
+
+ throw new ArgumentException(sprintf(
+ '%s cannot be supported',
+ gettype($value),
+ ));
+ }
+
+ /** @return array|Stringable|BackedEnum> */
public function getArguments(): array
{
return $this->arguments;
}
- /**
- * @return string
- */
protected function constructVariables(): string
{
if (empty($this->variables)) {
return '';
}
- $varsString = '(';
- $first = true;
- foreach ($this->variables as $variable) {
-
- // Append space at the beginning if it's not the first item on the list
- if ($first) {
- $first = false;
- } else {
- $varsString .= ' ';
- }
-
- // Append variable string value to the variables string
- $varsString .= (string) $variable;
- }
- $varsString .= ')';
-
- return $varsString;
+ return sprintf('( %s )', implode(' ', $this->variables));
}
- /**
- * @return string
- */
protected function constructArguments(): string
{
- // Return empty string if list is empty
if (empty($this->arguments)) {
return '';
}
- // Construct arguments string if list not empty
- $constraintsString = '(';
- $first = true;
+ $formattedArguments = [];
foreach ($this->arguments as $name => $value) {
+ $formattedArguments[] = sprintf('%s: %s', $name, is_array($value) ?
+ StringLiteralFormatter::formatArrayForGQLQuery($value) :
+ StringLiteralFormatter::formatValueForRHS($value));
+ }
- // Append space at the beginning if it's not the first item on the list
- if ($first) {
- $first = false;
- } else {
- $constraintsString .= ' ';
- }
+ return sprintf('(%s)', implode(' ', $formattedArguments));
+ }
- // Convert argument values to graphql string literal equivalent
- if (is_scalar($value) || $value === null) {
- // Convert scalar value to its literal in graphql
- $value = StringLiteralFormatter::formatValueForRHS($value);
- } elseif (is_array($value)) {
- // Convert PHP array to its array representation in graphql arguments
- $value = StringLiteralFormatter::formatArrayForGQLQuery($value);
- }
- // TODO: Handle cases where a non-string-convertible object is added to the arguments
- $constraintsString .= $name . ': ' . $value;
- }
- $constraintsString .= ')';
+ protected function generateFieldName(): string
+ {
+ return empty($this->alias) ? $this->fieldName : sprintf('%s: %s', $this->alias, $this->fieldName);
+ }
- return $constraintsString;
+ protected function generateSignature(): string
+ {
+ return sprintf(
+ '%s%s%s',
+ static::OPERATION_TYPE,
+ $this->operationName,
+ $this->constructVariables()
+ );
}
- /**
- * @return string
- */
- public function __toString()
+ public function setAsNested(): void
+ {
+ $this->isNested = true;
+ }
+
+ public function __toString(): string
{
- $queryFormat = static::QUERY_FORMAT;
+ $queryFormat = self::QUERY_FORMAT;
$selectionSetString = $this->constructSelectionSet();
if (!$this->isNested) {
$queryFormat = $this->generateSignature();
if ($this->fieldName === '') {
-
return $queryFormat . $selectionSetString;
} else {
- $queryFormat = $this->generateSignature() . " {" . PHP_EOL . static::QUERY_FORMAT . PHP_EOL . "}";
+ $queryFormat = $this->generateSignature() . ' { ' . static::QUERY_FORMAT . ' }';
}
}
$argumentsString = $this->constructArguments();
return sprintf($queryFormat, $this->generateFieldName(), $argumentsString, $selectionSetString);
}
-
- /**
- * @return string
- */
- protected function generateFieldName(): string
- {
- return empty($this->alias) ? $this->fieldName : sprintf('%s: %s', $this->alias, $this->fieldName);
- }
-
- /**
- * @return string
- */
- protected function generateSignature(): string
- {
- $signatureFormat = '%s%s%s';
-
- return sprintf($signatureFormat, static::OPERATION_TYPE, $this->operationName, $this->constructVariables());
- }
-
- /**
- *
- */
- protected function setAsNested()
- {
- $this->isNested = true;
- }
}
diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php
index 4fca5a1..3c6dd3c 100644
--- a/src/QueryBuilder/AbstractQueryBuilder.php
+++ b/src/QueryBuilder/AbstractQueryBuilder.php
@@ -2,67 +2,38 @@
namespace GraphQL\QueryBuilder;
+use BackedEnum;
use GraphQL\InlineFragment;
use GraphQL\Query;
use GraphQL\RawObject;
use GraphQL\Variable;
+use Stringable;
-/**
- * Class AbstractQueryBuilder
- *
- * @package GraphQL
- */
abstract class AbstractQueryBuilder implements QueryBuilderInterface
{
- /**
- * @var Query
- */
- protected $query;
+ protected Query $query;
- /**
- * @var array|Variable[]
- */
- private $variables;
+ /** @var Variable[] */
+ private array $variables = [];
- /**
- * @var array
- */
- private $selectionSet;
+ /** @var array */
+ private array $selectionSet = [];
- /**
- * @var array
- */
- private $argumentsList;
+ /** @var array|Stringable|BackedEnum> */
+ private array $argumentsList = [];
- /**
- * QueryBuilder constructor.
- *
- * @param string $queryObject
- * @param string $alias
- */
public function __construct(string $queryObject = '', string $alias = '')
{
- $this->query = new Query($queryObject, $alias);
- $this->variables = [];
- $this->selectionSet = [];
- $this->argumentsList = [];
+ $this->query = new Query($queryObject, $alias);
}
- /**
- * @param string $alias
- *
- * @return $this
- */
- public function setAlias(string $alias)
+ public function setAlias(string $alias): self
{
$this->query->setAlias($alias);
return $this;
}
- /**
- * @return Query
- */
public function getQuery(): Query
{
// Convert nested query builders to query objects
@@ -79,51 +50,41 @@ public function getQuery(): Query
return $this->query;
}
- /**
- * @param string|QueryBuilderInterface|InlineFragment|Query $selectedField
- *
- * @return $this
- */
- protected function selectField($selectedField)
- {
- if (
- is_string($selectedField)
- || $selectedField instanceof QueryBuilderInterface
- || $selectedField instanceof Query
- || $selectedField instanceof InlineFragment
- ) {
- $this->selectionSet[] = $selectedField;
- }
+ protected function selectField(
+ InlineFragment|Query|QueryBuilderInterface|string $selectedField,
+ ): AbstractQueryBuilder {
+ $this->selectionSet[] = $selectedField;
return $this;
}
/**
- * @param $argumentName
- * @param $argumentValue
- *
- * @return $this
+ * @param null|array|scalar|BackedEnum|Stringable $value
*/
- protected function setArgument(string $argumentName, $argumentValue)
- {
- if (is_scalar($argumentValue) || is_array($argumentValue) || $argumentValue instanceof RawObject) {
- $this->argumentsList[$argumentName] = $argumentValue;
+ protected function setArgument(
+ string $name,
+ null|bool|float|int|string|array|Stringable|BackedEnum $value
+ ): self {
+ if (!is_null($value)) {
+ $this->argumentsList[$name] = $value;
}
return $this;
}
- /**
- * @param string $name
- * @param string $type
- * @param bool $isRequired
- * @param null $defaultValue
- *
- * @return $this
- */
- protected function setVariable(string $name, string $type, bool $isRequired = false, $defaultValue = null)
- {
- $this->variables[] = new Variable($name, $type, $isRequired, $defaultValue);
+ /** @param null|array|scalar|BackedEnum|Stringable $defaultValue */
+ protected function setVariable(
+ string $name,
+ string $type,
+ bool $isRequired = false,
+ null|bool|float|int|string|array|Stringable|BackedEnum $defaultValue = null,
+ ): AbstractQueryBuilder {
+ $this->variables[] = new Variable(
+ $name,
+ $type,
+ $isRequired,
+ $defaultValue
+ );
return $this;
}
diff --git a/src/QueryBuilder/MutationBuilder.php b/src/QueryBuilder/MutationBuilder.php
index 2c506c1..9a33715 100644
--- a/src/QueryBuilder/MutationBuilder.php
+++ b/src/QueryBuilder/MutationBuilder.php
@@ -6,26 +6,15 @@
class MutationBuilder extends QueryBuilder
{
- /**
- * MutationBuilder constructor.
- *
- * @param string $queryObject
- * @param string $alias
- */
public function __construct(string $queryObject = '', string $alias = '')
{
parent::__construct($queryObject, $alias);
$this->query = new Mutation($queryObject, $alias);
}
- /**
- * Synonymous method to getQuery(), it just return a Mutation type instead of Query type creating a neater
- * interface when using interfaces
- *
- * @return Mutation
- */
public function getMutation(): Mutation
{
+ assert($this->getQuery() instanceof Mutation);
return $this->getQuery();
}
-}
\ No newline at end of file
+}
diff --git a/src/QueryBuilder/QueryBuilder.php b/src/QueryBuilder/QueryBuilder.php
index 94ccf65..e9a7dac 100644
--- a/src/QueryBuilder/QueryBuilder.php
+++ b/src/QueryBuilder/QueryBuilder.php
@@ -2,52 +2,34 @@
namespace GraphQL\QueryBuilder;
+use BackedEnum;
+use GraphQL\InlineFragment;
use GraphQL\Query;
+use Stringable;
-/**
- * Class QueryBuilder
- *
- * @package GraphQL
- */
class QueryBuilder extends AbstractQueryBuilder
{
- /**
- * Changing method visibility to public
- *
- * @param Query|QueryBuilder|string $selectedField
- *
- * @return $this
- */
- public function selectField($selectedField)
- {
+ public function selectField(
+ InlineFragment|Query|QueryBuilderInterface|string $selectedField,
+ ): AbstractQueryBuilder {
return parent::selectField($selectedField);
}
- /**
- * Changing method visibility to public
- *
- * @param string $argumentName
- * @param $argumentValue
- *
- * @return $this
- */
- public function setArgument(string $argumentName, $argumentValue)
- {
- return parent::setArgument($argumentName, $argumentValue);
+ /** @param null|scalar|array|BackedEnum|Stringable $value */
+ public function setArgument(
+ string $name,
+ null|bool|float|int|string|array|BackedEnum|Stringable $value,
+ ): AbstractQueryBuilder {
+ return parent::setArgument($name, $value);
}
- /**
- * Changing method visibility to public
- *
- * @param string $name
- * @param string $type
- * @param bool $isRequired
- * @param null $defaultValue
- *
- * @return $this
- */
- public function setVariable(string $name, string $type, bool $isRequired = false, $defaultValue = null)
- {
+ /** @param null|array|scalar|BackedEnum|Stringable $defaultValue */
+ public function setVariable(
+ string $name,
+ string $type,
+ bool $isRequired = false,
+ null|bool|float|int|string|array|Stringable|BackedEnum $defaultValue = null,
+ ): AbstractQueryBuilder {
return parent::setVariable($name, $type, $isRequired, $defaultValue);
}
}
diff --git a/src/QueryBuilder/QueryBuilderInterface.php b/src/QueryBuilder/QueryBuilderInterface.php
index d4a9745..81f094b 100644
--- a/src/QueryBuilder/QueryBuilderInterface.php
+++ b/src/QueryBuilder/QueryBuilderInterface.php
@@ -4,15 +4,7 @@
use GraphQL\Query;
-/**
- * Interface QueryBuilderInterface
- *
- * @package GraphQL\QueryBuilder
- */
interface QueryBuilderInterface
{
- /**
- * @return Query
- */
- function getQuery(): Query;
-}
\ No newline at end of file
+ public function getQuery(): Query;
+}
diff --git a/src/RawObject.php b/src/RawObject.php
index 8d35af4..71dd87a 100644
--- a/src/RawObject.php
+++ b/src/RawObject.php
@@ -2,33 +2,17 @@
namespace GraphQL;
-/**
- * Class RawObject
- *
- * @package GraphQL
- */
-class RawObject
-{
- /**
- * @var string
- */
- protected $objectString;
+use Stringable;
- /**
- * JsonObject constructor.
- *
- * @param string $objectString
- */
- public function __construct(string $objectString)
- {
- $this->objectString = $objectString;
+final readonly class RawObject implements Stringable
+{
+ public function __construct(
+ protected string $json
+ ) {
}
- /**
- * @return mixed
- */
- public function __toString()
+ public function __toString(): string
{
- return $this->objectString;
+ return $this->json;
}
-}
\ No newline at end of file
+}
diff --git a/src/Results.php b/src/Results.php
index 4bdfc43..f0f8238 100644
--- a/src/Results.php
+++ b/src/Results.php
@@ -5,101 +5,71 @@
use GraphQL\Exception\QueryError;
use Psr\Http\Message\ResponseInterface;
-/**
- * Class Result
- *
- * @package GraphQl
- */
class Results
{
- /**
- * @var string
- */
- protected $responseBody;
-
- /**
- * @var ResponseInterface
- */
- protected $responseObject;
+ protected string $responseBody;
- /**
- * @var array|object
- */
- protected $results;
+ /** @var array|object */
+ protected null|array|object $results;
/**
* Result constructor.
*
* Receives json response from GraphQL api response and parses it as associative array or nested object accordingly
- *
- * @param ResponseInterface $response
- * @param bool $asArray
- *
* @throws QueryError
*/
- public function __construct(ResponseInterface $response, $asArray = false)
- {
- $this->responseObject = $response;
- $this->responseBody = (string) $this->responseObject->getBody();
- $this->results = json_decode($this->responseBody, $asArray);
+ public function __construct(
+ protected ResponseInterface $response,
+ bool $asArray = false
+ ) {
+ $this->responseBody = (string) $this->response->getBody();
+ $this->results = json_decode($this->responseBody, $asArray);
- // Check if any errors exist, and throw exception if they do
- if ($asArray) $containsErrors = array_key_exists('errors', $this->results);
- else $containsErrors = isset($this->results->errors);
+ $containsErrors = is_array($this->results) ?
+ isset($this->results['errors']) :
+ isset($this->results->errors);
if ($containsErrors) {
-
- // Reformat results to an array and use it to initialize exception object
$this->reformatResults(true);
+ assert(is_array($this->results));
throw new QueryError($this->results);
}
}
- /**
- * @param bool $asArray
- */
public function reformatResults(bool $asArray): void
{
- $this->results = json_decode($this->responseBody, (bool) $asArray);
+ $this->results = json_decode($this->responseBody, $asArray);
}
/**
* Returns only parsed data objects in the requested format
*
- * @return array|object
+ * @return array|object
*/
public function getData()
{
- if (is_array($this->results)) {
- return $this->results['data'];
- }
-
- return $this->results->data;
+ return is_array($this->results) ?
+ $this->results['data'] ?? [] :
+ $this->results->data ?? [];
}
/**
* Returns entire parsed results in the requested format
*
- * @return array|object
+ * @return null|array|object
*/
- public function getResults()
+ public function getResults(): null|array|object
{
return $this->results;
}
- /**
- * @return string
- */
- public function getResponseBody()
+ public function getResponseBody(): string
{
return $this->responseBody;
}
- /**
- * @return ResponseInterface
- */
- public function getResponseObject()
+ public function getResponseObject(): ResponseInterface
{
- return $this->responseObject;
+ return $this->response;
}
-}
\ No newline at end of file
+}
diff --git a/src/Util/GuzzleAdapter.php b/src/Util/GuzzleAdapter.php
index 9ee3ced..add32a4 100644
--- a/src/Util/GuzzleAdapter.php
+++ b/src/Util/GuzzleAdapter.php
@@ -10,27 +10,12 @@
class GuzzleAdapter implements Client\ClientInterface
{
- /**
- * @var ClientInterface
- */
- private $client;
-
- /**
- * GuzzleAdapter constructor.
- *
- * @param ClientInterface $client
- */
- public function __construct(ClientInterface $client)
- {
- $this->client = $client;
+ public function __construct(
+ private ClientInterface $client
+ ) {
}
- /**
- * @param RequestInterface $request
- *
- * @return ResponseInterface
- * @throws GuzzleException
- */
+ /** @throws GuzzleException */
public function sendRequest(RequestInterface $request): ResponseInterface
{
/**
diff --git a/src/Util/StringLiteralFormatter.php b/src/Util/StringLiteralFormatter.php
index 2d78a5f..01ef759 100644
--- a/src/Util/StringLiteralFormatter.php
+++ b/src/Util/StringLiteralFormatter.php
@@ -2,14 +2,12 @@
namespace GraphQL\Util;
-/**
- * Class StringLiteralFormatter
- *
- * @package GraphQL\Util
- */
+use BackedEnum;
+use Stringable;
+
class StringLiteralFormatter
{
- const ESCAPE_SEQUENCES = [
+ private const ESCAPE_SEQUENCES = [
'\\u0000', '\\u0001', '\\u0002', '\\u0003', '\\u0004', '\\u0005', '\\u0006', '\\u0007',
'\\b', '\\t', '\\n', '\\u000B', '\\f', '\\r', '\\u000E', '\\u000F',
'\\u0010', '\\u0011', '\\u0012', '\\u0013', '\\u0014', '\\u0015', '\\u0016', '\\u0017',
@@ -32,96 +30,76 @@ class StringLiteralFormatter
'\\u0098', '\\u0099', '\\u009A', '\\u009B', '\\u009C', '\\u009D', '\\u009E', '\\u009F',
];
- /**
- * Converts the value provided to the equivalent RHS value to be put in a file declaration
- *
- * @param string|int|float|bool $value
- *
- * @return string
- */
- public static function formatValueForRHS($value): string
- {
- if (is_string($value)) {
- if (!static::isVariable($value)) {
- if (strpos($value, "\n") !== false) {
- $value = '"""' . $value . '"""';
- } else {
- $value = preg_replace_callback('/[\x00-\x1f\x22\x5c\x7f-\x9f]/u', function(array $matches) {
- $str = $matches[0];
- return self::ESCAPE_SEQUENCES[ord($str[0])];
- }, $value);
- $value = "\"$value\"";
- }
- }
- } elseif (is_bool($value)) {
- if ($value) {
- $value = 'true';
- } else {
- $value = 'false';
- }
- } elseif ($value === null) {
- $value = 'null';
- } else {
- $value = (string) $value;
+ public static function formatValueForRHS(
+ null|bool|float|int|string|BackedEnum|Stringable $value
+ ): string {
+ if (is_null($value)) {
+ return 'null';
+ }
+
+ if (is_bool($value)) {
+ return $value ? 'true' : 'false';
+ }
+
+ if (
+ is_float($value)
+ || is_int($value)
+ || $value instanceof Stringable
+ ) {
+ return (string) $value;
+ }
+
+ if ($value instanceof BackedEnum) {
+ return (string) $value->value;
}
- return $value;
+ if (self::isVariable($value)) {
+ return $value;
+ }
+
+ if (str_contains($value, "\n")) {
+ return sprintf('"""%s"""', $value);
+ }
+
+ $value = preg_replace_callback(
+ '/[\x00-\x1f\x22\x5c\x7f-\x9f]/u',
+ function (array $matches) {
+ $str = $matches[0];
+ return self::ESCAPE_SEQUENCES[ord($str[0])];
+ },
+ $value
+ );
+
+ return sprintf('"%s"', $value);
}
- /**
- * Treat string value as variable if it matches variable regex
- *
- * @param string $value
- *
- * @return bool
- */
- private static function isVariable(string $value): bool {
- return preg_match('/^\$[_A-Za-z][_0-9A-Za-z]*$/', $value);
+ private static function isVariable(string $value): bool
+ {
+ return preg_match('/^\$[_A-Za-z][_0-9A-Za-z]*$/', $value) === 1;
}
- /**
- * @param array $array
- *
- * @return string
- */
+ /** @param array $array */
public static function formatArrayForGQLQuery(array $array): string
{
- $arrString = '[';
- $first = true;
- foreach ($array as $element) {
- if ($first) {
- $first = false;
- } else {
- $arrString .= ', ';
- }
- $arrString .= StringLiteralFormatter::formatValueForRHS($element);
- }
- $arrString .= ']';
-
- return $arrString;
+ return sprintf('[%s]', implode(', ', array_map(
+ fn ($p) => is_array($p) ?
+ self::formatArrayForGQLQuery($p) :
+ self::formatValueForRHS($p),
+ $array,
+ )));
}
- /**
- * @param string $stringValue
- *
- * @return string
- */
public static function formatUpperCamelCase(string $stringValue): string
{
- if (strpos($stringValue, '_') === false) {
+ if (!str_contains($stringValue, '_')) {
return ucfirst($stringValue);
}
return str_replace('_', '', ucwords($stringValue, '_'));
}
- /**
- * @param string $stringValue
- *
- * @return string
- */
public static function formatLowerCamelCase(string $stringValue): string
{
- return lcfirst(static::formatUpperCamelCase($stringValue));
+ return lcfirst(self::formatUpperCamelCase($stringValue));
}
}
diff --git a/src/Variable.php b/src/Variable.php
index b137ce3..6b24cc8 100644
--- a/src/Variable.php
+++ b/src/Variable.php
@@ -4,61 +4,31 @@
use GraphQL\Util\StringLiteralFormatter;
-/**
- * Class Variable
- *
- * @package GraphQL
- */
-class Variable
+final readonly class Variable implements \Stringable
{
- /**
- * @var string
- */
- protected $name;
-
- /**
- * @var string
- */
- protected $type;
-
- /**
- * @var bool
- */
- protected $required;
-
- /**
- * @var null|string|int|float|bool
- */
- protected $defaultValue;
-
- /**
- * Variable constructor.
- *
- * @param string $name
- * @param string $type
- * @param bool $isRequired
- * @param null $defaultValue
- */
- public function __construct(string $name, string $type, bool $isRequired = false, $defaultValue = null)
- {
- $this->name = $name;
- $this->type = $type;
- $this->required = $isRequired;
- $this->defaultValue = $defaultValue;
+ public function __construct(
+ public string $name,
+ public string $type,
+ public bool $nonNullable = false,
+ public mixed $defaultValue = null
+ ) {
}
- /**
- * @return string
- */
public function __toString(): string
{
- $varString = "\$$this->name: $this->type";
- if ($this->required) {
- $varString .= '!';
- } elseif (!empty($this->defaultValue)) {
- $varString .= '=' . StringLiteralFormatter::formatValueForRHS($this->defaultValue);
+ $varString = sprintf(
+ '$%s: %s%s',
+ $this->name,
+ $this->type,
+ $this->nonNullable ? '!' : '',
+ );
+
+ if (!isset($this->defaultValue)) {
+ return $varString;
}
- return $varString;
+ return sprintf('%s=%s', $varString, is_array($this->defaultValue) ?
+ StringLiteralFormatter::formatArrayForGQLQuery($this->defaultValue) :
+ StringLiteralFormatter::formatValueForRHS($this->defaultValue));
}
-}
\ No newline at end of file
+}
diff --git a/tests/Auth/AwsIamAuthTest.php b/tests/Auth/AwsIamAuthTest.php
deleted file mode 100644
index 2719714..0000000
--- a/tests/Auth/AwsIamAuthTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-auth = new AwsIamAuth();
- }
-
- /**
- * @covers \GraphQL\Auth\AwsIamAuth::run
- * @covers \GraphQL\Exception\AwsRegionNotSetException::__construct
- */
- public function testRunMissingRegion()
- {
- $this->expectException(AwsRegionNotSetException::class);
- $request = new Request('POST', '');
- $this->auth->run($request, []);
- }
-
- /**
- * @covers \GraphQL\Auth\AwsIamAuth::run
- * @covers \GraphQL\Auth\AwsIamAuth::getSignature
- * @covers \GraphQL\Auth\AwsIamAuth::getCredentials
- */
- public function testRunSuccess()
- {
- $request = $this->auth->run(
- new Request('POST', ''),
- ['aws_region' => 'us-east-1']
- );
- $headers = $request->getHeaders();
- $this->assertArrayHasKey('X-Amz-Date', $headers);
- $this->assertArrayHasKey('X-Amz-Security-Token', $headers);
- $this->assertArrayHasKey('Authorization', $headers);
- }
-}
diff --git a/tests/ClientTest.php b/tests/ClientTest.php
deleted file mode 100644
index a2d52e3..0000000
--- a/tests/ClientTest.php
+++ /dev/null
@@ -1,272 +0,0 @@
-mockHandler = new MockHandler();
- $handler = HandlerStack::create($this->mockHandler);
- $this->client = new Client('', [], ['handler' => $handler]);
- }
-
- /**
- * @covers \GraphQL\Client::__construct
- * @covers \GraphQL\Client::runRawQuery
- * @covers \GraphQL\Util\GuzzleAdapter::__construct
- * @covers \GraphQL\Util\GuzzleAdapter::sendRequest
- */
- public function testConstructClient()
- {
- $mockHandler = new MockHandler();
- $handler = HandlerStack::create($mockHandler);
- $container = [];
- $history = Middleware::history($container);
- $handler->push($history);
-
- $mockHandler->append(new Response(200));
- $mockHandler->append(new Response(200));
- $mockHandler->append(new Response(200));
- $mockHandler->append(new Response(200));
- $mockHandler->append(new Response(200));
-
- $client = new Client('', [], ['handler' => $handler]);
- $client->runRawQuery('query_string');
-
- $client = new Client('', ['Authorization' => 'Basic xyz'], ['handler' => $handler]);
- $client->runRawQuery('query_string');
-
- $client = new Client('', [], ['handler' => $handler]);
- $client->runRawQuery('query_string', false, ['name' => 'val']);
-
- $client = new Client('', ['Authorization' => 'Basic xyz'], ['handler' => $handler, 'headers' => [ 'Authorization' => 'Basic zyx', 'User-Agent' => 'test' ]]);
- $client->runRawQuery('query_string');
-
- /** @var Request $firstRequest */
- $firstRequest = $container[0]['request'];
- $this->assertEquals('{"query":"query_string","variables":{}}', (string) $firstRequest->getBody());
- $this->assertSame('POST', $firstRequest->getMethod());
-
- /** @var Request $thirdRequest */
- $thirdRequest = $container[1]['request'];
- $this->assertNotEmpty($thirdRequest->getHeader('Authorization'));
- $this->assertEquals(
- ['Basic xyz'],
- $thirdRequest->getHeader('Authorization')
- );
-
- /** @var Request $secondRequest */
- $secondRequest = $container[2]['request'];
- $this->assertEquals('{"query":"query_string","variables":{"name":"val"}}', (string) $secondRequest->getBody());
-
- /** @var Request $fourthRequest */
- $fourthRequest = $container[3]['request'];
- $this->assertNotEmpty($fourthRequest->getHeader('Authorization'));
- $this->assertNotEmpty($fourthRequest->getHeader('User-Agent'));
- $this->assertEquals(['Basic zyx'], $fourthRequest->getHeader('Authorization'));
- $this->assertEquals(['test'], $fourthRequest->getHeader('User-Agent'));
- }
-
- /**
- * @covers \GraphQL\Client::__construct
- * @covers \GraphQL\Exception\MethodNotSupportedException
- */
- public function testConstructClientWithGetRequestMethod()
- {
- $this->expectException(MethodNotSupportedException::class);
- $client = new Client('', [], [], null, 'GET');
- }
-
- /**
- * @covers \GraphQL\Client::runQuery
- */
- public function testRunQueryBuilder()
- {
- $this->mockHandler->append(new Response(200, [], json_encode([
- 'data' => [
- 'someData'
- ]
- ])));
-
- $response = $this->client->runQuery((new QueryBuilder('obj'))->selectField('field'));
- $this->assertNotNull($response->getData());
- }
-
- /**
- * @covers \GraphQL\Client::runQuery
- */
- public function testRunInvalidQueryClass()
- {
- $this->expectException(TypeError::class);
- $this->client->runQuery(new RawObject('obj'));
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testValidQueryResponse()
- {
- $this->mockHandler->append(new Response(200, [], json_encode([
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ], [
- 'data' => 'value',
- ]
- ]
- ]
- ])));
-
- $objectResults = $this->client->runRawQuery('');
- $this->assertIsObject($objectResults->getResults());
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testValidQueryResponseToArray()
- {
- $this->mockHandler->append(new Response(200, [], json_encode([
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ], [
- 'data' => 'value',
- ]
- ]
- ]
- ])));
-
- $arrayResults = $this->client->runRawQuery('', true);
- $this->assertIsArray($arrayResults->getResults());
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testInvalidQueryResponseWith200()
- {
- $this->mockHandler->append(new Response(200, [], json_encode([
- 'errors' => [
- [
- 'message' => 'some syntax error',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ],
- ]
- ]
- ])));
-
- $this->expectException(QueryError::class);
- $this->client->runRawQuery('');
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testInvalidQueryResponseWith400()
- {
- $this->mockHandler->append(new ClientException('', new Request('post', ''),
- new Response(400, [], json_encode([
- 'errors' => [
- [
- 'message' => 'some syntax error',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ],
- ]
- ]
- ]))));
-
- $this->expectException(QueryError::class);
- $this->client->runRawQuery('');
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testUnauthorizedResponse()
- {
- $this->mockHandler->append(new ClientException('', new Request('post', ''),
- new Response(401, [], json_encode('Unauthorized'))
- ));
-
- $this->expectException(ClientException::class);
- $this->client->runRawQuery('');
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testNotFoundResponse()
- {
- $this->mockHandler->append(new ClientException('', new Request('post', ''), new Response(404, [])));
-
- $this->expectException(ClientException::class);
- $this->client->runRawQuery('');
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testInternalServerErrorResponse()
- {
- $this->mockHandler->append(new ServerException('', new Request('post', ''), new Response(500, [])));
-
- $this->expectException(ServerException::class);
- $this->client->runRawQuery('');
- }
-
- /**
- * @covers \GraphQL\Client::runRawQuery
- */
- public function testConnectTimeoutResponse()
- {
- $this->mockHandler->append(new ConnectException('Time Out', new Request('post', '')));
- $this->expectException(ConnectException::class);
- $this->client->runRawQuery('');
- }
-}
diff --git a/tests/InlineFragmentTest.php b/tests/InlineFragmentTest.php
deleted file mode 100644
index 43a67a6..0000000
--- a/tests/InlineFragmentTest.php
+++ /dev/null
@@ -1,113 +0,0 @@
-setSelectionSet(
- [
- 'field1',
- 'field2',
- ]
- );
-
- $this->assertEquals(
- '... on Test {
-field1
-field2
-}',
- (string) $fragment
- );
- }
-
- /**
- * @covers \GraphQL\InlineFragment::__construct
- * @covers \GraphQL\InlineFragment::setSelectionSet
- * @covers \GraphQL\InlineFragment::constructSelectionSet
- * @covers \GraphQL\InlineFragment::__toString
- */
- public function testConvertNestedFragmentToString()
- {
- $fragment = new InlineFragment('Test');
- $fragment->setSelectionSet(
- [
- 'field1',
- 'field2',
- (new Query('sub_field'))
- ->setArguments(
- [
- 'first' => 5
- ]
- )
- ->setSelectionSet(
- [
- 'sub_field3',
- (new InlineFragment('Nested'))
- ->setSelectionSet(
- [
- 'another_field'
- ]
- ),
- ]
- )
- ]
- );
-
- $this->assertEquals(
- '... on Test {
-field1
-field2
-sub_field(first: 5) {
-sub_field3
-... on Nested {
-another_field
-}
-}
-}',
- (string) $fragment
- );
- }
-
- /**
- * @covers \GraphQL\InlineFragment::__construct
- * @covers \GraphQL\InlineFragment::setSelectionSet
- * @covers \GraphQL\InlineFragment::getSelectionSet
- * @covers \GraphQL\InlineFragment::constructSelectionSet
- * @covers \GraphQL\InlineFragment::__toString
- */
- public function testConvertQueryBuilderToString()
- {
- $queryBuilder = new QueryBuilder();
-
- $fragment = new InlineFragment('Test', $queryBuilder);
- $queryBuilder->selectField('field1');
- $queryBuilder->selectField('field2');
-
- $this->assertEquals(
- '... on Test {
-field1
-field2
-}',
- (string) $fragment
- );
- }
-}
diff --git a/tests/MutationBuilderTest.php b/tests/MutationBuilderTest.php
deleted file mode 100644
index d98e1fc..0000000
--- a/tests/MutationBuilderTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-mutationBuilder = new MutationBuilder('createObject');
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\MutationBuilder::__construct
- * @covers \GraphQL\QueryBuilder\MutationBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\MutationBuilder::getMutation
- */
- public function testConstruct()
- {
- $builder = new MutationBuilder('createObject');
- $builder->selectField('field_one');
- $this->assertInstanceOf(Mutation::class, $builder->getQuery());
- $this->assertInstanceOf(Mutation::class, $builder->getMutation());
-
- $expectedString = 'mutation {
-createObject {
-field_one
-}
-}';
- $this->assertEquals($expectedString, (string) $builder->getQuery());
- $this->assertEquals($expectedString, (string) $builder->getMutation());
- }
-}
\ No newline at end of file
diff --git a/tests/MutationTest.php b/tests/MutationTest.php
deleted file mode 100644
index fb58ff1..0000000
--- a/tests/MutationTest.php
+++ /dev/null
@@ -1,113 +0,0 @@
-assertEquals(
- 'mutation {
-createObject
-}',
- (string) $mutation
- );
- }
-
- /**
- *
- */
- public function testMutationWithOperationType()
- {
- $mutation = new Mutation();
- $mutation
- ->setSelectionSet(
- [
- (new Mutation('createObject'))
- ->setArguments(['name' => 'TestObject'])
- ]
- );
-
- $this->assertEquals(
- 'mutation {
-createObject(name: "TestObject")
-}',
- (string) $mutation
- );
- }
-
- /**
- *
- */
- public function testMutationWithoutSelectedFields()
- {
- $mutation = (new Mutation('createObject'))
- ->setArguments(['name' => 'TestObject', 'type' => 'TestType']);
- $this->assertEquals(
- 'mutation {
-createObject(name: "TestObject" type: "TestType")
-}',
- (string) $mutation);
- }
-
- /**
- *
- */
- public function testMutationWithFields()
- {
- $mutation = (new Mutation('createObject'))
- ->setSelectionSet(
- [
- 'fieldOne',
- 'fieldTwo',
- ]
- );
-
- $this->assertEquals(
- 'mutation {
-createObject {
-fieldOne
-fieldTwo
-}
-}',
- (string) $mutation
- );
- }
-
- /**
- *
- */
- public function testMutationWithArgumentsAndFields()
- {
- $mutation = (new Mutation('createObject'))
- ->setSelectionSet(
- [
- 'fieldOne',
- 'fieldTwo',
- ]
- )->setArguments(
- [
- 'argOne' => 1,
- 'argTwo' => 'val'
- ]
- );
-
- $this->assertEquals(
- 'mutation {
-createObject(argOne: 1 argTwo: "val") {
-fieldOne
-fieldTwo
-}
-}',
- (string) $mutation
- );
- }
-}
\ No newline at end of file
diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php
deleted file mode 100644
index 828c004..0000000
--- a/tests/QueryBuilderTest.php
+++ /dev/null
@@ -1,338 +0,0 @@
-queryBuilder = new QueryBuilder('Object');
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::__construct
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::__construct
- */
- public function testConstruct()
- {
- $builder = new QueryBuilder('Object');
- $builder->selectField('field_one');
- $this->assertEquals(
- 'query {
-Object {
-field_one
-}
-}',
- (string) $builder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::__construct
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::__construct
- */
- public function testConstructWithAlias()
- {
- $builder = new QueryBuilder('Object', 'ObjectAlias');
- $builder->selectField('field_one');
- $this->assertEquals(
- 'query {
-ObjectAlias: Object {
-field_one
-}
-}',
- (string) $builder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::__construct
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::__construct
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::setAlias
- */
- public function testSetAlias()
- {
- $builder = (new QueryBuilder('Object'))
- ->setAlias('ObjectAlias');;
- $builder->selectField('field_one');
- $this->assertEquals(
- 'query {
-ObjectAlias: Object {
-field_one
-}
-}',
- (string) $builder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::setVariable
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::setVariable
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::getQuery
- */
- public function testAddVariables()
- {
- $this->queryBuilder
- ->setVariable('var', 'String')
- ->setVariable('intVar', 'Int', false, 4)
- ->selectField('fieldOne');
- $this->assertEquals(
- 'query($var: String $intVar: Int=4) {
-Object {
-fieldOne
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::getQuery
- */
- public function testAddVariablesToSecondLevelQueryDoesNothing()
- {
- $this->queryBuilder
- ->setVariable('var', 'String')
- ->selectField('fieldOne')
- ->selectField(
- (new QueryBuilder('Nested'))
- ->setVariable('var', 'String')
- ->selectField('fieldTwo')
- );
- $this->assertEquals(
- 'query($var: String) {
-Object {
-fieldOne
-Nested {
-fieldTwo
-}
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::selectField
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::selectField
- */
- public function testSelectScalarFields()
- {
- $this->queryBuilder->selectField('field_one');
- $this->queryBuilder->selectField('field_two');
- $this->assertEquals(
- 'query {
-Object {
-field_one
-field_two
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::selectField
- */
- public function testSelectNestedQuery()
- {
- $this->queryBuilder->selectField(
- (new Query('Nested'))
- ->setSelectionSet(['some_field'])
- );
- $this->assertEquals(
- 'query {
-Object {
-Nested {
-some_field
-}
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::selectField
- */
- public function testSelectNestedQueryBuilder()
- {
- $this->queryBuilder->selectField(
- (new QueryBuilder('Nested'))
- ->selectField('some_field')
- );
- $this->assertEquals(
- 'query {
-Object {
-Nested {
-some_field
-}
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::__construct
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::selectField
- */
- public function testQueryBuilderWithoutFieldName()
- {
- $builder = (new QueryBuilder())
- ->selectField(
- (new QueryBuilder('Object'))
- ->selectField('one')
- )
- ->selectField(
- (new QueryBuilder('Another'))
- ->selectField('two')
- );
-
- $this->assertEquals('query {
-Object {
-one
-}
-Another {
-two
-}
-}',
- (string) $builder->getQuery());
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::selectField
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::selectField
- */
- public function testSelectInlineFragment()
- {
- $this->queryBuilder->selectField(
- (new InlineFragment('Type'))
- ->setSelectionSet(['field'])
- );
- $this->assertEquals(
- 'query {
-Object {
-... on Type {
-field
-}
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::setArgument
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::setArgument
- */
- public function testSelectArguments()
- {
- $this->queryBuilder->selectField('field');
- $this->queryBuilder->setArgument('str_arg', 'value');
- $this->assertEquals(
- 'query {
-Object(str_arg: "value") {
-field
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
-
- $this->queryBuilder->setArgument('bool_arg', true);
- $this->assertEquals(
- 'query {
-Object(str_arg: "value" bool_arg: true) {
-field
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
-
- $this->queryBuilder->setArgument('int_arg', 10);
- $this->assertEquals(
- 'query {
-Object(str_arg: "value" bool_arg: true int_arg: 10) {
-field
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
-
- $this->queryBuilder->setArgument('array_arg', ['one', 'two', 'three']);
- $this->assertEquals(
- 'query {
-Object(str_arg: "value" bool_arg: true int_arg: 10 array_arg: ["one", "two", "three"]) {
-field
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
-
- $this->queryBuilder->setArgument('input_object_arg', new RawObject('{field_not: "x"}'));
- $this->assertEquals(
- 'query {
-Object(str_arg: "value" bool_arg: true int_arg: 10 array_arg: ["one", "two", "three"] input_object_arg: {field_not: "x"}) {
-field
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-
- /**
- * @covers \GraphQL\QueryBuilder\QueryBuilder::getQuery
- * @covers \GraphQL\QueryBuilder\QueryBuilder::setArgument
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::setArgument
- * @covers \GraphQL\QueryBuilder\QueryBuilder::selectField
- * @covers \GraphQL\QueryBuilder\AbstractQueryBuilder::selectField
- */
- public function testSetTwoLevelArguments()
- {
- $this->queryBuilder->selectField(
- (new QueryBuilder('Nested'))
- ->selectField('some_field')
- ->selectField('another_field')
- ->setArgument('nested_arg', [1, 2, 3])
- )
- ->setArgument('outer_arg', 'outer val');
- $this->assertEquals(
- 'query {
-Object(outer_arg: "outer val") {
-Nested(nested_arg: [1, 2, 3]) {
-some_field
-another_field
-}
-}
-}',
- (string) $this->queryBuilder->getQuery()
- );
- }
-}
\ No newline at end of file
diff --git a/tests/QueryErrorTest.php b/tests/QueryErrorTest.php
deleted file mode 100644
index 414e58b..0000000
--- a/tests/QueryErrorTest.php
+++ /dev/null
@@ -1,145 +0,0 @@
- [
- [
- 'message' => $exceptionMessage,
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ],
- ]
- ]
- ];
-
- $queryError = new QueryError($errorData);
- $this->assertEquals($exceptionMessage, $queryError->getMessage());
- $this->assertEquals(
- [
- 'message' => 'some syntax error',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ]
- ],
- $queryError->getErrorDetails()
- );
- $this->assertEquals([], $queryError->getData());
- }
-
- /**
- * @covers \GraphQL\Exception\QueryError::__construct
- * @covers \GraphQL\Exception\QueryError::getErrorDetails
- */
- public function testConstructQueryErrorWhenResponseHasData()
- {
- $errorData = [
- 'errors' => [
- [
- 'message' => 'first error message',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ],
- ],
- [
- 'message' => 'second error message',
- 'location' => [
- [
- 'line' => 2,
- 'column' => 4,
- ]
- ],
- ],
- ],
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ];
-
- $queryError = new QueryError($errorData);
- $this->assertEquals('first error message', $queryError->getMessage());
- $this->assertEquals(
- [
- 'message' => 'first error message',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ]
- ],
- $queryError->getErrorDetails()
- );
-
- $this->assertEquals(
- [
- [
- 'message' => 'first error message',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ]
- ],
- [
- 'message' => 'second error message',
- 'location' => [
- [
- 'line' => 2,
- 'column' => 4,
- ]
- ]
- ]
- ],
- $queryError->getErrors()
- );
-
- $this->assertEquals(
- [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ],
- $queryError->getData()
- );
- }
-}
diff --git a/tests/QueryTest.php b/tests/QueryTest.php
deleted file mode 100644
index e3bdb87..0000000
--- a/tests/QueryTest.php
+++ /dev/null
@@ -1,825 +0,0 @@
-assertIsString((string) $query, 'Failed to convert query to string');
-
- return $query;
- }
-
- /**
- * @depends testConvertsToString
- *
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testEmptyArguments(Query $query)
- {
- $this->assertStringNotContainsString("()", (string) $query, 'Query has empty arguments list');
-
- return $query;
- }
-
- /**
- * @covers \GraphQL\Query::__toString
- * @covers FieldTrait::constructSelectionSet
- */
- public function testQueryWithoutFieldName()
- {
- $query = new Query();
-
- $this->assertEquals(
- "query",
- (string) $query
- );
-
- $query->setSelectionSet(
- [
- (new Query('Object'))
- ->setSelectionSet(['one']),
- (new Query('Another'))
- ->setSelectionSet(['two'])
- ]
- );
-
- $this->assertEquals(
- "query {
-Object {
-one
-}
-Another {
-two
-}
-}",
- (string) $query
- );
- }
-
- /**
- * @depends testConvertsToString
- *
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithAlias()
- {
- $query = (new Query('Object', 'ObjectAlias'))
- ->setSelectionSet([
- 'one'
- ]);
-
- $this->assertEquals(
- "query {
-ObjectAlias: Object {
-one
-}
-}",
- (string) $query
- );
- }
-
- /**
- * @depends testConvertsToString
- *
- * @covers \GraphQL\Query::setAlias
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithSetAlias()
- {
- $query = (new Query('Object'))
- ->setAlias('ObjectAlias')
- ->setSelectionSet([
- 'one'
- ]);
-
- $this->assertEquals(
- "query {
-ObjectAlias: Object {
-one
-}
-}",
- (string) $query
- );
- }
-
- /**
- * @depends testConvertsToString
- *
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::setOperationName
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithOperationName()
- {
- $query = (new Query('Object'))
- ->setOperationName('retrieveObject');
- $this->assertEquals(
-'query retrieveObject {
-Object
-}',
- (string) $query
- );
- }
-
- /**
- * @depends testQueryWithoutFieldName
- * @depends testQueryWithOperationName
- *
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::setOperationName
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithOperationNameAndOperationType()
- {
- $query = (new Query())
- ->setOperationName('retrieveObject')
- ->setSelectionSet([new Query('Object')]);
- $this->assertEquals(
- 'query retrieveObject {
-Object
-}',
- (string) $query
- );
- }
-
- /**
- * @depends testQueryWithOperationName
- *
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::setOperationName
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithOperationNameInSecondLevelDoesNothing()
- {
- $query = (new Query('Object'))
- ->setOperationName('retrieveObject')
- ->setSelectionSet([(new Query('Nested'))->setOperationName('opName')]);
- $this->assertEquals(
- 'query retrieveObject {
-Object {
-Nested
-}
-}',
- (string) $query
- );
- }
-
- /**
- * @covers \GraphQL\Query::setVariables
- * @covers \GraphQL\Exception\InvalidVariableException
- */
- public function testSetVariablesWithoutVariableObjects()
- {
- $this->expectException(InvalidVariableException::class);
- (new Query('Object'))->setVariables(['one', 'two']);
- }
-
- /**
- * @depends testConvertsToString
- *
- * @covers \GraphQL\Query::setVariables
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::constructVariables
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithOneVariable()
- {
- $query = (new Query('Object'))
- ->setVariables([new Variable('var', 'String')]);
- $this->assertEquals(
- 'query($var: String) {
-Object
-}',
- (string) $query
- );
- }
-
- /**
- * @depends testQueryWithOneVariable
- *
- * @covers \GraphQL\Query::setVariables
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::constructVariables
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithMultipleVariables()
- {
- $query = (new Query('Object'))
- ->setVariables([new Variable('var', 'String'), new Variable('intVar', 'Int', false, 4)]);
- $this->assertEquals(
- 'query($var: String $intVar: Int=4) {
-Object
-}',
- (string) $query
- );
- }
-
- /**
- * @depends testConvertsToString
- *
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithVariablesInSecondLevelDoesNothing()
- {
- $query = (new Query('Object'))
- ->setVariables([new Variable('var', 'String'), new Variable('intVar', 'Int', false, 4)])
- ->setSelectionSet([(new Query('Nested'))])
- ->setVariables([new Variable('var', 'String'), new Variable('intVar', 'Int', false, 4)]);
- $this->assertEquals(
- 'query($var: String $intVar: Int=4) {
-Object {
-Nested
-}
-}',
- (string) $query
- );
- }
-
- /**
- * @depends testQueryWithMultipleVariables
- * @depends testQueryWithOperationName
- *
- * @covers \GraphQL\Query::generateSignature
- * @covers \GraphQL\Query::__toString
- */
- public function testQueryWithOperationNameAndVariables()
- {
- $query = (new Query('Object'))
- ->setOperationName('retrieveObject')
- ->setVariables([new Variable('var', 'String')]);
- $this->assertEquals(
- 'query retrieveObject($var: String) {
-Object
-}',
- (string) $query
- );
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::__toString
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testEmptyQuery(Query $query)
- {
- $this->assertEquals(
- "query {
-Object
-}",
- (string) $query,
- 'Incorrect empty query string'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Exception\ArgumentException
- * @covers \GraphQL\Query::setArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testArgumentWithoutName(Query $query)
- {
- $this->expectException(ArgumentException::class);
- $query->setArguments(['val']);
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testStringArgumentValue(Query $query)
- {
- $query->setArguments(['arg1' => 'value']);
- $this->assertEquals(
- "query {
-Object(arg1: \"value\")
-}",
- (string) $query,
- 'Query has improperly formatted parameter list'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testIntegerArgumentValue(Query $query)
- {
- $query->setArguments(['arg1' => 23]);
- $this->assertEquals(
- "query {
-Object(arg1: 23)
-}",
- (string) $query
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
-
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testBooleanArgumentValue(Query $query)
- {
- $query->setArguments(['arg1' => true]);
- $this->assertEquals(
- "query {
-Object(arg1: true)
-}",
- (string) $query
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testNullArgumentValue(Query $query)
- {
- $query->setArguments(['arg1' => null]);
- $this->assertEquals(
- "query {
-Object(arg1: null)
-}"
- , (string) $query
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testArrayIntegerArgumentValue(Query $query)
- {
- $query->setArguments(['arg1' => [1, 2, 3]]);
- $this->assertEquals(
- "query {
-Object(arg1: [1, 2, 3])
-}",
- (string) $query
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- * @covers \GraphQL\RawObject::__toString
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testJsonObjectArgumentValue(Query $query)
- {
- $query->setArguments(['obj' => new RawObject('{json_string_array: ["json value"]}')]);
- $this->assertEquals(
- "query {
-Object(obj: {json_string_array: [\"json value\"]})
-}"
- , (string) $query
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyArguments
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testArrayStringArgumentValue(Query $query)
- {
- $query->setArguments(['arg1' => ['one', 'two', 'three']]);
- $this->assertEquals(
- "query {
-Object(arg1: [\"one\", \"two\", \"three\"])
-}",
- (string) $query
- );
-
- return $query;
- }
-
- /**
- * @depends clone testStringArgumentValue
- * @depends testIntegerArgumentValue
- * @depends testBooleanArgumentValue
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testTwoOrMoreArguments(Query $query)
- {
- $query->setArguments(['arg1' => 'val1', 'arg2' => 2, 'arg3' => true]);
- $this->assertEquals(
- "query {
-Object(arg1: \"val1\" arg2: 2 arg3: true)
-}",
- (string) $query,
- 'Query has improperly formatted parameter list'
- );
-
- return $query;
- }
-
- /**
- * @depends testStringArgumentValue
- *
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- * @covers \GraphQL\Query::setArguments
- * @covers \GraphQL\Query::constructArguments
- */
- public function testStringWrappingWorks()
- {
- // TODO: Remove this in v1.0 release
- $queryWrapped = new Query('Object');
- $queryWrapped->setArguments(['arg1' => '"val"']);
-
- $queryNotWrapped = new Query('Object');
- $queryNotWrapped->setArguments(['arg1' => 'val']);
-
- $this->assertEquals((string) $queryWrapped, (string) $queryWrapped);
- }
-
- /**
- * @depends clone testEmptyQuery
- *
- * @covers \GraphQL\Query::setSelectionSet
- * @covers \GraphQL\FieldTrait::constructSelectionSet
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testSingleSelectionField(Query $query)
- {
- $query->setSelectionSet(['field1']);
- $this->assertEquals(
- "query {
-Object {
-field1
-}
-}",
- (string) $query,
- 'Query has improperly formatted selection set'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyQuery
- *
- * @covers \GraphQL\Query::setSelectionSet
- * @covers \GraphQL\FieldTrait::constructSelectionSet
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testTwoOrMoreSelectionFields(Query $query)
- {
- $query->setSelectionSet(['field1', 'field2']);
- $this->assertEquals(
- "query {
-Object {
-field1
-field2
-}
-}",
- (string) $query,
- 'Query has improperly formatted selection set'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyQuery
- *
- * @covers \GraphQL\Exception\InvalidSelectionException
- * @covers \GraphQL\Query::setSelectionSet
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testSelectNonStringValues(Query $query)
- {
- $this->expectException(InvalidSelectionException::class);
- $query->setSelectionSet([true, 1.5]);
-
- return $query;
- }
-
- /**
- * @depends clone testEmptyQuery
- *
- * @coversNothing
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testOneLevelQuery(Query $query)
- {
- $query->setSelectionSet(['field1', 'field2']);
- $query->setArguments(['arg1' => 'val1', 'arg2' => 'val2']);
- $this->assertEquals(
- "query {
-Object(arg1: \"val1\" arg2: \"val2\") {
-field1
-field2
-}
-}",
- (string) $query,
- 'One level query not formatted correctly'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testOneLevelQuery
- *
- * @covers \GraphQL\FieldTrait::constructSelectionSet
- * @covers \GraphQL\Query::setAsNested
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testTwoLevelQueryDoesNotContainWordQuery(Query $query)
- {
- $query->setSelectionSet(
- [
- 'field1',
- 'field2',
- (new Query('Object2'))
- ->setSelectionSet(['field3'])
- ]
- );
- $this->assertStringNotContainsString(
- "\nquery {",
- (string) $query,
- 'Nested query contains "query" word'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testTwoLevelQueryDoesNotContainWordQuery
- *
- * @covers \GraphQL\Query::setAsNested
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testTwoLevelQuery(Query $query)
- {
- $query->setSelectionSet(
- [
- 'field1',
- 'field2',
- (new Query('Object2'))
- ->setSelectionSet(['field3'])
- ]
- );
- $this->assertEquals(
- "query {
-Object(arg1: \"val1\" arg2: \"val2\") {
-field1
-field2
-Object2 {
-field3
-}
-}
-}",
- (string) $query,
- 'Two level query not formatted correctly'
- );
-
- return $query;
- }
-
- /**
- * @depends clone testTwoLevelQueryDoesNotContainWordQuery
- *
- * @param Query $query
- *
- * @return Query
- */
- public function testTwoLevelQueryWithInlineFragment(Query $query)
- {
- $query->setSelectionSet(
- [
- 'field1',
- (new InlineFragment('Object'))
- ->setSelectionSet(
- [
- 'fragment_field1',
- 'fragment_field2',
- ]
- ),
- ]
- );
- $this->assertEquals(
- 'query {
-Object(arg1: "val1" arg2: "val2") {
-field1
-... on Object {
-fragment_field1
-fragment_field2
-}
-}
-}',
- (string) $query
- );
-
- return $query;
- }
-
- /**
- * @covers \GraphQL\Query::getArguments
- */
- public function testGettingArguments()
- {
- $gql = (new Query('things'))
- ->setArguments(
- [
- 'someClientId' => 'someValueBasedOnCodebase'
- ]
- );
- $cursor_id = 'someCursor';
- $new_args = $gql->getArguments();
- $gql->setArguments(
- array_merge(
- $new_args,
- [
- 'after' => $cursor_id
- ]
- )
- );
- self::assertEquals(
- 'query {
-things(someClientId: "someValueBasedOnCodebase" after: "someCursor")
-}',
- (string) $gql
- );
- }
-
- /**
- * @covers \GraphQL\Query::getFieldName
- */
- public function testGettingNameAndAltering()
- {
- $gql = (new Query('things'))
- ->setSelectionSet(
- [
- 'id',
- 'name',
- (new Query('subThings'))
- ->setArguments(
- [
- 'filter' => 'providerId123',
- ]
- )
- ->setSelectionSet(
- [
- 'id',
- 'name'
- ]
- )
- ]);
- $sets = $gql->getSelectionSet();
- foreach ($sets as $set) {
- if (($set instanceof Query) === false) {
- continue;
- }
- $name = $set->getFieldName();
- if ($name !== 'subThings') {
- continue;
- }
- $set->setArguments(
- [
- 'filter' => 'providerId456'
- ]
- );
- $set->setSelectionSet(
- array_merge(
- $set->getSelectionSet(),
- [
- 'someField',
- 'someOtherField'
- ]
- )
- );
- }
- self::assertEquals(
- 'query {
-things {
-id
-name
-subThings(filter: "providerId456") {
-id
-name
-someField
-someOtherField
-}
-}
-}',
- (string) $gql);
- }
-}
diff --git a/tests/RawObjectTest.php b/tests/RawObjectTest.php
deleted file mode 100644
index 40c75cf..0000000
--- a/tests/RawObjectTest.php
+++ /dev/null
@@ -1,24 +0,0 @@
-assertEquals('[1, 4, "y", 6.7]', (string) $json);
-
- // Test convert graphql object
- $json = new RawObject('{arr: [1, "z"], str: "val", int: 1, obj: {x: "y"}}');
- $this->assertEquals('{arr: [1, "z"], str: "val", int: 1, obj: {x: "y"}}', (string) $json);
- }
-}
\ No newline at end of file
diff --git a/tests/ResultsTest.php b/tests/ResultsTest.php
deleted file mode 100644
index 65a48cb..0000000
--- a/tests/ResultsTest.php
+++ /dev/null
@@ -1,275 +0,0 @@
-mockHandler = new MockHandler();
- $this->client = new Client(['handler' => $this->mockHandler]);
- }
-
- /**
- * @covers \GraphQL\Results::__construct
- * @covers \GraphQL\Results::getResponseObject
- * @covers \GraphQL\Results::getResponseBody
- * @covers \GraphQL\Results::getResults
- * @covers \GraphQL\Results::getData
- */
- public function testGetSuccessResponseAsObject()
- {
- $body = json_encode([
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ]);
- $response = new Response(200, [], $body);
- $this->mockHandler->append($response);
-
- $response = $this->client->post('', []);
- $results = new Results($response);
-
- $this->assertEquals($response, $results->getResponseObject());
- $this->assertEquals($body, $results->getResponseBody());
-
- $object = new stdClass();
- $object->data = new stdClass();
- $object->data->someField = [];
- $object->data->someField[] = new stdClass();
- $object->data->someField[] = new stdClass();
- $object->data->someField[0]->data = 'value';
- $object->data->someField[1]->data = 'value';
- $this->assertEquals(
- $object,
- $results->getResults()
- );
- $this->assertEquals(
- $object->data,
- $results->getData()
- );
- }
-
- /**
- * @covers \GraphQL\Results::__construct
- * @covers \GraphQL\Results::getResponseObject
- * @covers \GraphQL\Results::getResponseBody
- * @covers \GraphQL\Results::getResults
- * @covers \GraphQL\Results::getData
- */
- public function testGetSuccessResponseAsArray()
- {
- $body = json_encode([
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ]);
- $originalResponse = new Response(200, [], $body);
- $this->mockHandler->append($originalResponse);
-
- $response = $this->client->post('', []);
- $results = new Results($response, true);
-
- $this->assertEquals($originalResponse, $results->getResponseObject());
- $this->assertEquals($body, $results->getResponseBody());
- $this->assertEquals(
- [
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ],
- $results->getResults()
- );
- $this->assertEquals(
- [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ],
- $results->getData()
- );
- }
-
- /**
- * @covers \GraphQL\Results::__construct
- */
- public function testGetQueryInvalidSyntaxError()
- {
- $body = json_encode([
- 'errors' => [
- [
- 'message' => 'some syntax error',
- 'location' => [
- [
- 'line' => 1,
- 'column' => 3,
- ]
- ],
- ]
- ]
- ]);
- $originalResponse = new Response(200, [], $body);
- $this->mockHandler->append($originalResponse);
-
- $response = $this->client->post('', []);
- $this->expectException(QueryError::class);
- new Results($response);
- }
-
- /**
- * @covers \GraphQL\Results::__construct
- * @covers \GraphQL\Results::reformatResults
- * @covers \GraphQL\Results::getResponseObject
- * @covers \GraphQL\Results::getResponseBody
- * @covers \GraphQL\Results::getResults
- * @covers \GraphQL\Results::getData
- */
- public function testReformatResultsFromObjectToArray()
- {
- $body = json_encode([
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ]);
- $originalResponse = new Response(200, [], $body);
- $this->mockHandler->append($originalResponse);
-
- $response = $this->client->post('', []);
- $results = new Results($response);
- $results->reformatResults(true);
-
- $this->assertEquals(
- [
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ],
- $results->getResults()
- );
- $this->assertEquals(
- [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ],
- $results->getData()
- );
- }
-
- /**
- * @covers \GraphQL\Results::__construct
- * @covers \GraphQL\Results::reformatResults
- * @covers \GraphQL\Results::getResponseObject
- * @covers \GraphQL\Results::getResponseBody
- * @covers \GraphQL\Results::getResults
- * @covers \GraphQL\Results::getData
- */
- public function testReformatResultsFromArrayToObject()
- {
- $body = json_encode([
- 'data' => [
- 'someField' => [
- [
- 'data' => 'value',
- ],
- [
- 'data' => 'value',
- ]
- ]
- ]
- ]);
- $originalResponse = new Response(200, [], $body);
- $this->mockHandler->append($originalResponse);
-
- $response = $this->client->post('', []);
- $results = new Results($response, true);
- $results->reformatResults(false);
-
- $object = new stdClass();
- $object->data = new stdClass();
- $object->data->someField = [];
- $object->data->someField[] = new stdClass();
- $object->data->someField[] = new stdClass();
- $object->data->someField[0]->data = 'value';
- $object->data->someField[1]->data = 'value';
- $this->assertEquals(
- $object,
- $results->getResults()
- );
- $this->assertEquals(
- $object->data,
- $results->getData()
- );
- }
-}
\ No newline at end of file
diff --git a/tests/StringLiteralFormatterTest.php b/tests/StringLiteralFormatterTest.php
deleted file mode 100644
index 1888ec6..0000000
--- a/tests/StringLiteralFormatterTest.php
+++ /dev/null
@@ -1,127 +0,0 @@
-assertEquals('null', $nullString);
-
- // String tests
- $emptyString = StringLiteralFormatter::formatValueForRHS('');
- $this->assertEquals('""', $emptyString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS('someString');
- $this->assertEquals('"someString"', $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS('"quotedString"');
- $this->assertEquals('"\"quotedString\""', $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS("\"quotedString\"");
- $this->assertEquals('"\"quotedString\""', $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS('');
- $this->assertEquals('""', $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS('\'singleQuotes\'');
- $this->assertEquals('"\'singleQuotes\'"', $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS("with \n newlines");
- $this->assertEquals("\"\"\"with \n newlines\"\"\"", $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS('$var');
- $this->assertEquals('$var', $formattedString);
-
- $formattedString = StringLiteralFormatter::formatValueForRHS('$400');
- $this->assertEquals('"$400"', $formattedString);
-
- // Integer tests
- $integerString = StringLiteralFormatter::formatValueForRHS(25);
- $this->assertEquals('25', $integerString);
-
- // Float tests
- $floatString = StringLiteralFormatter::formatValueForRHS(123.123);
- $this->assertEquals('123.123', $floatString);
-
- // Bool tests
- $stringTrue = StringLiteralFormatter::formatValueForRHS(true);
- $this->assertEquals('true', $stringTrue);
-
- $stringFalse = StringLiteralFormatter::formatValueForRHS(false);
- $this->assertEquals('false', $stringFalse);
- }
-
- /**
- * @covers \GraphQL\Util\StringLiteralFormatter::formatArrayForGQLQuery
- */
- public function testFormatArrayForGQLQuery()
- {
- $emptyArray = [];
- $stringArray = StringLiteralFormatter::formatArrayForGQLQuery($emptyArray);
- $this->assertEquals('[]', $stringArray);
-
- $oneValueArray = [1];
- $stringArray = StringLiteralFormatter::formatArrayForGQLQuery($oneValueArray);
- $this->assertEquals('[1]', $stringArray);
-
- $twoValueArray = [1, 2];
- $stringArray = StringLiteralFormatter::formatArrayForGQLQuery($twoValueArray);
- $this->assertEquals('[1, 2]', $stringArray);
-
- $stringArray = ['one', 'two'];
- $stringArray = StringLiteralFormatter::formatArrayForGQLQuery($stringArray);
- $this->assertEquals('["one", "two"]', $stringArray);
-
- $booleanArray = [true, false];
- $stringArray = StringLiteralFormatter::formatArrayForGQLQuery($booleanArray);
- $this->assertEquals('[true, false]', $stringArray);
-
- $floatArray = [1.1, 2.2];
- $stringArray = StringLiteralFormatter::formatArrayForGQLQuery($floatArray);
- $this->assertEquals('[1.1, 2.2]', $stringArray);
- }
-
- /**
- * @covers \GraphQL\Util\StringLiteralFormatter::formatUpperCamelCase
- */
- public function testFormatUpperCamelCase()
- {
- $snakeCase = 'some_snake_case';
- $camelCase = StringLiteralFormatter::formatUpperCamelCase($snakeCase);
- $this->assertEquals('SomeSnakeCase', $camelCase);
-
- $nonSnakeCase = 'somenonSnakeCase';
- $camelCase = StringLiteralFormatter::formatUpperCamelCase($nonSnakeCase);
- $this->assertEquals('SomenonSnakeCase', $camelCase);
- }
-
- /**
- * @covers \GraphQL\Util\StringLiteralFormatter::formatLowerCamelCase
- */
- public function testFormatLowerCamelCase()
- {
- $snakeCase = 'some_snake_case';
- $camelCase = StringLiteralFormatter::formatLowerCamelCase($snakeCase);
- $this->assertEquals('someSnakeCase', $camelCase);
-
- $nonSnakeCase = 'somenonSnakeCase';
- $camelCase = StringLiteralFormatter::formatLowerCamelCase($nonSnakeCase);
- $this->assertEquals('somenonSnakeCase', $camelCase);
- }
-
-
-}
diff --git a/tests/Unit/ClientTest.php b/tests/Unit/ClientTest.php
new file mode 100644
index 0000000..4f21370
--- /dev/null
+++ b/tests/Unit/ClientTest.php
@@ -0,0 +1,344 @@
+append($response);
+ $handlerStack = HandlerStack::create($handler);
+ $client = new Client('', [], ['handler' => $handlerStack]);
+
+ $this->expectException($expectedExceptionClass);
+
+ $client->runRawQuery('');
+ }
+
+ public static function provideUnsuccessfulResponses(): \Generator
+ {
+ yield '200 with syntax error' => [
+ QueryError::class,
+ new Response(200, [], json_encode([
+ 'errors' => [
+ [
+ 'message' => 'some syntax error',
+ 'location' => [
+ [
+ 'line' => 1,
+ 'column' => 3,
+ ],
+ ],
+ ],
+ ],
+ ])),
+ ];
+
+ yield 'ClientException: 400 with syntax error' => [
+ QueryError::class,
+ new ClientException(
+ '',
+ new Request('post', ''),
+ new Response(400, [], json_encode([
+ 'errors' => [
+ [
+ 'message' => 'some syntax error',
+ 'location' => [
+ [
+ 'line' => 1,
+ 'column' => 3,
+ ],
+ ],
+ ],
+ ],
+ ])),
+ ),
+ ];
+
+ yield 'ClientException: 401 Unauthorized' => [
+ ClientException::class,
+ new ClientException(
+ '',
+ new Request('post', ''),
+ new Response(401, [], '"Unauthorized"')
+ ),
+ ];
+
+ yield 'ClientException: 404 Not Found' => [
+ ClientException::class,
+ new ClientException(
+ '',
+ new Request('post', ''),
+ new Response(404, [], '"Not Found"')
+ ),
+ ];
+
+ yield 'ServerException: 500 Server Error' => [
+ ServerException::class,
+ new ServerException(
+ '',
+ new Request('post', ''),
+ new Response(500, [], '"Server Error"')
+ ),
+ ];
+
+ yield 'ConnectException: Time Out' => [
+ ConnectException::class,
+ new ConnectException('Time Out', new Request('post', '')),
+ ];
+ }
+
+
+ #[Test]
+ public function itOnlySupportsPostRequests(): void
+ {
+ self::expectException(MethodNotSupportedException::class);
+
+ new Client('', [], [], null, 'GET');
+ }
+
+ #[Test]
+ public function itReturnsResultsContainingResponse(): void
+ {
+ $expected = new Response(200, [], json_encode([
+ 'data' => ['firstField' => [['data' => 'value']]],
+ ]));
+
+ $handler = new MockHandler();
+ $handler->append($expected);
+ $handlerStack = HandlerStack::create($handler);
+
+ $sut = new Client('', [], ['handler' => $handlerStack]);
+
+ $actual = $sut->runRawQuery('')->getResponseObject();
+
+ self::assertEquals($expected, $actual);
+ }
+
+ /**
+ * @param array $variables
+ * @param array> $headers
+ */
+ #[Test]
+ #[DataProvider('provideQueries')]
+ public function itSendsQueries(
+ string $expectedQueryString,
+ Query|QueryBuilderInterface $query,
+ string $method,
+ array $variables,
+ array $headers,
+ ): void {
+ $handler = new MockHandler();
+ $handler->append(new Response(200));
+ $handlerStack = HandlerStack::create($handler);
+
+ $sut = new Client(
+ '',
+ $headers,
+ ['handler' => $handlerStack],
+ null,
+ $method,
+ );
+
+ $sut->runQuery($query, false, $variables);
+
+ self::assertSame(
+ $expectedQueryString,
+ (string) $handler->getLastRequest()->getBody(),
+ );
+
+ self::assertSame(
+ $method,
+ $handler->getLastRequest()->getMethod(),
+ );
+
+ foreach ($headers as $header => $value) {
+ self::assertSame(
+ is_string($value) ? [$value] : $value,
+ $handler->getLastRequest()->getHeader($header),
+ );
+ }
+ }
+
+ /**
+ * @param array $variables
+ * @param array> $headers
+ */
+ #[Test]
+ #[DataProvider('provideRawQueries')]
+ public function itSendsRawQueries(
+ string $expectedQueryString,
+ string $rawQueryString,
+ string $method,
+ array $variables,
+ array $headers,
+ ): void {
+ $handler = new MockHandler();
+ $handler->append(new Response(200));
+ $handlerStack = HandlerStack::create($handler);
+
+ $sut = new Client(
+ '',
+ $headers,
+ ['handler' => $handlerStack],
+ null,
+ $method,
+ );
+
+ $sut->runRawQuery($rawQueryString, false, $variables);
+
+ self::assertSame(
+ $expectedQueryString,
+ (string) $handler->getLastRequest()->getBody(),
+ );
+
+ self::assertSame(
+ $method,
+ $handler->getLastRequest()->getMethod(),
+ );
+
+ foreach ($headers as $header => $value) {
+ self::assertSame(
+ is_string($value) ? [$value] : $value,
+ $handler->getLastRequest()->getHeader($header),
+ );
+ }
+ }
+
+
+ /** @return \Generator,
+ * 4: array>,
+ * }>
+ */
+ public static function provideQueries(): \Generator
+ {
+ yield 'minimal query' => [
+ '{"query":"query","variables":{}}',
+ new Query(),
+ 'POST',
+ [],
+ [],
+ ];
+
+ yield 'minimal query builder' => [
+ '{"query":"query","variables":{}}',
+ new QueryBuilder(),
+ 'POST',
+ [],
+ [],
+ ];
+
+ yield 'one variable' => [
+ '{"query":"query","variables":{"name":"value"}}',
+ new Query(),
+ 'POST',
+ ['name' => 'value'],
+ [],
+ ];
+
+ yield 'one variable in query' => [
+ '{"query":"query( $name: string )","variables":{}}',
+ (new Query())->setVariables([new Variable('name', 'string')]),
+ 'POST',
+ [],
+ [],
+ ];
+
+ yield 'authorization header' => [
+ '{"query":"query","variables":{}}',
+ new Query(),
+ 'POST',
+ [],
+ ['Authorization' => 'Basic xyz'],
+ ];
+ }
+
+ /** @return \Generator,
+ * 4: array>,
+ * }>
+ */
+ public static function provideRawQueries(): \Generator
+ {
+ yield 'minimal raw query' => [
+ '{"query":"query_string","variables":{}}',
+ 'query_string',
+ 'POST',
+ [],
+ [],
+ ];
+
+ yield 'one variable' => [
+ '{"query":"query_string","variables":{"name":"value"}}',
+ 'query_string',
+ 'POST',
+ ['name' => 'value'],
+ [],
+ ];
+
+ yield 'authorization header' => [
+ '{"query":"query_string","variables":{}}',
+ 'query_string',
+ 'POST',
+ [],
+ ['Authorization' => 'Basic xyz'],
+ ];
+ }
+
+ #[Test]
+ public function testValidQueryResponseToArray(): void
+ {
+ $handler = new MockHandler();
+ $handler->append(new Response(200, [], json_encode([
+ 'data' => [
+ 'someField' => [
+ [
+ 'data' => 'value',
+ ], [
+ 'data' => 'value',
+ ],
+ ],
+ ],
+ ])));
+
+ $handlerStack = HandlerStack::create($handler);
+ $sut = new Client('', [], ['handler' => $handlerStack]);
+
+ $arrayResults = $sut->runRawQuery('', true);
+ $this->assertIsArray($arrayResults->getResults());
+ }
+}
diff --git a/tests/Unit/Exception/QueryErrorTest.php b/tests/Unit/Exception/QueryErrorTest.php
new file mode 100644
index 0000000..0291ca3
--- /dev/null
+++ b/tests/Unit/Exception/QueryErrorTest.php
@@ -0,0 +1,61 @@
+ [['message' => $expected]]];
+
+ $sut = new QueryError($errorDetails);
+
+ self::assertEquals($expected, $sut->getMessage());
+ }
+
+ #[Test]
+ public function itGetsErrorDetails(): void
+ {
+
+ $expected = [
+ 'message' => 'some syntax error',
+ 'location' => [['line' => 1, 'column' => 3]],
+ ];
+
+ $errorDetails = ['errors' => [$expected]];
+
+ $sut = new QueryError($errorDetails);
+
+ self::assertEquals($expected, $sut->getErrorDetails());
+ }
+
+ #[Test]
+ public function itGetsErrorData(): void
+ {
+ $expected = [
+ 'someField' => [['data' => 'firstValue'], ['data' => 'secondValue']]
+ ];
+
+ $errorDetails = [
+ 'errors' => [[
+ 'message' => 'some syntax error',
+ 'location' => [['line' => 1, 'column' => 3]],
+ ]],
+ 'data' => $expected,
+ ];
+
+ $sut = new QueryError($errorDetails);
+
+ self::assertEquals($expected, $sut->getData());
+ }
+}
diff --git a/tests/Unit/InlineFragmentTest.php b/tests/Unit/InlineFragmentTest.php
new file mode 100644
index 0000000..a037ed7
--- /dev/null
+++ b/tests/Unit/InlineFragmentTest.php
@@ -0,0 +1,112 @@
+*/
+ public static function provideInlineFragmentsCastToString(): \Generator
+ {
+ yield 'minimal example' => [
+ '... on minimal',
+ new InlineFragment('minimal'),
+ ];
+
+ yield 'one selection' => [
+ '... on OneSelection { field1 }',
+ (new InlineFragment('OneSelection'))->setSelectionSet(['field1']),
+ ];
+
+ yield 'three selections' => [
+ '... on ThreeSelections { field1 field2 field3 }',
+ (new InlineFragment('ThreeSelections'))
+ ->setSelectionSet(['field1', 'field2', 'field3']),
+ ];
+
+ yield 'minimal subquery selection' => [
+ '... on query_selection { sub_query }',
+ (new InlineFragment('query_selection'))->setSelectionSet([
+ (new Query('sub_query'))
+ ]),
+ ];
+
+ yield 'subquery (with args) selection ' => [
+ '... on query_selection { sub_query(firstArg: 5) }',
+ (new InlineFragment('query_selection'))->setSelectionSet([
+ (new Query('sub_query'))->setArguments(['firstArg' => 5]),
+ ]),
+ ];
+
+
+ yield 'subquery (with subselection) selection ' => [
+ '... on query_selection { sub_query { sub_selection } }',
+ (new InlineFragment('query_selection'))->setSelectionSet([
+ (new Query('sub_query'))->setSelectionSet(['sub_selection']),
+ ]),
+ ];
+
+ yield 'subquery (with sub-fragment selection) selection ' => [
+ '... on query_selection { sub_query { ... on Sub_Sub_Fragment { sub_sub_sub_field } } }',
+ (new InlineFragment('query_selection'))->setSelectionSet([
+ (new Query('sub_query'))->setSelectionSet([
+ (new InlineFragment('Sub_Sub_Fragment'))
+ ->setSelectionSet(['sub_sub_sub_field']),
+ ]),
+ ]),
+ ];
+
+ yield 'minimal querybuilder selection' => [
+ '... on QueryBuilder_Selection { }',
+ (new InlineFragment('QueryBuilder_Selection'))
+ ->setSelectionSet([new QueryBuilder()]),
+ ];
+
+ yield 'querybuilder (with alias) selection' => [
+ '... on QueryBuilder_Selection { query_alias: { sub_field } }',
+ (new InlineFragment('QueryBuilder_Selection'))->setSelectionSet([
+ (new QueryBuilder())
+ ->setAlias('query_alias')
+ ->selectField('sub_field')
+ ]),
+ ];
+ }
+
+ /**
+ * @covers \GraphQL\InlineFragment::__construct
+ * @covers \GraphQL\InlineFragment::setSelectionSet
+ * @covers \GraphQL\InlineFragment::getSelectionSet
+ * @covers \GraphQL\InlineFragment::constructSelectionSet
+ * @covers \GraphQL\InlineFragment::__toString
+ */
+ public function testConvertQueryBuilderToString()
+ {
+ $queryBuilder = new QueryBuilder();
+
+ $fragment = new InlineFragment('Test', $queryBuilder);
+ $queryBuilder->selectField('field1');
+ $queryBuilder->selectField('field2');
+
+ $this->assertEquals(
+ '... on Test { field1 field2 }',
+ (string) $fragment
+ );
+ }
+}
diff --git a/tests/Unit/MutationTest.php b/tests/Unit/MutationTest.php
new file mode 100644
index 0000000..d94607e
--- /dev/null
+++ b/tests/Unit/MutationTest.php
@@ -0,0 +1,325 @@
+setVariables(['one', 'two']);
+ }
+
+ #[Test]
+ #[TestDox('setArguments() MUST receive an array with string keys')]
+ public function itCannotSetArgumentsFromList(): void
+ {
+ $sut = new Mutation('Object');
+
+ self::expectException(ArgumentException::class);
+
+ $sut->setArguments(['val']);
+ }
+
+ #[Test]
+ public function itGetsArguments(): void
+ {
+ $arguments = ['someField' => 'someValue'];
+ $sut = (new Mutation('things'))->setArguments($arguments);
+
+ self::assertSame($arguments, $sut->getArguments());
+ }
+
+ #[Test]
+ #[DataProvider('provideMutationsToCastToString')]
+ public function itIsStringable(string $expected, Mutation $sut): void
+ {
+ self::assertSame($expected, $sut->__toString());
+ }
+
+ /** @return Generator */
+ public static function provideMutationsToCastToString(): Generator
+ {
+ yield 'empty mutation' => ['mutation', new Mutation()];
+
+ yield 'without fieldName' => (function () {
+ $mutation = new Mutation();
+ $mutation->setSelectionSet([
+ (new Mutation('First'))->setSelectionSet(['one']),
+ (new Mutation('Second'))->setSelectionSet(['two'])
+ ]);
+ return [
+ 'mutation { First { one } Second { two } }',
+ $mutation,
+ ];
+ })();
+
+ yield 'alias set in constructor' => (function () {
+ $mutation = new Mutation('Object', 'ObjectAlias');
+ $mutation->setSelectionSet(['one']);
+ return [
+ 'mutation { ObjectAlias: Object { one } }',
+ $mutation,
+ ];
+ })();
+
+ yield 'alias set after construction' => (function () {
+ $mutation = (new Mutation('Object'))
+ ->setAlias('ObjectAlias')
+ ->setSelectionSet([
+ 'one'
+ ]);
+ return [
+ 'mutation { ObjectAlias: Object { one } }',
+ $mutation,
+ ];
+ })();
+
+ yield 'operation name' => (function () {
+ $mutation = (new Mutation('Object'))
+ ->setOperationName('retrieveObject');
+
+ return [
+ 'mutation retrieveObject { Object }',
+ $mutation
+ ];
+ })();
+
+ yield 'operation name and selection set' => (function () {
+ $mutation = (new Mutation())
+ ->setOperationName('retrieveObject')
+ ->setSelectionSet([new Mutation('Object')]);
+
+ return [
+ 'mutation retrieveObject { Object }',
+ $mutation
+ ];
+ })();
+
+ yield 'nested operation name has no effect' => [
+ 'mutation retrieveObject { Object { Nested } }',
+ (new Mutation('Object'))
+ ->setOperationName('retrieveObject')
+ ->setSelectionSet([
+ (new Mutation('Nested'))
+ ->setOperationName('opName')
+ ])
+ ];
+
+ yield 'mutation with one variable' => [
+ 'mutation( $var: String ) { Object }',
+ (new Mutation('Object'))
+ ->setVariables([new Variable('var', 'String')])
+ ];
+
+ yield 'mutation with two variables' => [
+ 'mutation( $var: String $intVar: Int=4 ) { Object }',
+ (new Mutation('Object'))
+ ->setVariables([
+ new Variable('var', 'String'),
+ new Variable('intVar', 'Int', false, 4)
+ ])
+ ];
+
+ yield 'setting variables a second time overwrites the first set' => [
+ 'mutation( $secondString: String $secondInt: Int=4 ) { Object }',
+ (new Mutation('Object'))
+ ->setVariables([
+ new Variable('firstString', 'String'),
+ new Variable('firstInt', 'Int', false, 4)
+ ])
+ ->setVariables([
+ new Variable('secondString', 'String'),
+ new Variable('secondInt', 'Int', false, 4)
+ ])
+ ];
+
+ yield 'operation name and variables' => [
+ 'mutation retrieveObject( $var: String ) { Object }',
+ (new Mutation('Object'))
+ ->setOperationName('retrieveObject')
+ ->setVariables([new Variable('var', 'String')]),
+ ];
+
+ yield 'bool argument' => [
+ 'mutation { Object(boolArg: true) }',
+ (new Mutation('Object'))->setArguments(['boolArg' => true]),
+ ];
+
+ yield 'float argument' => [
+ 'mutation { Object(floatArg: 3.14) }',
+ (new Mutation('Object'))->setArguments(['floatArg' => 3.14]),
+ ];
+
+ yield 'int argument' => [
+ 'mutation { Object(intArg: 34) }',
+ (new Mutation('Object'))->setArguments(['intArg' => 34]),
+ ];
+
+ yield 'string argument' => [
+ 'mutation { Object(stringArg: "hello world") }',
+ (new Mutation('Object'))->setArguments(['stringArg' => 'hello world']),
+ ];
+
+ yield 'null argument' => [
+ 'mutation { Object(nullArg: null) }',
+ (new Mutation('Object'))->setArguments(['nullArg' => null]),
+ ];
+
+ yield 'int list argument' => [
+ 'mutation { Object(intListArg: [1, 2, 3]) }',
+ (new Mutation('Object'))->setArguments(['intListArg' => [1, 2, 3]]),
+ ];
+
+ yield 'string list argument' => [
+ 'mutation { Object(stringListArg: ["hello", "world"]) }',
+ (new Mutation('Object'))
+ ->setArguments(['stringListArg' => ['hello', 'world']]),
+ ];
+
+ yield 'json object argument' => [
+ 'mutation { Object(obj: {json_string_array: ["json value"]}) }',
+ (new Mutation('Object'))
+ ->setArguments(['obj' => new RawObject('{json_string_array: ["json value"]}')]),
+ ];
+
+ yield 'multiple arguments' => [
+ "mutation { Object(arg1: \"val1\" arg2: 2 arg3: true) }",
+ (new Mutation('Object'))
+ ->setArguments(['arg1' => 'val1', 'arg2' => 2, 'arg3' => true]),
+ ];
+
+ yield 'it overwrites previous set selection set' => [
+ 'mutation { Object { field2 field3 } }',
+ (new Mutation('Object'))
+ ->setSelectionSet(['field1'])
+ ->setSelectionSet(['field2', 'field3']),
+ ];
+
+ yield 'nested mutation' => [
+ "mutation { Object { field1 field2 Object2 { field3 } } }",
+ (new Mutation('Object'))
+ ->setSelectionSet([
+ 'field1',
+ 'field2',
+ (new Mutation('Object2'))
+ ->setSelectionSet(['field3'])
+ ])
+ ];
+
+ yield 'nested inline fragment' => [
+ 'mutation { Object { field1 ... on Object { fragment_field1 fragment_field2 } } }',
+ (new Mutation('Object'))
+ ->setSelectionSet([
+ 'field1',
+ (new InlineFragment('Object'))
+ ->setSelectionSet(
+ [
+ 'fragment_field1',
+ 'fragment_field2',
+ ]
+ ),
+ ]),
+ ];
+ }
+
+ #[Test]
+ public function testMutationWithoutOperationType(): void
+ {
+ $mutation = new Mutation('createObject');
+
+ $this->assertEquals(
+ 'mutation { createObject }',
+ (string) $mutation
+ );
+ }
+
+ #[Test]
+ public function testMutationWithOperationType(): void
+ {
+ $mutation = new Mutation();
+ $mutation
+ ->setSelectionSet(
+ [
+ (new Mutation('createObject'))
+ ->setArguments(['name' => 'TestObject'])
+ ]
+ );
+
+ $this->assertEquals(
+ 'mutation { createObject(name: "TestObject") }',
+ (string) $mutation
+ );
+ }
+
+ #[Test]
+ public function testMutationWithoutSelectedFields(): void
+ {
+ $mutation = (new Mutation('createObject'))
+ ->setArguments(['name' => 'TestObject', 'type' => 'TestType']);
+ $this->assertEquals(
+ 'mutation { createObject(name: "TestObject" type: "TestType") }',
+ (string) $mutation
+ );
+ }
+
+ #[Test]
+ public function testMutationWithFields(): void
+ {
+ $mutation = (new Mutation('createObject'))
+ ->setSelectionSet(
+ [
+ 'fieldOne',
+ 'fieldTwo',
+ ]
+ );
+
+ $this->assertEquals(
+ 'mutation { createObject { fieldOne fieldTwo } }',
+ (string) $mutation
+ );
+ }
+
+ #[Test]
+ public function testMutationWithArgumentsAndFields(): void
+ {
+ $mutation = (new Mutation('createObject'))
+ ->setSelectionSet(
+ [
+ 'fieldOne',
+ 'fieldTwo',
+ ]
+ )->setArguments(
+ [
+ 'argOne' => 1,
+ 'argTwo' => 'val'
+ ]
+ );
+
+ $this->assertEquals(
+ 'mutation { createObject(argOne: 1 argTwo: "val") { fieldOne fieldTwo } }',
+ (string) $mutation
+ );
+ }
+}
diff --git a/tests/Unit/QueryBuilder/MutationBuilderTest.php b/tests/Unit/QueryBuilder/MutationBuilderTest.php
new file mode 100644
index 0000000..25f19bc
--- /dev/null
+++ b/tests/Unit/QueryBuilder/MutationBuilderTest.php
@@ -0,0 +1,162 @@
+selectField(
+ (new MutationBuilder('Object'))
+ ->selectField('one')
+ )
+ ->selectField(
+ (new MutationBuilder('Another'))
+ ->selectField('two')
+ );
+
+ $this->assertEquals(
+ 'mutation { Object { one } Another { two } }',
+ (string) $builder->getMutation()
+ );
+ }
+
+
+ /**
+ * @param array $selectionSet
+ * @param Variable[] $variables
+ * @param array $arguments
+ */
+ #[Test]
+ #[DataProvider('provideDataToBuildMutation')]
+ public function itBuildsQueries(
+ string $name,
+ string $alias = '',
+ array $selectionSet = [],
+ array $variables = [],
+ array $arguments = [],
+ ): void {
+ $expected = (new Mutation($name, $alias))
+ ->setSelectionSet($selectionSet)
+ ->setVariables($variables)
+ ->setArguments($arguments);
+
+ $sut = new MutationBuilder($name, $alias);
+
+ foreach ($selectionSet as $selection) {
+ $sut->selectField($selection);
+ }
+
+ foreach ($variables as $variable) {
+ $sut->setVariable(
+ $variable->name,
+ $variable->type,
+ $variable->nonNullable,
+ $variable->defaultValue,
+ );
+ }
+
+ foreach ($arguments as $argumentName => $argumentValue) {
+ $sut->setArgument($argumentName, $argumentValue);
+ }
+
+ self::assertEquals($expected, $sut->getMutation());
+ }
+
+ /** @return \Generator,
+ * 3?: Variable[],
+ * 4?: array,
+ * }>
+ */
+ public static function provideDataToBuildMutation(): \Generator
+ {
+ yield 'minimal mutation' => ['Test'];
+
+ yield 'alias' => ['Test', 'Test_Alias'];
+
+ yield 'one selection' => ['One_Selection', '', ['first']];
+
+ yield 'three selections' => [
+ 'three_selections',
+ '',
+ ['first', 'second', 'third'],
+ ];
+
+ yield sprintf('%s selection', InlineFragment::class) => [
+ 'WithInlineFragmentSelection',
+ '',
+ [(new InlineFragment('Nested'))->setSelectionSet(['field'])],
+ ];
+
+ yield sprintf('%s selection', Mutation::class) => [
+ 'WithMutationSelection',
+ '',
+ [(new Mutation('Nested'))->setSelectionSet(['some_field'])],
+ ];
+
+ yield sprintf('%s selection', MutationBuilder::class) => [
+ 'WithMutationBuilderSelection',
+ '',
+ [(new MutationBuilder('Nested'))->selectField('fieldTwo')],
+ ];
+
+ yield 'one variable' => [
+ 'one_variable',
+ '',
+ [],
+ [new Variable('first_var', 'String', true, 'default string')],
+ ];
+
+ yield 'three variables' => [
+ 'ThreeVariables',
+ '',
+ [],
+ [
+ new Variable('first_var', 'String', true, 'default string'),
+ new Variable('second_var', 'Int', true, 5),
+ new Variable('third_var', 'Array', true, [1, 2, 4]),
+ ],
+ ];
+
+ yield 'one argument' => [
+ 'one_argument',
+ '',
+ [],
+ [],
+ ['string_argument' => 'value']
+ ];
+
+ yield 'three arguments' => [
+ 'Three_Arguments',
+ '',
+ [],
+ [],
+ [
+ 'string_argument' => 'value',
+ 'int_argument' => 1,
+ 'object_argument' => new RawObject('{field_not: "x"}'),
+ ]
+ ];
+ }
+}
diff --git a/tests/Unit/QueryBuilder/QueryBuilderTest.php b/tests/Unit/QueryBuilder/QueryBuilderTest.php
new file mode 100644
index 0000000..f879be0
--- /dev/null
+++ b/tests/Unit/QueryBuilder/QueryBuilderTest.php
@@ -0,0 +1,206 @@
+setArgument('name', 'test')
+ ->setArgument('description', 'pipeline description')
+ ->setArgument('labels', [new RawObject('{distribution: alpine}')]);
+ $queryStack[] = $pipeline;
+
+ $container = (new QueryBuilder('container'));
+ $queryStack[] = $container;
+
+
+ $from = (new QueryBuilder('from'))
+ ->setArgument('address', 'alpine:3.16.2');
+ $queryStack[] = $from;
+
+ $withExec = (new QueryBuilder('withExec'))
+ ->setArgument('args', ['cat', '/etc/alpine-release']);
+ $queryStack[] = $withExec;
+
+ $queryStack[] = new QueryBuilder('stdout');
+
+ foreach ($queryStack as $queryBuilder) {
+ $rootQb = $rootQb->selectField($queryBuilder);
+ }
+
+ self::assertSame(
+ 'query { pipeline' .
+ '(' .
+ 'name: "test" ' .
+ 'description: "pipeline description" ' .
+ 'labels: [{distribution: alpine}]' .
+ ') ' .
+ 'container ' .
+ 'from(address: "alpine:3.16.2") ' .
+ 'withExec(args: ["cat", "/etc/alpine-release"]) ' .
+ 'stdout }',
+ (string) $rootQb->getQuery()
+ );
+ }
+
+ #[Test]
+ public function itCanBuildQueryWithoutName(): void
+ {
+ $builder = (new QueryBuilder())
+ ->selectField(
+ (new QueryBuilder('Object'))
+ ->selectField('one')
+ )
+ ->selectField(
+ (new QueryBuilder('Another'))
+ ->selectField('two')
+ );
+
+ $this->assertEquals(
+ 'query { Object { one } Another { two } }',
+ (string) $builder->getQuery()
+ );
+ }
+
+
+ /**
+ * @param array $selectionSet
+ * @param Variable[] $variables
+ * @param array $arguments
+ */
+ #[Test]
+ #[DataProvider('provideDataToBuildQuery')]
+ public function itBuildsQueries(
+ string $name,
+ string $alias = '',
+ array $selectionSet = [],
+ array $variables = [],
+ array $arguments = [],
+ ): void {
+ $expected = (new Query($name, $alias))
+ ->setSelectionSet($selectionSet)
+ ->setVariables($variables)
+ ->setArguments($arguments);
+
+ $sut = new QueryBuilder($name, $alias);
+
+ foreach ($selectionSet as $selection) {
+ $sut->selectField($selection);
+ }
+
+ foreach ($variables as $variable) {
+ $sut->setVariable(
+ $variable->name,
+ $variable->type,
+ $variable->nonNullable,
+ $variable->defaultValue,
+ );
+ }
+
+ foreach ($arguments as $argumentName => $argumentValue) {
+ $sut->setArgument($argumentName, $argumentValue);
+ }
+
+ self::assertEquals($expected, $sut->getQuery());
+ }
+
+ /** @return \Generator,
+ * 3?: Variable[],
+ * 4?: array,
+ * }>
+ */
+ public static function provideDataToBuildQuery(): \Generator
+ {
+ yield 'minimal query' => ['Test'];
+
+ yield 'alias' => ['Test', 'Test_Alias'];
+
+ yield 'one selection' => ['One_Selection', '', ['first']];
+
+ yield 'three selections' => [
+ 'three_selections',
+ '',
+ ['first', 'second', 'third'],
+ ];
+
+ yield sprintf('%s selection', InlineFragment::class) => [
+ 'WithInlineFragmentSelection',
+ '',
+ [(new InlineFragment('Nested'))->setSelectionSet(['field'])],
+ ];
+
+ yield sprintf('%s selection', Query::class) => [
+ 'WithQuerySelection',
+ '',
+ [(new Query('Nested'))->setSelectionSet(['some_field'])],
+ ];
+
+ yield sprintf('%s selection', QueryBuilder::class) => [
+ 'WithQueryBuilderSelection',
+ '',
+ [(new QueryBuilder('Nested'))->selectField('fieldTwo')],
+ ];
+
+ yield 'one variable' => [
+ 'one_variable',
+ '',
+ [],
+ [new Variable('first_var', 'String', true, 'default string')],
+ ];
+
+ yield 'three variables' => [
+ 'ThreeVariables',
+ '',
+ [],
+ [
+ new Variable('first_var', 'String', true, 'default string'),
+ new Variable('second_var', 'Int', true, 5),
+ new Variable('third_var', 'Array', true, [1, 2, 4]),
+ ],
+ ];
+
+ yield 'one argument' => [
+ 'one_argument',
+ '',
+ [],
+ [],
+ ['string_argument' => 'value']
+ ];
+
+ yield 'three arguments' => [
+ 'Three_Arguments',
+ '',
+ [],
+ [],
+ [
+ 'string_argument' => 'value',
+ 'int_argument' => 1,
+ 'object_argument' => new RawObject('{field_not: "x"}'),
+ ]
+ ];
+ }
+}
diff --git a/tests/Unit/QueryTest.php b/tests/Unit/QueryTest.php
new file mode 100644
index 0000000..9c85d04
--- /dev/null
+++ b/tests/Unit/QueryTest.php
@@ -0,0 +1,383 @@
+setVariables(['one', 'two']);
+ }
+
+ #[Test]
+ #[TestDox('setArguments() MUST receive an array with string keys')]
+ public function itCannotSetArgumentsFromList(): void
+ {
+ $sut = new Query('Object');
+
+ self::expectException(ArgumentException::class);
+
+ $sut->setArguments(['val']);
+ }
+
+ #[Test]
+ public function itGetsArguments(): void
+ {
+ $arguments = ['someField' => 'someValue'];
+ $sut = (new Query('things'))->setArguments($arguments);
+
+ self::assertSame($arguments, $sut->getArguments());
+ }
+
+
+ /** @param array $arguments */
+ #[Test, DataProvider('provideInvalidArguments')]
+ public function itInvalidatesUnsupportedArguments(array $arguments): void
+ {
+ $sut = new Query();
+
+ self::expectException(ArgumentException::class);
+
+ $sut->setArguments($arguments);
+ }
+
+ #[Test]
+ #[DataProvider('provideQueriesToCastToString')]
+ public function itIsStringable(string $expected, Query $sut): void
+ {
+ self::assertSame($expected, $sut->__toString());
+ }
+
+ /** @return Generator }> */
+ public static function provideInvalidArguments(): Generator
+ {
+ yield \DateTime::class => [[new \DateTime()]];
+
+ yield sprintf('nested array of %s', \DateTime::class) => [
+ [[[[new \DateTime()]]]],
+ ];
+ }
+
+ /** @return Generator */
+ public static function provideQueriesToCastToString(): Generator
+ {
+ yield 'empty query' => ['query', new Query()];
+
+ yield 'without fieldName' => (function () {
+ $query = new Query();
+ $query->setSelectionSet([
+ (new Query('First'))->setSelectionSet(['one']),
+ (new Query('Second'))->setSelectionSet(['two'])
+ ]);
+ return [
+ 'query { First { one } Second { two } }',
+ $query,
+ ];
+ })();
+
+ yield 'alias set in constructor' => (function () {
+ $query = new Query('Object', 'ObjectAlias');
+ $query->setSelectionSet(['one']);
+ return [
+ 'query { ObjectAlias: Object { one } }',
+ $query,
+ ];
+ })();
+
+ yield 'alias set after construction' => (function () {
+ $query = (new Query('Object'))
+ ->setAlias('ObjectAlias')
+ ->setSelectionSet([
+ 'one'
+ ]);
+ return [
+ 'query { ObjectAlias: Object { one } }',
+ $query,
+ ];
+ })();
+
+ yield 'operation name' => (function () {
+ $query = (new Query('Object'))
+ ->setOperationName('retrieveObject');
+
+ return [
+ 'query retrieveObject { Object }',
+ $query
+ ];
+ })();
+
+ yield 'operation name and selection set' => (function () {
+ $query = (new Query())
+ ->setOperationName('retrieveObject')
+ ->setSelectionSet([new Query('Object')]);
+
+ return [
+ 'query retrieveObject { Object }',
+ $query
+ ];
+ })();
+
+ yield 'nested operation name has no effect' => [
+ 'query retrieveObject { Object { Nested } }',
+ (new Query('Object'))
+ ->setOperationName('retrieveObject')
+ ->setSelectionSet([
+ (new Query('Nested'))
+ ->setOperationName('opName')
+ ])
+ ];
+
+ yield 'query with one variable' => [
+ 'query( $var: String ) { Object }',
+ (new Query('Object'))
+ ->setVariables([new Variable('var', 'String')])
+ ];
+
+ yield 'query with two variables' => [
+ 'query( $var: String $intVar: Int=4 ) { Object }',
+ (new Query('Object'))
+ ->setVariables([
+ new Variable('var', 'String'),
+ new Variable('intVar', 'Int', false, 4)
+ ])
+ ];
+
+ yield 'setting variables a second time overwrites the first set' => [
+ 'query( $secondString: String $secondInt: Int=4 ) { Object }',
+ (new Query('Object'))
+ ->setVariables([
+ new Variable('firstString', 'String'),
+ new Variable('firstInt', 'Int', false, 4)
+ ])
+ ->setVariables([
+ new Variable('secondString', 'String'),
+ new Variable('secondInt', 'Int', false, 4)
+ ])
+ ];
+
+ yield 'operation name and variables' => [
+ 'query retrieveObject( $var: String ) { Object }',
+ (new Query('Object'))
+ ->setOperationName('retrieveObject')
+ ->setVariables([new Variable('var', 'String')]),
+ ];
+
+ yield 'bool argument' => [
+ 'query { Object(boolArg: true) }',
+ (new Query('Object'))->setArguments(['boolArg' => true]),
+ ];
+
+ yield 'float argument' => [
+ 'query { Object(floatArg: 3.14) }',
+ (new Query('Object'))->setArguments(['floatArg' => 3.14]),
+ ];
+
+ yield 'int argument' => [
+ 'query { Object(intArg: 34) }',
+ (new Query('Object'))->setArguments(['intArg' => 34]),
+ ];
+
+ yield 'string argument' => [
+ 'query { Object(stringArg: "hello world") }',
+ (new Query('Object'))->setArguments(['stringArg' => 'hello world']),
+ ];
+
+ yield 'null argument' => [
+ 'query { Object(nullArg: null) }',
+ (new Query('Object'))->setArguments(['nullArg' => null]),
+ ];
+
+ yield 'int list argument' => [
+ 'query { Object(intListArg: [1, 2, 3]) }',
+ (new Query('Object'))->setArguments(['intListArg' => [1, 2, 3]]),
+ ];
+
+ yield 'string list argument' => [
+ 'query { Object(stringListArg: ["hello", "world"]) }',
+ (new Query('Object'))
+ ->setArguments(['stringListArg' => ['hello', 'world']]),
+ ];
+
+ yield 'nested list argument' => [
+ 'query { Object(nestedListArg: [[["hello", "world"]]]) }',
+ (new Query('Object'))
+ ->setArguments(['nestedListArg' => [[['hello', 'world']]]]),
+ ];
+
+ yield 'nested list of BackedEnums argument' => [
+ 'query { Object(nestedEnumArg: [[[query, mutation, subscription]]]) }',
+ (new Query('Object'))
+ ->setArguments(['nestedEnumArg' => [[[
+ OperationType::Query,
+ OperationType::Mutation,
+ OperationType::Subscription,
+ ]]]]),
+ ];
+
+ yield 'json object argument' => [
+ 'query { Object(obj: {json_string_array: ["json value"]}) }',
+ (new Query('Object'))
+ ->setArguments(['obj' => new RawObject('{json_string_array: ["json value"]}')]),
+ ];
+
+ yield 'multiple arguments' => [
+ "query { Object(arg1: \"val1\" arg2: 2 arg3: true) }",
+ (new Query('Object'))
+ ->setArguments(['arg1' => 'val1', 'arg2' => 2, 'arg3' => true]),
+ ];
+ }
+
+ #[Test]
+ public function itOverwritesPreviousSelectionSets()
+ {
+ $query = (new Query('Object'))
+ ->setSelectionSet(['field1'])
+ ->setSelectionSet(['field2', 'field3']);
+ $this->assertEquals(
+ 'query { Object { field2 field3 } }',
+ (string) $query,
+ 'Query has improperly formatted selection set'
+ );
+
+ return $query;
+ }
+
+ public function testTwoLevelQuery()
+ {
+ $query = (new Query('Object'))
+ ->setSelectionSet([
+ 'field1',
+ 'field2',
+ (new Query('Object2'))
+ ->setSelectionSet(['field3'])
+ ]);
+ $this->assertEquals(
+ "query { Object { field1 field2 Object2 { field3 } } }",
+ (string) $query,
+ 'Two level query not formatted correctly'
+ );
+
+ return $query;
+ }
+
+ public function testTwoLevelQueryWithInlineFragment()
+ {
+ $query = (new Query('Object'))
+ ->setSelectionSet([
+ 'field1',
+ (new InlineFragment('Object'))
+ ->setSelectionSet(
+ [
+ 'fragment_field1',
+ 'fragment_field2',
+ ]
+ ),
+ ]);
+ $this->assertEquals(
+ 'query { Object { field1 ... on Object { fragment_field1 fragment_field2 } } }',
+ (string) $query
+ );
+
+ return $query;
+ }
+
+ public function testGettingArguments()
+ {
+ $gql = (new Query('things'))
+ ->setArguments(
+ [
+ 'someClientId' => 'someValueBasedOnCodebase'
+ ]
+ );
+ $cursor_id = 'someCursor';
+ $new_args = $gql->getArguments();
+ $gql->setArguments(
+ array_merge(
+ $new_args,
+ [
+ 'after' => $cursor_id
+ ]
+ )
+ );
+ self::assertEquals(
+ 'query { things(someClientId: "someValueBasedOnCodebase" after: "someCursor") }',
+ (string) $gql
+ );
+ }
+
+ public function testGettingNameAndAltering()
+ {
+ $gql = (new Query('things'))
+ ->setSelectionSet(
+ [
+ 'id',
+ 'name',
+ (new Query('subThings'))
+ ->setArguments(
+ [
+ 'filter' => 'providerId123',
+ ]
+ )
+ ->setSelectionSet(
+ [
+ 'id',
+ 'name'
+ ]
+ )
+ ]
+ );
+ $sets = $gql->getSelectionSet();
+ foreach ($sets as $set) {
+ if (($set instanceof Query) === false) {
+ continue;
+ }
+ $name = $set->getFieldName();
+ if ($name !== 'subThings') {
+ continue;
+ }
+ $set->setArguments(
+ [
+ 'filter' => 'providerId456'
+ ]
+ );
+ $set->setSelectionSet(
+ array_merge(
+ $set->getSelectionSet(),
+ [
+ 'someField',
+ 'someOtherField'
+ ]
+ )
+ );
+ }
+ self::assertEquals(
+ 'query { things { id name subThings(filter: "providerId456") { id name someField someOtherField } } }',
+ (string) $gql
+ );
+ }
+}
diff --git a/tests/Unit/RawObjectTest.php b/tests/Unit/RawObjectTest.php
new file mode 100644
index 0000000..5e0db71
--- /dev/null
+++ b/tests/Unit/RawObjectTest.php
@@ -0,0 +1,36 @@
+ */
+ public static function provideJson(): \Generator
+ {
+ yield 'array' => [
+ '[1, 4, "y", 6.7]',
+ ];
+
+ yield 'object' => [
+ '{arr: [1, "z"], str: "val", int: 1, obj: {x: "y"}}',
+ ];
+ }
+}
diff --git a/tests/Unit/ResultsTest.php b/tests/Unit/ResultsTest.php
new file mode 100644
index 0000000..d3969c7
--- /dev/null
+++ b/tests/Unit/ResultsTest.php
@@ -0,0 +1,206 @@
+ [
+ [
+ 'message' => 'some syntax error',
+ 'location' => [
+ [
+ 'line' => 1,
+ 'column' => 3,
+ ]
+ ],
+ ]
+ ]
+ ]));
+
+ $this->expectException(QueryError::class);
+
+ new Results($response);
+ }
+
+ /**
+ * @param array{data:array>} $body
+ */
+ #[Test]
+ #[DataProvider('provideResponses')]
+ public function itGetsResponses(array $body): void
+ {
+ $response = new Response(200, [], json_encode($body));
+ $results = new Results($response);
+
+ self::assertEquals($response, $results->getResponseObject());
+ }
+
+ /**
+ * @param array{data:array>} $body
+ */
+ #[Test]
+ #[DataProvider('provideResponses')]
+ public function itGetsResponseBodies(array $body): void
+ {
+ $response = new Response(200, [], json_encode($body));
+ $results = new Results($response);
+
+ self::assertEquals($response->getBody(), $results->getResponseBody());
+ }
+
+ /**
+ * @param array{data:array>} $body
+ */
+ #[Test]
+ #[DataProvider('provideResponses')]
+ public function itGetsResults(array $body): void
+ {
+ $response = new Response(200, [], json_encode($body));
+ $results = new Results($response);
+
+ self::assertEquals(json_decode(json_encode($body)), $results->getResults());
+ }
+
+ /**
+ * @param array{data:array>} $body
+ */
+ #[Test]
+ #[DataProvider('provideResponses')]
+ public function itGetsResponseData(array $body): void
+ {
+ $response = new Response(200, [], json_encode($body));
+ $results = new Results($response);
+
+ self::assertEquals(json_decode(json_encode($body['data']), false), $results->getData());
+ }
+
+ /**
+ * @return \Generator>
+ * }}>
+ */
+ public static function provideResponses(): \Generator
+ {
+ yield 'one field' => [['data' => [
+ 'firstField' => [['data' => 'firstValue']]
+ ]]];
+
+ yield 'two fields' => [['data' => [
+ 'firstField' => [['data' => 'firstValue']],
+ 'secondField' => [['data' => 'secondValue']],
+ ]]];
+
+ yield 'one field, two values' => [['data' => [
+ 'firstField' => [
+ ['data' => 'firstValue'],
+ ['data' => 'secondValue']
+ ],
+ ]]];
+ }
+
+ // #[Test]
+ // public function testReformatResultsFromObjectToArray()
+ // {
+ // $body = json_encode([
+ // 'data' => [
+ // 'someField' => [
+ // [
+ // 'data' => 'value',
+ // ],
+ // [
+ // 'data' => 'value',
+ // ]
+ // ]
+ // ]
+ // ]);
+ // $originalResponse = new Response(200, [], $body);
+ // $this->mockHandler->append($originalResponse);
+
+ // $response = $this->client->post('', []);
+ // $results = new Results($response);
+ // $results->reformatResults(true);
+
+ // $this->assertEquals(
+ // [
+ // 'data' => [
+ // 'someField' => [
+ // [
+ // 'data' => 'value',
+ // ],
+ // [
+ // 'data' => 'value',
+ // ]
+ // ]
+ // ]
+ // ],
+ // $results->getResults()
+ // );
+ // $this->assertEquals(
+ // [
+ // 'someField' => [
+ // [
+ // 'data' => 'value',
+ // ],
+ // [
+ // 'data' => 'value',
+ // ]
+ // ]
+ // ],
+ // $results->getData()
+ // );
+ // }
+
+ // #[Test]
+ // public function testReformatResultsFromArrayToObject(): void
+ // {
+// $body = json_encode([
+// 'data' => [
+// 'someField' => [
+// [
+// 'data' => 'value',
+// ],
+// [
+// 'data' => 'value',
+// ]
+// ]
+// ]
+// ]);
+// $originalResponse = new Response(200, [], $body);
+// $this->mockHandler->append($originalResponse);
+//
+// $response = $this->client->post('', []);
+// $results = new Results($response, true);
+// $results->reformatResults(false);
+//
+// $object = new stdClass();
+// $object->data = new stdClass();
+// $object->data->someField = [];
+// $object->data->someField[] = new stdClass();
+// $object->data->someField[] = new stdClass();
+// $object->data->someField[0]->data = 'value';
+// $object->data->someField[1]->data = 'value';
+ // self::assertEquals(
+ // $object,
+ // $results->getResults()
+ // );
+ // self::assertEquals(
+ // $object->data,
+ // $results->getData()
+ // );
+ // }
+}
diff --git a/tests/Unit/Util/StringLiteralFormatterTest.php b/tests/Unit/Util/StringLiteralFormatterTest.php
new file mode 100644
index 0000000..8de49fe
--- /dev/null
+++ b/tests/Unit/Util/StringLiteralFormatterTest.php
@@ -0,0 +1,217 @@
+ $array
+ */
+ #[Test]
+ #[DataProvider('provideArraysToFormatForGQLQueries')]
+ public function itFormatsArraysForGQLQueries(
+ string $expected,
+ array $array,
+ ): void {
+ $actual = StringLiteralFormatter::formatArrayForGQLQuery($array);
+
+ self::assertSame($expected, $actual);
+ }
+
+ #[Test]
+ #[DataProvider('provideStringsToFormatToUpperCamelCase')]
+ public function itFormatsSnakeCaseToUpperCamelCase(
+ string $expected,
+ string $stringToFormat,
+ ): void {
+ $actual = StringLiteralFormatter::formatUpperCamelCase($stringToFormat);
+
+ self::assertSame($expected, $actual);
+ }
+
+ #[Test]
+ #[DataProvider('provideStringsToFormatToLowerCamelCase')]
+ public function itFormatsStringsToLowerCamelCase(
+ string $expected,
+ string $stringToFormat,
+ ): void {
+ $actual = StringLiteralFormatter::formatLowerCamelCase($stringToFormat);
+
+ self::assertSame($expected, $actual);
+ }
+
+ /** @return Generator */
+ public static function provideValuesToFormatForRHS(): Generator
+ {
+ yield 'null' => ['null', null];
+
+ yield 'empty string' => ['""', ''];
+ yield 'non-empty string' => ['"someString"', 'someString'];
+ yield 'unescaped double quotes in string' => [
+ '"\"quotedString\""',
+ '"quotedString"',
+ ];
+ yield 'escaped double quotes in string' => [
+ '"\\\\\"quotedString\\\\\""',
+ '\\"quotedString\\"',
+ ];
+
+ yield 'escaped double quoted string in html' => [
+ '""',
+ '',
+
+ ];
+
+ yield 'unescaped single quotes in string' => [
+ '"\'singleQuotes\'"',
+ "'singleQuotes'",
+ ];
+
+ yield 'escaped single quotes in string' => [
+ '"\\\\\'singleQuotes\\\\\'"',
+ "\\'singleQuotes\\'",
+ ];
+
+ yield 'string with newlines' => [
+ "\"\"\"with \n newlines\"\"\"",
+ "with \n newlines",
+ ];
+
+ yield 'string variable name' => ['$var', '$var'];
+
+ yield 'string starts with $ but not a variable' => ['"$400"', '$400'];
+
+ yield 'integer 0' => ['0', 0];
+
+ yield 'integer 25' => ['25', 25];
+
+ yield 'float' => ['3.14', 3.14];
+
+ yield 'bool false' => ['false', false];
+
+ yield 'bool true' => ['true', true];
+
+ yield RawObject::class => [
+ '["one", "two", "three"]',
+ new RawObject('["one", "two", "three"]'),
+ ];
+
+ yield Stringable::class => [
+ 'Hello World',
+ new class () implements Stringable {
+ public function __toString(): string
+ {
+ return 'Hello World';
+ }
+ }
+ ];
+
+ yield BackedEnum::class => ['query', OperationType::Query];
+ }
+
+ /** @return Generator }> */
+ public static function provideArraysToFormatForGQLQueries(): Generator
+ {
+ yield 'empty' => ['[]', []];
+
+ yield 'one float' => ['[3.14]', [3.14]];
+ yield 'three floats' => ['[3.14, 9.81, 1.67]', [3.14, 9.81, 1.67]];
+
+ yield 'one integer' => ['[1]', [1]];
+ yield 'three integers' => ['[1, 2, 3]', [1, 2, 3]];
+
+ yield 'one string' => ['["one"]', ['one']];
+ yield 'three strings' => [
+ '["one", "two", "three"]',
+ ['one', 'two', 'three'],
+ ];
+
+ yield 'one bool' => ['[true]', [true]];
+ yield 'three bools' => ['[true, false, true]', [true, false, true]];
+
+ yield 'nested string array' => ['[["one"]]', [['one']]];
+ yield 'nested string arrays' => [
+ '[["one"], ["two"], ["three"]]',
+ [['one'], ['two'], ['three']],
+ ];
+ yield 'nested strings array' => [
+ '[["one", "two", "three"]]',
+ [['one', 'two', 'three']],
+ ];
+ yield 'nested strings arrays' => [
+ '[["one", "two", "three"], ["four", "five", "six"], ["seven", "eight", "nine"]]',
+ [['one', 'two', 'three'], ['four', 'five', 'six'], ['seven', 'eight', 'nine']],
+ ];
+
+ yield sprintf('nested %s array', BackedEnum::class) => [
+ '[[query], [mutation, subscription]]',
+ [
+ [OperationType::Query],
+ [OperationType::Mutation, OperationType::Subscription],
+ ]
+ ];
+ }
+
+ /** @return Generator */
+ public static function provideStringsToFormatToUpperCamelCase(): Generator
+ {
+ yield 'some_snake_case' => [
+ 'SomeSnakeCase',
+ 'some_snake_case',
+ ];
+
+ yield 'lowerCamelCase' => [
+ 'LowerCamelCase',
+ 'lowerCamelCase',
+ ];
+
+ yield 'UpperCamelCase' => [
+ 'UpperCamelCase',
+ 'UpperCamelCase',
+ ];
+ }
+
+ /** @return Generator */
+ public static function provideStringsToFormatToLowerCamelCase(): Generator
+ {
+ yield 'some_snake_case' => [
+ 'someSnakeCase',
+ 'some_snake_case',
+ ];
+
+ yield 'lowerCamelCase' => [
+ 'lowerCamelCase',
+ 'lowerCamelCase',
+ ];
+
+ yield 'UpperCamelCase' => [
+ 'upperCamelCase',
+ 'UpperCamelCase',
+ ];
+ }
+}
diff --git a/tests/Unit/VariableTest.php b/tests/Unit/VariableTest.php
new file mode 100644
index 0000000..881ab76
--- /dev/null
+++ b/tests/Unit/VariableTest.php
@@ -0,0 +1,87 @@
+ */
+ public static function provideVariables(): Generator
+ {
+ yield 'nullable string' => [
+ '$nullableString: String',
+ new Variable('nullableString', 'String'),
+ ];
+
+ yield 'nullable string with default' => [
+ '$nullableString: String="default"',
+ new Variable('nullableString', 'String', false, 'default'),
+ ];
+
+ yield 'non-nullable string' => [
+ '$nonNullableString: String!',
+ new Variable('nonNullableString', 'String', true),
+ ];
+
+ yield 'non-nullable string with default' => [
+ '$nonNullableString: String!="default"',
+ new Variable('nonNullableString', 'String', true, 'default'),
+ ];
+
+ yield 'nullable int' => [
+ '$nullableInt: Int',
+ new Variable('nullableInt', 'Int', false),
+ ];
+
+ yield 'nullable int with default' => [
+ '$nullableInt: Int=4',
+ new Variable('nullableInt', 'Int', false, 4),
+ ];
+
+ yield 'nullable string with a numeric-string default' => [
+ '$nullableString: String="4"',
+ new Variable('nullableString', 'String', false, '4'),
+ ];
+
+ yield 'nullable bool with default true' => [
+ '$nullableBool: Boolean=true',
+ new Variable('nullableBool', 'Boolean', false, true),
+ ];
+
+ yield 'nullable bool with default false' => [
+ '$nullableBool: Boolean=false',
+ new Variable('nullableBool', 'Boolean', false, false),
+ ];
+
+ yield 'nullable string with a bool-string default' => [
+ '$nullableString: String="true"',
+ new Variable('nullableString', 'String', false, 'true'),
+ ];
+
+ yield 'nullable int list' => [
+ '$nullableIntList: [Int]',
+ new Variable('nullableIntList', '[Int]', false, null)
+ ];
+
+ yield 'non-nullable int list, default empty array' => [
+ '$nonNullableIntList: [Int]!=[]',
+ new Variable('nonNullableIntList', '[Int]', true, [])
+ ];
+ }
+}
diff --git a/tests/VariableTest.php b/tests/VariableTest.php
deleted file mode 100644
index 6100e30..0000000
--- a/tests/VariableTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-assertEquals('$var: String', (string) $variable);
- }
-
- /**
- * @depends testCreateVariable
- *
- * @covers \GraphQL\Variable::__construct
- * @covers \GraphQL\Variable::__toString
- */
- public function testCreateRequiredVariable()
- {
- $variable = new Variable('var', 'String', true);
- $this->assertEquals('$var: String!', (string) $variable);
- }
-
- /**
- * @depends testCreateRequiredVariable
- *
- * @covers \GraphQL\Variable::__construct
- * @covers \GraphQL\Variable::__toString
- */
- public function testRequiredVariableWithDefaultValueDoesNothing()
- {
- $variable = new Variable('var', 'String', true, 'def');
- $this->assertEquals('$var: String!', (string) $variable);
- }
-
- /**
- * @depends testCreateVariable
- *
- * @covers \GraphQL\Variable::__construct
- * @covers \GraphQL\Variable::__toString
- */
- public function testOptionalVariableWithDefaultValue()
- {
- $variable = new Variable('var', 'String', false, 'def');
- $this->assertEquals('$var: String="def"', (string) $variable);
-
- $variable = new Variable('var', 'String', false, '4');
- $this->assertEquals('$var: String="4"', (string) $variable);
-
- $variable = new Variable('var', 'Int', false, 4);
- $this->assertEquals('$var: Int=4', (string) $variable);
-
- $variable = new Variable('var', 'Boolean', false, true);
- $this->assertEquals('$var: Boolean=true', (string) $variable);
- }
-}
\ No newline at end of file