2018-08-05 00:39:53 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
use PHPUnit\Framework\TestResult;
|
|
|
|
use PHPUnit\Framework\AssertionFailedError;
|
|
|
|
|
2018-11-10 19:42:49 +01:00
|
|
|
require_once __DIR__ . '/../lib/rssbridge.php';
|
2018-08-05 00:39:53 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class checks bridges for implementation details:
|
|
|
|
*
|
|
|
|
* - A bridge must not implement public functions other than the ones specified
|
|
|
|
* by the bridge interfaces. Custom functions must be defined in private or
|
|
|
|
* protected scope.
|
|
|
|
* - getName() must return a valid string (non-empty)
|
|
|
|
* - getURI() must return a valid URI
|
|
|
|
* - A bridge must define constants for NAME, URI, DESCRIPTION and MAINTAINER,
|
|
|
|
* CACHE_TIMEOUT and PARAMETERS are optional
|
|
|
|
*/
|
|
|
|
final class BridgeImplementationTest extends TestCase {
|
|
|
|
|
|
|
|
private function CheckBridgePublicFunctions($bridgeName){
|
|
|
|
|
|
|
|
$parent_methods = array();
|
|
|
|
|
|
|
|
if(in_array('BridgeInterface', class_parents($bridgeName))) {
|
|
|
|
$parent_methods = array_merge($parent_methods, get_class_methods('BridgeInterface'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(in_array('BridgeAbstract', class_parents($bridgeName))) {
|
|
|
|
$parent_methods = array_merge($parent_methods, get_class_methods('BridgeAbstract'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(in_array('FeedExpander', class_parents($bridgeName))) {
|
|
|
|
$parent_methods = array_merge($parent_methods, get_class_methods('FeedExpander'));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Receive all non abstract methods
|
|
|
|
$methods = array_diff(get_class_methods($bridgeName), $parent_methods);
|
|
|
|
$method_names = implode(', ', $methods);
|
|
|
|
|
|
|
|
$errmsg = $bridgeName
|
|
|
|
. ' implements additional public method(s): '
|
|
|
|
. $method_names
|
|
|
|
. '! Custom functions must be defined in private or protected scope!';
|
|
|
|
|
|
|
|
$this->assertEmpty($method_names, $errmsg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private function CheckBridgeGetNameDefaultValue($bridgeName){
|
|
|
|
|
|
|
|
if(in_array('BridgeAbstract', class_parents($bridgeName))) { // Is bridge
|
|
|
|
|
|
|
|
if(!$this->isFunctionMemberOf($bridgeName, 'getName'))
|
|
|
|
return;
|
|
|
|
|
|
|
|
$bridge = new $bridgeName();
|
|
|
|
$abstract = new BridgeAbstractTest();
|
|
|
|
|
|
|
|
$message = $bridgeName . ': \'getName\' must return a valid name!';
|
|
|
|
|
|
|
|
$this->assertNotEmpty(trim($bridge->getName()), $message);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks whether the getURI function returns empty or default values
|
|
|
|
private function CheckBridgeGetURIDefaultValue($bridgeName){
|
|
|
|
|
|
|
|
if(in_array('BridgeAbstract', class_parents($bridgeName))) { // Is bridge
|
|
|
|
|
|
|
|
if(!$this->isFunctionMemberOf($bridgeName, 'getURI'))
|
|
|
|
return;
|
|
|
|
|
|
|
|
$bridge = new $bridgeName();
|
|
|
|
$abstract = new BridgeAbstractTest();
|
|
|
|
|
|
|
|
$message = $bridgeName . ': \'getURI\' must return a valid URI!';
|
|
|
|
|
|
|
|
$this->assertNotEmpty(trim($bridge->getURI()), $message);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private function CheckBridgePublicConstants($bridgeName){
|
|
|
|
|
|
|
|
// Assertion only works for BridgeAbstract!
|
|
|
|
if(in_array('BridgeAbstract', class_parents($bridgeName))) {
|
|
|
|
|
|
|
|
$ref = new ReflectionClass($bridgeName);
|
|
|
|
$constants = $ref->getConstants();
|
|
|
|
|
|
|
|
$ref = new ReflectionClass('BridgeAbstract');
|
|
|
|
$parent_constants = $ref->getConstants();
|
|
|
|
|
|
|
|
foreach($parent_constants as $key => $value) {
|
|
|
|
|
|
|
|
$this->assertArrayHasKey($key, $constants, 'Constant ' . $key . ' missing in ' . $bridgeName);
|
|
|
|
|
|
|
|
// Skip optional constants
|
|
|
|
if($key !== 'PARAMETERS' && $key !== 'CACHE_TIMEOUT') {
|
|
|
|
$this->assertNotEquals($value, $constants[$key], 'Constant ' . $key . ' missing in ' . $bridgeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private function isFunctionMemberOf($bridgeName, $functionName){
|
|
|
|
|
|
|
|
$bridgeReflector = new ReflectionClass($bridgeName);
|
|
|
|
$bridgeMethods = $bridgeReflector->GetMethods();
|
|
|
|
$bridgeHasMethod = false;
|
|
|
|
|
|
|
|
foreach($bridgeMethods as $method) {
|
|
|
|
|
|
|
|
if($method->name === $functionName && $method->class === $bridgeReflector->name) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testBridgeImplementation($bridgeName){
|
|
|
|
|
|
|
|
require_once('bridges/' . $bridgeName . '.php');
|
|
|
|
|
|
|
|
$this->CheckBridgePublicFunctions($bridgeName);
|
|
|
|
$this->CheckBridgePublicConstants($bridgeName);
|
|
|
|
$this->CheckBridgeGetNameDefaultValue($bridgeName);
|
|
|
|
$this->CheckBridgeGetURIDefaultValue($bridgeName);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public function count() {
|
2018-11-15 19:42:14 +01:00
|
|
|
return count(Bridge::getBridgeNames());
|
2018-08-05 00:39:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function run(TestResult $result = null) {
|
|
|
|
|
|
|
|
if ($result === null) {
|
|
|
|
$result = new TestResult;
|
|
|
|
}
|
|
|
|
|
2018-11-15 19:42:14 +01:00
|
|
|
foreach (Bridge::getBridgeNames() as $bridge) {
|
2018-08-05 00:39:53 +02:00
|
|
|
|
|
|
|
$bridge .= 'Bridge';
|
|
|
|
|
|
|
|
$result->startTest($this);
|
|
|
|
PHP_Timer::start();
|
|
|
|
$stopTime = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
$this->testBridgeImplementation($bridge);
|
|
|
|
} catch (AssertionFailedError $e) {
|
|
|
|
|
|
|
|
$stopTime = PHP_Timer::stop();
|
|
|
|
$result->addFailure($this, $e, $stopTime);
|
|
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
|
|
|
$stopTime = PHP_Timer::stop();
|
|
|
|
$result->addError($this, $e, $stopTime);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($stopTime === null) {
|
|
|
|
$stopTime = PHP_Timer::stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
$result->endTest($this, $stopTime);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class BridgeAbstractTest extends BridgeAbstract {
|
|
|
|
public function collectData(){}
|
|
|
|
}
|