aboutsummaryrefslogtreecommitdiff
path: root/tests/unit
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /tests/unit
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/_bootstrap.php72
-rw-r--r--tests/unit/lib/CalendarcolumnClassTest.php2
-rw-r--r--tests/unit/lib/CalendarviewClassTest.php2
-rw-r--r--tests/unit/lib/FunctionsTest.php25
-rw-r--r--tests/unit/lib/VisualTest.php16
-rw-r--r--tests/unit/lib/classes/AvatarClassTest.php2
-rw-r--r--tests/unit/lib/classes/CronjobScheduleTest.php54
-rw-r--r--tests/unit/lib/classes/IconClassTest.php48
-rw-r--r--tests/unit/lib/classes/MarkupClassTest.php10
-rw-r--r--tests/unit/lib/classes/MigrationTest.php5
-rw-r--r--tests/unit/lib/classes/OAuth1Test.php118
-rw-r--r--tests/unit/lib/classes/OpenGraphTest.php34
-rw-r--r--tests/unit/lib/classes/PluginRepositoryTest.php2
-rw-r--r--tests/unit/lib/classes/RequestParametersTest.php94
-rw-r--r--tests/unit/lib/classes/SimpleOrMapNodbTest.php7
-rw-r--r--tests/unit/lib/classes/StudipCachedArrayTest.php5
-rw-r--r--tests/unit/lib/classes/StudipControllerTest.php6
-rw-r--r--tests/unit/lib/classes/StudipFileloaderTest.php4
-rw-r--r--tests/unit/lib/classes/TrailsTest.php25
-rw-r--r--tests/unit/lib/classes/extTPLTemplateTest.php213
-rw-r--r--tests/unit/lib/flexi/FactoryTest.php119
-rw-r--r--tests/unit/lib/flexi/PHPTemplatePartialBugTest.php45
-rw-r--r--tests/unit/lib/flexi/PHPTemplateTest.php136
-rw-r--r--tests/unit/lib/flexi/TemplateEmptyTest.php44
-rw-r--r--tests/unit/lib/flexi/TemplateMagicMethodsTest.php78
-rw-r--r--tests/unit/lib/flexi/TemplateTest.php68
-rw-r--r--tests/unit/varstream.php106
27 files changed, 1158 insertions, 182 deletions
diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php
index 2216111..0cf0f7e 100644
--- a/tests/unit/_bootstrap.php
+++ b/tests/unit/_bootstrap.php
@@ -21,10 +21,7 @@
// SOFTWARE.
// set error reporting
-error_reporting(E_ALL & ~E_NOTICE);
-if (version_compare(phpversion(), '5.4', '>=')) {
- error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
-}
+error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
// set include path
$inc_path = ini_get('include_path');
@@ -32,47 +29,32 @@ $inc_path .= PATH_SEPARATOR . __DIR__ . '/../..';
$inc_path .= PATH_SEPARATOR . __DIR__ . '/../../config';
ini_set('include_path', $inc_path);
+global $ABSOLUTE_URI_STUDIP,
+ $ASSETS_URL,
+ $CACHING_ENABLE,
+ $CACHING_FILECACHE_PATH,
+ $CANONICAL_RELATIVE_PATH_STUDIP,
+ $DYNAMIC_CONTENT_PATH,
+ $DYNAMIC_CONTENT_URL,
+ $STUDIP_BASE_PATH,
+ $SYMBOL_SHORT,
+ $TMP_PATH,
+ $UPLOAD_PATH;
+
// load varstream for easier filesystem testing
require_once 'varstream.php';
-define("TEST_FIXTURES_PATH", dirname(__DIR__) . "/_data/");
+define('TEST_FIXTURES_PATH', dirname(__DIR__) . '/_data/');
require __DIR__ . '/../../composer/autoload.php';
global $STUDIP_BASE_PATH;
$STUDIP_BASE_PATH = realpath(dirname(__DIR__) . '/..');
-require 'lib/classes/StudipAutoloader.php';
+require 'lib/helpers.php';
require 'lib/functions.php';
require 'lib/visual.inc.php';
-StudipAutoloader::setBasePath(realpath(__DIR__ . '/../..'));
-StudipAutoloader::register();
-
-StudipAutoloader::addAutoloadPath('lib/activities', 'Studip\\Activity');
-StudipAutoloader::addAutoloadPath('lib/models');
-StudipAutoloader::addAutoloadPath('lib/classes');
-StudipAutoloader::addAutoloadPath('lib/classes', 'Studip');
-StudipAutoloader::addAutoloadPath('lib/exceptions');
-StudipAutoloader::addAutoloadPath('lib/classes/sidebar');
-StudipAutoloader::addAutoloadPath('lib/classes/helpbar');
-StudipAutoloader::addAutoloadPath('lib/plugins/engine');
-StudipAutoloader::addAutoloadPath('lib/plugins/core');
-StudipAutoloader::addAutoloadPath('lib/plugins/db');
-
-StudipAutoloader::addClassLookup('StudipController', 'app/controllers/studip_controller.php');
-$trails_classes = [
- 'Trails_Dispatcher', 'Trails_Response', 'Trails_Controller',
- 'Trails_Inflector', 'Trails_Flash',
- 'Trails_Exception', 'Trails_DoubleRenderError', 'Trails_MissingFile',
- 'Trails_RoutingError', 'Trails_UnknownAction', 'Trails_UnknownController',
- 'Trails_SessionRequiredException',
-];
-StudipAutoloader::addClassLookup(
- $trails_classes,
- 'vendor/trails/trails.php'
-);
-
// load config-variables
$added_configs = [];
StudipFileloader::load(
@@ -86,16 +68,16 @@ foreach ($added_configs as $key => $value) {
$GLOBALS[$key] = $value;
}
-$config = Symfony\Component\Yaml\Yaml::parseFile(__DIR__ .'/../unit.suite.yml');
+$config = Symfony\Component\Yaml\Yaml::parseFile(__DIR__ . '/../unit.suite.yml');
// connect to database if configured
if (isset($config['modules']['config']['Db'])) {
- DBManager::getInstance()->setConnection('studip',
+ DBManager::getInstance()->setConnection(
+ 'studip',
$config['modules']['config']['Db']['dsn'],
$config['modules']['config']['Db']['user'],
- $config['modules']['config']['Db']['password']);
-} else {
- //DBManager::getInstance()->setConnection('studip', 'sqlite://'. $GLOBALS ,'', '');
+ $config['modules']['config']['Db']['password']
+ );
}
// Disable caching to fallback to memory cache
@@ -108,7 +90,7 @@ if (!class_exists('StudipTestHelper')) {
static function set_up_tables($tables)
{
// first step, set fake cache
- $cache = StudipCacheFactory::getCache(false);
+ $cache = \Studip\Cache\Factory::getCache(false);
// second step, expire table scheme
SimpleORMap::expireTableScheme();
@@ -116,17 +98,17 @@ if (!class_exists('StudipTestHelper')) {
$schemes = [];
foreach ($tables as $db_table) {
- include TEST_FIXTURES_PATH."simpleormap/$db_table.php";
+ include TEST_FIXTURES_PATH . "simpleormap/$db_table.php";
$db_fields = $pk = [];
foreach ($result as $rs) {
$db_fields[mb_strtolower($rs['name'])] = [
- 'name' => $rs['name'],
- 'null' => $rs['null'],
+ 'name' => $rs['name'],
+ 'null' => $rs['null'],
'default' => $rs['default'],
- 'type' => $rs['type'],
- 'extra' => $rs['extra']
+ 'type' => $rs['type'],
+ 'extra' => $rs['extra'],
];
- if ($rs['key'] == 'PRI'){
+ if ($rs['key'] == 'PRI') {
$pk[] = mb_strtolower($rs['name']);
}
}
diff --git a/tests/unit/lib/CalendarcolumnClassTest.php b/tests/unit/lib/CalendarcolumnClassTest.php
index 063f97e..d2ac9e0 100644
--- a/tests/unit/lib/CalendarcolumnClassTest.php
+++ b/tests/unit/lib/CalendarcolumnClassTest.php
@@ -9,7 +9,7 @@
* the License, or (at your option) any later version.
*/
-require_once 'lib/calendar/CalendarColumn.class.php';
+require_once 'lib/calendar/CalendarColumn.php';
class CalendarColumnCase extends \Codeception\Test\Unit {
diff --git a/tests/unit/lib/CalendarviewClassTest.php b/tests/unit/lib/CalendarviewClassTest.php
index 962cd06..d810575 100644
--- a/tests/unit/lib/CalendarviewClassTest.php
+++ b/tests/unit/lib/CalendarviewClassTest.php
@@ -9,7 +9,7 @@
* the License, or (at your option) any later version.
*/
-require_once 'lib/calendar/CalendarView.class.php';
+require_once 'lib/calendar/CalendarView.php';
class CalendarViewCase extends \Codeception\Test\Unit {
diff --git a/tests/unit/lib/FunctionsTest.php b/tests/unit/lib/FunctionsTest.php
index 9a92f1a..c254fda 100644
--- a/tests/unit/lib/FunctionsTest.php
+++ b/tests/unit/lib/FunctionsTest.php
@@ -75,16 +75,35 @@ class FunctionsTest extends \Codeception\Test\Unit
}
/**
- * @covers Trails_Controller::extract_action_and_args()
+ * @covers Trails\Controller::extract_action_and_args()
*/
public function testTrailsControllerExtractActionAndArgs()
{
- $controller = new Trails_Controller(null);
- list($action, $args, $format) = $controller->extract_action_and_args('foo/bar//42.html');
+ $dispatcher = new Trails\Dispatcher('', '', '');
+ $controller = new Trails\Controller($dispatcher);
+ [$action, $args, $format] = $controller->extract_action_and_args('foo/bar//42.html');
$this->assertEquals('foo', $action);
$this->assertEquals(['bar', '', '42'], $args);
$this->assertEquals('html', $format);
}
+
+ /**
+ * @covers ::studip_interpolate
+ */
+ public function testStudipInterpolate()
+ {
+ $this->assertEquals(
+ '12bar34',
+ studip_interpolate('12%{foo}34', ['foo' => 'bar'])
+ );
+ $this->assertEquals(
+ 'foo',
+ studip_interpolate('%{ bar }', ['bar' => 'foo'])
+ );
+
+ $this->expectException(Exception::class);
+ studip_interpolate('%{foo}', []);
+ }
}
diff --git a/tests/unit/lib/VisualTest.php b/tests/unit/lib/VisualTest.php
index dfa2945..2ea8334 100644
--- a/tests/unit/lib/VisualTest.php
+++ b/tests/unit/lib/VisualTest.php
@@ -9,10 +9,9 @@
* the License, or (at your option) any later version.
*/
-require_once 'lib/models/SimpleORMap.class.php';
-require_once 'lib/models/OpenGraphURL.class.php';
+require_once 'lib/classes/SimpleORMap.php';
require_once 'lib/visual.inc.php';
-require_once 'lib/classes/Config.class.php';
+require_once 'lib/classes/Config.php';
class VisualFunctionsTest extends \Codeception\Test\Unit
{
@@ -21,6 +20,7 @@ class VisualFunctionsTest extends \Codeception\Test\Unit
static $config = [
'LOAD_EXTERNAL_MEDIA' => 'allow',
'OPENGRAPH_ENABLE' => false,
+ 'CONVERT_IDNA_URL' => true,
];
Config::set(new Config($config));
@@ -224,6 +224,16 @@ class VisualFunctionsTest extends \Codeception\Test\Unit
$this->assertEquals($expected, formatReady($input));
}
+ public function testIdnaLink()
+ {
+ $input = htmlentities('https://www.täst-dömäne-mit-ümläuten.de');
+
+ $this->assertEquals(
+ 'https://www.xn--tst-dmne-mit-mluten-gwbfj61b7e.de',
+ idna_link($input)
+ );
+ }
+
private function wrap($string)
{
return sprintf(FORMATTED_CONTENT_WRAPPER, $string);
diff --git a/tests/unit/lib/classes/AvatarClassTest.php b/tests/unit/lib/classes/AvatarClassTest.php
index 8172e20..e09a3c2 100644
--- a/tests/unit/lib/classes/AvatarClassTest.php
+++ b/tests/unit/lib/classes/AvatarClassTest.php
@@ -9,7 +9,7 @@
* the License, or (at your option) any later version.
*/
-require_once 'lib/phplib/Seminar_Perm.class.php';
+require_once 'lib/phplib/Seminar_Perm.php';
abstract class AvatarTest extends \Codeception\Test\Unit
{
diff --git a/tests/unit/lib/classes/CronjobScheduleTest.php b/tests/unit/lib/classes/CronjobScheduleTest.php
index a97872e..b6fd573 100644
--- a/tests/unit/lib/classes/CronjobScheduleTest.php
+++ b/tests/unit/lib/classes/CronjobScheduleTest.php
@@ -26,69 +26,15 @@ class CronjobScheduleTest extends \Codeception\Test\Unit
StudipTestHelper::tear_down_tables();
}
- function testOnceSchedule()
- {
- $schedule = new CronjobSchedule();
- $schedule->type = 'once';
-
- $this->assertEquals('once', $schedule->type);
-
- return $schedule;
- }
-
- /**
- * @depends testOnceSchedule
- */
- function testNextExecutionOncePast($schedule)
- {
- $now = strtotime('10.11.2013 01:02:00');
- $then = strtotime('-2 weeks', $now);
-
- $schedule->next_execution = $then;
- $schedule->calculateNextExecution();
-
- $this->assertEquals($then, $schedule->next_execution);
- }
-
- /**
- * @depends testOnceSchedule
- */
- function testNextExecutionOncePresent($schedule)
- {
- $now = strtotime('10.11.2013 01:02:00');
-
- $schedule->next_execution = $now;
- $schedule->calculateNextExecution();
-
- $this->assertEquals($now, $schedule->next_execution);
- }
-
- /**
- * @depends testOnceSchedule
- */
- function testNextExecutionOnceFuture(CronjobSchedule $schedule)
- {
- $now = strtotime('10.11.2013 01:02:00');
- $then = strtotime('+2 weeks', $now);
-
- $schedule->next_execution = $then;
- $schedule->calculateNextExecution($now);
-
- $this->assertEquals($then, $schedule->next_execution);
- }
-
function testPeriodicSchedule()
{
$schedule = new CronjobSchedule();
- $schedule->type = 'periodic';
$schedule->minute = null;
$schedule->hour = null;
$schedule->day = null;
$schedule->month = null;
$schedule->day_of_week = null;
- $this->assertEquals('periodic', $schedule->type);
-
return $schedule;
}
diff --git a/tests/unit/lib/classes/IconClassTest.php b/tests/unit/lib/classes/IconClassTest.php
index eb743b9..0e79df9 100644
--- a/tests/unit/lib/classes/IconClassTest.php
+++ b/tests/unit/lib/classes/IconClassTest.php
@@ -27,7 +27,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img width="16" height="16" src="images/icons/blue/vote.svg" alt="" class="icon-role-clickable icon-shape-vote">',
- Icon::create('vote', 'clickable')->asImg()
+ Icon::create('vote')->asImg()
);
}
@@ -35,7 +35,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img width="16" height="16" src="images/icons/blue/vote.svg" alt="" class="icon-role-clickable icon-shape-vote">',
- Icon::create('vote', 'clickable')->asImg()
+ Icon::create('vote')->asImg()
);
}
@@ -43,7 +43,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img width="20" height="20" src="images/icons/blue/vote.svg" alt="" class="icon-role-clickable icon-shape-vote">',
- Icon::create('vote', 'clickable')->asImg(20)
+ Icon::create('vote')->asImg(20)
);
}
@@ -51,7 +51,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img title="Mit Anhang" width="20" height="20" src="images/icons/blue/vote.svg" class="icon-role-clickable icon-shape-vote">',
- Icon::create('vote', 'clickable', ['title' => _("Mit Anhang")])->asImg(20)
+ Icon::create('vote')->asImg(20, ['title' => _('Mit Anhang')])
);
}
@@ -59,7 +59,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img hspace="3" width="16" height="16" src="images/icons/blue/arr_2left.svg" alt="" class="icon-role-clickable icon-shape-arr_2left">',
- Icon::create('arr_2left', 'clickable')->asImg(['hspace' => 3])
+ Icon::create('arr_2left')->asImg(['hspace' => 3])
);
}
@@ -67,7 +67,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img class="text-bottom icon-role-info icon-shape-staple" width="20" height="20" src="images/icons/black/staple.svg" alt="">',
- Icon::create('staple', 'info')->asImg(20, ['class' => 'text-bottom'])
+ Icon::create('staple', Icon::ROLE_INFO)->asImg(20, ['class' => 'text-bottom'])
);
}
@@ -75,7 +75,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img title="Datei hochladen" class="text-bottom icon-role-new icon-shape-upload" width="20" height="20" src="images/icons/red/upload.svg">',
- Icon::create('upload', 'new', ['title' => _("Datei hochladen")])
+ Icon::create('upload', Icon::ROLE_NEW, ['title' => _("Datei hochladen")])
->asImg(20, ['class' => 'text-bottom'])
);
}
@@ -84,22 +84,22 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<input type="image" class="text-bottom icon-role-clickable icon-shape-upload" width="20" height="20" src="images/icons/blue/upload.svg" alt="">',
- Icon::create('upload', 'clickable')->asInput(20, ['class' => 'text-bottom'])
+ Icon::create('upload')->asInput(20, ['class' => 'text-bottom'])
);
}
function testIconIsImmutable()
{
- $icon = Icon::create('upload', 'clickable', ['title' => _('a title')]);
- $copy = $icon->copyWithRole('clickable');
+ $icon = Icon::create('upload', Icon::ROLE_CLICKABLE, ['title' => _('a title')]);
+ $copy = $icon->copyWithRole(Icon::ROLE_CLICKABLE);
$this->assertNotSame($icon, $copy);
}
function testIconCopyWithRole()
{
- $icon = Icon::create('upload', 'clickable', ['title' => _('a title')]);
- $copy = $icon->copyWithRole('info');
+ $icon = Icon::create('upload', Icon::ROLE_CLICKABLE, ['title' => _('a title')]);
+ $copy = $icon->copyWithRole(Icon::ROLE_INFO);
$this->assertEquals($icon->getShape(), $copy->getShape());
$this->assertNotEquals($icon->getRole(), $copy->getRole());
@@ -108,7 +108,7 @@ class IconClassTest extends \Codeception\Test\Unit
function testIconCopyWithShape()
{
- $icon = Icon::create('upload', 'clickable', ['title' => _('a title')]);
+ $icon = Icon::create('upload', Icon::ROLE_CLICKABLE, ['title' => _('a title')]);
$copy = $icon->copyWithShape('staple');
$this->assertNotEquals($icon->getShape(), $copy->getShape());
@@ -118,7 +118,7 @@ class IconClassTest extends \Codeception\Test\Unit
function testIconCopyWithAttributes()
{
- $icon = Icon::create('upload', 'clickable', ['title' => _('a title')]);
+ $icon = Icon::create('upload', Icon::ROLE_CLICKABLE, ['title' => _('a title')]);
$copy = $icon->copyWithAttributes(['title' => _('another title')]);
$this->assertEquals($icon->getShape(), $copy->getShape());
@@ -136,7 +136,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'background-image:url(images/icons/blue/vote.svg);background-size:17px 17px;',
- Icon::create('vote', 'clickable')->asCSS(17)
+ Icon::create('vote')->asCSS(17)
);
}
@@ -144,7 +144,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'images/icons/blue/vote.svg',
- Icon::create('vote', 'clickable')->asImagePath()
+ Icon::create('vote')->asImagePath()
);
}
@@ -152,7 +152,7 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<img src="images/icons/blue/vote.svg" alt="" class="icon-role-clickable icon-shape-vote">',
- Icon::create('vote', 'clickable')->asImg(false)
+ Icon::create('vote')->asImg(false)
);
}
@@ -160,7 +160,19 @@ class IconClassTest extends \Codeception\Test\Unit
{
$this->assertEquals(
'<input type="image" src="images/icons/blue/upload.svg" alt="" class="icon-role-clickable icon-shape-upload">',
- Icon::create('upload', 'clickable')->asInput(false)
+ Icon::create('upload')->asInput(false)
+ );
+ }
+
+ function testIconCreateRemovedExtras()
+ {
+ $this->assertEquals(
+ '<img src="images/icons/blue/vote.svg" alt="" class="icon-role-clickable icon-shape-vote">',
+ Icon::create('add/vote')->asImg(false)
+ );
+ $this->assertEquals(
+ '<img src="images/icons/blue/vote.svg" alt="" class="icon-role-clickable icon-shape-vote">',
+ Icon::create('vote+add')->asImg(false)
);
}
}
diff --git a/tests/unit/lib/classes/MarkupClassTest.php b/tests/unit/lib/classes/MarkupClassTest.php
index d1c35b1..347e453 100644
--- a/tests/unit/lib/classes/MarkupClassTest.php
+++ b/tests/unit/lib/classes/MarkupClassTest.php
@@ -21,15 +21,15 @@
require_once 'tests/unit/fakeserver.php';
# needed by visual.inc.php
-require_once 'lib/classes/DbView.class.php';
-require_once 'lib/classes/TreeAbstract.class.php';
+require_once 'lib/classes/DbView.php';
+require_once 'lib/classes/TreeAbstract.php';
-# needed by Markup.class.php
+# needed by Markup.php
require_once 'lib/visual.inc.php';
-require_once 'lib/classes/Config.class.php';
+require_once 'lib/classes/Config.php';
# class and functions that are tested by this script
-require_once 'lib/classes/Markup.class.php';
+require_once 'lib/classes/Markup.php';
# Seminar_Session cannot be mocked since it uses static functions.
# Also, including phplib_local.inc.php, where Seminar_Session is
diff --git a/tests/unit/lib/classes/MigrationTest.php b/tests/unit/lib/classes/MigrationTest.php
index 444ebf2..12df120 100644
--- a/tests/unit/lib/classes/MigrationTest.php
+++ b/tests/unit/lib/classes/MigrationTest.php
@@ -16,11 +16,6 @@ class MigrationTest extends \Codeception\Test\Unit
$this->before = $GLOBALS['CACHING_ENABLE'] ?? null;
$GLOBALS['CACHING_ENABLE'] = false;
- require_once 'lib/classes/StudipCache.class.php';
- require_once 'lib/classes/StudipMemoryCache.class.php';
- require_once 'lib/classes/StudipCacheFactory.class.php';
- require_once 'lib/models/SimpleORMap.class.php';
-
require_once 'lib/migrations/Migration.php';
require_once 'lib/migrations/Migrator.php';
require_once 'lib/migrations/SchemaVersion.php';
diff --git a/tests/unit/lib/classes/OAuth1Test.php b/tests/unit/lib/classes/OAuth1Test.php
new file mode 100644
index 0000000..84d4fb2
--- /dev/null
+++ b/tests/unit/lib/classes/OAuth1Test.php
@@ -0,0 +1,118 @@
+<?php
+
+use Psr\Http\Message\ServerRequestInterface;
+use Studip\OAuth1;
+
+/**
+ * All values are from the OAuth 1.0 Authentication Sandbox (using the example
+ * used in the OAuth Specification).
+ *
+ * @see http://lti.tools/oauth/
+ */
+final class OAuth1Test extends \Codeception\Test\Unit
+{
+ /**
+ * @covers OAuth1::getSignatureBaseString
+ */
+ public function testCreationOfBaseString(): void
+ {
+ $this->assertEquals(
+ 'GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal',
+ OAuth1::getSignatureBaseString($this->getDefaultTestRequest())
+ );
+ }
+
+ /**
+ * @covers OAuth1::signRequest
+ */
+ public function testSigningARequest(): void
+ {
+ $this->assertEquals(
+ 'tR3+Ty81lMeYAr/Fid0kMTYa/WM=',
+ OAuth1::signRequest(
+ $this->getDefaultTestRequest(),
+ 'kd94hf93k423kf44',
+ 'pfkkdhi9sl3r4s00',
+ 'HMAC-SHA1'
+ )
+ );
+ }
+
+ /**
+ * @covers OAuth1::verifyRequest
+ */
+ public function testVerifyingARequest(): void
+ {
+ $this->assertTrue(
+ OAuth1::verifyRequest(
+ $this->getDefaultTestRequest(['oauth_signature' => 'tR3+Ty81lMeYAr/Fid0kMTYa/WM=']),
+ 'kd94hf93k423kf44',
+ 'pfkkdhi9sl3r4s00'
+ )
+ );
+ }
+
+ /**
+ * @covers OAuth1::verifyRequest
+ * @covers OAuth1::extractParameters
+ */
+ public function testVerifyingARequestFromAuthorizationHeader(): void
+ {
+ $parameters = [
+ ...$this->getDefaultParameters(),
+ 'oauth_signature' => 'tR3+Ty81lMeYAr/Fid0kMTYa/WM='
+ ];
+
+
+ $request = $this->getTestRequest()->withHeader(
+ 'Authorization',
+ 'OAuth ' . implode(',', array_map(
+ fn($key, $value) => sprintf('%s="%s"', $key, $value),
+ array_keys($parameters),
+ array_values($parameters)
+ ))
+ );
+
+ $this->assertTrue(
+ OAuth1::verifyRequest(
+ $request,
+ 'kd94hf93k423kf44',
+ 'pfkkdhi9sl3r4s00'
+ )
+ );
+ }
+
+ private function getTestRequest(): ServerRequestInterface
+ {
+ $factory = new Slim\Psr7\Factory\ServerRequestFactory();
+ return $factory->createServerRequest(
+ 'GET',
+ 'http://photos.example.net/photos'
+ )->withQueryParams([
+ 'size' => 'original',
+ 'file' => 'vacation.jpg',
+ ]);
+ }
+
+ private function getDefaultTestRequest(array $parameters = []): ServerRequestInterface
+ {
+ $request = $this->getTestRequest();
+ return $request->withQueryParams([
+ ...$request->getQueryParams(),
+ ...$this->getDefaultParameters(),
+ ...$parameters,
+ ]);
+ }
+
+ private function getDefaultParameters(): array
+ {
+ return [
+ 'oauth_consumer_key' => 'dpf43f3p2l4k3l03',
+ 'oauth_token' => 'nnch734d00sl2jdk',
+ 'oauth_nonce' => 'kllo9940pd9333jh',
+ 'oauth_timestamp' => '1191242096',
+ 'oauth_signature_method' => 'HMAC-SHA1',
+ 'oauth_version' => '1.0',
+ ];
+ }
+}
diff --git a/tests/unit/lib/classes/OpenGraphTest.php b/tests/unit/lib/classes/OpenGraphTest.php
new file mode 100644
index 0000000..416660b
--- /dev/null
+++ b/tests/unit/lib/classes/OpenGraphTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
+ * @license GPL2 or any later version
+ */
+class OpenGraphTest extends \Codeception\Test\Unit
+{
+ public function setUp(): void
+ {
+ static $config = [
+ 'OPENGRAPH_ENABLE' => true,
+ ];
+
+ Config::set(new Config($config));
+ }
+
+ public function testURLExtraction()
+ {
+ $text = 'this is a link: https://example.org?foo=bar&bar=foo - believe it or not';
+ $urls = OpenGraph::extractUrlsFromText($text);
+
+ $this->assertCount(1, $urls);
+ $this->assertEquals('https://example.org?foo=bar&bar=foo', $urls[0]);
+ }
+
+ public function testURLExtractionFromHTML()
+ {
+ $html = Studip\Markup::HTML_MARKER . '<a href="https://example.org?foo=bar&amp;bar=foo">this is a link</a> - believe it or not';
+ $urls = OpenGraph::extractUrlsFromHtml($html);
+
+ $this->assertCount(1, $urls);
+ $this->assertEquals('https://example.org?foo=bar&bar=foo', $urls[0]);
+ }
+}
diff --git a/tests/unit/lib/classes/PluginRepositoryTest.php b/tests/unit/lib/classes/PluginRepositoryTest.php
index 6676b7c..d045d3f 100644
--- a/tests/unit/lib/classes/PluginRepositoryTest.php
+++ b/tests/unit/lib/classes/PluginRepositoryTest.php
@@ -10,7 +10,7 @@
* the License, or (at your option) any later version.
*/
-require_once 'lib/plugins/engine/PluginRepository.class.php';
+require_once 'lib/plugins/engine/PluginRepository.php';
class PluginRepositoryTest extends \Codeception\Test\Unit
{
diff --git a/tests/unit/lib/classes/RequestParametersTest.php b/tests/unit/lib/classes/RequestParametersTest.php
index 85194c4..85ef33c 100644
--- a/tests/unit/lib/classes/RequestParametersTest.php
+++ b/tests/unit/lib/classes/RequestParametersTest.php
@@ -33,12 +33,20 @@ class RequestParametersTest extends Codeception\Test\Unit
$_GET['v3'] = ['root@studip', 'hotte.testfreund', 42, '!"$%&/()'];
$_POST['v4'] = ['0', '1', '', 'foo'];
+ $_GET['date'] = '2025-03-25';
+ $_GET['time'] = '17:39:04';
+ $_GET['datetime'] = '2025-03-25 17:39:04';
+ $_GET['invalid_date'] = 'foobar';
+
$testconfig = new Config([
'USERNAME_REGULAR_EXPRESSION' => '/^([a-zA-Z0-9_@.-]{4,})$/',
]);
Config::set($testconfig);
}
+ /**
+ * @covers Request::offsetGet
+ */
public function testArrayAccess ()
{
$request = Request::getInstance();
@@ -49,6 +57,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame($request['c'], '-23');
}
+ /**
+ * @covers Request::set
+ */
public function testSetParam ()
{
Request::set('yyy', 'xyzzy');
@@ -58,6 +69,10 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::getArray('zzz'), [1, 2]);
}
+ /**
+ * @covers Request::get
+ * @covers Request::quoted
+ */
public function testStringParam ()
{
$this->assertNull(Request::get('null'));
@@ -74,6 +89,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertNull(Request::quoted('v2'));
}
+ /**
+ * @covers Request::option
+ */
public function testOptionParam ()
{
$this->assertNull(Request::option('null'));
@@ -82,6 +100,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertNull(Request::option('v1'));
}
+ /**
+ * @covers Request::int
+ */
public function testIntParam ()
{
$this->assertNull(Request::int('null'));
@@ -92,6 +113,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertNull(Request::int('v1'));
}
+ /**
+ * @covers Request::float
+ */
public function testFloatParam ()
{
$this->assertNull(Request::float('null'));
@@ -102,6 +126,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertNull(Request::float('v1'));
}
+ /**
+ * @covers Request::bool
+ */
public function testBoolParam ()
{
$this->assertNull(Request::bool('null'));
@@ -115,6 +142,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertNull(Request::bool('v1'));
}
+ /**
+ * @covers Request::username
+ */
public function testUsernameParam ()
{
$this->assertNull(Request::username('null'));
@@ -124,6 +154,10 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertNull(Request::username('v1'));
}
+ /**
+ * @covers Request::getArray
+ * @covers Request::quotedArray
+ */
public function testStringArrayParam ()
{
$this->assertSame(Request::getArray('null'), []);
@@ -137,6 +171,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::quotedArray('v2'), ['on\\\'e', 'two', 'thr33']);
}
+ /**
+ * @covers Request::optionArray
+ */
public function testOptionArrayParam ()
{
$this->assertSame(Request::optionArray('null'), []);
@@ -145,6 +182,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::optionArray('v2'), [1 => 'two', 2 => 'thr33']);
}
+ /**
+ * @covers Request::intArray
+ */
public function testIntArrayParam ()
{
$this->assertSame(Request::intArray('null'), []);
@@ -153,6 +193,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::intArray('v2'), [0, 0, 0]);
}
+ /**
+ * @covers Request::floatArray
+ */
public function testFloatArrayParam ()
{
$this->assertSame(Request::floatArray('null'), []);
@@ -161,6 +204,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::floatArray('v2'), [0.0, 0.0, 0.0]);
}
+ /**
+ * @covers Request::boolArray
+ */
public function testBoolArrayParam ()
{
$this->assertSame(Request::boolArray('null'), []);
@@ -168,6 +214,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::boolArray('v4'), [false, true, false, true]);
}
+ /**
+ * @covers Request::usernameArray
+ */
public function testUsernameArrayParam ()
{
$this->assertSame(Request::usernameArray('null'), []);
@@ -177,6 +226,9 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertSame(Request::usernameArray('v3'), ['root@studip', 'hotte.testfreund']);
}
+ /**
+ * @covers Request::submitted
+ */
public function testSubmitted ()
{
$this->assertFalse(Request::submitted('null'));
@@ -184,12 +236,54 @@ class RequestParametersTest extends Codeception\Test\Unit
$this->assertTrue(Request::submitted('v1'));
}
+ /**
+ * @covers Request::submittedSome
+ */
public function testSubmittedSome ()
{
$this->assertFalse(Request::submittedSome('null', 'null'));
$this->assertTrue(Request::submittedSome('null', 's', 'v'));
}
+ /**
+ * @covers Request::getDateTime
+ */
+ public function testGetDatetimeWithDate()
+ {
+ $date = Request::getDateTime();
+ $this->assertNotFalse($date);
+ $this->assertEquals('2025-03-25 00:00:00', $date->format('Y-m-d H:i:s'));
+ }
+
+ /**
+ * @covers Request::getDateTime
+ */
+ public function testGetDatetimeWithDateAndTime()
+ {
+ $datetime = Request::getDateTime('datetime', 'Y-m-d H:i:s');
+ $this->assertNotFalse($datetime);
+ $this->assertEquals('2025-03-25 17:39:04', $datetime->format('Y-m-d H:i:s'));
+ }
+
+ /**
+ * @covers Request::getDateTime
+ */
+ public function testGetDatetimeWithDateAndTimeInTwoParameters()
+ {
+ $date = Request::getDateTime('date', 'Y-m-d', 'time', 'H:i:s');
+ $this->assertNotFalse($date);
+ $this->assertEquals('2025-03-25 17:39:04', $date->format('Y-m-d H:i:s'));
+ }
+
+ /**
+ * @covers Request::getDateTime
+ */
+ public function testGetDatetimeWithInvalidDate()
+ {
+ $invalid_date = Request::getDateTime('invalid_date');
+ $this->assertFalse($invalid_date);
+ }
+
public function tearDown(): void
{
Config::set(null);
diff --git a/tests/unit/lib/classes/SimpleOrMapNodbTest.php b/tests/unit/lib/classes/SimpleOrMapNodbTest.php
index 4c35d27..3ede1aa 100644
--- a/tests/unit/lib/classes/SimpleOrMapNodbTest.php
+++ b/tests/unit/lib/classes/SimpleOrMapNodbTest.php
@@ -46,10 +46,17 @@ class auth_user_md5 extends SimpleORMap
}
}
+/**
+ * @backupGlobals enabled
+ */
class SimpleOrMapNodbTest extends \Codeception\Test\Unit
{
protected static function setupFixture(): void
{
+ if (count($GLOBALS['CONTENT_LANGUAGES']) < 2) {
+ $GLOBALS['CONTENT_LANGUAGES']['en_GB'] = ['picture' => 'lang_en.gif', 'name' => 'English'];
+ }
+
StudipTestHelper::set_up_tables(['auth_user_md5']);
}
diff --git a/tests/unit/lib/classes/StudipCachedArrayTest.php b/tests/unit/lib/classes/StudipCachedArrayTest.php
index c98c1bd..5fd39f2 100644
--- a/tests/unit/lib/classes/StudipCachedArrayTest.php
+++ b/tests/unit/lib/classes/StudipCachedArrayTest.php
@@ -1,4 +1,7 @@
<?php
+
+use Studip\Cache\MemoryCache;
+
/**
* StudipCachedArrayTest.php - unit tests for the StudipCachedArray class
*
@@ -6,7 +9,7 @@
* @license GPL2 or any later version
*
* @covers StudipCachedArray
- * @uses StudipMemoryCache
+ * @uses MemoryCache
*/
class StudipCachedArrayTest extends \Codeception\Test\Unit
diff --git a/tests/unit/lib/classes/StudipControllerTest.php b/tests/unit/lib/classes/StudipControllerTest.php
index f7e4ef4..51359ab 100644
--- a/tests/unit/lib/classes/StudipControllerTest.php
+++ b/tests/unit/lib/classes/StudipControllerTest.php
@@ -27,13 +27,13 @@ final class StudipControllerTest extends Codeception\Test\Unit
parent::tearDown();
}
- private function getDispatcher(): Trails_Dispatcher
+ private function getDispatcher(): Trails\Dispatcher
{
$trails_root = $GLOBALS['STUDIP_BASE_PATH'] . DIRECTORY_SEPARATOR . 'app';
$trails_uri = rtrim($GLOBALS['ABSOLUTE_URI_STUDIP'], '/') . '/dispatch.php';
$default_controller = 'default';
- return new Trails_Dispatcher($trails_root, $trails_uri, $default_controller);
+ return new Trails\Dispatcher($trails_root, $trails_uri, $default_controller);
}
private function getController(): StudipController
@@ -247,7 +247,7 @@ final class StudipControllerTest extends Codeception\Test\Unit
{
$args = [$should_fail];
- $this->expectException(Trails_Exception::class);
+ $this->expectException(Trails\Exception::class);
$this->getController()->validate_args($args);
}
diff --git a/tests/unit/lib/classes/StudipFileloaderTest.php b/tests/unit/lib/classes/StudipFileloaderTest.php
index 1ffe6b5..102aaac 100644
--- a/tests/unit/lib/classes/StudipFileloaderTest.php
+++ b/tests/unit/lib/classes/StudipFileloaderTest.php
@@ -20,7 +20,7 @@ class StudipFileloaderTestCase extends \Codeception\Test\Unit
]);
if (!stream_wrapper_register('var', 'ArrayFileStream')) {
- new Exception('Failed to register protocol');
+ throw new Exception('Failed to register protocol');
}
}
@@ -56,7 +56,7 @@ class StudipFileloaderTestCase extends \Codeception\Test\Unit
public function test_should_balk_upon_file_not_found()
{
- $this->expectException(\PHPUnit\Framework\Exception::class);
+ $this->expectException(Exception::class);
StudipFileloader::load('var://pathto/not-there.php', $container);
}
}
diff --git a/tests/unit/lib/classes/TrailsTest.php b/tests/unit/lib/classes/TrailsTest.php
new file mode 100644
index 0000000..d51b795
--- /dev/null
+++ b/tests/unit/lib/classes/TrailsTest.php
@@ -0,0 +1,25 @@
+<?php
+class TrailsTest extends \Codeception\Test\Unit
+{
+ /**
+ * @covers Trails\Inflector::camelize
+ */
+ public function testInflectorCamelize(): void
+ {
+ $this->assertEquals(
+ 'Path_SubPath_UnderscoreController',
+ Trails\Inflector::camelize('path/sub_path/underscore_controller')
+ );
+ }
+
+ /**
+ * @covers Trails\Inflector::underscore
+ */
+ public function testInflectorUnderscore(): void
+ {
+ $this->assertEquals(
+ 'path/sub_path/underscore_controller',
+ Trails\Inflector::underscore('Path_SubPath_UnderscoreController')
+ );
+ }
+}
diff --git a/tests/unit/lib/classes/extTPLTemplateTest.php b/tests/unit/lib/classes/extTPLTemplateTest.php
new file mode 100644
index 0000000..43a9629
--- /dev/null
+++ b/tests/unit/lib/classes/extTPLTemplateTest.php
@@ -0,0 +1,213 @@
+<?php
+/*
+ * template_test.php - expression template unit tests
+ *
+ * Copyright (c) 2013 Elmar Ludwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+use exTpl\Template;
+
+class extTplTemplateTest extends \Codeception\Test\Unit
+{
+ public function testSimpleString()
+ {
+ $bindings = [];
+ $template = 'The quick brown fox jumps over the layz dog.';
+ $expected = $template;
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testConstantExpression()
+ {
+ $bindings = array();
+ $template = '17 + 4 = {"foo" != "bar" ? 17 + 4 : 42.0}';
+ $expected = '17 + 4 = 21';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testConditionExpression()
+ {
+ $bindings = array('a' => 0, 'b' => 42);
+ $template = 'answer is {"" ?: a ?: b}';
+ $expected = 'answer is 42';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testStringEscapes()
+ {
+ $bindings = array();
+ $template = '"{"\\tfoo\'\\"\\n"}{\'{"bar"}\'}"';
+ $expected = "\"\tfoo'\"\n{\"bar\"}\"";
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testOperatorPrecedence()
+ {
+ $bindings = array('val' => array(array(42)));
+ $template = '{-val[0][0] / (17+4) + 8 > 6 && "foo" == "f"~"o"~"o" ? 1 : 2}';
+ $expected = '2';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testSimpleBindings()
+ {
+ $bindings = array('foo' => 'bar', 'val' => array(17, 4), 'pi' => 3.14159);
+ $template = 'foo = "{foo}", sum = {val[0] + val[1]}, pi^2 = {pi * pi}, x = {x}';
+ $expected = 'foo = "bar", sum = 21, pi^2 = 9.8695877281, x = ';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testConditional()
+ {
+ $bindings = array('foo' => 'bar', 'pi' => 3.14159);
+ $template = '{if foo == "foo"}NO{elseif foo == "bar"}pi = {pi}{else}NO{endif}';
+ $expected = 'pi = 3.14159';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testConditionalIteration()
+ {
+ $bindings = array('foo' => 'bar', 'pi' => 3.14159);
+ $template = '{foreach foo}{if foo}{foo}{endif}{endforeach}';
+ $expected = 'bar';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testIteration()
+ {
+ $bindings = array('persons' => array(
+ 1 => array('user' => 'jane', 'phone' => '555-81281'),
+ 2 => array('user' => 'mike', 'phone' => '230-28382'),
+ 3 => array('user' => 'john', 'phone' => '911-19212')
+ ));
+ $template = '<ul>{foreach persons as person}<li>{index~":"~person.user~":"~phone}</li>{endforeach}</ul>';
+ $expected = '<ul>' .
+ '<li>1:jane:555-81281</li>' .
+ '<li>2:mike:230-28382</li>' .
+ '<li>3:john:911-19212</li>' .
+ '</ul>';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testEmptyIteration()
+ {
+ $bindings = array('foo' => array(), 'bar' => false);
+ $template = '{foreach foo}foo{endforeach}:{foreach bar}bar{endforeach}';
+ $expected = ':';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testVariableScope()
+ {
+ $bindings = array('value' => 42, 'test' => array(
+ array(),
+ array('value' => 17),
+ array('test' => array(
+ array(),
+ array('value' => 4)
+ ))
+ ));
+ $template = '{foreach test}{value}:{foreach test}{value}~{endforeach}{endforeach}';
+ $expected = '42:42~17~42~17:17~17~17~42:42~4~';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testNestedStatements()
+ {
+ foreach (range(0, 9) as $i) {
+ $bindings['loop'][$i]['i'] = "$i";
+ }
+ $template = '{foreach loop}' .
+ '{if i+1>4 && i<(1+10/2)}{i==4*1 ? \'foo\'~i : "bar"}' .
+ '{elseif !(i<=+4)}+{elseif i==""}..{else}{"-"}{endif}' .
+ '{endforeach}';
+ $expected = '----foo4bar++++';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testFunctionCall()
+ {
+ $bindings = array('val' => array(0, 1, 2, 3));
+ $template = '{strlen("foobar") + count(val)}';
+ $expected = '10';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testFilters()
+ {
+ $bindings = array(
+ 'pi' => 3.14159,
+ 'format' => function($a, $b) { return number_format($a, $b); },
+ 'upper' => function($a) { return strtoupper($a); }
+ );
+ $template = '{pi|format(3) ~ ":" ~ "foobar"|upper}';
+ $expected = '3.142:FOOBAR';
+ $tmpl_obj = new Template($template);
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testRawFilter()
+ {
+ $bindings = array('foo' => '<img>', 'upper' => function($a) { return strtoupper($a); });
+ $template = '{foo}:{foo|upper|raw}';
+ $expected = '&lt;img&gt;:<IMG>';
+ $tmpl_obj = new Template($template);
+ $tmpl_obj->autoescape('html');
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testHtmlAutoEscape()
+ {
+ $bindings = array('foo' => '<img>', 'pi' => 3.14159);
+ $template = '{foo}:{pi}';
+ $expected = '&lt;img&gt;:3.14159';
+ $tmpl_obj = new Template($template);
+ $tmpl_obj->autoescape('html');
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+
+ public function testJsonAutoEscape()
+ {
+ $bindings = array('foo' => '<img>', 'pi' => 3.14159);
+ $template = '{foo}:{pi}';
+ $expected = '"<img>":3.14159';
+ $tmpl_obj = new Template($template);
+ $tmpl_obj->autoescape('json');
+
+ $this->assertEquals($expected, $tmpl_obj->render($bindings));
+ }
+}
diff --git a/tests/unit/lib/flexi/FactoryTest.php b/tests/unit/lib/flexi/FactoryTest.php
new file mode 100644
index 0000000..f8b9b87
--- /dev/null
+++ b/tests/unit/lib/flexi/FactoryTest.php
@@ -0,0 +1,119 @@
+<?php
+
+use Flexi\Factory;
+use Flexi\TemplateNotFoundException;
+use Flexi\PhpTemplate;
+
+final class FactoryTestCase extends \Codeception\Test\Unit
+{
+ private Factory $factory;
+
+ public function setUp(): void
+ {
+ $this->setUpFS();
+
+ $this->factory = new Factory('var://templates');
+ }
+
+ public function tearDown(): void
+ {
+ unset($this->factory);
+ stream_wrapper_unregister('var');
+ }
+
+ public function setUpFS(): void
+ {
+ ArrayFileStream::set_filesystem([
+ 'templates' => [
+ 'foo.php' => 'some content',
+ 'baz.unknown' => 'some content',
+ 'multiplebasenames' => [
+ 'foo.txt' => 'there is no matching template class',
+ 'foo.php' => 'some content',
+ 'bar.txt' => 'there is no matching template class',
+ ],
+ 'baz.known-ext' => 'some content',
+ ],
+ ]);
+ if (!stream_wrapper_register('var', ArrayFileStream::class)) {
+ die('Failed to register protocol');
+ }
+ }
+
+ public function testShouldCreateFactory()
+ {
+ $factory = new Factory('.');
+ $this->assertNotNull($factory);
+ }
+
+ public function testShouldCreateFactoryUsingPath()
+ {
+ $path = 'var://';
+ $factory = new Factory($path);
+ $this->assertNotNull($factory);
+ }
+
+ public function testShouldOpenTemplateUsingRelativePath()
+ {
+ $foo = $this->factory->open('foo');
+ $this->assertNotNull($foo);
+ }
+
+ public function testShouldOpenTemplateUsingAbsolutePath()
+ {
+ $foo = $this->factory->open('var://templates/foo');
+ $this->assertNotNull($foo);
+ }
+
+ public function testShouldThrowAnExceptionOpeningAMissingTemplateWithoutFileExtension()
+ {
+ $this->expectException(TemplateNotFoundException::class);
+ $this->factory->open('bar');
+ }
+
+ public function testShouldThrowAnExceptionOpeningAMissingTemplateWithFileExtension()
+ {
+ $this->expectException(TemplateNotFoundException::class);
+ $this->factory->open('bar.php');
+ }
+
+ public function testShouldOpenTemplateUsingExtension()
+ {
+ $this->assertInstanceOf(
+ PhpTemplate::class,
+ $this->factory->open('foo.php')
+ );
+ }
+
+ public function testShouldThrowAnExceptionWhenOpeningATemplateWithUnknownExtension()
+ {
+ $this->expectException(TemplateNotFoundException::class);
+ $this->factory->open('baz');
+ }
+
+ public function testShouldThrowAnExceptionOpeningATemplateInANonExistingDirectory()
+ {
+ $this->expectException(TemplateNotFoundException::class);
+ $this->factory->open('doesnotexist/foo');
+ }
+
+ public function testShouldSearchForASupportedTemplate()
+ {
+ $this->assertInstanceOf(
+ PhpTemplate::class,
+ $this->factory->open('multiplebasenames/foo')
+ );
+ }
+
+ public function testShouldRespondToAddedHandlers()
+ {
+ $handler = new class('', $this->factory) extends Flexi\Template {
+ protected function _render(): string
+ {
+ return '';
+ }
+ };
+ $this->factory->add_handler('known-ext', $handler::class);
+ $this->factory->open('baz.known-ext');
+ }
+}
diff --git a/tests/unit/lib/flexi/PHPTemplatePartialBugTest.php b/tests/unit/lib/flexi/PHPTemplatePartialBugTest.php
new file mode 100644
index 0000000..ef265cf
--- /dev/null
+++ b/tests/unit/lib/flexi/PHPTemplatePartialBugTest.php
@@ -0,0 +1,45 @@
+<?php
+
+use Flexi\Factory;
+
+final class PhpTemplatePartialBugTestCase extends Codeception\Test\Unit
+{
+ public function setUp(): void
+ {
+ $this->setUpFS();
+ $this->factory = new Factory('var://templates/');
+ }
+
+ public function tearDown(): void
+ {
+ unset($this->factory);
+
+ stream_wrapper_unregister("var");
+ }
+
+ public function setUpFS(): void
+ {
+ ArrayFileStream::set_filesystem([
+ 'templates' => [
+ 'layout.php' =>
+ '<? $do_not_echo_this = $this->render_partial_collection("partial", range(1, 5));' .
+ 'echo $content_for_layout;',
+ 'partial.php' =>
+ 'partial',
+ 'template.php' =>
+ 'template',
+ ]
+ ]);
+ if (!stream_wrapper_register('var', ArrayFileStream::class)) {
+ die('Failed to register protocol');
+ }
+ }
+
+ public function testPartialBug()
+ {
+ $template = $this->factory->open('template');
+ $template->set_layout('layout');
+ $result = $template->render();
+ $this->assertEquals($result, "template");
+ }
+}
diff --git a/tests/unit/lib/flexi/PHPTemplateTest.php b/tests/unit/lib/flexi/PHPTemplateTest.php
new file mode 100644
index 0000000..5dfd247
--- /dev/null
+++ b/tests/unit/lib/flexi/PHPTemplateTest.php
@@ -0,0 +1,136 @@
+<?php
+
+use Flexi\Factory;
+use Flexi\TemplateNotFoundException;
+
+final class PhpTemplateTestCase extends Codeception\Test\Unit
+{
+ private Factory $factory;
+
+ public function setUp(): void
+ {
+ $this->setUpFS();
+ $this->factory = new Factory('var://templates/');
+ }
+
+
+ public function tearDown(): void
+ {
+ unset($this->factory);
+
+ stream_wrapper_unregister('var');
+ }
+
+ public function setUpFS()
+ {
+ ArrayFileStream::set_filesystem([
+ 'templates' => [
+ 'foo_using_partial.php' =>
+ 'Hello, <?= $this->render_partial("foos_partial") ?>!',
+
+ 'foos_partial.php' =>
+ '<h1><?= $whom ?> at <?= $when ?></h1>',
+
+ 'foo_with_partial_collection.php' =>
+ '[<?= $this->render_partial_collection("item", $items, "spacer") ?>]',
+
+ 'item.php' =>
+ '"<?= $item ?>"',
+
+ 'spacer.php' =>
+ ', ',
+
+ 'attributes.php' =>
+ '<? foreach (get_defined_vars() as $name => $value) : ?>' .
+ '<?= $name ?><?= $value ?>' .
+ '<? endforeach ?>',
+
+ 'foo.php' =>
+ 'Hello, <?= $whom ?>!',
+
+ 'layout.php' =>
+ '[<?= $content_for_layout ?>]',
+ ]
+ ]);
+ if (!stream_wrapper_register('var', ArrayFileStream::class)) {
+ die('Failed to register protocol');
+ }
+ }
+
+ public function testRenderPartial()
+ {
+ $template = $this->factory->open('foo_using_partial');
+ $template->set_attribute('whom', 'bar');
+ $this->assertEquals(
+ 'Hello, <h1>bar at now</h1>!',
+ $template->render(['when' => 'now'])
+ );
+ }
+
+ public function testRenderPartialCollection()
+ {
+ $template = $this->factory->open('foo_with_partial_collection');
+ $result = $template->render_partial_collection(
+ 'item',
+ range(1, 3),
+ 'spacer'
+ );
+ $this->assertEquals('"1", "2", "3"', $result);
+ }
+
+ public function testShouldOverrideAttributesWithThosePassedToRender()
+ {
+ $template = $this->factory->open('attributes');
+ $template->set_attribute('foo', 'baz');
+
+ $template->render(['foo' => 'bar']);
+ $this->assertEquals('bar', $template->get_attribute('foo'));
+
+ $template->render();
+ $this->assertEquals('bar', $template->get_attribute('foo'));
+ }
+
+ public function testRenderWithoutLayout()
+ {
+ $foo = $this->factory->open('foo');
+ $foo->set_attribute('whom', 'bar');
+ $this->assertEquals('Hello, bar!', $foo->render());
+ }
+
+ public function testRenderWithLayout()
+ {
+ $foo = $this->factory->open('foo');
+ $foo->set_attribute('whom', 'bar');
+ $foo->set_layout('layout');
+ $out = $foo->render();
+ $this->assertEquals('[Hello, bar!]', $out);
+ }
+
+ public function testRenderWithLayoutInline()
+ {
+ $this->assertEquals(
+ '[Hello, bar!]',
+ $this->factory->render('foo', ['whom' => 'bar'], 'layout')
+ );
+ }
+
+ public function testRenderWithMissingLayout()
+ {
+ $foo = $this->factory->open('foo');
+ $this->expectException(TemplateNotFoundException::class);
+ $foo->set_layout('nosuchlayout');
+ }
+
+ public function testRenderWithAttributes()
+ {
+ $foo = $this->factory->open('foo');
+ $foo->set_attribute('whom', 'bar');
+ $foo->set_layout('layout');
+ $foo_out = $foo->render();
+
+ $bar = $this->factory->open('foo');
+ $bar_out = $bar->render(['whom' => 'bar'], 'layout');
+
+ $this->assertEquals($foo_out, $bar_out);
+ }
+}
diff --git a/tests/unit/lib/flexi/TemplateEmptyTest.php b/tests/unit/lib/flexi/TemplateEmptyTest.php
new file mode 100644
index 0000000..c5ebd79
--- /dev/null
+++ b/tests/unit/lib/flexi/TemplateEmptyTest.php
@@ -0,0 +1,44 @@
+<?php
+
+use Flexi\Factory;
+use Flexi\Template;
+
+final class TemplateEmptyTestCase extends \Codeception\Test\Unit
+{
+ private Factory $factory;
+
+ public function setUp(): void
+ {
+ $this->factory = $this->make(Factory::class, [
+ 'open' => $this->make(Template::class),
+ ]);
+ }
+
+ public function tearDown(): void
+ {
+ unset($this->factory);
+ }
+
+ public function testShouldHaveNoAttributes()
+ {
+ $template = $this->factory->open('');
+ $this->assertCount(0, $template->get_attributes());
+ }
+
+ public function testShouldNotBeEmptyAfterSettingAnAttribute()
+ {
+ $template = $this->factory->open('');
+ $template->set_attribute('foo', 'bar');
+ $this->assertNotEmpty($template->get_attributes());
+ }
+
+ public function testShouldBeEmptyAfterClear()
+ {
+ $template = $this->factory->open('foo');
+
+ $this->assertEmpty($template->get_attributes());
+
+ $template->clear_attributes();
+ $this->assertEmpty($template->get_attributes());
+ }
+}
diff --git a/tests/unit/lib/flexi/TemplateMagicMethodsTest.php b/tests/unit/lib/flexi/TemplateMagicMethodsTest.php
new file mode 100644
index 0000000..ad2690a
--- /dev/null
+++ b/tests/unit/lib/flexi/TemplateMagicMethodsTest.php
@@ -0,0 +1,78 @@
+<?php
+
+use Flexi\Factory;
+use Flexi\Template;
+
+final class TemplateMagicMethodsTestCase extends \Codeception\Test\Unit
+{
+ private Factory $factory;
+
+ public function setUp(): void
+ {
+ $this->factory = $this->make(Factory::class, [
+ 'open' => $this->make(Template::class),
+ ]);
+ $this->template = $this->factory->open('');
+ }
+
+ public function tearDown(): void
+ {
+ unset($this->factory);
+ unset($this->template);
+ }
+
+ public function testShouldSetAnAttributeUsingTheMagicMethods()
+ {
+ $this->template->foo = 'bar';
+ $this->assertEquals('bar', $this->template->get_attribute('foo'));
+ }
+
+ public function testShouldNotSetAProtectedMemberFieldAsAnAttribute()
+ {
+ $this->template->layout = 'bar';
+ $this->assertEquals('bar', $this->template->layout);
+ $this->assertNotEquals('bar', $this->template->get_layout());
+ }
+
+ public function testShouldOverwriteAnAttribute()
+ {
+ $this->template->set_attribute('foo', 'bar');
+ $this->template->foo = 'baz';
+ $this->assertEquals('baz', $this->template->get_attribute('foo'));
+ }
+
+ public function testShouldReturnAnExistingAttributeUsingTheMagicMethods()
+ {
+ $this->template->set_attribute('foo', 'bar');
+ $this->assertEquals('bar', $this->template->foo);
+ }
+
+ public function testShouldReturnNullForANonExistingAttributeUsingTheMagicMethods()
+ {
+ $this->assertNull($this->template->foo);
+ }
+
+ public function testShouldUnsetAnAttributeUsingTheMagicMethods()
+ {
+ $this->template->foo = 'bar';
+ unset($this->template->foo);
+ $this->assertNull($this->template->foo);
+ }
+
+ public function testShouldReturnNullOnUnsettingANonAttribute()
+ {
+ unset($this->template->foo);
+ $this->assertNull($this->template->foo);
+ }
+
+ public function testShouldReturnTrueOnIssetForAnAttribute()
+ {
+ $this->template->foo = 'bar';
+ $this->assertTrue(isset($this->template->foo));
+ }
+
+ public function testShouldReturnFalseOnIssetForANonExistingAttribute()
+ {
+ $this->assertFalse(isset($this->template->foo));
+ }
+}
diff --git a/tests/unit/lib/flexi/TemplateTest.php b/tests/unit/lib/flexi/TemplateTest.php
new file mode 100644
index 0000000..95e9145
--- /dev/null
+++ b/tests/unit/lib/flexi/TemplateTest.php
@@ -0,0 +1,68 @@
+<?php
+
+use Flexi\Factory;
+use Flexi\Template;
+
+final class TemplateTestCase extends \Codeception\Test\Unit
+{
+ private Factory $factory;
+
+ public function setUp(): void
+ {
+ $this->factory = $this->make(Factory::class, [
+ 'open' => $this->make(Template::class),
+ ]);
+ }
+
+ public function tearDown(): void
+ {
+ unset($this->factory);
+ }
+
+ public function testShouldReturnAPreviouslySetAttribute()
+ {
+ $template = $this->factory->open('foo');
+ $template->set_attribute('whom', 'bar');
+ $this->assertEquals('bar', $template->get_attribute('whom'));
+ }
+
+ public function testShouldReturnPreviouslySetAttributes()
+ {
+ $template = $this->factory->open('foo');
+ $template->set_attributes(['whom' => 'bar', 'foo' => 'baz']);
+
+ $attributes = $template->get_attributes();
+ $this->assertIsArray($attributes);
+ $this->assertCount(2, $attributes);
+ $this->assertEquals('bar', $attributes['whom']);
+ $this->assertEquals('baz', $attributes['foo']);
+ }
+
+ public function testShouldMergeAttributesWithSetAttributes()
+ {
+ $template = $this->factory->open('foo');
+ $template->set_attributes(['a' => 1, 'b' => 2]);
+
+ $this->assertCount(2, $template->get_attributes());
+ $this->assertEquals(1, $template->get_attribute('a'));
+ $this->assertEquals(2, $template->get_attribute('b'));
+
+ $template->set_attributes(['b' => 8, 'c' => 9]);
+
+ $this->assertCount(3, $template->get_attributes());
+ $this->assertEquals(1, $template->get_attribute('a'));
+ $this->assertEquals(8, $template->get_attribute('b'));
+ $this->assertEquals(9, $template->get_attribute('c'));
+ }
+
+ public function testShouldBeEmptyAfterClear()
+ {
+ $template = $this->factory->open('foo');
+
+ $template->set_attributes(['a' => 1, 'b' => 2]);
+ $this->assertNotEmpty($template->get_attributes());
+
+ $template->clear_attributes();
+ $this->assertCount(0, $template->get_attributes());
+ }
+}
diff --git a/tests/unit/varstream.php b/tests/unit/varstream.php
index 9a3acb5..d2047c0 100644
--- a/tests/unit/varstream.php
+++ b/tests/unit/varstream.php
@@ -7,15 +7,17 @@ class ArrayFileStream
private static $fs;
- static function set_filesystem(array $fs) {
+ static function set_filesystem(array $fs)
+ {
ArrayFileStream::$fs = $fs;
}
- private static function &get_element($path) {
+ private static function &get_element($path)
+ {
$result =& ArrayFileStream::$fs;
foreach (preg_split('/\//', $path, -1, PREG_SPLIT_NO_EMPTY) as $element) {
if (!isset($result[$element])) {
- $null = NULL;
+ $null = null;
return $null;
}
$result =& $result[$element];
@@ -23,9 +25,10 @@ class ArrayFileStream
return $result;
}
- private static function &get_file($path) {
+ private static function &get_file($path)
+ {
$url = parse_url($path);
- $file =& self::get_element($url['host'] . $url['path']);
+ $file =& self::get_element($url['host'] . ($url['path'] ?? ''));
if (is_null($file)) {
throw new Exception("file not found.");
@@ -33,15 +36,18 @@ class ArrayFileStream
return $file;
}
- public function stream_close() {
+ public function stream_close()
+ {
# nothing to do
}
- public function stream_flush() {
+ public function stream_flush()
+ {
# nothing to do
}
- public function stream_open($path, $mode, $options, $opened_path) {
+ public function stream_open($path, $mode, $options, $opened_path)
+ {
try {
$this->open_file =& self::get_file($path);
$this->position = 0;
@@ -51,37 +57,41 @@ class ArrayFileStream
}
}
- public function stream_read($count) {
+ public function stream_read($count)
+ {
$ret = mb_substr($this->open_file, $this->position, $count);
$this->position += mb_strlen($ret);
return $ret;
}
- public function stream_write($data) {
- $left = mb_substr($this->open_file, 0, $this->position);
+ public function stream_write($data)
+ {
+ $left = mb_substr($this->open_file, 0, $this->position);
$right = mb_substr($this->open_file, $this->position + mb_strlen($data));
$this->open_file = $left . $data . $right;
$this->position += mb_strlen($data);
return mb_strlen($data);
}
- public function stream_tell() {
+ public function stream_tell()
+ {
return $this->position;
}
- public function stream_eof() {
+ public function stream_eof()
+ {
return $this->position >= mb_strlen($this->open_file);
}
- public function stream_seek($offset, $whence) {
+ public function stream_seek($offset, $whence)
+ {
switch ($whence) {
case SEEK_SET:
if ($offset < mb_strlen($this->open_file) && $offset >= 0) {
$this->position = $offset;
return true;
- }
- else {
+ } else {
return false;
}
break;
@@ -90,8 +100,7 @@ class ArrayFileStream
if ($offset >= 0) {
$this->position += $offset;
return true;
- }
- else {
+ } else {
return false;
}
break;
@@ -100,8 +109,7 @@ class ArrayFileStream
if (mb_strlen($this->open_file) + $offset >= 0) {
$this->position = mb_strlen($this->open_file) + $offset;
return true;
- }
- else {
+ } else {
return false;
}
break;
@@ -115,44 +123,61 @@ class ArrayFileStream
{
}
- public function stream_stat() {
- return array('size' => is_array($this->open_file)
- ? sizeof($this->open_file)
- : mb_strlen($this->open_file));
+ public function stream_stat()
+ {
+ return [
+ 'size' => is_array($this->open_file)
+ ? sizeof($this->open_file)
+ : mb_strlen($this->open_file),
+ ];
}
- public function unlink($path) {
+ public function unlink($path)
+ {
$parent =& self::get_file(dirname($path));
if (is_array($parent) && isset($parent[basename($path)])) {
unset($parent[basename($path)]);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
- public function rename($path_from, $path_to) {
+ public function rename($path_from, $path_to)
+ {
throw new Exception('not implemented yet');
}
- public function mkdir($path, $mode, $options) {
+ public function mkdir($path, $mode, $options)
+ {
throw new Exception('not implemented yet');
}
- public function rmdir($path, $options) {
+ public function rmdir($path, $options)
+ {
throw new Exception('not implemented yet');
}
- public function dir_opendir($path, $options) {
+ public function dir_opendir($path, $options)
+ {
throw new Exception('not implemented yet');
}
- public function url_stat($path, $flags) {
+ public function url_stat($path, $flags)
+ {
+ try {
+ if (!self::get_file($path)) {
+ return false;
+ }
+ } catch (Exception $e) {
+ return false;
+ }
+
$time = time();
- $keys = array(
+ $keys = [
'dev' => 0,
'ino' => 0,
'mode' => 33216, // chmod 700
@@ -161,25 +186,28 @@ class ArrayFileStream
'gid' => function_exists('posix_getgid') ? posix_getgid() : 0,
'rdev' => 0,
'size' => $flags & STREAM_URL_STAT_QUIET
- ? @mb_strlen($this->open_file) : mb_strlen($this->open_file),
+ ? @mb_strlen($this->open_file) : mb_strlen($this->open_file),
'atime' => $time,
'mtime' => $time,
'ctime' => $time,
'blksize' => 0,
- 'blocks' => 0
- );
+ 'blocks' => 0,
+ ];
return array_merge(array_values($keys), $keys);
}
- public function dir_readdir() {
+ public function dir_readdir()
+ {
throw new Exception('not implemented yet');
}
- public function dir_rewinddir() {
+ public function dir_rewinddir()
+ {
throw new Exception('not implemented yet');
}
- public function dir_closedir() {
+ public function dir_closedir()
+ {
throw new Exception('not implemented yet');
}
}