Permalink
Browse files

added Environment::bypassFinals() & FileMutator (#348)

  • Loading branch information...
dg committed Aug 16, 2017
1 parent b464a75 commit 721dc05de11938ca2f2e6e06d9dedec8f84f485f
@@ -172,6 +172,27 @@ public static function getTestAnnotations()
}
/**
* Removes keyword final from source codes.
* @return void
*/
public static function bypassFinals()
{
FileMutator::addMutator(function ($code) {
if (strpos($code, 'final') !== false) {
$tokens = token_get_all($code);
$code = '';
foreach ($tokens as $token) {
$code .= is_array($token)
? ($token[0] === T_FINAL ? '' : $token[1])
: $token;
}
}
return $code;
});
}
/**
* Loads data according to the file annotation or specified by Tester\Runner\TestHandler::initiateDataProvider()
* @return array
@@ -0,0 +1,212 @@
<?php
/**
* This file is part of the Nette Tester.
* Copyright (c) 2009 David Grudl (https://davidgrudl.com)
*/
namespace Tester;
/**
* PHP file mutator.
*/
class FileMutator
{
const PROTOCOL = 'file';
/** @var resource|null */
public $context;
/** @var resource|null */
private $handle;
/** @var callable[] */
private static $mutators = [];
public static function addMutator(callable $mutator)
{
self::$mutators[] = $mutator;
stream_wrapper_unregister(self::PROTOCOL);
stream_wrapper_register(self::PROTOCOL, __CLASS__);
}
public function dir_closedir()
{
closedir($this->handle);
}
public function dir_opendir($path, $options)
{
$this->handle = $this->native('opendir', $path, $this->context);
return (bool) $this->handle;
}
public function dir_readdir()
{
return readdir($this->handle);
}
public function dir_rewinddir()
{
return rewinddir($this->handle);
}
public function mkdir($path, $mode, $options)
{
return $this->native('mkdir', $mode, false, $this->context);
}
public function rename($pathFrom, $pathTo)
{
return $this->native('rename', $pathFrom, $pathTo, $this->context);
}
public function rmdir($path, $options)
{
return $this->native('rmdir', $this->context);
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_flush()
{
return fflush($this->handle);
}
public function stream_lock($operation)
{
return flock($this->handle, $operation);
}
public function stream_metadata($path, $option, $value)
{
switch ($option) {
case STREAM_META_TOUCH:
return $this->native('touch', $path, $value[0], $value[1]);
case STREAM_META_OWNER_NAME:
case STREAM_META_OWNER:
return $this->native('chown', $path, $value);
case STREAM_META_GROUP_NAME:
case STREAM_META_GROUP:
return $this->native('chgrp', $path, $value);
case STREAM_META_ACCESS:
return $this->native('chmod', $path, $value);
}
}
public function stream_open($path, $mode, $options, &$openedPath)
{
$usePath = (bool) ($options & STREAM_USE_PATH);
if (pathinfo($path, PATHINFO_EXTENSION) === 'php') {
$content = $this->native('file_get_contents', $path, $usePath, $this->context);
if ($content === false) {
return false;
} else {
foreach (self::$mutators as $mutator) {
$content = call_user_func($mutator, $content);
}
$this->handle = tmpfile();
$this->native('fwrite', $this->handle, $content);
$this->native('fseek', $this->handle, 0);
return true;
}
} else {
$this->handle = $this->context
? $this->native('fopen', $path, $mode, $usePath, $this->context)
: $this->native('fopen', $path, $mode, $usePath);
return (bool) $this->handle;
}
}
public function stream_read($count)
{
return fread($this->handle, $count);
}
public function stream_seek($offset, $whence = SEEK_SET)
{
return fseek($this->handle, $offset, $whence);
}
public function stream_set_option($option, $arg1, $arg2)
{
}
public function stream_stat()
{
return fstat($this->handle);
}
public function stream_tell()
{
return ftell($this->handle);
}
public function stream_truncate($newSize)
{
return ftruncate($this->handle, $newSize);
}
public function stream_write($data)
{
return fwrite($this->handle, $data);
}
public function unlink($path)
{
return $this->native('unlink', $path);
}
public function url_stat($path, $flags)
{
return $this->native('fstat', $path, $flags);
}
private function native($func)
{
stream_wrapper_restore(self::PROTOCOL);
$res = call_user_func_array($func, array_slice(func_get_args(), 1));
stream_wrapper_unregister(self::PROTOCOL);
stream_wrapper_register(self::PROTOCOL, __CLASS__);
return $res;
}
}
@@ -13,6 +13,7 @@
require __DIR__ . '/Framework/FileMock.php';
require __DIR__ . '/Framework/TestCase.php';
require __DIR__ . '/Framework/DomQuery.php';
require __DIR__ . '/Framework/FileMutator.php';
require __DIR__ . '/CodeCoverage/Collector.php';
require __DIR__ . '/Runner/Job.php';
@@ -0,0 +1,14 @@
<?php
use Tester\Assert;
require __DIR__ . '/../bootstrap.php';
Tester\Environment::bypassFinals();

This comment has been minimized.

@f3l1x

f3l1x Aug 17, 2017

Member

πŸ‘

require __DIR__ . '/fixtures/final.class.php';
$rc = new ReflectionClass('FinalClass');
Assert::false($rc->isFinal());
Assert::false($rc->getMethod('finalMethod')->isFinal());
@@ -0,0 +1,8 @@
<?php
final class FinalClass
{
final function finalMethod()
{
}
}
@@ -5,3 +5,4 @@ parameters:
skip:
PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff:
- src/Framework/FileMock.php
- src/Framework/FileMutator.php

0 comments on commit 721dc05

Please sign in to comment.