Skip to content

Commit

Permalink
Merge 10a388c into 598c368
Browse files Browse the repository at this point in the history
  • Loading branch information
lamp-of-god committed Sep 9, 2017
2 parents 598c368 + 10a388c commit 1b30430
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 0 deletions.
21 changes: 21 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/class.php
@@ -0,0 +1,21 @@
<?php
namespace TestNamespace;


class Test
{
public function publicFunction()
{
return true;
}

protected function protectedFunction()
{
return true;
}

private function privateFunction()
{
return true;
}
}
4 changes: 4 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/code.php
@@ -0,0 +1,4 @@
<?php

$i = 0;
$i++;
12 changes: 12 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/function.php
@@ -0,0 +1,12 @@
<?php


function test1()
{
return '';
}

function test2()
{
return '';
}
8 changes: 8 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/functionProcessed.php
@@ -0,0 +1,8 @@
<?php
function test1()
{
return '';
}function test2()
{
return '';
}
9 changes: 9 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/nested.php
@@ -0,0 +1,9 @@
<?php

function parent() {
return nested();

function nested() {
return true;
}
}
8 changes: 8 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/nestedProcessed.php
@@ -0,0 +1,8 @@
<?php
function parent() {
return nested();

function nested() {
return true;
}
}
3 changes: 3 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/use.php
@@ -0,0 +1,3 @@
<?php
use SomeClass;
use \SomeClass;
3 changes: 3 additions & 0 deletions spec/Fixture/Jit/Patcher/Isolator/useProcessed.php
@@ -0,0 +1,3 @@
<?php
use SomeClass;
use \SomeClass;
85 changes: 85 additions & 0 deletions spec/Suite/Jit/Patcher/Isolator.spec.php
@@ -0,0 +1,85 @@
<?php
namespace Kahlan\Spec\Suite\Jit\Patcher;

use Kahlan\Jit\Parser;
use Kahlan\Jit\Patcher\Isolator;

describe("Isolator", function () {

beforeAll(function () {
$this->empty = "<?php\n";
});

beforeEach(function () {
$this->path = 'spec/Fixture/Jit/Patcher/Isolator';
$this->patcher = new Isolator();
});

describe("->process()", function () {

it("keeps open PHP tag", function () {
$nodes = Parser::parse('<?php '); // Extra space is parser workaround
$result = Parser::unparse($this->patcher->process($nodes));
expect($result)->toBe('<?php ');
});

it("keeps functions", function () {
$nodes = Parser::parse(
file_get_contents($this->path.'/function.php')
);
$expected = file_get_contents($this->path.'/functionProcessed.php');
$actual = Parser::unparse($this->patcher->process($nodes));
expect($actual)->toBe($expected);
});

it("removes PHP code outside of functions", function () {
$nodes = Parser::parse(
file_get_contents($this->path.'/code.php')
);
$actual = Parser::unparse($this->patcher->process($nodes));
expect($actual)->toBe($this->empty);
});

it("removes classes", function () {
$nodes = Parser::parse(
file_get_contents($this->path.'/class.php')
);
$actual = Parser::unparse($this->patcher->process($nodes));
expect($actual)->toBe($this->empty);
});

it("supports nested functions", function () {
$nodes = Parser::parse(
file_get_contents($this->path.'/nested.php')
);
$expected = file_get_contents($this->path.'/nestedProcessed.php');
$actual = Parser::unparse($this->patcher->process($nodes));
expect($actual)->toBe($expected);
});

it("keeps 'use' statements", function () {
$nodes = Parser::parse(file_get_contents($this->path.'/use.php'));
$expected = file_get_contents($this->path.'/useProcessed.php');
$actual = Parser::unparse($this->patcher->process($nodes));
expect($actual)->toBe($expected);
});

});

describe("->patchable()", function () {

it("returns `true`", function () {
expect($this->patcher->patchable('SomeClass'))->toBe(true);
});

});

describe("->findFile()", function () {

it("returns file name AS IS", function () {
expect($this->patcher->findFile('', '', 'path'))->toBe('path');
});

});

});
42 changes: 42 additions & 0 deletions spec/Suite/Plugin/Isolator.spec.php
@@ -0,0 +1,42 @@
<?php
namespace Kahlan\Spec\Suite\Plugin;

use Kahlan\Jit\Interceptor;
use Kahlan\Plugin\Double;
use Kahlan\Plugin\Isolator;

describe("Isolator", function () {

/**
* Save current & reinitialize the Interceptor class.
*/
beforeAll(function () {
$this->previous = Interceptor::instance();
Interceptor::unpatch();
});

/**
* Restore Interceptor class.
*/
afterAll(function () {
Interceptor::load($this->previous);
});

describe("::isolate()", function () {

it("adds patcher, loads file and removes patcher", function () {
$interceptor = Double::instance();
$patchers = Double::instance();
Interceptor::load($interceptor);
allow($interceptor)->toReceive('patchers')->andReturn($patchers);

expect($patchers)->toReceive('add')->with('isolator');
expect($interceptor)->toReceive('loadFile')->with('something');
expect($patchers)->toReceive('remove')->with('isolator');

Isolator::isolate('something');
});

});

});
67 changes: 67 additions & 0 deletions src/Jit/Patcher/Isolator.php
@@ -0,0 +1,67 @@
<?php
namespace Kahlan\Jit\Patcher;

/**
* Patcher for functions isolation from old legacy code.
* It removes everything except "use" statements and functions.
*/
class Isolator
{
/**
* The JIT find file patcher.
*
* @param object $loader The autoloader instance.
* @param string $class The fully-namespaced class name.
* @param string $file The corresponding found file path.
*
* @return string The patched file path.
*/
public function findFile($loader, $class, $file)
{
return $file;
}

/**
* The JIT patchable checker.
*
* @param string $class The fully-namespaced class name to check.
*
* @return boolean
*/
public function patchable($class)
{
return true;
}

/**
* The JIT patcher.
*
* @param object $node The node instance to patch.
* @param string $path The file path of the source code.
*
* @return object The patched node.
*/
public function process($node, $path = null)
{
$this->_processTree($node);
return $node;
}

/**
* Helper for `Isolator::process()`.
*
* @param object $parent The node instance tor process.
*/
protected function _processTree($parent)
{
foreach ($parent->tree as $node) {
if ($node->processable
&& !in_array($node->type, ['open', 'use', 'function'])
) {
$node->body = '';
$node->close = '';
$node->tree = [];
}
}
}
}
24 changes: 24 additions & 0 deletions src/Plugin/Isolator.php
@@ -0,0 +1,24 @@
<?php
namespace Kahlan\Plugin;

use Kahlan\Jit\Interceptor;
use Kahlan\Jit\Patcher\Isolator as Patcher;

/**
* Plugin that allows to isolate functions from given file.
*/
class Isolator
{
/**
* Performs functions isolation and requires them from given file.
*
* @param string $file File path to isolate functions from.
*/
public static function isolate($file)
{
$interceptor = Interceptor::instance();
$interceptor->patchers()->add('isolator', new Patcher());
$interceptor->loadFile($file);
$interceptor->patchers()->remove('isolator');
}
}

0 comments on commit 1b30430

Please sign in to comment.