Skip to content

Commit

Permalink
Merge pull request #448 from tienvx/plugin-formatter
Browse files Browse the repository at this point in the history
refactor: Add PluginFormatter
  • Loading branch information
tienvx authored Jan 23, 2024
2 parents 9b3e8c9 + 12120e2 commit 61b4f69
Show file tree
Hide file tree
Showing 44 changed files with 572 additions and 148 deletions.
10 changes: 7 additions & 3 deletions example/csv/consumer/tests/Service/HttpClientServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use CsvConsumer\Service\HttpClientService;
use PhpPact\Consumer\InteractionBuilder;
use PhpPact\Consumer\Matcher\Formatters\PluginFormatter;
use PhpPact\Consumer\Matcher\Matcher;
use PhpPact\Consumer\Model\Body\Text;
use PhpPact\Consumer\Model\ConsumerRequest;
use PhpPact\Consumer\Model\ProviderResponse;
Expand All @@ -15,6 +17,8 @@ class HttpClientServiceTest extends TestCase
{
public function testGetCsvFile(): void
{
$matcher = new Matcher(new PluginFormatter());

$request = new ConsumerRequest();
$request
->setMethod('GET')
Expand All @@ -28,9 +32,9 @@ public function testGetCsvFile(): void
->setBody(new Text(
json_encode([
'csvHeaders' => false,
'column:1' => "matching(type,'Name')",
'column:2' => 'matching(number,100)',
'column:3' => "matching(datetime, 'yyyy-MM-dd','2000-01-01')",
'column:1' => $matcher->like('Name'),
'column:2' => $matcher->number(100),
'column:3' => $matcher->datetime('yyyy-MM-dd', '2000-01-01'),
]),
'text/csv'
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace ProtobufSyncMessageConsumer\Tests;

use PhpPact\Consumer\Matcher\Formatters\PluginFormatter;
use PhpPact\Consumer\Matcher\Matcher;
use PhpPact\Consumer\Model\Body\Text;
use PhpPact\Plugins\Protobuf\Factory\ProtobufSyncMessageDriverFactory;
use PhpPact\Standalone\MockService\MockServerConfig;
Expand All @@ -15,6 +17,7 @@ class ProtobufClientTest extends TestCase
{
public function testCalculateArea(): void
{
$matcher = new Matcher(new PluginFormatter());
$protoPath = __DIR__ . '/../../library/proto/area_calculator.proto';

$config = new MockServerConfig();
Expand All @@ -38,12 +41,12 @@ public function testCalculateArea(): void

'request' => [
'rectangle' => [
'length' => 'matching(number, 3)',
'width' => 'matching(number, 4)',
'length' => $matcher->number(3),
'width' => $matcher->number(4),
],
],
'response' => [
'value' => 'matching(number, 12)',
'value' => $matcher->number(12),
]
]),
'application/grpc'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace PhpPact\Consumer\Matcher\Exception;

class MatchingExpressionException extends MatcherException
{
}
3 changes: 1 addition & 2 deletions src/PhpPact/Consumer/Matcher/Formatters/MinimalFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\FormatterInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class MinimalFormatter implements FormatterInterface
{
/**
* @return array<string, string>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
public function format(MatcherInterface $matcher): array
{
return [
'pact:matcher:type' => $matcher->getType(),
Expand Down
104 changes: 104 additions & 0 deletions src/PhpPact/Consumer/Matcher/Formatters/PluginFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Exception\GeneratorNotRequiredException;
use PhpPact\Consumer\Matcher\Exception\MatcherNotSupportedException;
use PhpPact\Consumer\Matcher\Exception\MatchingExpressionException;
use PhpPact\Consumer\Matcher\Matchers\AbstractDateTime;
use PhpPact\Consumer\Matcher\Matchers\ContentType;
use PhpPact\Consumer\Matcher\Matchers\EachKey;
use PhpPact\Consumer\Matcher\Matchers\EachValue;
use PhpPact\Consumer\Matcher\Matchers\MatchingField;
use PhpPact\Consumer\Matcher\Matchers\NotEmpty;
use PhpPact\Consumer\Matcher\Matchers\NullValue;
use PhpPact\Consumer\Matcher\Matchers\Regex;
use PhpPact\Consumer\Matcher\Matchers\Type;
use PhpPact\Consumer\Matcher\Model\FormatterInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorAwareInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class PluginFormatter implements FormatterInterface
{
public const MATCHERS_WITHOUT_CONFIG = ['equality', 'type', 'number', 'integer', 'decimal', 'include', 'boolean', 'semver'];

public function format(MatcherInterface $matcher): string
{
if ($matcher instanceof GeneratorAwareInterface && null !== $matcher->getGenerator()) {
throw new GeneratorNotRequiredException('Generator is not support in plugin');
}

if ($matcher instanceof MatchingField) {
return $this->formatMatchingFieldMatcher($matcher);
}
if ($matcher instanceof NotEmpty) {
return $this->formatNotEmptyMatcher($matcher);
}
if ($matcher instanceof EachKey || $matcher instanceof EachValue) {
return $this->formatEachKeyAndEachValueMatchers($matcher);
}
if ($matcher instanceof NullValue) {
return $this->formatMatchersWithoutConfig(new Type(null));
}

if (in_array($matcher->getType(), self::MATCHERS_WITHOUT_CONFIG)) {
return $this->formatMatchersWithoutConfig($matcher);
}
if ($matcher instanceof AbstractDateTime || $matcher instanceof Regex || $matcher instanceof ContentType) {
return $this->formatMatchersWithConfig($matcher);
}

throw new MatcherNotSupportedException(sprintf("Matcher '%s' is not supported by plugin", $matcher->getType()));
}

private function formatMatchingFieldMatcher(MatchingField $matcher): string
{
return sprintf("matching($%s)", $this->normalize($matcher->getFieldName()));
}

private function formatMatchersWithoutConfig(MatcherInterface $matcher): string
{
$type = $matcher->getType() === 'equality' ? 'equalTo' : $matcher->getType();

return sprintf('matching(%s, %s)', $type, $this->normalize($matcher->getValue()));
}

private function formatMatchersWithConfig(AbstractDateTime|Regex|ContentType $matcher): string
{
$config = match (true) {
$matcher instanceof AbstractDateTime => $matcher->getFormat(),
$matcher instanceof Regex => $matcher->getRegex(),
$matcher instanceof ContentType => $matcher->getValue(),
};

return sprintf("matching(%s, %s, %s)", $matcher->getType(), $this->normalize($config), $this->normalize($matcher->getValue()));
}

private function formatNotEmptyMatcher(NotEmpty $matcher): string
{
return sprintf('notEmpty(%s)', $this->normalize($matcher->getValue()));
}

private function formatEachKeyAndEachValueMatchers(EachKey|EachValue $matcher): string
{
$rules = $matcher->getRules();
if (count($rules) === 0 || count($rules) > 1) {
throw new MatchingExpressionException(sprintf("Matcher '%s' only support 1 rule, %d provided", $matcher->getType(), count($rules)));
}
$rule = reset($rules);

return sprintf('%s(%s)', $matcher->getType(), $this->format($rule));
}

private function normalize(mixed $value): string
{
return match (gettype($value)) {
'string' => sprintf("'%s'", str_replace("'", "\\'", $value)),
'boolean' => $value ? 'true' : 'false',
'integer' => (string) $value,
'double' => (string) $value,
'NULL' => 'null',
default => throw new MatchingExpressionException(sprintf("Plugin formatter doesn't support value of type %s", gettype($value))),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@
namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\FormatterInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorAwareInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class ValueOptionalFormatter implements FormatterInterface
{
/**
* @return array<string, mixed>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
public function format(MatcherInterface $matcher): array
{
$data = [
'pact:matcher:type' => $matcher->getType(),
];
$attributes = $matcher->getAttributes();
$generator = $matcher instanceof GeneratorAwareInterface ? $matcher->getGenerator() : null;

if ($generator) {
return $data + ['pact:generator:type' => $generator->getType()] + $matcher->getAttributes()->merge($generator->getAttributes())->getData();
return $data + ['pact:generator:type' => $generator->getType()] + $attributes->merge($generator->getAttributes())->getData();
}

return $data + $matcher->getAttributes()->getData() + ['value' => $value];
return $data + $attributes->getData() + ['value' => $matcher->getValue()];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@

namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class ValueRequiredFormatter extends ValueOptionalFormatter
{
/**
* @return array<string, mixed>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
public function format(MatcherInterface $matcher): array
{
return parent::format($matcher, $generator, $value) + ['value' => $value];
return parent::format($matcher) + ['value' => $matcher->getValue()];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\Attributes;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorAwareInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class XmlContentFormatter extends ValueOptionalFormatter
{
/**
* @return array<string, mixed>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
public function format(MatcherInterface $matcher): array
{
$generator = $matcher instanceof GeneratorAwareInterface ? $matcher->getGenerator() : null;
$data = [
'content' => $value,
'content' => $matcher->getValue(),
'matcher' => [
'pact:matcher:type' => $matcher->getType(),
] + $matcher->getAttributes()->merge($generator ? $generator->getAttributes() : new Attributes($matcher))->getData(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Exception\InvalidValueException;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;
use PhpPact\Xml\XmlElement;

Expand All @@ -12,13 +11,14 @@ class XmlElementFormatter extends ValueOptionalFormatter
/**
* @return array<string, mixed>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
public function format(MatcherInterface $matcher): array
{
$value = $matcher->getValue();
if (!$value instanceof XmlElement) {
throw new InvalidValueException('Value must be xml element');
}

$result = parent::format($matcher, $generator, $value);
$result = parent::format($matcher);
$examples = $value->getExamples();

if (null !== $examples) {
Expand Down
Loading

0 comments on commit 61b4f69

Please sign in to comment.