<?php
namespace Tlf\Tester;
class NewCli {
use OutputTrait;
/**
* A combination of default inputs + inputs given via cli
* @structure a key=>value array
* @warning use $answers, not configs for most things
*/
protected $inputs = [];
/** the direcotry from which this is being executed */
public $pwd;
/** the directory in which tests are run */
public $dir;
protected $reports = [];
/**
* Keys who's values should always be converted to array
*/
protected $arrayify = [
'test'=>true,
'dir.exclude'=>true,
];
/**
* The configs built from default configs + config file
* @warning use $answers, not configs for most things
*/
protected $configs = [];
/**
* The combination of cli inputs + configs.
*/
protected $answers = [];
/**
*
*
*/
public function __construct(string $pwd, array $args=[]){
$this->pwd = $pwd;
$this->inputs = array_merge($this->getDefaultInputs(), $this->parseArgs($args));
$this->configs = array_merge($this->getDefaultConfigs(), $this->getConfigFile());
$this->answers = array_merge($this->configs, $this->inputs);
$this->dir = $pwd.'/'.$this->answers['dir.test'];
// load autoload file
$autoloadFile = $pwd.'/'.$this->answers['file.autoloader'];
if (is_file($autoloadFile)){
require_once($autoloadFile);
} else {
$this->report("answer 'file.autoloader' was '$autoloadFile', but '$pwd/$autoloadFile' does not exist");
}
if (empty($this->answers['file.require'])&&!empty($this->answers['autoload'])){
$this->answers['file.require'] = $this->answers['autoload'];
}
foreach ($this->answers['file.require'] as $relFile){
$path = $pwd.'/'.$relFile;
if (is_file($path))require_once($path);
else $this->report("'$relFile' of 'file.require' does not exist inside '$pwd'");
}
foreach ($this->answers['dir.require'] as $relFile){
$path = $pwd.'/'.$relFile;
if (is_dir($path))$this->requireDir($path);
else $this->report("'$relFile' of 'dir.require' does not exist inside '$pwd'");
}
echo "\n";
}
public function requireDir($path){
foreach (scandir($path) as $file){
if (substr($file,-4)!='.php')continue;
require_once($path.'/'.$file);
}
}
public function init(){
$dir = getcwd().'/test';
$continue = readline("Initialize test dir at $dir? (y/n) ");
if ($continue!=='y')return;
mkdir($dir);
mkdir($dir.'/run');
mkdir($dir.'/src');
$files = [
'run/Blogs.php',
'src/Tester.php',
'bootstrap.php',
'config.json',
];
foreach ($files as $f){
copy(dirname(__DIR__).'/.setup/test/'.$f, $dir.'/'.$f);
}
}
public function run(){
if (($this->inputs['init']??false)==true){
$this->init();
return;
}
$dir = $this->dir;
$phpFiles = [];
foreach ($this->answers['testDirs']??['.'] as $sub_dir){
$search_dir = $dir.'/'.$sub_dir;
$phpFiles = array_merge($phpFiles, \Tlf\Tester\Utility::getAllFiles($search_dir,$dir,'.php'));
}
$excludes = $this->answers['dir.exclude'];
$testSet = [];
foreach ($phpFiles as $relPath){
foreach ($excludes as $e){
$re = $relPath;
if ($re[0]!='/')$re = '/'.$re;
if ($e[0]!='/')$e = '/'.$e;
if (substr($relPath,0,strlen($e))==$e)continue 2;
}
if (in_array($relPath, $excludes))continue;
$filePath = $dir.'/'.$relPath;
$ob_level = Utility::startOb();
require_once($filePath);
$class = Utility::getClassFromFile($filePath);
if ($class==null){
$this->report("No class found in $filePath");
continue;
}
if (!is_a($class, '\\Tlf\\Tester', true))continue;
$tester = new $class($this->answers, $this);
$results = $tester->run();
$output = Utility::endOb($ob_level);
$testSet[$dir][$class] = ['file'=>$filePath, 'object'=>$tester, 'tests'=>$results];
//I'm trying to return something like this:
// $allCompletedTests = [
// 'dir'=>[
// '\\Clasname\\That\\Was\\Tested'=>
// [
// 'file'=> 'file path',
// 'object' => $theTesterInstance,
// 'tests'=> [
// // for function testMethodName()
// 'MethodName' => $resultObject
// ]//or should this be an array of the testers??
// ],
// '\\Another\\Class' => $andItsTests
// ]
// ];
}
echo $this->cliOutput($testSet);
$html = $this->htmlOutput($testSet);
$this->writeTestResults($html);
echo "\n\n";
return $testSet;
}
public function report($msg){
$this->reports[] = $msg;
echo "\n".$msg;
}
/**
* Get an array of parsed inputs
*/
public function getInputs(){
return $this->inputs;
}
/**
* Get configs as they're stored on disk
*/
public function getConfigs(){
return $this->configs;
}
/**
* Get all answers given to this program. Cli inputs, config file, and defaults where answers were not given
*/
public function getAnswers(){
return $this->answers;
}
protected function parseArgs(array $args){
$out = [];
foreach ($args as $index=>$input){
if ($input[0]=='-'){
if ($input[1]=='-'){
$key = substr($input,2);
$out[$key] = true;
continue;
}
$key = substr($input,1);
continue;
}
if ($key!=null){
if ($input=='true')$input = true;
else if ($input=='false')$input = false;
if (isset($this->arrayify[$key]))$out[$key][] = $input;
else $out[$key] = $input;
$key = null;
continue;
}
$this->report("input '$input' is not valid at index $index");
}
return $out;
}
protected function getConfigFile(){
$configFile = $this->pwd.'/'.$this->inputs['file.config'];
if (is_file($configFile)){
// var_dump($configFile);
$configs = json_decode(file_get_contents($configFile),true);
if (!is_array($configs))return [];
// var_dump($configs);
// exit;
$confs = $configs;
foreach ($confs as $key=>$value){
if (isset($this->arrayify[$key])
&&!is_array($value)
){
$configs[$key][] = $value;
}
}
return $configs;
}
//@todo prompt to write a default config file
return [];
}
/**
*
* @return an array of default inputs
*/
public function getDefaultInputs(){
return [
'file.config'=>'test/config.json',
'test'=>null,
// 'testDir'=>'something',
];
}
public function getDefaultConfigs(){
return [
'dir.test'=>'test',
'dir.exclude'=>['extra'],
'file.autoloader'=>'vendor/autoload.php',
'file.require'=>[],
'dir.require'=>[],
'results.writeHtml'=>true,
];
}
protected function runTestFile($filePath,$options, &$testSet){
}
}