Skip to content

Commit adc6ce5

Browse files
committed
Initial commit
0 parents  commit adc6ce5

10 files changed

+217
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea
2+
vendor
3+
composer.lock
4+
build
5+
.phpunit.result.cache

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: php
2+
sudo: false
3+
php:
4+
- 7.2
5+
- 7.3
6+
7+
before_install:
8+
- composer self-update
9+
10+
install:
11+
- travis_retry composer install --no-interaction --prefer-source
12+
13+
script:
14+
- vendor/bin/phpstan analyze src/ tests/ --level max
15+
- vendor/bin/phpunit --coverage-clover build/logs/clover.xml
16+
17+
after_success:
18+
- travis_retry php vendor/bin/php-coveralls -v

LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2019 Vsevolod Vietluzhskykh
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Espionage - simple tool for primitive spying on your classes dependencies.
2+
3+
[![Build Status](https://travis-ci.com/ThoroughPHP/Espionage.svg?branch=master)](https://travis-ci.com/ThoroughPHP/Espionage)
4+
[![Coverage Status](https://coveralls.io/repos/github/ThoroughPHP/Espionage/badge.svg)](https://coveralls.io/github/ThoroughPHP/Espionage)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6+
[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat)](https://github.com/phpstan/phpstan)

composer.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "thorough-php/espionage",
3+
"type": "library",
4+
"require": {
5+
"php": ">=7.2"
6+
},
7+
"require-dev": {
8+
"phpunit/phpunit": "^8.2",
9+
"phpstan/phpstan": "^0.11.12",
10+
"php-coveralls/php-coveralls": "^2.1"
11+
},
12+
"autoload": {
13+
"psr-4": {
14+
"ThoroughPHP\\Espionage\\": "src/"
15+
}
16+
},
17+
"autoload-dev": {
18+
"psr-4": {
19+
"ThoroughPHP\\Espionage\\Tests\\": "tests/"
20+
}
21+
},
22+
"license": "MIT",
23+
"authors": [
24+
{
25+
"name": "sevavietl",
26+
"email": "sevavietl@gmail.com"
27+
}
28+
]
29+
}

phpunit.xml.dist

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false">
11+
<filter>
12+
<whitelist processUncoveredFilesFromWhitelist="true">
13+
<directory suffix=".php">./src</directory>
14+
</whitelist>
15+
</filter>
16+
<testsuites>
17+
<testsuite name="unit">
18+
<directory suffix="Test.php">tests/</directory>
19+
</testsuite>
20+
</testsuites>
21+
</phpunit>

src/ObjectUnderSurveillance.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace ThoroughPHP\Espionage;
4+
5+
final class ObjectUnderSurveillance
6+
{
7+
/** @var object */
8+
private $object;
9+
10+
/** @var Spy */
11+
private $spy;
12+
13+
/**
14+
* ObjectUnderSurveillance constructor.
15+
* @param object $object
16+
* @param Spy $spy
17+
*/
18+
public function __construct(object $object, Spy $spy)
19+
{
20+
$this->object = $object;
21+
$this->spy = $spy;
22+
}
23+
24+
public function __call($name, $arguments)
25+
{
26+
if (! is_callable([$this->object, $name])) {
27+
throw new \BadMethodCallException();
28+
}
29+
30+
$debugBacktrace = debug_backtrace();
31+
$caller = array_shift($debugBacktrace);
32+
33+
$this->spy->registerMethodCall(
34+
spl_object_hash($this->object),
35+
$name,
36+
$arguments,
37+
$result = $this->object->{$name}(...$arguments),
38+
$caller['file'],
39+
$caller['line']
40+
);
41+
42+
return $result;
43+
}
44+
}

src/Spy.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace ThoroughPHP\Espionage;
4+
5+
final class Spy
6+
{
7+
/** @var array */
8+
private $protocol;
9+
10+
public function getProtocol(): array
11+
{
12+
return $this->protocol;
13+
}
14+
15+
public function spyOn(object $object): ObjectUnderSurveillance
16+
{
17+
if (! isset($this->protocol[spl_object_hash($object)])) {
18+
$this->protocol[spl_object_hash($object)] = [];
19+
$this->protocol[spl_object_hash($object)]['class'] = get_class($object);
20+
$this->protocol[spl_object_hash($object)]['calls'] = [];
21+
}
22+
23+
return new ObjectUnderSurveillance($object, $this);
24+
}
25+
26+
public function registerMethodCall(string $splObjectHash, string $method, array $input, $output, $file, $line): void
27+
{
28+
if (! isset($this->protocol[$splObjectHash])) {
29+
$this->protocol[$splObjectHash] = [];
30+
}
31+
32+
$this->protocol[$splObjectHash]['calls'][] = [
33+
'method' => $method,
34+
'input' => $input,
35+
'output' => $output,
36+
'file' => $file,
37+
'line' => $line,
38+
];
39+
}
40+
}

tests/SpyTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace ThoroughPHP\Espionage\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use ThoroughPHP\Espionage\Spy;
7+
8+
final class SpyTest extends TestCase
9+
{
10+
public function testSpyOn(): void
11+
{
12+
$spy = new Spy();
13+
14+
$object = new StubObject();
15+
/** @var StubObject $objectUnderSurveillance */
16+
$objectUnderSurveillance = $spy->spyOn($object);
17+
$objectUnderSurveillance->method();
18+
19+
$protocol = $spy->getProtocol();
20+
21+
$this->assertArrayHasKey($hash = spl_object_hash($object), $protocol);
22+
$this->assertEquals('method', $protocol[$hash]['calls'][0]['method']);
23+
}
24+
}

tests/StubObject.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace ThoroughPHP\Espionage\Tests;
4+
5+
final class StubObject
6+
{
7+
public function method(): void
8+
{
9+
// Intentionally left blank
10+
}
11+
}

0 commit comments

Comments
 (0)