summaryrefslogtreecommitdiffstats
path: root/tests/README.md
blob: 4d819fe70ee3020775e926df69fe8fb36f0d76f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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.

  1. 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.
  • Requestany(), get(), post() backed by PHP superglobals with simple type casting.
  • Render — records addTemplate() calls for assertions.
  • PermissionaddGlobalTags() 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.