aboutsummaryrefslogtreecommitdiff
path: root/tests/Regression
diff options
context:
space:
mode:
authorBrett Parson <brett@brett-parson.com>2026-08-29 15:56:31 -0500
committerBrett Parson <brett@brett-parson.com>2026-08-29 15:56:31 -0500
commit965551532d684456b74baf960157c0c2cef7335d (patch)
tree1445afbc47730caa11d08fd84d9d65db132821f5 /tests/Regression
parentd039a5d62a9ac6ababae70d9d96422ca59f2b2d4 (diff)
downloadminiroute-965551532d684456b74baf960157c0c2cef7335d.tar.gz
miniroute-965551532d684456b74baf960157c0c2cef7335d.zip
Add regression and integration test suite
Port the stress-test findings into PHPUnit: realistic brett-parson.com route model, known-issue baselines, router boundary cases, and a standalone scaling benchmark (composer bench).
Diffstat (limited to 'tests/Regression')
-rw-r--r--tests/Regression/KnownIssuesTest.php158
1 files changed, 158 insertions, 0 deletions
diff --git a/tests/Regression/KnownIssuesTest.php b/tests/Regression/KnownIssuesTest.php
new file mode 100644
index 0000000..5a6c6f7
--- /dev/null
+++ b/tests/Regression/KnownIssuesTest.php
@@ -0,0 +1,158 @@
+<?php
+
+declare(strict_types=1);
+
+namespace BrettParson\MiniRoute\Tests\Regression;
+
+use BrettParson\MiniRoute\Routing\RouteLoader;
+use BrettParson\MiniRoute\Routing\RouteNotFoundException;
+use BrettParson\MiniRoute\Routing\Router;
+use BrettParson\MiniRoute\Tests\Fixtures\DuplicateParamController;
+use BrettParson\MiniRoute\Tests\Fixtures\FakeController;
+use BrettParson\MiniRoute\Tests\Fixtures\FakeResolver;
+use BrettParson\MiniRoute\Tests\Fixtures\MixedVisibilityController;
+use BrettParson\MiniRoute\Tests\Fixtures\OnlyGetController;
+use BrettParson\MiniRoute\Tests\Fixtures\StatefulController;
+use BrettParson\MiniRoute\Tests\Fixtures\StatefulMiddleware;
+use BrettParson\MiniRoute\Tests\Fixtures\TestRequest;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Known-issue baselines: pin v0.1.0 behavior for every confirmed stress
+ * finding so the suite is green today and each case flips to the desired
+ * behavior when its v0.2.0 fix lands.
+ *
+ * Bead: miniroute-4dh.2. Fixes tracked in the v0.2.0 epic (miniroute-uhs).
+ */
+final class KnownIssuesTest extends TestCase
+{
+ private function routerWith(object $controller, string $class): Router
+ {
+ $resolver = new FakeResolver();
+ $resolver->bind($class, $controller);
+
+ return new Router($resolver);
+ }
+
+ /**
+ * Baseline: duplicated parameter names produce a route that can never
+ * match, and emit a PHP warning on every match attempt.
+ *
+ * Desired (miniroute-uhs.1): registration throws
+ * RouteRegistrationException. Flip this test when the fix lands.
+ */
+ public function testDuplicateParamNamesAreADeadRoute(): void
+ {
+ $router = $this->routerWith(new DuplicateParamController(), DuplicateParamController::class);
+ $router->registerController(DuplicateParamController::class);
+
+ $warnings = [];
+ set_error_handler(static function (int $errno, string $errstr) use (&$warnings): bool {
+ $warnings[] = $errstr;
+
+ return true;
+ });
+
+ try {
+ $router->dispatch(new TestRequest('GET', '/dup/1/x/2'));
+ $matched = true;
+ } catch (RouteNotFoundException) {
+ $matched = false;
+ } finally {
+ restore_error_handler();
+ }
+
+ $this->assertFalse($matched, 'duplicate-param route must not match');
+ $this->assertNotEmpty($warnings, 'matching a duplicate-param route emits a preg warning');
+ }
+
+ /**
+ * Baseline: a wrong method on an existing path is a 404, with no way to
+ * distinguish method-not-allowed.
+ *
+ * Desired (miniroute-uhs.2): MethodNotAllowedException carrying the
+ * allowed methods, so the app can render 405 + Allow. Flip this test.
+ */
+ public function testWrongMethodOnExistingPathIsNotFound(): void
+ {
+ $router = $this->routerWith(new OnlyGetController(), OnlyGetController::class);
+ $router->registerController(OnlyGetController::class);
+
+ $this->expectException(RouteNotFoundException::class);
+
+ $router->dispatch(new TestRequest('POST', '/only'));
+ }
+
+ /**
+ * Baseline: HEAD requests never map to GET handlers.
+ *
+ * Desired (miniroute-uhs.3): HEAD dispatches to the GET handler and the
+ * app's response layer suppresses the body. Flip this test.
+ */
+ public function testHeadDoesNotMapToGet(): void
+ {
+ $router = $this->routerWith(new OnlyGetController(), OnlyGetController::class);
+ $router->registerController(OnlyGetController::class);
+
+ $this->expectException(RouteNotFoundException::class);
+
+ $router->dispatch(new TestRequest('HEAD', '/only'));
+ }
+
+ /**
+ * Baseline: route attributes on non-public methods are silently skipped
+ * by the loader.
+ *
+ * Desired (miniroute-uhs.4): loading a controller with a route attribute
+ * on a non-public method throws RouteRegistrationException. Flip this test.
+ */
+ public function testNonPublicMethodsWithRouteAttributesAreSkipped(): void
+ {
+ $routes = (new RouteLoader())->load(MixedVisibilityController::class);
+
+ $this->assertCount(1, $routes);
+ $this->assertSame('/pub', $routes[0]->path);
+ }
+
+ /**
+ * Baseline: a resolver returning the same middleware instance across
+ * requests accumulates state (singleton-container leak). This is a usage
+ * contract, not a kernel bug: middleware must be stateless or
+ * per-request scoped. ADR work tracked in miniroute-k4i.3.
+ */
+ public function testSingletonMiddlewareAccumulatesStateAcrossRequests(): void
+ {
+ $stateful = new StatefulMiddleware();
+
+ $resolver = new FakeResolver();
+ $resolver->bind(StatefulController::class, new StatefulController());
+ $resolver->bind(StatefulMiddleware::class, $stateful);
+
+ $router = new Router($resolver);
+ $router->registerController(StatefulController::class);
+
+ $router->dispatch(new TestRequest('GET', '/stateful'));
+ $router->dispatch(new TestRequest('GET', '/stateful'));
+
+ $this->assertSame(2, $stateful->count, 'state leaks across dispatches with a shared instance');
+ }
+
+ /**
+ * Baseline: {param} segments are greedy — any single segment matches, so
+ * a typo'd URL gets a 200 from the parameterized route, not a 404.
+ *
+ * Documented behavior, no kernel fix planned: controllers validate the
+ * captured value (the blog controller 404s on an unknown slug). Decision
+ * recorded in miniroute-k4i.3 (param constraints rejected).
+ */
+ public function testParamRoutesAreGreedy(): void
+ {
+ $router = $this->routerWith(new FakeController(), FakeController::class);
+ $router->registerController(FakeController::class);
+
+ $response = $router->dispatch(new TestRequest('GET', '/entries/typo-of-known-path'));
+
+ $this->assertSame(200, $response->status());
+ $this->assertSame('show:typo-of-known-path', $response->body());
+ }
+}