coduo/php-matcher

PHP Matcher 允许您使用模式匹配值

6.0.15 2024-04-25 21:08 UTC

README

Type Coverage

为测试所有种类的 JSON/XML/TXT/标量值与模式匹配而创建的库。

API

PHPMatcher::match($value = '{"foo": "bar"}', $pattern = '{"foo": "@string@"}') : bool;
PHPMatcher::backtrace() : Backtrace;
PHPMatcher::error() : ?string;

它旨在简化 API 功能测试。

Latest Stable Version Total Downloads Latest Unstable Version License

我们反对恐怖主义

2022年2月24日,俄罗斯对乌克兰发动了未经宣战的战争并全面入侵。俄罗斯目前正在轰炸和平的乌克兰城市,包括学校和医院,并攻击逃离冲突区的平民。

2023年10月7日,赎罪节的全国假日,哈马斯恐怖分子在凌晨对以色列发起了袭击,针对平民。他们释放了暴力,造成至少1,400人死亡,绑架了至少200人,不仅限于以色列人。

沙盒

请随意先使用沙盒进行尝试。

安装

使用 composer 需要新的开发依赖项

composer require --dev "coduo/php-matcher"

基本用法

直接使用 PHPMatcher

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();
$match = $matcher->match("lorem ipsum dolor", "@string@");

if (!$match) {
    echo "Error: " . $matcher->error();
    echo "Backtrace: \n";
    echo (string) $matcher->backtrace();
}

PHPUnit 扩展 PHPMatcherTestCase

<?php

use Coduo\PHPMatcher\PHPUnit\PHPMatcherTestCase;

class MatcherTest extends PHPMatcherTestCase
{
    public function test_matcher_that_value_matches_pattern()
    {
        $this->assertMatchesPattern('{"name": "@string@"}', '{"name": "Norbert"}');
    }
}

PHPUnit 使用 PHPMatcherAssertions 特性

<?php

use Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions;
use PHPUnit\Framework\TestCase;

class MatcherTest extends TestCase
{
    use PHPMatcherAssertions;

    public function test_matcher_that_value_matches_pattern()
    {
        $this->assertMatchesPattern('{"name": "@string@"}', '{"name": "Norbert"}');
    }
}

可用的模式

  • @string@
  • @integer@
  • @number@
  • @double@
  • @boolean@
  • @time@
  • @date@
  • @datetime@
  • @timezone@ || @tz
  • @array@
  • @array_previous@ - 使用前一个元素的图案匹配下一个数组元素
  • @array_previous_repeat@ - 使用前一个元素的图案匹配所有剩余的数组元素
  • @...@ - 无界数组,一旦使用匹配器,将跳过任何进一步的数组元素
  • @null@
  • @*@ || @wildcard@
  • expr(expression) - 可选,需要存在 symfony/expression-language: ^2.3|^3.0|^4.0|^5.0
  • @uuid@
  • @ulid@
  • @json@
  • @string@||@integer@ - 字符串 OR 整数

可用的模式扩展器

  • startsWith($stringBeginning, $ignoreCase = false)
  • endsWith($stringEnding, $ignoreCase = false)
  • contains($string, $ignoreCase = false)
  • notContains($string, $ignoreCase = false)
  • isDateTime()
  • isInDateFormat($format) - 示例 "@[email protected]('Y-m-d H:i:s')
  • before(string $date) - 示例 "@[email protected]().before(\"2020-01-01 00:00:00\")"
  • after(string $date) - 示例 "@[email protected]().after(\"2020-01-01 00:00:00\")"
  • isTzOffset()
  • isTzIdentifier()
  • isTzAbbreviation()
  • isEmail()
  • isUrl()
  • isIp()
  • isEmpty()
  • isNotEmpty()
  • 小于($boundry)
  • 大于($boundry)
  • inArray($value) - 示例 "@[email protected](\"ROLE_USER\")"
  • hasProperty($propertyName) - 示例 "@[email protected](\"property_name\")"
  • oneOf(...$expanders) - 示例 "@[email protected](contains('foo'), contains('bar'), contains('baz'))"
  • matchRegex($regex) - 示例 "@[email protected]('/^lorem.+/')
  • optional() - 仅与 ArrayMatcherJsonMatcherXmlMatcher 一起使用
  • count() - 仅与 ArrayMatcher 一起使用 - 示例 "@[email protected](5)"
  • repeat($pattern, $isStrict = true) - 示例 '@[email protected]({"name": "foe"})'"@[email protected]('@string@')"
  • match($pattern) - 示例 {"image":"@[email protected]({\"url\":\"@[email protected]()\"})"}

示例用法

标量匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(1, 1);
$matcher->match('string', 'string');

字符串匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('Norbert', '@string@');
$matcher->match("lorem ipsum dolor", "@[email protected]('lorem').contains('ipsum').endsWith('dolor')");

时间匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('00:00:00', '@time@');
$matcher->match('00:01:00.000000', '@time@');
$matcher->match('00:01:00', '@[email protected]("00:00:00")');
$matcher->match('00:00:00', '@[email protected]("01:00:00")');

日期匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('2014-08-19', '@date@');
$matcher->match('2020-01-11', '@date@');
$matcher->match('2014-08-19', '@[email protected]("2016-08-19")');
$matcher->match('2014-08-19', '@[email protected]("today").after("+ 100year")');

日期时间匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('2014-08-19', '@datetime@');
$matcher->match('2020-01-11 00:00:00', '@datetime@');
$matcher->match('2014-08-19', '@[email protected]("2016-08-19")');
$matcher->match('2014-08-19', '@[email protected]("today").after("+ 100year")');

时区匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('Europe/Warsaw', '@timezone@');
$matcher->match('Europe/Warsaw', '@tz@');
$matcher->match('GMT', '@tz@');
$matcher->match('01:00', '@tz@');
$matcher->match('01:00', '@[email protected]()');
$matcher->match('GMT', '@[email protected]()');
$matcher->match('Europe/Warsaw', '@[email protected]()');

整数匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(100, '@integer@');
$matcher->match(100, '@[email protected](200).greaterThan(10)');

数字匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(100, '@number@');
$matcher->match('200', '@number@');
$matcher->match(1.25, '@number@');
$matcher->match('1.25', '@number@');
$matcher->match(0b10100111001, '@number@');

双精度浮点数匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(10.1, "@double@");
$matcher->match(10.1, "@[email protected](50.12).greaterThan(10)");

布尔匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(true, "@boolean@");
$matcher->match(false, "@boolean@");

通配符匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match("@integer@", "@*@");
$matcher->match("foobar", "@*@");
$matcher->match(true, "@*@");
$matcher->match(6.66, "@*@");
$matcher->match(array("bar"), "@wildcard@");
$matcher->match(new \stdClass, "@wildcard@");

表达式匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(new \DateTime('2014-04-01'), "expr(value.format('Y-m-d') == '2014-04-01'");
$matcher->match("Norbert", "expr(value === 'Norbert')");

UUID匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('9f4db639-0e87-4367-9beb-d64e3f42ae18', '@uuid@');

ULID匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('01BX5ZZKBKACTAV9WEVGEMMVS0', '@ulid@');

数组匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(
   array(
      'users' => array(
          array(
              'id' => 1,
              'firstName' => 'Norbert',
              'lastName' => 'Orzechowicz',
              'roles' => array('ROLE_USER'),
              'position' => 'Developer',
          ),
          array(
              'id' => 2,
              'firstName' => 'Michał',
              'lastName' => 'Dąbrowski',
              'roles' => array('ROLE_USER')
          ),
          array(
              'id' => 3,
              'firstName' => 'Johnny',
              'lastName' => 'DąbrowsBravoki',
              'roles' => array('ROLE_HANDSOME_GUY')
          )
      ),
      true,
      6.66
  ),
   array(
      'users' => array(
          array(
              'id' => '@[email protected](0)',
              'firstName' => '@string@',
              'lastName' => 'Orzechowicz',
              'roles' => '@array@',
              'position' => '@[email protected]()'
          ),
          array(
              'id' => '@integer@',
              'firstName' => '@string@',
              'lastName' => 'Dąbrowski',
              'roles' => '@array@'
          ),
          '@...@'
      ),
      '@boolean@',
      '@double@'
  )
);

数组前一个

@array_previous@ 也可以在匹配 JSON 和 XML 时使用

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(
   array(
      'users' => array(
          array(
              'id' => 1,
              'firstName' => 'Norbert',
              'lastName' => 'Orzechowicz',
              'roles' => array('ROLE_USER'),
              'position' => 'Developer',
          ),
          array(
              'id' => 2,
              'firstName' => 'Michał',
              'lastName' => 'Dąbrowski',
              'roles' => array('ROLE_USER')
          ),
          array(
              'id' => 3,
              'firstName' => 'Johnny',
              'lastName' => 'DąbrowsBravoki',
              'roles' => array('ROLE_HANDSOME_GUY')
          )
      ),
      true,
      6.66
  ),
   array(
      'users' => array(
          array(
              'id' => '@[email protected](0)',
              'firstName' => '@string@',
              'lastName' => 'Orzechowicz',
              'roles' => '@array@',
              'position' => '@[email protected]()'
          ),
          '@array_previous@',
          '@array_previous@'
      ),
      '@boolean@',
      '@double@'
  )
);

数组前一个重复

@array_previous_repeat@ 也可以在匹配 JSON 和 XML 时使用

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(
   array(
      'users' => array(
          array(
              'id' => 1,
              'firstName' => 'Norbert',
              'lastName' => 'Orzechowicz',
              'roles' => array('ROLE_USER'),
              'position' => 'Developer',
          ),
          array(
              'id' => 2,
              'firstName' => 'Michał',
              'lastName' => 'Dąbrowski',
              'roles' => array('ROLE_USER')
          ),
          array(
              'id' => 3,
              'firstName' => 'Johnny',
              'lastName' => 'DąbrowsBravoki',
              'roles' => array('ROLE_HANDSOME_GUY')
          )
      ),
      true,
      6.66
  ),
   array(
      'users' => array(
          array(
              'id' => '@[email protected](0)',
              'firstName' => '@string@',
              'lastName' => 'Orzechowicz',
              'roles' => '@array@',
              'position' => '@[email protected]()'
          ),
          '@array_previous_repeat@'
      ),
      '@boolean@',
      '@double@'
  )
);

JSON 匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(
  '{
    "users":[
      {
        "firstName": "Norbert",
        "lastName": "Orzechowicz",
        "created": "2014-01-01",
        "roles":["ROLE_USER", "ROLE_DEVELOPER"]
      }
    ]
  }',
  '{
    "users":[
      {
        "firstName": "@string@",
        "lastName": "@string@",
        "created": "@[email protected]()",
        "roles": "@array@",
        "position": "@[email protected]()"
      }
    ]
  }'
);

带有无界数组和对象的 JSON 匹配

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(
  '{
    "users":[
      {
        "firstName": "Norbert",
        "lastName": "Orzechowicz",
        "created": "2014-01-01",
        "roles":["ROLE_USER", "ROLE_DEVELOPER"],
        "attributes": {
          "isAdmin": false,
          "dateOfBirth": null,
          "hasEmailVerified": true
        },
        "avatar": {
          "url": "http://avatar-image.com/avatar.png"
        }
      },
      {
        "firstName": "Michał",
        "lastName": "Dąbrowski",
        "created": "2014-01-01",
        "roles":["ROLE_USER", "ROLE_DEVELOPER", "ROLE_ADMIN"],
        "attributes": {
          "isAdmin": true,
          "dateOfBirth": null,
          "hasEmailVerified": true
        },
        "avatar": null
      }
    ]
  }',
  '{
    "users":[
      {
        "firstName": "@string@",
        "lastName": "@string@",
        "created": "@[email protected]()",
        "roles": [
            "ROLE_USER",
            "@...@"
        ],
        "attributes": {
          "isAdmin": @boolean@,
          "@*@": "@*@"
        },
        "avatar": "@[email protected]({\"url\":\"@[email protected]()\"})"
      }
      ,
      @...@
    ]
  }'
);

XML 匹配

可选 - 需要 openlss/lib-array2xml: ^1.0 库存在。

<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match(<<<XML
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

<soap:Body xmlns:m="http://www.example.org/stock">
  <m:GetStockPrice>
    <m:StockName>IBM</m:StockName>
    <m:StockValue>Any Value</m:StockValue>
  </m:GetStockPrice>
</soap:Body>

</soap:Envelope>
XML
                ,
                <<<XML
<?xml version="1.0"?>
<soap:Envelope
    xmlns:soap="@string@"
            soap:encodingStyle="@string@">

<soap:Body xmlns:m="@string@">
  <m:GetStockPrice>
    <m:StockName>@string@</m:StockName>
    <m:StockValue>@string@</m:StockValue>
    <m:StockQty>@[email protected]()</m:StockQty>
  </m:GetStockPrice>
</soap:Body>

</soap:Envelope>
XML
        );

使用 mongo 的 behat api 示例场景

@profile, @user
Feature: Listing user toys

  As a user
  I want to list my toys

  Background:
    Given I send and accept JSON

  Scenario: Listing toys
    Given the following users exist:
      | firstName     | lastName     |
      | Chuck         | Norris       |

    And the following toys user "Chuck Norris" exist:
      | name            |
      | Barbie          |
      | GI Joe          |
      | Optimus Prime   |

    When I set valid authorization code oauth header for user "Chuck Norris"
    And I send a GET request on "/api/toys"
    Then the response status code should be 200
    And the JSON response should match:
    """
      [
        {
          "id": "@string@",
          "name": "Barbie",
          "_links: "@*@"
        },
        {
          "id": "@string@",
          "name": "GI Joe",
          "_links": "@*@"
        },
        {
          "id": "@string@",
          "name": "Optimus Prime",
          "_links": "@*@"
        }
      ]
    """

PHPUnit 集成

assertMatchesPattern() 是一个方便的断言,用于在 PHPUnit 测试中匹配值。要使用它,可以包含 Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions 特性,或者扩展 Coduo\PHPMatcher\PHPUnit\PHPMatcherTestCase

namespace Coduo\PHPMatcher\Tests\PHPUnit;

use Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions;
use PHPUnit\Framework\TestCase;

class PHPMatcherAssertionsTest extends TestCase
{
    use PHPMatcherAssertions;

    public function test_it_asserts_if_a_value_matches_the_pattern()
    {
        $this->assertMatchesPattern('@string@', 'foo');
    }
}

matchesPattern() 方法可用于 PHPUnit 模拟或存根

$mock = $this->createMock(Foo::class);
$mock->method('bar')
    ->with($this->matchesPattern('@string@'))
    ->willReturn('foo');

许可证

此库根据 MIT 许可证分发。请参阅 LICENSE 文件。

致谢

此库受到 JSON Expressions gemBehat RestExtension 的启发