more tests

This commit is contained in:
Shish 2024-02-09 12:43:53 +00:00
parent 2e536e980c
commit 43e8ff3e3e
9 changed files with 299 additions and 189 deletions

View File

@ -688,7 +688,7 @@ class NavLink
$this->description = $description;
$this->order = $order;
if ($active == null) {
$query = ltrim(_get_query(), "/");
$query = _get_query();
if ($query === "") {
// This indicates the front page, so we check what's set as the front page
$front_page = trim($config->get_string(SetupConfig::FRONT_PAGE), "/");
@ -716,7 +716,7 @@ class NavLink
/**
* Woo! We can actually SEE THE CURRENT PAGE!! (well... see it highlighted in the menu.)
*/
$url = $url ?? ltrim(_get_query(), "/");
$url = $url ?? _get_query();
$re1 = '.*?';
$re2 = '((?:[a-z][a-z_]+))';

View File

@ -47,6 +47,7 @@ class InitExtEvent extends Event
class PageRequestEvent extends Event
{
public string $method;
public string $path;
/**
* @var string[]
*/
@ -61,13 +62,12 @@ class PageRequestEvent extends Event
$this->method = $method;
// trim starting slashes
$path = ltrim($path, "/");
// if path is not specified, use the default front page
if (empty($path)) { /* empty is faster than strlen */
// if we're looking at the root of the install,
// use the default front page
if ($path == "") {
$path = $config->get_string(SetupConfig::FRONT_PAGE);
}
$this->path = $path;
// break the path into parts
$args = explode('/', $path);

View File

@ -293,51 +293,6 @@ function zglob(string $pattern): array
}
}
/**
* Figure out the path to the shimmie install directory.
*
* eg if shimmie is visible at https://foo.com/gallery, this
* function should return /gallery
*
* PHP really, really sucks.
*/
function get_base_href(): string
{
if (defined("BASE_HREF") && !empty(BASE_HREF)) {
return BASE_HREF;
}
if(str_ends_with($_SERVER['PHP_SELF'], 'index.php')) {
$self = $_SERVER['PHP_SELF'];
} elseif(isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['DOCUMENT_ROOT'])) {
$self = substr($_SERVER['SCRIPT_FILENAME'], strlen(rtrim($_SERVER['DOCUMENT_ROOT'], "/")));
} else {
die("PHP_SELF or SCRIPT_FILENAME need to be set");
}
$dir = dirname($self);
$dir = str_replace("\\", "/", $dir);
$dir = rtrim($dir, "/");
return $dir;
}
/**
* The opposite of the standard library's parse_url
*
* @param array<string, string|int> $parsed_url
*/
function unparse_url(array $parsed_url): string
{
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$host = $parsed_url['host'] ?? '';
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
$user = $parsed_url['user'] ?? '';
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = $parsed_url['path'] ?? '';
$query = !empty($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$fragment = !empty($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return "$scheme$user$pass$host$port$path$query$fragment";
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Input / Output Sanitising *

View File

@ -254,45 +254,4 @@ class PolyfillsTest extends TestCase
deltree($dir);
$this->assertFalse(file_exists($dir));
}
/**
* @param array<string, string> $vars
*/
private function _tbh(array $vars, string $result): void
{
// update $_SERVER with $vars, call get_base_href() and check result, then reset $_SERVER to original value
$old_server = $_SERVER;
$_SERVER = array_merge($_SERVER, $vars);
$this->assertEquals($result, get_base_href());
$_SERVER = $old_server;
}
public function test_get_base_href(): void
{
// PHP_SELF should point to "the currently executing script
// relative to the document root"
$this->_tbh(["PHP_SELF" => "/index.php"], "");
$this->_tbh(["PHP_SELF" => "/mydir/index.php"], "/mydir");
// SCRIPT_FILENAME should point to "the absolute pathname of
// the currently executing script" and DOCUMENT_ROOT should
// point to "the document root directory under which the
// current script is executing"
$this->_tbh([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/mydir/index.php",
"DOCUMENT_ROOT" => "/var/www/html",
], "/mydir");
$this->_tbh([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/mydir/index.php",
"DOCUMENT_ROOT" => "/var/www/html/",
], "/mydir");
$this->_tbh([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/index.php",
"DOCUMENT_ROOT" => "/var/www/html",
], "");
}
}

View File

@ -5,74 +5,224 @@ declare(strict_types=1);
namespace Shimmie2;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\Depends;
require_once "core/urls.php";
class UrlsTest extends TestCase
{
public function test_search_link(): void
/**
* An integration test for
* - search_link()
* - make_link()
* - _get_query()
* - get_search_terms()
*/
#[Depends("test_search_link")]
public function test_get_search_terms_from_search_link(): void
{
$this->assertEquals(
"/test/post/list/bar%20foo/1",
search_link(["foo", "bar"])
);
$this->assertEquals(
"/test/post/list/cat%2A%20rating%3D%3F/1",
search_link(["rating=?", "cat*"])
);
/**
* @param array<string> $vars
* @return array<string>
*/
function _gst(array $terms): array
{
$pre = new PageRequestEvent("GET", _get_query(search_link($terms)));
$pre->page_matches("post/list");
return $pre->get_search_terms();
}
global $config;
foreach([true, false] as $nice_urls) {
$config->set_bool('nice_urls', $nice_urls);
$this->assertEquals(
["bar", "foo"],
_gst(["foo", "bar"])
);
$this->assertEquals(
["AC/DC"],
_gst(["AC/DC"])
);
$this->assertEquals(
["cat*", "rating=?"],
_gst(["rating=?", "cat*"]),
);
}
}
#[Depends("test_get_base_href")]
public function test_make_link(): void
{
// basic
global $config;
foreach([true, false] as $nice_urls) {
$config->set_bool('nice_urls', $nice_urls);
// basic
$this->assertEquals(
$nice_urls ? "/test/foo" : "/test/index.php?q=foo",
make_link("foo")
);
// remove leading slash from path
$this->assertEquals(
$nice_urls ? "/test/foo" : "/test/index.php?q=foo",
make_link("/foo")
);
// query
$this->assertEquals(
$nice_urls ? "/test/foo?a=1&b=2" : "/test/index.php?q=foo&a=1&b=2",
make_link("foo", "a=1&b=2")
);
// hash
$this->assertEquals(
$nice_urls ? "/test/foo#cake" : "/test/index.php?q=foo#cake",
make_link("foo", null, "cake")
);
// query + hash
$this->assertEquals(
$nice_urls ? "/test/foo?a=1&b=2#cake" : "/test/index.php?q=foo&a=1&b=2#cake",
make_link("foo", "a=1&b=2", "cake")
);
}
}
#[Depends("test_make_link")]
public function test_search_link(): void
{
global $config;
foreach([true, false] as $nice_urls) {
$config->set_bool('nice_urls', $nice_urls);
$this->assertEquals(
$nice_urls ? "/test/post/list/bar%20foo/1" : "/test/index.php?q=post/list/bar%20foo/1",
search_link(["foo", "bar"])
);
$this->assertEquals(
$nice_urls ? "/test/post/list/AC%2FDC/1" : "/test/index.php?q=post/list/AC%2FDC/1",
search_link(["AC/DC"])
);
$this->assertEquals(
$nice_urls ? "/test/post/list/cat%2A%20rating%3D%3F/1" : "/test/index.php?q=post/list/cat%2A%20rating%3D%3F/1",
search_link(["rating=?", "cat*"])
);
}
}
#[Depends("test_get_base_href")]
public function test_get_query(): void
{
// just validating an assumption that this test relies upon
$this->assertEquals(get_base_href(), "/test");
$this->assertEquals(
"/test/foo",
make_link("foo")
"tasty/cake",
_get_query("/test/tasty/cake"),
'http://$SERVER/$INSTALL_DIR/$PATH should return $PATH'
);
$this->assertEquals(
"tasty/cake",
_get_query("/test/index.php?q=tasty/cake"),
'http://$SERVER/$INSTALL_DIR/index.php?q=$PATH should return $PATH'
);
// remove leading slash from path
$this->assertEquals(
"/test/foo",
make_link("/foo")
"tasty/cake%20pie",
_get_query("/test/index.php?q=tasty/cake%20pie"),
'URL encoded paths should be left alone'
);
$this->assertEquals(
"tasty/cake%20pie",
_get_query("/test/tasty/cake%20pie"),
'URL encoded queries should be left alone'
);
// query
$this->assertEquals(
"/test/foo?a=1&b=2",
make_link("foo", "a=1&b=2")
"",
_get_query("/test/"),
'If just viewing install directory, should return /'
);
$this->assertEquals(
"",
_get_query("/test/index.php"),
'If just viewing index.php, should return /'
);
// hash
$this->assertEquals(
"/test/foo#cake",
make_link("foo", null, "cake")
"post/list/tasty%2Fcake/1",
_get_query("/test/post/list/tasty%2Fcake/1"),
'URL encoded niceurls should be left alone, even encoded slashes'
);
// query + hash
$this->assertEquals(
"/test/foo?a=1&b=2#cake",
make_link("foo", "a=1&b=2", "cake")
"post/list/tasty%2Fcake/1",
_get_query("/test/index.php?q=post/list/tasty%2Fcake/1"),
'URL encoded uglyurls should be left alone, even encoded slashes'
);
}
public function test_is_https_enabled(): void
{
$this->assertFalse(is_https_enabled(), "HTTPS should be disabled by default");
$_SERVER['HTTPS'] = "on";
$this->assertTrue(is_https_enabled(), "HTTPS should be enabled when set to 'on'");
unset($_SERVER['HTTPS']);
}
public function test_get_base_href(): void
{
// PHP_SELF should point to "the currently executing script
// relative to the document root"
$this->assertEquals("", get_base_href(["PHP_SELF" => "/index.php"]));
$this->assertEquals("/mydir", get_base_href(["PHP_SELF" => "/mydir/index.php"]));
// SCRIPT_FILENAME should point to "the absolute pathname of
// the currently executing script" and DOCUMENT_ROOT should
// point to "the document root directory under which the
// current script is executing"
$this->assertEquals("", get_base_href([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/index.php",
"DOCUMENT_ROOT" => "/var/www/html",
]), "root directory");
$this->assertEquals("/mydir", get_base_href([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/mydir/index.php",
"DOCUMENT_ROOT" => "/var/www/html",
]), "subdirectory");
$this->assertEquals("", get_base_href([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/index.php",
"DOCUMENT_ROOT" => "/var/www/html/",
]), "trailing slash in DOCUMENT_ROOT root should be ignored");
$this->assertEquals("/mydir", get_base_href([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/mydir/index.php",
"DOCUMENT_ROOT" => "/var/www/html/",
]), "trailing slash in DOCUMENT_ROOT subdir should be ignored");
}
#[Depends("test_is_https_enabled")]
#[Depends("test_get_base_href")]
public function test_make_http(): void
{
// relative to shimmie install
$this->assertEquals(
"http://cli-command/test/foo",
make_http("foo")
make_http("foo"),
"relative to shimmie root"
);
// relative to web server
$this->assertEquals(
"http://cli-command/foo",
make_http("/foo")
make_http("/foo"),
"relative to web server"
);
// absolute
$this->assertEquals(
"https://foo.com",
make_http("https://foo.com")
make_http("https://foo.com"),
"absolute URL should be left alone"
);
}

View File

@ -162,35 +162,4 @@ class UtilTest extends TestCase
path_to_tags("/category:/tag/baz.jpg")
);
}
public function test_get_query(): void
{
// niceurls
$_SERVER["REQUEST_URI"] = "/test/tasty/cake";
$this->assertEquals("/tasty/cake", _get_query());
// no niceurls
$_SERVER["REQUEST_URI"] = "/test/index.php?q=/tasty/cake";
$this->assertEquals("/tasty/cake", _get_query());
// leave url encoding alone
$_SERVER["REQUEST_URI"] = "/test/index.php?q=/tasty/cake%20pie";
$this->assertEquals("/tasty/cake%20pie", _get_query());
// if just viewing index.php
$_SERVER["REQUEST_URI"] = "/test/index.php";
$this->assertEquals("/", _get_query());
// niceurl root
$_SERVER["REQUEST_URI"] = "/test/";
$this->assertEquals("/", _get_query());
// niceurls with encoded slashes
$_SERVER["REQUEST_URI"] = "/test/post/list/tasty%2Fcake/1";
$this->assertEquals("/post/list/tasty%2Fcake/1", _get_query());
// query string with encoded slashes
$_SERVER["REQUEST_URI"] = "/test/index.php?q=/post/list/tasty%2Fcake/1";
$this->assertEquals("/post/list/tasty%2Fcake/1", _get_query());
}
}

View File

@ -41,7 +41,8 @@ function search_link(array $terms = [], int $page = 1): string
* Figure out the correct way to link to a page, taking into account
* things like the nice URLs setting.
*
* eg make_link("foo/bar") becomes "/v2/index.php?q=foo/bar"
* eg make_link("foo/bar") becomes either "/v2/foo/bar" (niceurls) or
* "/v2/index.php?q=foo/bar" (uglyurls)
*/
function make_link(?string $page = null, ?string $query = null, ?string $fragment = null): string
{
@ -66,6 +67,106 @@ function make_link(?string $page = null, ?string $query = null, ?string $fragmen
return unparse_url($parts);
}
/**
* Figure out the current page from a link that make_link() generated
*
* SHIT: notes for the future, because the web stack is a pile of hacks
*
* - According to some specs, "/" is for URL dividers with heiracial
* significance and %2F is for slashes that are just slashes. This
* is what shimmie currently does - eg if you search for "AC/DC",
* the shimmie URL will be /post/list/AC%2FDC/1
* - According to some other specs "/" and "%2F" are identical...
* - PHP's $_GET[] automatically urldecodes the inputs so we can't
* tell the difference between q=foo/bar and q=foo%2Fbar
* - REQUEST_URI contains the exact URI that was given to us, so we
* can parse it for ourselves
* - <input type="hidden" name="q" value="post/list"> generates
* q=post%2Flist
*
* This function should always return strings with no leading slashes
*/
function _get_query(?string $uri = null): string
{
$parsed_url = parse_url($uri ?? $_SERVER['REQUEST_URI']);
// if we're looking at http://site.com/$INSTALL_DIR/index.php,
// then get the query from the "q" parameter
if(($parsed_url["path"] ?? "") == (get_base_href() . "/index.php")) {
// $q = $_GET["q"] ?? "";
// default to looking at the root
$q = "";
// (we need to manually parse the query string because PHP's $_GET
// does an extra round of URL decoding, which we don't want)
foreach(explode('&', $parsed_url['query'] ?? "") as $z) {
$qps = explode('=', $z, 2);
if(count($qps) == 2 && $qps[0] == "q") {
$q = $qps[1];
}
}
}
// if we're looking at http://site.com/$INSTALL_DIR/$PAGE,
// then get the query from the path
else {
$q = substr($parsed_url["path"] ?? "", strlen(get_base_href() . "/"));
}
assert(!str_starts_with($q, "/"));
return $q;
}
/**
* Figure out the path to the shimmie install directory.
*
* eg if shimmie is visible at https://foo.com/gallery, this
* function should return /gallery
*
* PHP really, really sucks.
*
* This function should always return strings with no trailing
* slashes, so that it can be used like `get_base_href() . "/data/asset.abc"`
*
* @param array<string, string>|null $server_settings
*/
function get_base_href(?array $server_settings = null): string
{
if (defined("BASE_HREF") && !empty(BASE_HREF)) {
return BASE_HREF;
}
$server_settings = $server_settings ?? $_SERVER;
if(str_ends_with($server_settings['PHP_SELF'], 'index.php')) {
$self = $server_settings['PHP_SELF'];
} elseif(isset($server_settings['SCRIPT_FILENAME']) && isset($server_settings['DOCUMENT_ROOT'])) {
$self = substr($server_settings['SCRIPT_FILENAME'], strlen(rtrim($server_settings['DOCUMENT_ROOT'], "/")));
} else {
die("PHP_SELF or SCRIPT_FILENAME need to be set");
}
$dir = dirname($self);
$dir = str_replace("\\", "/", $dir);
$dir = rtrim($dir, "/");
return $dir;
}
/**
* The opposite of the standard library's parse_url
*
* @param array<string, string|int> $parsed_url
*/
function unparse_url(array $parsed_url): string
{
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$host = $parsed_url['host'] ?? '';
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
$user = $parsed_url['user'] ?? '';
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = $parsed_url['path'] ?? '';
$query = !empty($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$fragment = !empty($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return "$scheme$user$pass$host$port$path$query$fragment";
}
/**
* Take the current URL and modify some parameters

View File

@ -713,37 +713,6 @@ function _get_user(): User
return $my_user;
}
function _get_query(): string
{
// if q is set in POST, use that
if(isset($_POST["q"])) {
return $_POST["q"];
}
// if q is set in GET, use that
// (we need to manually parse the query string because PHP's $_GET
// does an extra round of URL decoding, which we don't want)
$parts = parse_url($_SERVER['REQUEST_URI']);
$qs = [];
foreach(explode('&', $parts['query'] ?? "") as $z) {
$qps = explode('=', $z, 2);
if(count($qps) == 2) {
$qs[$qps[0]] = $qps[1];
}
}
if(isset($qs["q"])) {
return $qs["q"];
}
// if we're just looking at index.php, use the default query
if(str_ends_with($parts["path"] ?? "", "index.php")) {
return "/";
}
// otherwise, use the request URI minus the base path
return substr($parts["path"] ?? "", strlen(get_base_href()));
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* HTML Generation *

View File

@ -319,6 +319,13 @@ class Setup extends Extension
{
global $config, $page, $user;
if ($event->page_matches("nicedebug")) {
$page->set_mode(PageMode::DATA);
$page->set_data(json_encode_ex([
"args" => $event->args,
]));
}
if ($event->page_matches("nicetest")) {
$page->set_mode(PageMode::DATA);
$page->set_data("ok");