Skip to content

Commit 2b4767d

Browse files
committed
first commit
0 parents  commit 2b4767d

File tree

8 files changed

+155
-0
lines changed

8 files changed

+155
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
vendor/
2+
composer.lock
3+
composer.phar
4+
.phpunit.cache/test-results

.phpunit.cache/test-results

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":2,"defects":{"MintyPHP\\Mocking\\Tests\\StaticMethodMockTest::testStaticMethodMock":8},"times":{"MintyPHP\\Mocking\\Tests\\StaticMethodMockTest::testStaticMethodMock":0}}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# MintyPHP Mocking

composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "mintyphp/mocking",
3+
"license": "MIT",
4+
"authors": [
5+
{
6+
"name": "Maurits van der Schee",
7+
"email": "[email protected]",
8+
"homepage": "https://www.tqdev.com"
9+
}
10+
],
11+
"require": {
12+
"php": ">=7.4"
13+
},
14+
"require-dev": {
15+
"phpunit/phpunit": "*",
16+
"phpstan/phpstan": "*"
17+
},
18+
"autoload": {
19+
"psr-4": {
20+
"MintyPHP\\Mocking\\": "src/",
21+
"MintyPHP\\Mocking\\Tests\\": "tests/"
22+
}
23+
}
24+
}

phpstan.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
parameters:
2+
level: 7
3+
paths:
4+
- src

phpunit.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
cacheDirectory=".phpunit.cache"
6+
>
7+
<testsuites>
8+
<testsuite name="default">
9+
<directory>tests</directory>
10+
</testsuite>
11+
</testsuites>
12+
13+
<source>
14+
<include>
15+
<directory>src</directory>
16+
</include>
17+
</source>
18+
</phpunit>

src/StaticMethodMock.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MintyPHP\Mocking;
6+
7+
class StaticMethodMock
8+
{
9+
/** @var ?callable */
10+
private static $autoloader = null;
11+
/** @var array<string,StaticMethodMock> */
12+
public static array $mocks = [];
13+
/** @var string */
14+
private string $className;
15+
/** @var array<int,array{method:string,arguments:array,returnsVoid:bool,returns:mixed,exception:?Throwable}> */
16+
private array $expectations = [];
17+
18+
// Register a static mock for the given class name.
19+
public function __construct(string $className) {
20+
$this->className = $className;
21+
self::$mocks[$className] = $this;
22+
if (self::$autoloader === null) {
23+
self::$autoloader = function (string $class) {
24+
if ($class === $this->className) {
25+
$namespace = substr($this->className, 0, strrpos($this->className, '\\'));
26+
$shortClassName = substr($this->className, strrpos($this->className, '\\') + 1);
27+
eval('namespace ' . $namespace . ' { class ' . $shortClassName . ' { public static function __callStatic($name, $arguments) { return \MintyPHP\Tests\StaticMethodMock::handleStaticCall(\'' . $this->className . '\', $name, $arguments); } } }');
28+
return true;
29+
}
30+
return false;
31+
};
32+
spl_autoload_register(self::$autoloader, true, true);
33+
}
34+
}
35+
36+
/** Expect a with specific body (exact match). */
37+
public function expect(string $method, array $arguments, bool $returnsVoid = true, mixed $returns = null, ?\Throwable $exception = null)
38+
{
39+
$this->expectations[] = [
40+
'method' => strtoupper($method),
41+
'arguments' => $arguments,
42+
'returnsVoid' => $returnsVoid,
43+
'returns' => $returns,
44+
'exception' => $exception,
45+
];
46+
}
47+
48+
public static function handleStaticCall(string $className, string $method, array $arguments)
49+
{
50+
if (!isset(self::$mocks[$className])) {
51+
throw new \Exception(sprintf('StaticMethodMock no mock registered for class: %s', $className));
52+
}
53+
$mock = self::$mocks[$className];
54+
if (empty($mock->expectations)) {
55+
throw new \Exception(sprintf('StaticMethodMock unexpected call: %s::%s', $className, $method));
56+
}
57+
$expected = array_shift($mock->expectations);
58+
// Basic matching
59+
if ($expected['method'] != strtoupper($method)) {
60+
throw new \Exception(sprintf('StaticMethodMock method mismatch: expected %s got %s for %s::%s', $expected['method'], strtoupper($method), $className, $method));
61+
}
62+
if ($expected['arguments'] != $arguments) {
63+
throw new \Exception(sprintf('StaticMethodMock arguments mismatch for %s::%s: expected %s got %s', $className, $method, json_encode($expected['arguments']), json_encode($arguments)));
64+
}
65+
if ($expected['exception'] !== null) {
66+
throw $expected['exception'];
67+
}
68+
if ($expected['returnsVoid']) {
69+
return;
70+
}
71+
return $expected['returns'];
72+
}
73+
}

tests/StaticMethodMockTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MintyPHP\Mocking\Tests;
6+
7+
use MintyPHP\Mocking\StaticMethodMock;
8+
9+
class Adder
10+
{
11+
public static function add($a, $b):int
12+
{
13+
return $a+$b;
14+
}
15+
}
16+
17+
class StaticMethodMockTest extends \PHPUnit\Framework\TestCase
18+
{
19+
public function testStaticMethodMock(): void
20+
{
21+
// Create a static method mock for the Adder class
22+
$mock = new StaticMethodMock(Adder::class);
23+
// Set expectation for the add method
24+
$mock->expect('add', [1, 2], false, 3);
25+
// Call the public static add method
26+
$result = Adder::add(1, 2);
27+
// Verify the result
28+
$this->assertEquals(3, $result);
29+
}
30+
}

0 commit comments

Comments
 (0)