_plg = $this->make('e107plugin');
}
catch (Exception $e)
{
$this->assertTrue(false, "Couldn't load e107plugin object");
}*/
}
private function makePluginReport($pluginDir)
{
$debug = $this->_debugPlugin;
$debug_text = "\n\n---- Log \n\n";
$log = e107::getPlugin()->getLog();
foreach($log as $line)
{
$debug_text .= " - ".$line."\n";
}
$debug_text .= "----------------------------------------\n\n";
$debug_text .= "---- Pref: plug_installed (version)\n\n";
$pref = e107::getConfig('core',true,true)->get('plug_installed');
$installedPref = isset($pref[$pluginDir]) ? $pref[$pluginDir] : false;
$debug_text .= print_r($installedPref,true);
$debug_text .= "\n\n---- Plugin Prefs: \n\n";
$pluginPref = e107::pref($pluginDir);
$debug_text .= print_r($pluginPref,true);
$debug_text .= "\n---- Plugin Table: ".$pluginDir."\n\n";
$pluginTable = e107::getDb()->retrieve('plugin','*', "plugin_path='".$pluginDir."' LIMIT 1", true);
$debug_text .= print_r($pluginTable,true);
$debug_text .= "\n---- Menu Table: ".$pluginDir."\n\n";
$menuTable = e107::getDb()->retrieve('menus','*', "menu_location = 0 AND menu_path='".$pluginDir."/' LIMIT 10", true);
$debug_text .= print_r($menuTable, true);
$debug_text .= "\n---- Site Links Table: ".$pluginDir."\n\n";
$linksTable = e107::getDb()->retrieve('links','*', "link_owner='".$pluginDir."' ", true);
$debug_text .= print_r($linksTable, true);
$files_in_plugin_directory = @scandir(e_PLUGIN.$pluginDir) ?: [];
$corePref = e107::getConfig('core',true,true)->getPref();
$debug_text .= "\n---- Addons\n\n";
$debug_text .= "-------------------------------------------------------------------\n";
$debug_text .= "Addon file In Core pref e_xxxx_list \n";
$debug_text .= "-------------------------------------------------------------------\n";
$addonPref = array();
$plugin_addon_names = $this->pluginFileListToPluginAddonNames($files_in_plugin_directory);
foreach($plugin_addon_names as $plugin_addon_name)
{
$key = $plugin_addon_name."_list";
$addon_pref_is_present = !empty($corePref[$key][$pluginDir]);
$debug_addon_pref_is_present = ($addon_pref_is_present) ? 'YES' : 'NO';
if($key === 'e_admin_events_list')
{
$debug_addon_pref_is_present = "DEPRECATED by Admin-UI events";
}
if($key === 'e_help_list')
{
$debug_addon_pref_is_present = "DEPRECATED by Admin-UI renderHelp()";
}
else
{
$addonPref[$plugin_addon_name] = $addon_pref_is_present;
}
$debug_text .= str_pad("$plugin_addon_name.php",20)
."\t\t$debug_addon_pref_is_present\n";
}
$debug_text .= "-------------------------------------------------------------------\n";
if(!empty($debug) && $pluginDir === $debug)
{
codecept_debug($debug_text);
echo $debug_text;
}
return array(
'log' => $log,
'installedPref' => $installedPref,
'pluginPref' => $pluginPref,
'pluginTable' => $pluginTable,
'menuTable' => $menuTable,
'linksTable' => $linksTable,
'addonPref' => $addonPref
);
}
/**
* @see https://github.com/e107inc/e107/issues/3547
*/
public function testBlank()
{
// $this->_debugPlugin = '_blank';
$result = $this->pluginInstall('_blank');
// print_r($result);
// $this->pluginUninstall('_blank');
}
public function testSortOrderPeriodUnderscore()
{
$expected = ['banner.php', 'banner_menu.php'];
$input = ['banner_menu.php', 'banner.php'];
sort($input);
$this->assertEquals($expected, $input);
}
/**
* @runInSeparateProcess
* @return void
*/
public function testPluginScripts()
{
$core = e107::getPlug()->getCorePluginList();
$exclude = [
'forum/forum_post.php',
'forum/forum_viewtopic.php',
'forum/index.php',
'online/online_menu.php',
'pm/pm.php',
'poll/admin_config.php',
'rss_menu/rss.php',
'tagcloud/tagcloud_menu.php',
'tinymce4/wysiwyg.php',
];
$focus = [];
$errors = [];
foreach($core as $plug)
{
$path = realpath(e107::getFolder('plugins') . $plug);
if($path === false)
{
fwrite(STDOUT, "Plugin directory not found: {$plug}\n");
continue;
}
$file[$plug] = scandir($path);
unset($file[$plug][0], $file[$plug][1]);
sort($file[$plug]);
if(!empty($focus) && !isset($focus[$plug]))
{
unset($file[$plug]);
continue;
}
e107::plugLan($plug, 'global');
e107::getConfig()->setPref('plug_installed/' . $plug, 1);
}
foreach($file as $plug => $files)
{
$pluginFiles = [];
foreach($files as $f)
{
$filePath = realpath(e107::getFolder('plugins') . $plug) . DIRECTORY_SEPARATOR . $f;
if(!empty($focus) && $f !== $focus[$plug])
{
continue;
}
if(is_dir($filePath) || strpos($f, '_sql.php') !== false || strpos($f, '.php') === false || in_array($plug . '/' . $f, $exclude))
{
continue;
}
if(!file_exists($filePath))
{
fwrite(STDOUT, "File not found: {$plug}/{$f}\n");
continue;
}
$pluginFiles[$plug . '/' . $f] = $filePath;
}
if(empty($pluginFiles))
{
fwrite(STDOUT, "No testable files found for plugin: {$plug}\n");
continue;
}
fwrite(STDOUT, "Testing plugin: {$plug}\n");
foreach($pluginFiles as $relativePath => $_)
{
fwrite(STDOUT, " - $relativePath\n");
}
// Build the command
$requireStatements = '';
$firstFilePath = reset($pluginFiles);
$e107Root = realpath(dirname($firstFilePath) . '/../../');
$class2Path = $e107Root . '/class2.php';
if($class2Path === false || !file_exists($class2Path))
{
fwrite(STDOUT, "Error: Could not locate class2.php at $class2Path\n");
$errors[] = "Error: Could not locate class2.php for plugin {$plug}";
continue;
}
$lanAdminPath = $e107Root . '/e107_languages/English/admin/lan_admin.php';
if(!file_exists($lanAdminPath))
{
fwrite(STDOUT, "Error: Could not locate lan_admin.php at $lanAdminPath\n");
$errors[] = "Error: Could not locate lan_admin.php for plugin {$plug}";
continue;
}
$requireStatements .= "error_reporting(E_ALL); ini_set('display_errors', 1); ";
$requireStatements .= "require_once ('" . addslashes($class2Path) . "'); ";
$requireStatements .= "e107::includeLan( '" . addslashes($lanAdminPath) . "'); ";
$requireStatements .= "e107::plugLan('" . addslashes($plug) . "', 'global'); ";
$requireStatements .= "e107::getConfig()->setPref('plug_installed/" . addslashes($plug) . "', 1); ";
foreach($pluginFiles as $relativePath => $filePath)
{
$requireStatements .= "echo 'START: " . addslashes($relativePath) . "\\n'; ";
$requireStatements .= "require_once '" . addslashes($filePath) . "'; ";
$requireStatements .= "echo 'END: " . addslashes($relativePath) . "\\n'; ";
}
$runCommand = sprintf('php -r %s 1>NUL 2>&1', escapeshellarg($requireStatements));
// fwrite(STDOUT, "Debug run command:\n$runCommand\n\n\n\n");
// Execute and capture errors
exec($runCommand, $runOutput, $runExitCode);
if($runExitCode !== 0 || !empty($runOutput))
{
$output = implode("\n", $runOutput);
if(!empty($output))
{
if(preg_match('/(Parse error|Fatal error|Warning|Notice):.*in\s+([^\s]+)\s+on\s+line\s+(\d+)/i', $output, $match))
{
$errorMessage = $match[0];
$errorFile = $match[2];
$relativePath = array_search($errorFile, $pluginFiles) ?: $plug . '/unknown';
$error = "Error in {$relativePath}: $errorMessage";
fwrite(STDOUT, "$error\n");
$errors[] = $error;
}
else
{
$firstLine = strtok($output, "\n");
$error = "Error in {$plug}: $firstLine";
fwrite(STDOUT, "$error\n");
$errors[] = $error;
}
}
else
{
// Sequentially check files to find the error
$lastGoodFile = null;
foreach($pluginFiles as $relativePath => $filePath)
{
$testCommand = sprintf('php -r %s 1>NUL 2>&1', escapeshellarg(
"error_reporting(E_ALL); ini_set('display_errors', 1); " .
"require_once('" . addslashes($class2Path) . "'); " .
"e107::includeLan('" . addslashes($lanAdminPath) . "'); " .
"e107::plugLan('" . addslashes($plug) . "', 'global'); " .
"e107::getConfig()->setPref('plug_installed/" . addslashes($plug) . "', 1); " .
"e107::includeLan('" . addslashes($filePath) . "');"
));
exec($testCommand, $testOutput, $testExitCode);
if($testExitCode !== 0)
{
$errorOutput = !empty($testOutput) ? implode("\n", $testOutput) : "Syntax error detected (exit code $testExitCode)";
if(preg_match('/(Parse error|Fatal error|Warning|Notice):.*in\s+([^\s]+)\s+on\s+line\s+(\d+)/i', $errorOutput, $match))
{
$errorMessage = $match[0];
}
else
{
$errorMessage = $errorOutput;
}
$error = "Error in {$relativePath}: $errorMessage";
fwrite(STDOUT, "$error\n");
$errors[] = $error;
break;
}
$lastGoodFile = $relativePath;
}
if(empty($errors) && $lastGoodFile)
{
$error = "Error after {$lastGoodFile}: Syntax error detected (exit code $runExitCode)";
fwrite(STDOUT, "$error\n");
$errors[] = $error;
}
}
}
}
if(!empty($errors))
{
self::fail("Errors found in plugin scripts:\n" . implode("\n", $errors));
}
}
/**
* @see https://github.com/e107inc/e107/issues/3547
*/
public function testBanner()
{
$this->pluginInstall('banner');
// App needs e_parse_shortcode to be reloaded because another test
// could have initialized e_parse_shortcode already before the
// "banner" plugin was installed.
e107::getScParser()->__construct();
$tp = e107::getParser();
$result = $tp->parseTemplate("{BANNER=e107promo}", true);
$this->assertStringContainsString('
parseTemplate("{BANNER=e107promo}", false, e107::getScBatch('banner', true));
$this->assertStringContainsString('
parseTemplate("{BANNER=e107promo}", false);
$this->assertEquals("", $result);
$this->pluginUninstall('banner');
$result = $tp->parseTemplate("{BANNER=e107promo}", true);
// The expected value below was the actual observed output when the assertion was written:
$this->assertEquals(' ', $result,
"Banner shortcode is not returning an empty value, despite banner being uninstalled");
}
public function testChatbox_Menu()
{
$this->pluginInstall('chatbox_menu');
$this->pluginUninstall('chatbox_menu');
}
public function testDownload()
{
$this->pluginInstall('download');
$this->pluginUninstall('download');
}
public function testFaqs()
{
$this->pluginInstall('faqs');
$this->pluginUninstall('faqs');
}
public function testFeaturebox()
{
$this->pluginInstall('featurebox');
$this->pluginUninstall('featurebox');
}
public function testForum()
{
$this->pluginInstall('forum');
$this->pluginUninstall('forum');
}
public function testGallery()
{
$this->pluginInstall('gallery');
$this->pluginUninstall('gallery');
}
public function testGsitemap()
{
$this->pluginInstall('gsitemap');
$this->pluginUninstall('gsitemap');
}
public function testImport()
{
$this->pluginInstall('import');
$this->pluginUninstall('import');
}
public function testLinkwords()
{
$this->pluginInstall('linkwords');
$pref1 = e107::pref('linkwords', 'lw_custom_class');
$this->assertNotEmpty($pref1);
$pref2 = e107::pref('linkwords', 'lw_context_visibility');
$this->assertNotEmpty($pref2['SUMMARY']);
$this->pluginUninstall('linkwords');
$pref2 = e107::pref('linkwords', 'lw_context_visibility');
$this->assertEmpty($pref2);
}
public function testPm()
{
$this->pluginInstall('pm');
$this->pluginUninstall('pm');
}
public function testPoll()
{
$this->pluginInstall('poll');
$this->pluginUninstall('poll');
}
public function testRss_menu()
{
$this->pluginInstall('rss_menu');
$installed = e107::isInstalled('rss_menu');
self::assertTrue($installed);
$this->pluginUninstall('rss_menu');
$installed = e107::isInstalled('rss_menu');
self::assertFalse($installed);
}
public function testSocial()
{
$this->pluginUninstall('social');
$this->pluginInstall('social');
}
public function testTagcloud()
{
$this->pluginInstall('tagcloud');
$this->pluginUninstall('tagcloud');
}
public function testRefreshExtendedFields()
{
$this->pluginInstall('_blank');
$count = e107::getDb()->count('user_extended_struct', '(*)', "user_extended_struct_name LIKE 'plugin__blank_custom%'");
$this::assertEquals(1, $count, 'Field was not installed');
$this->pluginRefresh('_blank');
$count = e107::getDb()->count('user_extended_struct', '(*)', "user_extended_struct_name LIKE 'plugin__blank_custom%'");
$this::assertEquals(1, $count, 'Field was duplicated or is missing');
e107::getDb()->delete('user_extended_struct', "user_extended_struct_name LIKE 'plugin__blank_custom%'");
$count = e107::getDb()->count('user_extended_struct', '(*)', "user_extended_struct_name LIKE 'plugin__blank_custom%'");
$this::assertEquals(0, $count, 'Field was not deleted');
$this->pluginRefresh('_blank');
$count = e107::getDb()->count('user_extended_struct', '(*)', "user_extended_struct_name LIKE 'plugin__blank_custom%'");
$this::assertEquals(1, $count, 'Field was not re-installed');
$this->pluginUninstall('_blank');
}
/*
public function testThirdParty()
{
$coreList = e107::getPlug()->getCorePluginList();
$all = scandir(e_PLUGIN);
unset($all[0], $all[1]);
$diff = array_diff($all, $coreList);
foreach($diff as $plug)
{
if(!is_dir(e_PLUGIN.$plug) || !is_dir(e_PLUGIN.$plug.'/tests'))
{
continue;
}
$tests = scandir(e_PLUGIN.$plug.'/tests');
unset($tests[0], $tests[1]);
foreach($tests as $t)
{
require_once(e_PLUGIN.$plug.'/tests/'.$t);
$Codecept = new \Codeception\Codecept(array(
'steps' => true,
'verbosity' => 1,
// some other options (see Codeception docs/sources)
));
// var_export($Codecept);
$Codecept->run('unit');
// require_once '/path/to/codeception/autoload.php';
}
}
//array_intersect(
}*/
public function testplugInstalledStatus()
{
$sql = e107::getDb();
$plg = e107::getPlug()->clearCache();
$plg->load('tagcloud');
// check it's NOT installed.
$status = $plg->isInstalled();
$dbStatus = (bool) $sql->retrieve('plugin', "plugin_installflag", "plugin_path='tagcloud'");
$this->assertEquals($status,$dbStatus,"e_plugin:isInstalled() doesn't match plugin_installflag in db table.");
$this->assertFalse($status, "Status for tagcloud being installed should be false");
e107::getPlugin()->install('tagcloud');
// check it's installed.
$status = (int) $plg->isInstalled();
$actual = (bool) $status;
$dbStatus = (int) $sql->retrieve('plugin', "plugin_installflag", "plugin_path='tagcloud'");
$this->assertEquals($status,$dbStatus,"e_plugin:isInstalled() = ".$status." but plugin_installflag = ".$dbStatus." after install.");
$this->assertTrue($actual, "Status for tagcloud being installed should be true after being installed.");
e107::getPlugin()->uninstall('tagcloud');
// check it's NOT installed.
$status = (int) $plg->isInstalled();
$actual = (bool) $status;
$dbStatus = (int) $sql->retrieve('plugin', "plugin_installflag", "plugin_path='tagcloud'");
$this->assertEquals($status,$dbStatus,"e_plugin:isInstalled() = ".$status." but plugin_installflag = ".$dbStatus." after uninstall.");
$this->assertFalse($actual, "Status for tagcloud being installed should be false after being uninstalled.");
}
/**
* @runInSeparateProcess
* @return void
*/
public function testPluginAddons()
{
$plg = e107::getPlug()->clearCache();
$plg->buildAddonPrefLists();
$errors = array(
1 => 'PHP tag Syntax issue',
2 => "File Missing",
);
foreach($plg->getCorePluginList() as $folder)
{
$plg->load($folder);
$errMsg = '';
$addons = $plg->getAddons();
foreach(explode(',', $addons) as $this_addon)
{
if(empty($this_addon))
{
continue;
}
$result = $plg->getAddonErrors($this_addon);
if(is_numeric($result) && $result != 0)
{
$errMsg = " (".$errors[$result].")";
}
elseif(isset($result['msg']))
{
$errMsg = " (".$result['msg'].")";
}
$this->assertEmpty($result, $folder." > ".$this_addon." returned error #".$result.$errMsg);
}
}
}
public function testRemotePlugin()
{
require_once(e_HANDLER."e_marketplace.php");
try
{
$mock_adapter = $this->make('e_marketplace_adapter_wsdl',
[
'getRemoteFile' => function($remote_url, $local_file, $type='temp')
{
file_put_contents(e_TEMP.$local_file, self::samplePluginContents());
return true;
}
]);
$mp = $this->make('e_marketplace',
[
'adapter' => $mock_adapter
]);
}
catch (Exception $e)
{
$this->fail("Couldn't load e_marketplace object");
}
$mp->__construct();
$id = 912; // No-follow plugin on e107.org
$this->assertFalse(is_dir(e_PLUGIN."nofollow"), "Plugin nofollow exists before download");
$mp->download($id, '', 'plugin');
$this->assertTrue(is_dir(e_PLUGIN."nofollow"), "Plugin nofollow is missing after download");
$this->pluginInstall('nofollow');
$opts = array(
'delete_tables' => 1,
'delete_files' => 1
);
$this->pluginUninstall('nofollow',$opts);
$status = is_dir(e_PLUGIN."nofollow");
$this->assertFalse($status,"nofollow plugin still exists, despite opt to have it removed during uninstall.");
}
private function pluginRefresh($pluginDir)
{
$return_text = e107::getPlugin()->refresh($pluginDir);
}
private function pluginInstall($pluginDir)
{
e107::setRegistry('core/form/related'); // reset.
e107::getPlugin()->uninstall($pluginDir);
$return_text = e107::getPlugin()->install($pluginDir);
$this->assertNotEquals("Plugin is already installed.", $return_text);
$install = $this->makePluginReport($pluginDir);
//todo additional checks
foreach($install['addonPref'] as $key=>$val)
{
$this->assertTrue($val, $key." list pref is missing for ".$pluginDir);
}
return $install;
}
private function pluginUninstall($pluginDir, $opts=array())
{
if(empty($opts))
{
$opts = array(
'delete_tables' => 1,
'delete_files' => 0
);
}
e107::getPlugin()->uninstall($pluginDir, $opts);
$uninstall = $this->makePluginReport($pluginDir);
//todo additional checks
$this->assertEmpty($uninstall['linksTable'], $pluginDir." link still exists in the links table");
foreach($uninstall['addonPref'] as $key=>$val)
{
$message = $key." list pref still contains '".$pluginDir."' after uninstall of ".$pluginDir.". ";
$message .= print_r($uninstall,true);
$this->assertEmpty($val, $message);
}
return $uninstall;
}
/**
* @param $plugin_file_list
* @return array
*/
private function pluginFileListToPluginAddonNames($plugin_file_list)
{
$plugin_addon_names = array_map(function ($addon_path)
{
return basename($addon_path, '.php');
}, $plugin_file_list);
$class_name_that_has_plugin_addons_array = 'e107plugin';
try
{
$reflectionClass = new ReflectionClass($class_name_that_has_plugin_addons_array);
}
catch(ReflectionException $e)
{
$this->fail("Could not instantiate $class_name_that_has_plugin_addons_array to get \$plugin_addons");
}
$reflectionProperty = $reflectionClass->getProperty('plugin_addons');
$reflectionProperty->setAccessible(true);
$valid_plugin_addon_names = $reflectionProperty->getValue(new $class_name_that_has_plugin_addons_array());
$plugin_addon_names = array_filter($plugin_addon_names, function ($plugin_addon_name) use ($valid_plugin_addon_names)
{
return in_array($plugin_addon_name, $valid_plugin_addon_names);
});
return $plugin_addon_names;
}
private static function samplePluginContents()
{
return base64_decode(<<