summaryrefslogtreecommitdiffstats
path: root/tests/README.md
diff options
context:
space:
mode:
authorSimon Rettberg2025-11-26 10:46:51 +0100
committerSimon Rettberg2025-12-12 15:16:59 +0100
commit7c173411785f959d250d3dfbd7d4cfcb0e20f0e0 (patch)
tree242157791a76afb7af23ec2cd3d22b599e54ce9d /tests/README.md
parent[exams] Fix incorrect count() clause (diff)
downloadslx-admin-7c173411785f959d250d3dfbd7d4cfcb0e20f0e0.tar.gz
slx-admin-7c173411785f959d250d3dfbd7d4cfcb0e20f0e0.tar.xz
slx-admin-7c173411785f959d250d3dfbd7d4cfcb0e20f0e0.zip
Add tests using PHPUnit
Tests generated by Junie AI. Might not have the best possible quality but at least we got something, and if it turns out to be complete rubbish, we can just throw it out again without any issues, as this is independent of the actual code base.
Diffstat (limited to 'tests/README.md')
-rw-r--r--tests/README.md106
1 files changed, 106 insertions, 0 deletions
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 00000000..4d819fe7
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,106 @@
+# PHPUnit in this project (no Composer)
+
+This legacy project does not use Composer. To run tests, use the PHPUnit PHAR.
+
+Quick start:
+
+1. Download phpunit.phar (pick a version compatible with your PHP):
+
+ ```bash
+ curl -L -o phpunit.phar https://phar.phpunit.de/phpunit-9.6.phar
+ chmod +x phpunit.phar
+ ```
+
+ Alternatively, place `phpunit.phar` somewhere in your PATH.
+
+2. From the project root, run the tests:
+
+ ```bash
+ php phpunit.phar
+ # or
+ php phpunit.phar --configuration phpunit.xml.dist
+ ```
+
+Structure added:
+- `phpunit.xml.dist` — PHPUnit configuration using `tests/bootstrap.php`.
+- `tests/bootstrap.php` — sets up error reporting and an autoloader matching `./inc/<lowername>.inc.php`.
+- `tests/` — test files live here. Initial tests added for `IpUtil` under `tests/Inc/IpUtilTest.php`.
+
+Notes:
+- The bootstrap avoids including `index.php`/`api.php` to prevent side effects; it only loads `config.php` if present and registers an autoloader for `inc/`.
+- Tests target self-contained helpers first to build coverage without refactoring entangled code.
+
+## Testing real classes when stubs exist
+Some tests load global stubs (e.g., `Database`, `User`) by default via a stub-first autoloader. To test a real class that also has a stub:
+
+- Run the test in a separate PHP process so it starts clean and doesn’t inherit classes from prior tests:
+ - Add these annotations to the test class (or individual test methods):
+ - `@runTestsInSeparateProcesses`
+ - `@preserveGlobalState disabled`
+- Before the first reference to the class, tell the stub autoloader to allowlist the real class:
+ ```php
+ $GLOBALS['__TEST_USE_REAL_CLASSES'] = ['User'];
+ ```
+ Alternatively, set an environment variable when running PHPUnit:
+ ```bash
+ TEST_USE_REAL_CLASSES=User php phpunit.phar tests/Inc/UserTest.php
+ ```
+- Optionally force-load the class immediately afterwards:
+ ```php
+ require_once __DIR__ . '/../../inc/user.inc.php';
+ ```
+
+See `tests/Inc/UserTest.php` for a complete example.
+
+
+## Module testing (modules-available/*/page.inc.php)
+This project’s modules define page classes (e.g., `Page_SysLog`) that normally run under `index.php`, which defines a global `Page` class and provides request/rendering infrastructure. For unit tests, a lightweight harness is provided via stubs under `tests/Stubs`:
+
+- `Page` — minimal base with `preprocess()` and `render()` calling the module’s `doPreprocess()`/`doRender()`. Also provides `Page::getModule()` and `getIdentifier()` as needed by some code.
+- `Request` — `any()`, `get()`, `post()` backed by PHP superglobals with simple type casting.
+- `Render` — records `addTemplate()` calls for assertions.
+- `Permission` — `addGlobalTags()` no-op that fills the provided array with the requested tags.
+- `Paginate` — captures the SQL and args, returns queued results in tests, and records the template/data passed to `render()`.
+- Existing stubs like `Database`, `User`, `Session`, `Message`, `Dictionary`, and `Property` are reused.
+
+How to write a module test:
+- Reset stubs and superglobals in `setUp()`.
+- Make sure your test loads the module file directly:
+ ```php
+ require_once __DIR__ . '/../../modules-available/syslog/page.inc.php';
+ $page = new Page_SysLog('syslog');
+ $page->render();
+ ```
+- Drive inputs via `$_GET`, `$_POST`, and the `User`/`Property` stubs.
+- Seed DB and pagination data by pushing into stub queues:
+ ```php
+ Database::$simpleQueryResponses[] = [ ['logtypeid' => 'x', 'counter' => 1] ];
+ Paginate::$queuedResults[] = [ ['dateline' => time(), 'logtypeid' => 'x', ...] ];
+ ```
+- Assert on `Paginate::$lastExecArgs`, `Paginate::$lastRender`, and `Render::$templates`.
+
+See `tests/Modules/SyslogPageTest.php` for a complete example that covers:
+- Permission denial path (no `view` permission)
+- Filter/search handling and type list augmentation
+- Location restriction joining via `getAllowedLocations()`
+
+## Database-backed tests without MySQL (SQLite test backend)
+
+Global schema and seed data:
+- The SQLite backend now auto-creates a minimal schema on first use and seeds a canonical dataset so tests can share consistent data without duplicating setup.
+- Tables created include: location, subnet, machine, user, role, role_x_user, role_x_location, role_x_permission, clientlog, mail_queue, mail_config, audit.
+- Seed content highlights:
+ - Locations: Campus (1) → Building A (2) → Room 101 (4); Building B (3); Offsite (5)
+ - Subnets: 10.0.0.0/24 @ 1, 10.0.0.128/26 @ 2, 192.168.1.0/24 @ 5
+ - Users/roles: alice(1), bob(2); roles Admin(1, builtin), Tech(2) with sample permissions
+
+Utility helpers (optional):
+- `Database::resetSchema()` — drop and recreate the in-memory DB with fresh schema and seed.
+- `Database::reseed()` — reinsert the seed data into the existing schema.
+- `Database::truncateAll()` — delete rows from all known tables.
+- `Database::pdo()` — access the underlying PDO if you need custom SQL.
+
+Parameter handling:
+- Array parameters in `IN (:list)` and bulk inserts like `VALUES :arg` (legacy pattern) are expanded automatically.
+
+There is a very thin translation layer that tries to convert MySQL-specific syntax into SQLite syntax. It might need improvements and extensions as more tests get added. \ No newline at end of file