'alice', 'password' => 'secret', // censored to ***** 'apiToken' => 'tok-123', // censored to ***** 'my_privatekey' => 'abc', // censored to ***** (ends with key) 'pw_hint' => 'hello', // censored to ***** (starts with pw) 'prevent_autofill' => 'x', // skipped entirely 'action' => 'should-be-skipped-in-data', // skipped in data (but appears in metadata via $_REQUEST) 'arr' => [ 'nestedPassword' => 'verysecret', // censored in nested 'value' => 'ok', ], 'long' => str_repeat('A', 1200), // will be truncated to 1000 + ... initially; still under maxTotalLen -> accepted ]; // Act Audit::run('mod.settings'); // Assert: fetch the last audit row $row = Database::queryFirst('SELECT * FROM audit ORDER BY id DESC LIMIT 1'); $this->assertNotFalse($row); $this->assertSame(123, (int)$row['userid']); $this->assertSame('203.0.113.5', $row['ipaddr']); $this->assertSame('mod.settings', $row['module']); $this->assertSame('update', $row['action']); // Decode filtered JSON $filtered = json_decode($row['data'], true); $this->assertIsArray($filtered); // Skipped keys not present $this->assertArrayNotHasKey('prevent_autofill', $filtered); $this->assertArrayNotHasKey('action', $filtered); // Censored keys $this->assertSame('*****', $filtered['password']); $this->assertSame('*****', $filtered['apiToken']); $this->assertSame('*****', $filtered['my_privatekey']); $this->assertSame('*****', $filtered['pw_hint']); // Nested censoring preserved $this->assertSame('*****', $filtered['arr']['nestedPassword']); $this->assertSame('ok', $filtered['arr']['value']); // Truncation behavior for long field: ends with ellipsis and length > 1000 due to ... $this->assertStringEndsWith('...', $filtered['long']); $this->assertSame(1003, strlen($filtered['long'])); } public function testRunExcessPayloadTriggersTraceAndStoresEXCESS(): void { // Not logged in -> smaller total limit (10000) User::$loggedIn = false; User::$id = 7; $_SERVER['REMOTE_ADDR'] = '198.51.100.9'; $_REQUEST['action'] = 'bulk'; // Build a very large POST that even after truncation to 200 still exceeds 10000 $big = []; for ($i = 0; $i < 60; $i++) { $big['f' . $i] = str_repeat('x', 5000); } $_POST = $big; Audit::run('mod.big'); // Assert row stored with EXCESS data marker $row = Database::queryFirst('SELECT * FROM audit ORDER BY id DESC LIMIT 1'); $this->assertNotFalse($row); $this->assertSame('EXCESS', $row['data']); // ErrorHandler should record the trace $this->assertNotEmpty(ErrorHandler::$traces); $this->assertStringContainsString('exceeded', strtolower(ErrorHandler::$traces[0])); } }