From b0925ce489926e15791df7dd93200831fb2ca74a Mon Sep 17 00:00:00 2001 From: Ismo Vuorinen Date: Sun, 8 Mar 2026 13:50:17 +0200 Subject: [PATCH] refactor: replace hardcoded strings with constant references (#100) * fix(tests): remove error_log calls and clean up ComprehensiveValidationTest * refactor: replace hardcoded strings with MaskConstants and TestConstants references * fix(streaming): replace overcounting '[' heuristic with proper mask detection StreamingProcessor::getStatistics() was counting any message containing '[' as masked, causing false positives. Now checks for specific mask constants (MASK_GENERIC, MASK_BRACKETS, MASK_REDACTED_BRACKETS) instead. Also adds MASK_REDACTED_BRACKETS constant to MaskConstants and removes the now-unnecessary UnusedFunctionCall psalm suppression. * refactor(tests): replace remaining hardcoded literals with constant references Add new constants to TestConstants (MASK_REDACTED_PLAIN, MASK_SECRET_BRACKETS, MASK_SSN_BRACKETS, PATTERN_REDOS_NESTED_STAR, FIELD_USER_SSN, FIELD_USER_DATA) and replace all matching literals across 21 test files. Also removes dead memory_get_usage() call and uses existing TestConstants::IP_ADDRESS_PUBLIC for hardcoded IP. * fix(streaming): replace mask-token heuristic with accurate record comparison in getStatistics() The previous implementation only detected masking when specific mask tokens appeared in the message, missing cases where context was masked or different mask values were used. Compare original vs processed records instead. * refactor(tests): add PATTERN_EMAIL_SIMPLE, MASK_CARD_BRACKETS, EXPECTED_SSN_MASKED constants Replace cross-file duplicate literals with TestConstants references: - Email regex (4 files), '[CARD]' (2 files), 'SSN: [SSN]' (2 files) * fix(streaming): bypass audit logger in getStatistics() by calling orchestrator directly getStatistics() previously routed through processStream()/processChunk() which triggered the audit logger for each record. A read-only statistics method should not produce audit side-effects. Now calls orchestrator.process() directly and processes records one at a time without materializing the entire iterable. * refactor(tests): fix test quality issues and add PATTERN_CREDIT_CARD constant - Replace fail() message that leaked sensitive terms with count-only message - Replace bare 'EMAIL' string with MaskConstants::MASK_EMAIL for consistency - Remove error_log() debug output from CriticalBugRegressionTest - Add TestConstants::PATTERN_CREDIT_CARD and replace inline regex in 3 files --- psalm.xml | 7 -- src/MaskConstants.php | 1 + src/Streaming/StreamingProcessor.php | 6 +- tests/AdvancedRegexMaskProcessorTest.php | 6 +- tests/Anonymization/KAnonymizerTest.php | 26 +++---- .../ArrayAccessorFactoryTest.php | 7 +- .../ArrayAccessorInterfaceTest.php | 34 ++++---- tests/Audit/ErrorContextTest.php | 10 +-- tests/Audit/StructuredAuditLoggerTest.php | 36 ++++----- .../GdprProcessorBuilderEdgeCasesTest.php | 36 ++++----- tests/Builder/GdprProcessorBuilderTest.php | 14 ++-- tests/Builder/PluginAwareProcessorTest.php | 10 +-- tests/ConditionalRuleFactoryInstanceTest.php | 14 ++-- tests/ContextProcessorTest.php | 4 +- ...AuditLoggingExceptionComprehensiveTest.php | 4 +- tests/Exceptions/CustomExceptionsTest.php | 4 +- .../MaskingOperationFailedExceptionTest.php | 3 +- tests/Factory/AuditLoggerFactoryTest.php | 11 +-- tests/GdprProcessorComprehensiveTest.php | 4 +- tests/GdprProcessorEdgeCasesTest.php | 6 +- tests/GdprProcessorMethodsTest.php | 4 +- tests/GdprProcessorTest.php | 4 +- .../FieldMaskConfigValidationTest.php | 6 +- .../GdprProcessorValidationTest.php | 4 +- tests/InputValidatorTest.php | 6 +- tests/JsonMaskingTest.php | 30 ++++---- tests/MaskingOrchestratorTest.php | 28 +++---- tests/Plugins/AbstractMaskingPluginTest.php | 11 +-- tests/Recovery/RecoveryResultTest.php | 4 +- tests/Recovery/RetryStrategyTest.php | 2 +- tests/RecursiveProcessorTest.php | 8 +- tests/RegexMaskProcessorTest.php | 8 +- .../ComprehensiveValidationTest.php | 77 ++----------------- .../CriticalBugRegressionTest.php | 21 +---- .../SecurityRegressionTest.php | 8 +- tests/Retention/RetentionPolicyTest.php | 9 ++- tests/SecuritySanitizerTest.php | 5 +- tests/SerializedDataProcessorTest.php | 34 ++++---- .../AbstractMaskingStrategyTest.php | 20 ++--- .../CallbackMaskingStrategyTest.php | 77 ++++++++++--------- ...tionalMaskingStrategyComprehensiveTest.php | 2 +- ...taTypeMaskingStrategyComprehensiveTest.php | 8 +- .../DataTypeMaskingStrategyTest.php | 14 ++-- .../FieldPathMaskingStrategyEnhancedTest.php | 2 +- .../FieldPathMaskingStrategyTest.php | 12 +-- tests/Strategies/MaskingStrategiesTest.php | 6 +- tests/Strategies/RegexMaskingStrategyTest.php | 20 ++--- tests/Strategies/StrategyEdgeCasesTest.php | 47 +++++------ .../StrategyManagerComprehensiveTest.php | 8 +- tests/Streaming/StreamingProcessorTest.php | 74 +++++++++++------- tests/TestConstants.php | 14 ++++ 51 files changed, 386 insertions(+), 430 deletions(-) diff --git a/psalm.xml b/psalm.xml index 55955de..25949d7 100644 --- a/psalm.xml +++ b/psalm.xml @@ -115,13 +115,6 @@ - - - - - - - diff --git a/src/MaskConstants.php b/src/MaskConstants.php index 86c21d9..b752073 100644 --- a/src/MaskConstants.php +++ b/src/MaskConstants.php @@ -28,6 +28,7 @@ final class MaskConstants public const MASK_REDACTED = '***REDACTED***'; public const MASK_FILTERED = '***FILTERED***'; public const MASK_BRACKETS = '[MASKED]'; + public const MASK_REDACTED_BRACKETS = '[REDACTED]'; // Personal identifiers public const MASK_HETU = '***HETU***'; // Finnish SSN diff --git a/src/Streaming/StreamingProcessor.php b/src/Streaming/StreamingProcessor.php index 79ff697..6b1ab42 100644 --- a/src/Streaming/StreamingProcessor.php +++ b/src/Streaming/StreamingProcessor.php @@ -176,10 +176,10 @@ final class StreamingProcessor { $stats = ['processed' => 0, 'masked' => 0, 'errors' => 0]; - foreach ($this->processStream($records) as $record) { + foreach ($records as $record) { $stats['processed']++; - // Count if any masking occurred (simple heuristic) - if (str_contains($record['message'], '***') || str_contains($record['message'], '[')) { + $processed = $this->orchestrator->process($record['message'], $record['context']); + if ($processed !== $record) { $stats['masked']++; } } diff --git a/tests/AdvancedRegexMaskProcessorTest.php b/tests/AdvancedRegexMaskProcessorTest.php index 0a64980..a3b829a 100644 --- a/tests/AdvancedRegexMaskProcessorTest.php +++ b/tests/AdvancedRegexMaskProcessorTest.php @@ -35,7 +35,7 @@ class AdvancedRegexMaskProcessorTest extends TestCase ]; $fieldPaths = [ - "user.ssn" => "[GDPR]", + TestConstants::FIELD_USER_SSN => "[GDPR]", "payment.card" => "[CC]", "contact.email" => FieldMaskConfig::useProcessorPatterns(), // use regex-masked "metadata.session" => "[SESSION]", @@ -48,7 +48,7 @@ class AdvancedRegexMaskProcessorTest extends TestCase { $record = $this->logEntry()->with(message: "Card: 1234567812345678"); $result = ($this->processor)($record)->toArray(); - $this->assertSame("Card: " . MaskConstants::MASK_CC, $result["message"]); + $this->assertSame("Card: " . MaskConstants::MASK_CC, $result[TestConstants::FIELD_MESSAGE]); } public function testMaskEmailInMessage(): void @@ -56,7 +56,7 @@ class AdvancedRegexMaskProcessorTest extends TestCase $record = $this->logEntry()->with(message: "Email: user@example.com"); $result = ($this->processor)($record)->toArray(); - $this->assertSame("Email: " . MaskConstants::MASK_EMAIL, $result["message"]); + $this->assertSame("Email: " . MaskConstants::MASK_EMAIL, $result[TestConstants::FIELD_MESSAGE]); } public function testContextFieldPathReplacements(): void diff --git a/tests/Anonymization/KAnonymizerTest.php b/tests/Anonymization/KAnonymizerTest.php index 30b10d0..0e47013 100644 --- a/tests/Anonymization/KAnonymizerTest.php +++ b/tests/Anonymization/KAnonymizerTest.php @@ -19,11 +19,11 @@ final class KAnonymizerTest extends TestCase $anonymizer = new KAnonymizer(); $anonymizer->registerAgeStrategy('age'); - $record = ['name' => 'John', 'age' => 25]; + $record = ['name' => TestConstants::NAME_FIRST, 'age' => 25]; $result = $anonymizer->anonymize($record); $this->assertSame(TestConstants::AGE_RANGE_20_29, $result['age']); - $this->assertSame('John', $result['name']); + $this->assertSame(TestConstants::NAME_FIRST, $result['name']); } public function testAnonymizeWithAgeStrategyDifferentRanges(): void @@ -84,7 +84,7 @@ final class KAnonymizerTest extends TestCase $anonymizer = new KAnonymizer(); $anonymizer->registerLocationStrategy('zip_code', 3); - $record = ['zip_code' => '12345']; + $record = ['zip_code' => TestConstants::DATA_NUMBER_STRING]; $result = $anonymizer->anonymize($record); $this->assertSame('123**', $result['zip_code']); @@ -115,17 +115,17 @@ final class KAnonymizerTest extends TestCase public function testAnonymizeWithCustomStrategy(): void { $anonymizer = new KAnonymizer(); - $anonymizer->registerCustomStrategy('email', fn(mixed $v): string => explode('@', (string) $v)[1] ?? 'unknown'); + $anonymizer->registerCustomStrategy(TestConstants::CONTEXT_EMAIL, fn(mixed $v): string => explode('@', (string) $v)[1] ?? 'unknown'); - $record = ['email' => 'john@example.com']; + $record = [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_JOHN]; $result = $anonymizer->anonymize($record); - $this->assertSame('example.com', $result['email']); + $this->assertSame(TestConstants::DOMAIN, $result[TestConstants::CONTEXT_EMAIL]); } public function testRegisterStrategy(): void { - $strategy = new GeneralizationStrategy(fn(mixed $v): string => 'masked', 'test'); + $strategy = new GeneralizationStrategy(fn(mixed $v): string => TestConstants::DATA_MASKED, 'test'); $anonymizer = new KAnonymizer(); $anonymizer->registerStrategy('field', $strategy); @@ -133,7 +133,7 @@ final class KAnonymizerTest extends TestCase $record = ['field' => 'value']; $result = $anonymizer->anonymize($record); - $this->assertSame('masked', $result['field']); + $this->assertSame(TestConstants::DATA_MASKED, $result['field']); } public function testAnonymizeIgnoresMissingFields(): void @@ -141,10 +141,10 @@ final class KAnonymizerTest extends TestCase $anonymizer = new KAnonymizer(); $anonymizer->registerAgeStrategy('age'); - $record = ['name' => 'John']; + $record = ['name' => TestConstants::NAME_FIRST]; $result = $anonymizer->anonymize($record); - $this->assertSame(['name' => 'John'], $result); + $this->assertSame(['name' => TestConstants::NAME_FIRST], $result); } public function testAnonymizeBatch(): void @@ -153,7 +153,7 @@ final class KAnonymizerTest extends TestCase $anonymizer->registerAgeStrategy('age'); $records = [ - ['name' => 'John', 'age' => 25], + ['name' => TestConstants::NAME_FIRST, 'age' => 25], ['name' => 'Jane', 'age' => 32], ]; @@ -258,13 +258,13 @@ final class KAnonymizerTest extends TestCase $anonymizer->registerLocationStrategy('zip', 2); $anonymizer->registerDateStrategy('date', 'year'); - $record = ['age' => 28, 'zip' => '12345', 'date' => '2024-06-15', 'name' => 'John']; + $record = ['age' => 28, 'zip' => TestConstants::DATA_NUMBER_STRING, 'date' => '2024-06-15', 'name' => TestConstants::NAME_FIRST]; $result = $anonymizer->anonymize($record); $this->assertSame(TestConstants::AGE_RANGE_20_29, $result['age']); $this->assertSame('12***', $result['zip']); $this->assertSame('2024', $result['date']); - $this->assertSame('John', $result['name']); + $this->assertSame(TestConstants::NAME_FIRST, $result['name']); } public function testFluentInterface(): void diff --git a/tests/ArrayAccessor/ArrayAccessorFactoryTest.php b/tests/ArrayAccessor/ArrayAccessorFactoryTest.php index 3f3b8e2..89b2c97 100644 --- a/tests/ArrayAccessor/ArrayAccessorFactoryTest.php +++ b/tests/ArrayAccessor/ArrayAccessorFactoryTest.php @@ -8,6 +8,7 @@ use Ivuorinen\MonologGdprFilter\ArrayAccessor\ArrayAccessorFactory; use Ivuorinen\MonologGdprFilter\ArrayAccessor\DotArrayAccessor; use Ivuorinen\MonologGdprFilter\Contracts\ArrayAccessorInterface; use PHPUnit\Framework\TestCase; +use Tests\TestConstants; /** * Tests for ArrayAccessorFactory. @@ -29,11 +30,11 @@ final class ArrayAccessorFactoryTest extends TestCase { $factory = ArrayAccessorFactory::default(); $accessor = $factory->create([ - 'user' => ['email' => 'test@example.com'], + 'user' => [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST], ]); - $this->assertTrue($accessor->has('user.email')); - $this->assertSame('test@example.com', $accessor->get('user.email')); + $this->assertTrue($accessor->has(TestConstants::FIELD_USER_EMAIL)); + $this->assertSame(TestConstants::EMAIL_TEST, $accessor->get(TestConstants::FIELD_USER_EMAIL)); } public function testWithClassFactoryMethod(): void diff --git a/tests/ArrayAccessor/ArrayAccessorInterfaceTest.php b/tests/ArrayAccessor/ArrayAccessorInterfaceTest.php index 3c49f20..9c3662d 100644 --- a/tests/ArrayAccessor/ArrayAccessorInterfaceTest.php +++ b/tests/ArrayAccessor/ArrayAccessorInterfaceTest.php @@ -28,22 +28,22 @@ final class ArrayAccessorInterfaceTest extends TestCase { $accessor = new DotArrayAccessor([ 'user' => [ - 'email' => TestConstants::EMAIL_TEST, + TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, ], ]); - $this->assertTrue($accessor->has('user.email')); + $this->assertTrue($accessor->has(TestConstants::FIELD_USER_EMAIL)); } public function testHasReturnsFalseForMissingPath(): void { $accessor = new DotArrayAccessor([ 'user' => [ - 'email' => TestConstants::EMAIL_TEST, + TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, ], ]); - $this->assertFalse($accessor->has('user.name')); + $this->assertFalse($accessor->has(TestConstants::FIELD_USER_NAME)); $this->assertFalse($accessor->has('nonexistent')); } @@ -51,12 +51,12 @@ final class ArrayAccessorInterfaceTest extends TestCase { $accessor = new DotArrayAccessor([ 'user' => [ - 'email' => TestConstants::EMAIL_TEST, + TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, 'age' => 25, ], ]); - $this->assertSame(TestConstants::EMAIL_TEST, $accessor->get('user.email')); + $this->assertSame(TestConstants::EMAIL_TEST, $accessor->get(TestConstants::FIELD_USER_EMAIL)); $this->assertSame(25, $accessor->get('user.age')); } @@ -72,43 +72,43 @@ final class ArrayAccessorInterfaceTest extends TestCase { $accessor = new DotArrayAccessor([]); - $accessor->set('user.email', TestConstants::EMAIL_NEW); + $accessor->set(TestConstants::FIELD_USER_EMAIL, TestConstants::EMAIL_NEW); - $this->assertTrue($accessor->has('user.email')); - $this->assertSame(TestConstants::EMAIL_NEW, $accessor->get('user.email')); + $this->assertTrue($accessor->has(TestConstants::FIELD_USER_EMAIL)); + $this->assertSame(TestConstants::EMAIL_NEW, $accessor->get(TestConstants::FIELD_USER_EMAIL)); } public function testSetOverwritesExistingPath(): void { $accessor = new DotArrayAccessor([ - 'user' => ['email' => 'old@example.com'], + 'user' => [TestConstants::CONTEXT_EMAIL => 'old@example.com'], ]); - $accessor->set('user.email', TestConstants::EMAIL_NEW); + $accessor->set(TestConstants::FIELD_USER_EMAIL, TestConstants::EMAIL_NEW); - $this->assertSame(TestConstants::EMAIL_NEW, $accessor->get('user.email')); + $this->assertSame(TestConstants::EMAIL_NEW, $accessor->get(TestConstants::FIELD_USER_EMAIL)); } public function testDeleteRemovesPath(): void { $accessor = new DotArrayAccessor([ 'user' => [ - 'email' => TestConstants::EMAIL_TEST, + TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, 'name' => 'Test User', ], ]); - $accessor->delete('user.email'); + $accessor->delete(TestConstants::FIELD_USER_EMAIL); - $this->assertFalse($accessor->has('user.email')); - $this->assertTrue($accessor->has('user.name')); + $this->assertFalse($accessor->has(TestConstants::FIELD_USER_EMAIL)); + $this->assertTrue($accessor->has(TestConstants::FIELD_USER_NAME)); } public function testAllReturnsCompleteArray(): void { $data = [ 'user' => [ - 'email' => TestConstants::EMAIL_TEST, + TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, 'profile' => [ 'bio' => 'Hello world', ], diff --git a/tests/Audit/ErrorContextTest.php b/tests/Audit/ErrorContextTest.php index f0cabb2..dd506b3 100644 --- a/tests/Audit/ErrorContextTest.php +++ b/tests/Audit/ErrorContextTest.php @@ -111,10 +111,10 @@ final class ErrorContextTest extends TestCase public function testSanitizesConnectionStrings(): void { - $message = 'Failed: redis://admin:password@localhost:6379'; + $message = 'Failed: redis://admin:' . TestConstants::CONTEXT_PASSWORD . '@localhost:6379'; $context = ErrorContext::create('ConnError', $message); - $this->assertStringNotContainsString('password', $context->message); + $this->assertStringNotContainsString(TestConstants::CONTEXT_PASSWORD, $context->message); $this->assertStringContainsString(TestConstants::MASK_REDACTED_BRACKETS, $context->message); } @@ -141,7 +141,7 @@ final class ErrorContextTest extends TestCase { $context = new ErrorContext( errorType: 'TestError', - message: 'Test message', + message: TestConstants::MESSAGE_DEFAULT, code: 100, file: '/test/file.php', line: 50, @@ -151,14 +151,14 @@ final class ErrorContextTest extends TestCase $array = $context->toArray(); $this->assertArrayHasKey('error_type', $array); - $this->assertArrayHasKey('message', $array); + $this->assertArrayHasKey(TestConstants::FIELD_MESSAGE, $array); $this->assertArrayHasKey('code', $array); $this->assertArrayHasKey('file', $array); $this->assertArrayHasKey('line', $array); $this->assertArrayHasKey('metadata', $array); $this->assertSame('TestError', $array['error_type']); - $this->assertSame('Test message', $array['message']); + $this->assertSame(TestConstants::MESSAGE_DEFAULT, $array[TestConstants::FIELD_MESSAGE]); $this->assertSame(100, $array['code']); } diff --git a/tests/Audit/StructuredAuditLoggerTest.php b/tests/Audit/StructuredAuditLoggerTest.php index b6c8d9a..2ac33e5 100644 --- a/tests/Audit/StructuredAuditLoggerTest.php +++ b/tests/Audit/StructuredAuditLoggerTest.php @@ -43,7 +43,7 @@ final class StructuredAuditLoggerTest extends TestCase $this->logs[] = [ 'path' => $path, 'original' => $original, - 'masked' => $masked + TestConstants::DATA_MASKED => $masked ]; }; } @@ -52,12 +52,12 @@ final class StructuredAuditLoggerTest extends TestCase { $logger = new StructuredAuditLogger($this->createBaseLogger()); - $logger->log('user.email', TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS); + $logger->log(TestConstants::FIELD_USER_EMAIL, TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS); $this->assertCount(1, $this->logs); - $this->assertSame('user.email', $this->logs[0]['path']); + $this->assertSame(TestConstants::FIELD_USER_EMAIL, $this->logs[0]['path']); $this->assertSame(TestConstants::EMAIL_JOHN, $this->logs[0]['original']); - $this->assertSame(TestConstants::MASK_MASKED_BRACKETS, $this->logs[0]['masked']); + $this->assertSame(TestConstants::MASK_MASKED_BRACKETS, $this->logs[0][TestConstants::DATA_MASKED]); } public function testLogWithContext(): void @@ -65,7 +65,7 @@ final class StructuredAuditLoggerTest extends TestCase $logger = new StructuredAuditLogger($this->createBaseLogger()); $context = AuditContext::success(AuditContext::OP_REGEX, 5.0); - $logger->log('user.email', TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS, $context); + $logger->log(TestConstants::FIELD_USER_EMAIL, TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS, $context); $this->assertCount(1, $this->logs); } @@ -75,15 +75,15 @@ final class StructuredAuditLoggerTest extends TestCase $logger = new StructuredAuditLogger($this->createBaseLogger()); $logger->logSuccess( - 'user.ssn', - '123-45-6789', - '[SSN]', + TestConstants::FIELD_USER_SSN, + TestConstants::SSN_US, + TestConstants::MASK_SSN_BRACKETS, AuditContext::OP_REGEX, 10.5 ); $this->assertCount(1, $this->logs); - $this->assertSame('user.ssn', $this->logs[0]['path']); + $this->assertSame(TestConstants::FIELD_USER_SSN, $this->logs[0]['path']); } public function testLogFailure(): void @@ -92,14 +92,14 @@ final class StructuredAuditLoggerTest extends TestCase $error = ErrorContext::create('RegexError', 'Pattern failed'); $logger->logFailure( - 'user.data', + TestConstants::FIELD_USER_DATA, 'sensitive value', AuditContext::OP_REGEX, $error ); $this->assertCount(1, $this->logs); - $this->assertSame('[MASKING_FAILED]', $this->logs[0]['masked']); + $this->assertSame('[MASKING_FAILED]', $this->logs[0][TestConstants::DATA_MASKED]); } public function testLogRecovery(): void @@ -107,7 +107,7 @@ final class StructuredAuditLoggerTest extends TestCase $logger = new StructuredAuditLogger($this->createBaseLogger()); $logger->logRecovery( - 'user.email', + TestConstants::FIELD_USER_EMAIL, TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS, AuditContext::OP_REGEX, @@ -131,14 +131,14 @@ final class StructuredAuditLoggerTest extends TestCase $this->assertCount(1, $this->logs); $this->assertSame(TestConstants::NAME_FULL, $this->logs[0]['original']); - $this->assertSame(TestConstants::NAME_FULL, $this->logs[0]['masked']); + $this->assertSame(TestConstants::NAME_FULL, $this->logs[0][TestConstants::DATA_MASKED]); } public function testWrapStaticFactory(): void { $logger = StructuredAuditLogger::wrap($this->createBaseLogger()); - $logger->log('test.path', 'original', 'masked'); + $logger->log('test.path', 'original', TestConstants::DATA_MASKED); $this->assertCount(1, $this->logs); } @@ -152,7 +152,7 @@ final class StructuredAuditLoggerTest extends TestCase ); $logger = new StructuredAuditLogger($rateLimited); - $logger->log('user.email', TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS); + $logger->log(TestConstants::FIELD_USER_EMAIL, TestConstants::EMAIL_JOHN, TestConstants::MASK_MASKED_BRACKETS); $this->assertCount(1, $this->logs); } @@ -177,7 +177,7 @@ final class StructuredAuditLoggerTest extends TestCase $wrapped = $logger->getWrappedLogger(); // Verify the wrapped logger works by calling it - $wrapped('test.path', 'original', 'masked'); + $wrapped('test.path', 'original', TestConstants::DATA_MASKED); $this->assertCount(1, $this->logs); } @@ -188,7 +188,7 @@ final class StructuredAuditLoggerTest extends TestCase includeTimestamp: false ); - $logger->log('test', 'original', 'masked'); + $logger->log('test', 'original', TestConstants::DATA_MASKED); $this->assertCount(1, $this->logs); } @@ -200,7 +200,7 @@ final class StructuredAuditLoggerTest extends TestCase includeDuration: false ); - $logger->log('test', 'original', 'masked'); + $logger->log('test', 'original', TestConstants::DATA_MASKED); $this->assertCount(1, $this->logs); } diff --git a/tests/Builder/GdprProcessorBuilderEdgeCasesTest.php b/tests/Builder/GdprProcessorBuilderEdgeCasesTest.php index 023a293..16e1367 100644 --- a/tests/Builder/GdprProcessorBuilderEdgeCasesTest.php +++ b/tests/Builder/GdprProcessorBuilderEdgeCasesTest.php @@ -292,7 +292,7 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase #[\Override] public function getFieldPaths(): array { - return ['secret.key' => FieldMaskConfig::replace('[REDACTED]')]; + return ['secret.key' => FieldMaskConfig::replace(TestConstants::MASK_REDACTED_BRACKETS)]; } }; @@ -303,7 +303,7 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase $record = $this->createLogRecord('Test', ['secret' => ['key' => 'sensitive-value']]); $processed = $processor($record); - $this->assertSame('[REDACTED]', $processed->context['secret']['key']); + $this->assertSame(TestConstants::MASK_REDACTED_BRACKETS, $processed->context['secret']['key']); } #[Test] @@ -313,16 +313,16 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase $processor = GdprProcessorBuilder::create() ->withArrayAccessorFactory($factory) - ->addFieldPath('user.email', MaskConstants::MASK_EMAIL) + ->addFieldPath(TestConstants::FIELD_USER_EMAIL, MaskConstants::MASK_EMAIL) ->build(); $record = $this->createLogRecord('Test', [ - 'user' => ['email' => 'test@example.com'], + 'user' => [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST], ]); $processed = $processor($record); - $this->assertSame(MaskConstants::MASK_EMAIL, $processed->context['user']['email']); + $this->assertSame(MaskConstants::MASK_EMAIL, $processed->context['user'][TestConstants::CONTEXT_EMAIL]); } #[Test] @@ -330,13 +330,13 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase { $processor = GdprProcessorBuilder::create() ->withMaxDepth(2) - ->addPattern('/secret/', TestConstants::MASK_MASKED_BRACKETS) + ->addPattern(TestConstants::PATTERN_SECRET, TestConstants::MASK_MASKED_BRACKETS) ->build(); $record = $this->createLogRecord('Test', [ 'level1' => [ 'level2' => [ - 'level3' => 'secret data', + 'level3' => TestConstants::MESSAGE_SECRET_DATA, ], ], ]); @@ -353,13 +353,13 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase $auditLogs = []; $processor = GdprProcessorBuilder::create() - ->addFieldPath('password', MaskConstants::MASK_REDACTED) + ->addFieldPath(TestConstants::CONTEXT_PASSWORD, MaskConstants::MASK_REDACTED) ->withAuditLogger(function ($path, $original, $masked) use (&$auditLogs): void { - $auditLogs[] = ['path' => $path, 'original' => $original, 'masked' => $masked]; + $auditLogs[] = ['path' => $path, 'original' => $original, TestConstants::DATA_MASKED => $masked]; }) ->build(); - $record = $this->createLogRecord('Test', ['password' => 'secret123']); + $record = $this->createLogRecord('Test', [TestConstants::CONTEXT_PASSWORD => 'secret123']); $processor($record); $this->assertNotEmpty($auditLogs); @@ -390,21 +390,21 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase { $processor = GdprProcessorBuilder::create() ->addFieldPaths([ - 'user.email' => MaskConstants::MASK_EMAIL, + TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL, 'user.phone' => MaskConstants::MASK_PHONE, ]) ->build(); $record = $this->createLogRecord('Test', [ 'user' => [ - 'email' => 'test@example.com', + TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, 'phone' => '555-1234', ], ]); $processed = $processor($record); - $this->assertSame(MaskConstants::MASK_EMAIL, $processed->context['user']['email']); + $this->assertSame(MaskConstants::MASK_EMAIL, $processed->context['user'][TestConstants::CONTEXT_EMAIL]); $this->assertSame(MaskConstants::MASK_PHONE, $processed->context['user']['phone']); } @@ -413,15 +413,15 @@ final class GdprProcessorBuilderEdgeCasesTest extends TestCase { $processor = GdprProcessorBuilder::create() ->addPatterns([ - '/\d{3}-\d{2}-\d{4}/' => '[SSN]', - '/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/' => '[EMAIL]', + TestConstants::PATTERN_SSN_FORMAT => TestConstants::MASK_SSN_BRACKETS, + TestConstants::PATTERN_EMAIL_FULL => TestConstants::MASK_EMAIL_BRACKETS, ]) ->build(); - $record = $this->createLogRecord('SSN: 123-45-6789, Email: user@example.com'); + $record = $this->createLogRecord('SSN: ' . TestConstants::SSN_US . ', Email: ' . TestConstants::EMAIL_USER); $processed = $processor($record); - $this->assertStringContainsString('[SSN]', $processed->message); - $this->assertStringContainsString('[EMAIL]', $processed->message); + $this->assertStringContainsString(TestConstants::MASK_SSN_BRACKETS, $processed->message); + $this->assertStringContainsString(TestConstants::MASK_EMAIL_BRACKETS, $processed->message); } } diff --git a/tests/Builder/GdprProcessorBuilderTest.php b/tests/Builder/GdprProcessorBuilderTest.php index 84c3fbf..f018c95 100644 --- a/tests/Builder/GdprProcessorBuilderTest.php +++ b/tests/Builder/GdprProcessorBuilderTest.php @@ -58,7 +58,7 @@ final class GdprProcessorBuilderTest extends TestCase { $patterns = [ TestConstants::PATTERN_DIGITS => TestConstants::MASK_DIGITS_BRACKETS, - TestConstants::PATTERN_TEST => '[TEST]', + TestConstants::PATTERN_TEST => TestConstants::REPLACEMENT_TEST, ]; $builder = GdprProcessorBuilder::create()->addPatterns($patterns); @@ -70,7 +70,7 @@ final class GdprProcessorBuilderTest extends TestCase { $builder = GdprProcessorBuilder::create() ->addPattern(TestConstants::PATTERN_DIGITS, TestConstants::MASK_DIGITS_BRACKETS) - ->setPatterns([TestConstants::PATTERN_TEST => '[TEST]']); + ->setPatterns([TestConstants::PATTERN_TEST => TestConstants::REPLACEMENT_TEST]); $patterns = $builder->getPatterns(); @@ -82,7 +82,7 @@ final class GdprProcessorBuilderTest extends TestCase public function testAddFieldPath(): void { $builder = GdprProcessorBuilder::create() - ->addFieldPath(TestConstants::CONTEXT_EMAIL, FieldMaskConfig::replace('[EMAIL]')); + ->addFieldPath(TestConstants::CONTEXT_EMAIL, FieldMaskConfig::replace(TestConstants::MASK_EMAIL_BRACKETS)); $this->assertArrayHasKey(TestConstants::CONTEXT_EMAIL, $builder->getFieldPaths()); } @@ -90,7 +90,7 @@ final class GdprProcessorBuilderTest extends TestCase public function testAddFieldPaths(): void { $fieldPaths = [ - TestConstants::CONTEXT_EMAIL => FieldMaskConfig::replace('[EMAIL]'), + TestConstants::CONTEXT_EMAIL => FieldMaskConfig::replace(TestConstants::MASK_EMAIL_BRACKETS), TestConstants::CONTEXT_PASSWORD => FieldMaskConfig::remove(), ]; @@ -128,7 +128,7 @@ final class GdprProcessorBuilderTest extends TestCase }; $processor = GdprProcessorBuilder::create() - ->addFieldPath('field', FieldMaskConfig::replace('[MASKED]')) + ->addFieldPath('field', FieldMaskConfig::replace(MaskConstants::MASK_BRACKETS)) ->withAuditLogger($auditLogger) ->build(); @@ -229,7 +229,7 @@ final class GdprProcessorBuilderTest extends TestCase public function getPatterns(): array { - return ['/secret/' => '[SECRET]']; + return [TestConstants::PATTERN_SECRET => TestConstants::MASK_SECRET_BRACKETS]; } }; @@ -297,7 +297,7 @@ final class GdprProcessorBuilderTest extends TestCase public function getPatterns(): array { - return ['/secret/' => '[SECRET]']; + return [TestConstants::PATTERN_SECRET => TestConstants::MASK_SECRET_BRACKETS]; } }; diff --git a/tests/Builder/PluginAwareProcessorTest.php b/tests/Builder/PluginAwareProcessorTest.php index 42e383e..ae0051c 100644 --- a/tests/Builder/PluginAwareProcessorTest.php +++ b/tests/Builder/PluginAwareProcessorTest.php @@ -33,7 +33,7 @@ final class PluginAwareProcessorTest extends TestCase }; $processor = GdprProcessorBuilder::create() - ->addPattern('/TEST/', '[MASKED]') + ->addPattern('/TEST/', MaskConstants::MASK_BRACKETS) ->addPlugin($plugin) ->buildWithPlugins(); @@ -48,7 +48,7 @@ final class PluginAwareProcessorTest extends TestCase $result = $processor($record); // Message should be uppercased, then 'TEST' should be masked - $this->assertStringContainsString('[MASKED]', $result->message); + $this->assertStringContainsString(TestConstants::MASK_MASKED_BRACKETS, $result->message); } public function testInvokeAppliesPostProcessing(): void @@ -263,7 +263,7 @@ final class PluginAwareProcessorTest extends TestCase ->buildWithPlugins(); $this->assertInstanceOf(PluginAwareProcessor::class, $processor); - $this->assertSame(MaskConstants::MASK_GENERIC . ' message', $processor->regExpMessage('test message')); + $this->assertSame(MaskConstants::MASK_GENERIC . ' message', $processor->regExpMessage(TestConstants::MESSAGE_TEST_LOWERCASE)); } public function testRecursiveMaskDelegates(): void @@ -282,9 +282,9 @@ final class PluginAwareProcessorTest extends TestCase $this->assertInstanceOf(PluginAwareProcessor::class, $processor); - $result = $processor->recursiveMask(['key' => 'test value']); + $result = $processor->recursiveMask(['key' => TestConstants::VALUE_TEST]); - $this->assertSame(MaskConstants::MASK_GENERIC . ' value', $result['key']); + $this->assertSame(MaskConstants::MASK_GENERIC . TestConstants::VALUE_SUFFIX, $result['key']); } public function testSetAuditLoggerDelegates(): void diff --git a/tests/ConditionalRuleFactoryInstanceTest.php b/tests/ConditionalRuleFactoryInstanceTest.php index e3915f7..daaf919 100644 --- a/tests/ConditionalRuleFactoryInstanceTest.php +++ b/tests/ConditionalRuleFactoryInstanceTest.php @@ -48,18 +48,18 @@ final class ConditionalRuleFactoryInstanceTest extends TestCase public function testContextFieldRuleWithPresentField(): void { $factory = new ConditionalRuleFactory(); - $rule = $factory->contextFieldRule('user_id'); + $rule = $factory->contextFieldRule(TestConstants::CONTEXT_USER_ID); - $record = $this->createLogRecord('Test message', ['user_id' => 123]); + $record = $this->createLogRecord(TestConstants::MESSAGE_DEFAULT, [TestConstants::CONTEXT_USER_ID => 123]); $this->assertTrue($rule($record)); } public function testContextFieldRuleWithMissingField(): void { $factory = new ConditionalRuleFactory(); - $rule = $factory->contextFieldRule('user_id'); + $rule = $factory->contextFieldRule(TestConstants::CONTEXT_USER_ID); - $record = $this->createLogRecord('Test message', []); + $record = $this->createLogRecord(TestConstants::MESSAGE_DEFAULT, []); $this->assertFalse($rule($record)); } @@ -185,14 +185,14 @@ final class ConditionalRuleFactoryInstanceTest extends TestCase $instanceFactory = new ConditionalRuleFactory(); // Create rules using both methods - $instanceFieldRule = $instanceFactory->contextFieldRule('user.email'); - $staticFieldRule = ConditionalRuleFactory::createContextFieldRule('user.email'); + $instanceFieldRule = $instanceFactory->contextFieldRule(TestConstants::FIELD_USER_EMAIL); + $staticFieldRule = ConditionalRuleFactory::createContextFieldRule(TestConstants::FIELD_USER_EMAIL); $instanceValueRule = $instanceFactory->contextValueRule('type', 'admin'); $staticValueRule = ConditionalRuleFactory::createContextValueRule('type', 'admin'); $record = $this->createLogRecord('Test', [ - 'user' => ['email' => 'test@example.com'], + 'user' => [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST], 'type' => 'admin', ]); diff --git a/tests/ContextProcessorTest.php b/tests/ContextProcessorTest.php index ba2e1f9..969fa11 100644 --- a/tests/ContextProcessorTest.php +++ b/tests/ContextProcessorTest.php @@ -63,7 +63,7 @@ final class ContextProcessorTest extends TestCase { $regexProcessor = fn(string $val): string => $val; $processor = new ContextProcessor( - [TestConstants::CONTEXT_PASSWORD => FieldMaskConfig::replace('[REDACTED]')], + [TestConstants::CONTEXT_PASSWORD => FieldMaskConfig::replace(TestConstants::MASK_REDACTED_BRACKETS)], [], null, $regexProcessor @@ -73,7 +73,7 @@ final class ContextProcessorTest extends TestCase $processed = $processor->maskFieldPaths($accessor); $this->assertSame([TestConstants::CONTEXT_PASSWORD], $processed); - $this->assertSame('[REDACTED]', $accessor->get(TestConstants::CONTEXT_PASSWORD)); + $this->assertSame(TestConstants::MASK_REDACTED_BRACKETS, $accessor->get(TestConstants::CONTEXT_PASSWORD)); } public function testMaskFieldPathsSkipsNonExistentPaths(): void diff --git a/tests/Exceptions/AuditLoggingExceptionComprehensiveTest.php b/tests/Exceptions/AuditLoggingExceptionComprehensiveTest.php index 2a9e4a9..f228bb7 100644 --- a/tests/Exceptions/AuditLoggingExceptionComprehensiveTest.php +++ b/tests/Exceptions/AuditLoggingExceptionComprehensiveTest.php @@ -98,14 +98,14 @@ final class AuditLoggingExceptionComprehensiveTest extends TestCase $value = ['data' => 'test']; $exception = AuditLoggingException::serializationFailed( - 'user.data', + TestConstants::FIELD_USER_DATA, $value, 'JSON encoding failed' ); $this->assertInstanceOf(AuditLoggingException::class, $exception); $message = $exception->getMessage(); - $this->assertStringContainsString('user.data', $message); + $this->assertStringContainsString(TestConstants::FIELD_USER_DATA, $message); $this->assertStringContainsString('JSON encoding failed', $message); $this->assertStringContainsString('serialization_failure', $message); } diff --git a/tests/Exceptions/CustomExceptionsTest.php b/tests/Exceptions/CustomExceptionsTest.php index bcbec42..e951f64 100644 --- a/tests/Exceptions/CustomExceptionsTest.php +++ b/tests/Exceptions/CustomExceptionsTest.php @@ -228,13 +228,13 @@ class CustomExceptionsTest extends TestCase public function testAuditLoggingExceptionSerializationFailed(): void { $exception = AuditLoggingException::serializationFailed( - 'user.data', + TestConstants::FIELD_USER_DATA, ['circular' => 'reference'], 'Circular reference detected' ); $this->assertStringContainsString( - "Audit data serialization failed for path 'user.data'", + "Audit data serialization failed for path '" . TestConstants::FIELD_USER_DATA . "'", $exception->getMessage() ); $this->assertStringContainsString('Circular reference detected', $exception->getMessage()); diff --git a/tests/Exceptions/MaskingOperationFailedExceptionTest.php b/tests/Exceptions/MaskingOperationFailedExceptionTest.php index 3ab5205..7b051b3 100644 --- a/tests/Exceptions/MaskingOperationFailedExceptionTest.php +++ b/tests/Exceptions/MaskingOperationFailedExceptionTest.php @@ -7,6 +7,7 @@ namespace Tests\Exceptions; use Ivuorinen\MonologGdprFilter\Exceptions\MaskingOperationFailedException; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; +use Tests\TestConstants; #[CoversClass(MaskingOperationFailedException::class)] final class MaskingOperationFailedExceptionTest extends TestCase @@ -77,7 +78,7 @@ final class MaskingOperationFailedExceptionTest extends TestCase $previous = new \RuntimeException('Inner error'); $exception = MaskingOperationFailedException::fieldPathMaskingFailed( - 'user.data', + TestConstants::FIELD_USER_DATA, ['complex' => 'value'], 'Failed', $previous diff --git a/tests/Factory/AuditLoggerFactoryTest.php b/tests/Factory/AuditLoggerFactoryTest.php index 0c36358..96137af 100644 --- a/tests/Factory/AuditLoggerFactoryTest.php +++ b/tests/Factory/AuditLoggerFactoryTest.php @@ -9,6 +9,7 @@ use Ivuorinen\MonologGdprFilter\Factory\AuditLoggerFactory; use Ivuorinen\MonologGdprFilter\RateLimitedAuditLogger; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; +use Tests\TestConstants; #[CoversClass(AuditLoggerFactory::class)] final class AuditLoggerFactoryTest extends TestCase @@ -66,12 +67,12 @@ final class AuditLoggerFactoryTest extends TestCase $storage = []; $logger = $factory->createArrayLogger($storage); - $logger('test.path', 'original', 'masked'); + $logger('test.path', 'original', TestConstants::DATA_MASKED); $this->assertCount(1, $storage); $this->assertSame('test.path', $storage[0]['path']); $this->assertSame('original', $storage[0]['original']); - $this->assertSame('masked', $storage[0]['masked']); + $this->assertSame(TestConstants::DATA_MASKED, $storage[0][TestConstants::DATA_MASKED]); $this->assertArrayHasKey('timestamp', $storage[0]); } @@ -90,7 +91,7 @@ final class AuditLoggerFactoryTest extends TestCase $logger = $factory->createNullLogger(); // Should not throw - $logger('path', 'original', 'masked'); + $logger('path', 'original', TestConstants::DATA_MASKED); $this->assertTrue(true); } @@ -109,11 +110,11 @@ final class AuditLoggerFactoryTest extends TestCase $factory = AuditLoggerFactory::create(); $calls = []; $callback = function (string $path, mixed $original, mixed $masked) use (&$calls): void { - $calls[] = ['path' => $path, 'original' => $original, 'masked' => $masked]; + $calls[] = ['path' => $path, 'original' => $original, TestConstants::DATA_MASKED => $masked]; }; $logger = $factory->createCallbackLogger($callback); - $logger('test.path', 'original', 'masked'); + $logger('test.path', 'original', TestConstants::DATA_MASKED); $this->assertCount(1, $calls); $this->assertSame('test.path', $calls[0]['path']); diff --git a/tests/GdprProcessorComprehensiveTest.php b/tests/GdprProcessorComprehensiveTest.php index 5c33ef7..0601438 100644 --- a/tests/GdprProcessorComprehensiveTest.php +++ b/tests/GdprProcessorComprehensiveTest.php @@ -175,7 +175,7 @@ final class GdprProcessorComprehensiveTest extends TestCase // Should not throw exception GdprProcessor::validatePatternsArray([ TestConstants::PATTERN_DIGITS => Mask::MASK_MASKED, - '/[a-z]+/' => Mask::MASK_REDACTED, + TestConstants::PATTERN_SAFE => Mask::MASK_REDACTED, ]); $this->assertTrue(true); @@ -202,7 +202,7 @@ final class GdprProcessorComprehensiveTest extends TestCase $data = [ 'level1' => [ 'level2' => [ - 'value' => 'secret data', + 'value' => TestConstants::MESSAGE_SECRET_DATA, ], ], ]; diff --git a/tests/GdprProcessorEdgeCasesTest.php b/tests/GdprProcessorEdgeCasesTest.php index 6112a08..69b7c07 100644 --- a/tests/GdprProcessorEdgeCasesTest.php +++ b/tests/GdprProcessorEdgeCasesTest.php @@ -59,10 +59,10 @@ final class GdprProcessorEdgeCasesTest extends TestCase ); // Call maskMessage directly - $result = $processor->maskMessage('test value'); + $result = $processor->maskMessage(TestConstants::VALUE_TEST); // Should work normally - $this->assertSame(Mask::MASK_MASKED . ' value', $result); + $this->assertSame(Mask::MASK_MASKED . TestConstants::VALUE_SUFFIX, $result); // Now test with patterns that might cause issues // Note: It's hard to trigger preg_replace null return in normal usage @@ -79,7 +79,7 @@ final class GdprProcessorEdgeCasesTest extends TestCase // Test recursiveMask with array $data = [ 'level1' => [ - 'level2' => 'secret data', + 'level2' => TestConstants::MESSAGE_SECRET_DATA, ], ]; diff --git a/tests/GdprProcessorMethodsTest.php b/tests/GdprProcessorMethodsTest.php index 3a231ad..23b0f70 100644 --- a/tests/GdprProcessorMethodsTest.php +++ b/tests/GdprProcessorMethodsTest.php @@ -33,7 +33,7 @@ class GdprProcessorMethodsTest extends TestCase ]; $fieldPaths = [ TestConstants::FIELD_USER_EMAIL => FieldMaskConfig::useProcessorPatterns(), - 'user.ssn' => FieldMaskConfig::remove(), + TestConstants::FIELD_USER_SSN => FieldMaskConfig::remove(), 'user.card' => FieldMaskConfig::replace('MASKED'), ]; $context = [ @@ -75,7 +75,7 @@ class GdprProcessorMethodsTest extends TestCase { $patterns = []; $fieldPaths = [ - 'user.ssn' => FieldMaskConfig::remove(), + TestConstants::FIELD_USER_SSN => FieldMaskConfig::remove(), ]; $context = ['user' => ['ssn' => self::TEST_HETU]]; diff --git a/tests/GdprProcessorTest.php b/tests/GdprProcessorTest.php index 47e73a7..186885d 100644 --- a/tests/GdprProcessorTest.php +++ b/tests/GdprProcessorTest.php @@ -58,7 +58,7 @@ class GdprProcessorTest extends TestCase { $patterns = DefaultPatterns::get(); $fieldPaths = [ - 'user.ssn' => FieldMaskConfig::remove(), + TestConstants::FIELD_USER_SSN => FieldMaskConfig::remove(), ]; $processor = $this->createProcessor($patterns, $fieldPaths); $record = new LogRecord( @@ -284,7 +284,7 @@ class GdprProcessorTest extends TestCase $validPatterns = [ TestConstants::PATTERN_TEST => 'REPLACED', TestConstants::PATTERN_DIGITS => 'NUMBER', - '/[a-z]+/' => 'LETTERS' + TestConstants::PATTERN_SAFE => 'LETTERS' ]; $processor = $this->createProcessor($validPatterns); diff --git a/tests/InputValidation/FieldMaskConfigValidationTest.php b/tests/InputValidation/FieldMaskConfigValidationTest.php index fa8a200..85a906e 100644 --- a/tests/InputValidation/FieldMaskConfigValidationTest.php +++ b/tests/InputValidation/FieldMaskConfigValidationTest.php @@ -70,9 +70,9 @@ class FieldMaskConfigValidationTest extends TestCase public function regexMaskThrowsExceptionForIncompleteRegexPattern(): void { $this->expectException(InvalidRegexPatternException::class); - $this->expectExceptionMessage("Invalid regex pattern '/unclosed'"); + $this->expectExceptionMessage("Invalid regex pattern '" . TestConstants::PATTERN_INVALID_UNCLOSED . "'"); - FieldMaskConfig::regexMask('/unclosed'); + FieldMaskConfig::regexMask(TestConstants::PATTERN_INVALID_UNCLOSED); } #[Test] @@ -217,7 +217,7 @@ class FieldMaskConfigValidationTest extends TestCase #[Test] public function toArrayAndFromArrayRoundTripWorksCorrectly(): void { - $original = FieldMaskConfig::replace('[REDACTED]'); + $original = FieldMaskConfig::replace(TestConstants::MASK_REDACTED_BRACKETS); $array = $original->toArray(); $restored = FieldMaskConfig::fromArray($array); diff --git a/tests/InputValidation/GdprProcessorValidationTest.php b/tests/InputValidation/GdprProcessorValidationTest.php index 092abe0..e22a147 100644 --- a/tests/InputValidation/GdprProcessorValidationTest.php +++ b/tests/InputValidation/GdprProcessorValidationTest.php @@ -144,7 +144,7 @@ class GdprProcessorValidationTest extends TestCase $processor = new GdprProcessor([], [ TestConstants::FIELD_USER_EMAIL => FieldMaskConfig::remove(), TestConstants::FIELD_USER_NAME => 'masked_value', - 'payment.card' => FieldMaskConfig::replace('[CARD]') + 'payment.card' => FieldMaskConfig::replace(TestConstants::MASK_CARD_BRACKETS) ]); $this->assertInstanceOf(GdprProcessor::class, $processor); @@ -429,7 +429,7 @@ class GdprProcessorValidationTest extends TestCase { $processor = new GdprProcessor([], [ TestConstants::FIELD_USER_EMAIL => FieldMaskConfig::remove(), - TestConstants::FIELD_USER_NAME => FieldMaskConfig::replace('[REDACTED]'), + TestConstants::FIELD_USER_NAME => FieldMaskConfig::replace(TestConstants::MASK_REDACTED_BRACKETS), 'user.phone' => FieldMaskConfig::regexMask('/\d/', '*'), 'metadata.ip' => 'simple_string_replacement' ]); diff --git a/tests/InputValidatorTest.php b/tests/InputValidatorTest.php index abd0802..5efe8d7 100644 --- a/tests/InputValidatorTest.php +++ b/tests/InputValidatorTest.php @@ -84,7 +84,7 @@ final class InputValidatorTest extends TestCase { InputValidator::validatePatterns([ TestConstants::PATTERN_SSN_FORMAT => MaskConstants::MASK_SSN_PATTERN, - '/[a-z]+/' => 'REDACTED', + TestConstants::PATTERN_SAFE => TestConstants::MASK_REDACTED_PLAIN, ]); $this->assertTrue(true); @@ -140,7 +140,7 @@ final class InputValidatorTest extends TestCase InputValidator::validateFieldPaths([ TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL_PATTERN, TestConstants::FIELD_USER_PASSWORD => FieldMaskConfig::remove(), - 'user.ssn' => $ssnConfig, + TestConstants::FIELD_USER_SSN => $ssnConfig, ]); $this->assertTrue(true); @@ -297,7 +297,7 @@ final class InputValidatorTest extends TestCase InputValidator::validateDataTypeMasks([ 'integer' => MaskConstants::MASK_GENERIC, 'double' => MaskConstants::MASK_GENERIC, - 'string' => 'REDACTED', + 'string' => TestConstants::MASK_REDACTED_PLAIN, 'boolean' => MaskConstants::MASK_GENERIC, 'NULL' => 'null', 'array' => '[]', diff --git a/tests/JsonMaskingTest.php b/tests/JsonMaskingTest.php index d52a6d0..8c44a7d 100644 --- a/tests/JsonMaskingTest.php +++ b/tests/JsonMaskingTest.php @@ -28,7 +28,7 @@ class JsonMaskingTest extends TestCase TestConstants::PATTERN_EMAIL_FULL => MaskConstants::MASK_EMAIL ]); - $message = 'User data: {"email": "user@example.com", "name": "John Doe"}'; + $message = 'User data: {"' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_USER . '", "name": "' . TestConstants::NAME_FULL . '"}'; $result = $processor->regExpMessage($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -47,7 +47,7 @@ class JsonMaskingTest extends TestCase TestConstants::PATTERN_EMAIL_FULL => MaskConstants::MASK_EMAIL ]); - $message = 'Users: [{"email": "admin@example.com"}, {"email": "user@test.com"}]'; + $message = 'Users: [{"' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_ADMIN . '"}, {"' . TestConstants::CONTEXT_EMAIL . '": "user@test.com"}]'; $result = $processor->regExpMessage($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -69,7 +69,7 @@ class JsonMaskingTest extends TestCase ]); $message = 'Complex data: {"user": {"contact": ' - . '{"email": "nested@example.com", "ssn": "' . TestConstants::SSN_US . '"}, "id": 42}}'; + . '{"' . TestConstants::CONTEXT_EMAIL . '": "nested@example.com", "ssn": "' . TestConstants::SSN_US . '"}, "id": 42}}'; $result = $processor->regExpMessage($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -91,7 +91,7 @@ class JsonMaskingTest extends TestCase TestConstants::PATTERN_EMAIL_FULL => MaskConstants::MASK_EMAIL ]); - $message = 'Request: {"email": "req@example.com"} Response: {"email": "resp@test.com", "status": "ok"}'; + $message = 'Request: {"' . TestConstants::CONTEXT_EMAIL . '": "req@example.com"} Response: {"' . TestConstants::CONTEXT_EMAIL . '": "resp@test.com", "status": "ok"}'; $result = $processor->regExpMessage($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -135,7 +135,7 @@ class JsonMaskingTest extends TestCase TestConstants::PATTERN_EMAIL_FULL => MaskConstants::MASK_EMAIL ]); - $message = 'Data: {"email": "user@example.com", "message": "Hello \"world\"", "unicode": "café ñoño"}'; + $message = 'Data: {"' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_USER . '", "' . TestConstants::FIELD_MESSAGE . '": "Hello \"world\"", "unicode": "café ñoño"}'; $result = $processor->regExpMessage($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -159,7 +159,7 @@ class JsonMaskingTest extends TestCase ['integer' => MaskConstants::MASK_INT, 'string' => MaskConstants::MASK_STRING] ); - $message = 'Data: {"email": "user@example.com", "id": 12345, "active": true}'; + $message = 'Data: {"' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_USER . '", "id": 12345, "active": true}'; $result = $processor->regExpMessage($message); $extractedJson = $this->extractJsonFromMessage($result); @@ -187,7 +187,7 @@ class JsonMaskingTest extends TestCase $auditLogger ); - $message = 'User: {"email": "test@example.com", "name": "Test User"}'; + $message = 'User: {"' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_TEST . '", "name": "Test User"}'; $result = $processor->regExpMessage($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -218,7 +218,7 @@ class JsonMaskingTest extends TestCase new DateTimeImmutable(), 'test', Level::Info, - 'API Response: {"user": {"email": "api@example.com"}, "status": "success"}', + 'API Response: {"user": {"' . TestConstants::CONTEXT_EMAIL . '": "api@example.com"}, "status": "success"}', [] ); @@ -253,7 +253,7 @@ class JsonMaskingTest extends TestCase new DateTimeImmutable(), 'test', Level::Error, - 'Error data: {"email": "error@example.com"}', + 'Error data: {"' . TestConstants::CONTEXT_EMAIL . '": "error@example.com"}', [] ); @@ -266,7 +266,7 @@ class JsonMaskingTest extends TestCase new DateTimeImmutable(), 'test', Level::Info, - 'Info data: {"email": "info@example.com"}', + 'Info data: {"' . TestConstants::CONTEXT_EMAIL . '": "info@example.com"}', [] ); @@ -286,18 +286,18 @@ class JsonMaskingTest extends TestCase "users": [ { "id": 1, - "email": "john@example.com", + "' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_JOHN . '", "contacts": { "phone": "' . TestConstants::PHONE_US . '", "emergency": { - "email": "emergency@example.com", + "' . TestConstants::CONTEXT_EMAIL . '": "emergency@example.com", "phone": "' . TestConstants::PHONE_US_ALT . '" } } }, { "id": 2, - "email": "jane@test.com", + "' . TestConstants::CONTEXT_EMAIL . '": "jane@test.com", "contacts": { "phone": "+1-555-456-7890" } @@ -310,7 +310,7 @@ class JsonMaskingTest extends TestCase $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); $this->assertStringContainsString(MaskConstants::MASK_PHONE, $result); - $this->assertStringNotContainsString('john@example.com', $result); + $this->assertStringNotContainsString(TestConstants::EMAIL_JOHN, $result); $this->assertStringNotContainsString('jane@test.com', $result); $this->assertStringNotContainsString('emergency@example.com', $result); $this->assertStringNotContainsString(TestConstants::PHONE_US, $result); @@ -420,7 +420,7 @@ class JsonMaskingTest extends TestCase TestConstants::PATTERN_EMAIL_FULL => MaskConstants::MASK_EMAIL ]); - $message = 'Data: {"email": "user@example.com", "optional": null, "empty": ""}'; + $message = 'Data: {"' . TestConstants::CONTEXT_EMAIL . '": "' . TestConstants::EMAIL_USER . '", "optional": null, "empty": ""}'; $result = $processor->regExpMessage($message); $extractedJson = $this->extractJsonFromMessage($result); diff --git a/tests/MaskingOrchestratorTest.php b/tests/MaskingOrchestratorTest.php index f261d45..f4dc851 100644 --- a/tests/MaskingOrchestratorTest.php +++ b/tests/MaskingOrchestratorTest.php @@ -25,7 +25,7 @@ final class MaskingOrchestratorTest extends TestCase $result = $orchestrator->process('This is a test message', []); - $this->assertSame('This is a ' . MaskConstants::MASK_GENERIC . ' message', $result['message']); + $this->assertSame('This is a ' . MaskConstants::MASK_GENERIC . ' message', $result[TestConstants::FIELD_MESSAGE]); $this->assertSame([], $result['context']); } @@ -35,9 +35,9 @@ final class MaskingOrchestratorTest extends TestCase [TestConstants::PATTERN_TEST => MaskConstants::MASK_GENERIC] ); - $result = $orchestrator->process('message', ['key' => TestConstants::VALUE_TEST]); + $result = $orchestrator->process(TestConstants::FIELD_MESSAGE, ['key' => TestConstants::VALUE_TEST]); - $this->assertSame('message', $result['message']); + $this->assertSame(TestConstants::FIELD_MESSAGE, $result[TestConstants::FIELD_MESSAGE]); $this->assertSame(MaskConstants::MASK_GENERIC . TestConstants::VALUE_SUFFIX, $result['context']['key']); } @@ -48,7 +48,7 @@ final class MaskingOrchestratorTest extends TestCase [TestConstants::CONTEXT_EMAIL => FieldMaskConfig::replace(TestConstants::MASK_EMAIL_BRACKETS)] ); - $result = $orchestrator->process('message', [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST]); + $result = $orchestrator->process(TestConstants::FIELD_MESSAGE, [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST]); $this->assertSame(TestConstants::MASK_EMAIL_BRACKETS, $result['context'][TestConstants::CONTEXT_EMAIL]); } @@ -61,7 +61,7 @@ final class MaskingOrchestratorTest extends TestCase ['name' => fn(mixed $val): string => strtoupper((string) $val)] ); - $result = $orchestrator->process('message', ['name' => 'john']); + $result = $orchestrator->process(TestConstants::FIELD_MESSAGE, ['name' => 'john']); $this->assertSame('JOHN', $result['context']['name']); } @@ -80,12 +80,12 @@ final class MaskingOrchestratorTest extends TestCase public function testRegExpMessageMasksPatterns(): void { $orchestrator = new MaskingOrchestrator( - [TestConstants::PATTERN_SSN_FORMAT => '[SSN]'] + [TestConstants::PATTERN_SSN_FORMAT => TestConstants::MASK_SSN_BRACKETS] ); $result = $orchestrator->regExpMessage('SSN: 123-45-6789'); - $this->assertSame('SSN: [SSN]', $result); + $this->assertSame(TestConstants::EXPECTED_SSN_MASKED, $result); } public function testRegExpMessagePreservesEmptyString(): void @@ -115,7 +115,7 @@ final class MaskingOrchestratorTest extends TestCase [TestConstants::PATTERN_TEST => MaskConstants::MASK_GENERIC] ); - $result = $orchestrator->recursiveMask('test string'); + $result = $orchestrator->recursiveMask(TestConstants::MESSAGE_TEST_STRING); $this->assertSame(MaskConstants::MASK_GENERIC . ' string', $result); } @@ -136,7 +136,7 @@ final class MaskingOrchestratorTest extends TestCase public function testCreateWithValidParameters(): void { $orchestrator = MaskingOrchestrator::create( - [TestConstants::PATTERN_DIGITS => '[DIGITS]'], + [TestConstants::PATTERN_DIGITS => TestConstants::MASK_DIGITS_BRACKETS], [], [], null, @@ -178,7 +178,7 @@ final class MaskingOrchestratorTest extends TestCase $orchestrator = new MaskingOrchestrator( [], - ['field' => FieldMaskConfig::replace('[MASKED]')] + ['field' => FieldMaskConfig::replace(MaskConstants::MASK_BRACKETS)] ); $orchestrator->setAuditLogger($auditLogger); @@ -218,11 +218,11 @@ final class MaskingOrchestratorTest extends TestCase [ TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, 'name' => 'john', - 'message' => 'test' + TestConstants::FIELD_MESSAGE => 'test' ] ); - $this->assertSame('Hello ' . MaskConstants::MASK_GENERIC, $result['message']); + $this->assertSame('Hello ' . MaskConstants::MASK_GENERIC, $result[TestConstants::FIELD_MESSAGE]); $this->assertSame(TestConstants::MASK_EMAIL_BRACKETS, $result['context'][TestConstants::CONTEXT_EMAIL]); $this->assertSame('JOHN', $result['context']['name']); } @@ -235,12 +235,12 @@ final class MaskingOrchestratorTest extends TestCase [], null, 100, - ['integer' => '[INT]'] + ['integer' => TestConstants::MASK_INT_BRACKETS] ); $result = $orchestrator->processContext(['count' => 42]); - $this->assertSame('[INT]', $result['count']); + $this->assertSame(TestConstants::MASK_INT_BRACKETS, $result['count']); } public function testProcessContextWithRemoveConfig(): void diff --git a/tests/Plugins/AbstractMaskingPluginTest.php b/tests/Plugins/AbstractMaskingPluginTest.php index 1f36fb9..e8c0837 100644 --- a/tests/Plugins/AbstractMaskingPluginTest.php +++ b/tests/Plugins/AbstractMaskingPluginTest.php @@ -8,6 +8,7 @@ use Ivuorinen\MonologGdprFilter\Contracts\MaskingPluginInterface; use Ivuorinen\MonologGdprFilter\Plugins\AbstractMaskingPlugin; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; +use Tests\TestConstants; #[CoversClass(AbstractMaskingPlugin::class)] final class AbstractMaskingPluginTest extends TestCase @@ -92,7 +93,7 @@ final class AbstractMaskingPluginTest extends TestCase } }; - $message = 'test message'; + $message = TestConstants::MESSAGE_TEST_LOWERCASE; $result = $plugin->preProcessMessage($message); $this->assertSame($message, $result); @@ -107,7 +108,7 @@ final class AbstractMaskingPluginTest extends TestCase } }; - $message = 'test message'; + $message = TestConstants::MESSAGE_TEST_LOWERCASE; $result = $plugin->postProcessMessage($message); $this->assertSame($message, $result); @@ -185,13 +186,13 @@ final class AbstractMaskingPluginTest extends TestCase public function getPatterns(): array { - return ['/secret/' => '[REDACTED]']; + return [TestConstants::PATTERN_SECRET => TestConstants::MASK_REDACTED_BRACKETS]; } }; $patterns = $plugin->getPatterns(); - $this->assertArrayHasKey('/secret/', $patterns); - $this->assertSame('[REDACTED]', $patterns['/secret/']); + $this->assertArrayHasKey(TestConstants::PATTERN_SECRET, $patterns); + $this->assertSame(TestConstants::MASK_REDACTED_BRACKETS, $patterns[TestConstants::PATTERN_SECRET]); } } diff --git a/tests/Recovery/RecoveryResultTest.php b/tests/Recovery/RecoveryResultTest.php index 90dd901..2d988c4 100644 --- a/tests/Recovery/RecoveryResultTest.php +++ b/tests/Recovery/RecoveryResultTest.php @@ -41,9 +41,9 @@ final class RecoveryResultTest extends TestCase public function testFallbackCreation(): void { $error = ErrorContext::create('TestError', 'Failed to mask'); - $result = RecoveryResult::fallback('[REDACTED]', 3, $error, 50.0); + $result = RecoveryResult::fallback(TestConstants::MASK_REDACTED_BRACKETS, 3, $error, 50.0); - $this->assertSame('[REDACTED]', $result->value); + $this->assertSame(TestConstants::MASK_REDACTED_BRACKETS, $result->value); $this->assertSame(RecoveryResult::OUTCOME_FALLBACK, $result->outcome); $this->assertSame(3, $result->attempts); $this->assertSame($error, $result->lastError); diff --git a/tests/Recovery/RetryStrategyTest.php b/tests/Recovery/RetryStrategyTest.php index d5d72f8..04831d2 100644 --- a/tests/Recovery/RetryStrategyTest.php +++ b/tests/Recovery/RetryStrategyTest.php @@ -286,7 +286,7 @@ final class RetryStrategyTest extends TestCase $auditLogs[] = [ 'path' => $path, 'original' => $original, - 'masked' => $masked + TestConstants::DATA_MASKED => $masked ]; }; diff --git a/tests/RecursiveProcessorTest.php b/tests/RecursiveProcessorTest.php index a65fe85..4c3b5f6 100644 --- a/tests/RecursiveProcessorTest.php +++ b/tests/RecursiveProcessorTest.php @@ -115,7 +115,7 @@ final class RecursiveProcessorTest extends TestCase $dataTypeMasker = new DataTypeMasker([]); $processor = new RecursiveProcessor($regexProcessor, $dataTypeMasker, null, 10); - $data = ['field1' => 'secret data', 'field2' => TestConstants::DATA_PUBLIC]; + $data = ['field1' => TestConstants::MESSAGE_SECRET_DATA, 'field2' => TestConstants::DATA_PUBLIC]; $result = $processor->processStandardArray($data, 0); $this->assertSame('*** data', $result['field1']); @@ -128,7 +128,7 @@ final class RecursiveProcessorTest extends TestCase $dataTypeMasker = new DataTypeMasker([]); $processor = new RecursiveProcessor($regexProcessor, $dataTypeMasker, null, 10); - $result = $processor->processValue('test string', 0); + $result = $processor->processValue(TestConstants::MESSAGE_TEST_STRING, 0); $this->assertSame('*** string', $result); } @@ -158,7 +158,7 @@ final class RecursiveProcessorTest extends TestCase public function testProcessStringValueWithRegexMatch(): void { - $regexProcessor = fn(string $val): string => str_replace(TestConstants::CONTEXT_PASSWORD, '[REDACTED]', $val); + $regexProcessor = fn(string $val): string => str_replace(TestConstants::CONTEXT_PASSWORD, TestConstants::MASK_REDACTED_BRACKETS, $val); $dataTypeMasker = new DataTypeMasker([]); $processor = new RecursiveProcessor($regexProcessor, $dataTypeMasker, null, 10); @@ -198,7 +198,7 @@ final class RecursiveProcessorTest extends TestCase $dataTypeMasker = new DataTypeMasker([]); $processor = new RecursiveProcessor($regexProcessor, $dataTypeMasker, null, 10); - $result = $processor->processArrayValue(['key' => 'secret data'], 0); + $result = $processor->processArrayValue(['key' => TestConstants::MESSAGE_SECRET_DATA], 0); $this->assertIsArray($result); $this->assertSame('*** data', $result['key']); diff --git a/tests/RegexMaskProcessorTest.php b/tests/RegexMaskProcessorTest.php index 99fddfb..988a4ca 100644 --- a/tests/RegexMaskProcessorTest.php +++ b/tests/RegexMaskProcessorTest.php @@ -40,7 +40,7 @@ class RegexMaskProcessorTest extends TestCase "/\b\d{6}[-+A]?\d{3}[A-Z]\b/u" => Mask::MASK_MASKED, ]; $fieldPaths = [ - "user.ssn" => self::GDPR_REPLACEMENT, + TestConstants::FIELD_USER_SSN => self::GDPR_REPLACEMENT, "order.total" => FieldMaskConfig::useProcessorPatterns(), ]; $this->processor = new GdprProcessor($patterns, $fieldPaths); @@ -49,7 +49,7 @@ class RegexMaskProcessorTest extends TestCase public function testRemoveFieldRemovesKey(): void { $patterns = DefaultPatterns::get(); - $fieldPaths = ["user.ssn" => FieldMaskConfig::remove()]; + $fieldPaths = [TestConstants::FIELD_USER_SSN => FieldMaskConfig::remove()]; $processor = new GdprProcessor($patterns, $fieldPaths); $record = $this->logEntry()->with( message: "Remove SSN", @@ -177,7 +177,7 @@ class RegexMaskProcessorTest extends TestCase foreach ($testHetu as $hetu) { $record = $this->logEntry()->with(message: 'ID: ' . $hetu); $result = ($this->processor)($record)->toArray(); - $this->assertSame("ID: " . Mask::MASK_MASKED, $result["message"]); + $this->assertSame("ID: " . Mask::MASK_MASKED, $result[TestConstants::FIELD_MESSAGE]); } } @@ -208,7 +208,7 @@ class RegexMaskProcessorTest extends TestCase context: ["user" => ["ssn" => "not-a-hetu"]], ); $result = ($this->processor)($record)->toArray(); - $this->assertSame("No sensitive data here", $result["message"]); + $this->assertSame("No sensitive data here", $result[TestConstants::FIELD_MESSAGE]); $this->assertSame(self::GDPR_REPLACEMENT, $result["context"]["user"]["ssn"]); } diff --git a/tests/RegressionTests/ComprehensiveValidationTest.php b/tests/RegressionTests/ComprehensiveValidationTest.php index 870845e..30847bc 100644 --- a/tests/RegressionTests/ComprehensiveValidationTest.php +++ b/tests/RegressionTests/ComprehensiveValidationTest.php @@ -126,9 +126,6 @@ class ComprehensiveValidationTest extends TestCase $this->assertInstanceOf(LogRecord::class, $result); $this->assertArrayHasKey('test_value', $result->context); - - // Log successful processing for each type - error_log('✅ Successfully processed PHP type: ' . $typeName); } $this->assertCount( @@ -158,7 +155,6 @@ class ComprehensiveValidationTest extends TestCase $rateLimiter->isAllowed('memory_test_key_' . $i); } - memory_get_usage(true); $initialStats = RateLimiter::getMemoryStats(); // Phase 2: Wait for cleanup window and trigger cleanup @@ -196,12 +192,6 @@ class ComprehensiveValidationTest extends TestCase $cleanupStats['total_keys'], 'Keys should not accumulate indefinitely' ); - - error_log(sprintf( - '✅ Memory management working: Keys before=%d, after=%d', - $initialStats['total_keys'], - $cleanupStats['total_keys'] - )); } /** @@ -226,50 +216,27 @@ class ComprehensiveValidationTest extends TestCase ]; $caughtCount = 0; - $totalPatterns = count($definitelyDangerousPatterns) + count($possiblyDangerousPatterns); // Test definitely dangerous patterns - foreach ($definitelyDangerousPatterns as $pattern => $description) { + foreach (array_keys($definitelyDangerousPatterns) as $pattern) { try { PatternValidator::validateAll([sprintf('/%s/', $pattern) => TestConstants::DATA_MASKED]); - error_log(sprintf( - '⚠️ Pattern not caught: %s (%s)', - $pattern, - $description - )); } catch (Throwable) { $caughtCount++; - error_log(sprintf( - '✅ Caught dangerous pattern: %s (%s)', - $pattern, - $description - )); } } // Test possibly dangerous patterns (implementation may vary) - foreach ($possiblyDangerousPatterns as $pattern => $description) { + foreach (array_keys($possiblyDangerousPatterns) as $pattern) { try { PatternValidator::validateAll([sprintf('/%s/', $pattern) => TestConstants::DATA_MASKED]); - error_log(sprintf( - 'ℹ️ Pattern allowed: %s (%s)', - $pattern, - $description - )); } catch (Throwable) { $caughtCount++; - error_log(sprintf( - '✅ Caught potentially dangerous pattern: %s (%s)', - $pattern, - $description - )); } } // At least some dangerous patterns should be caught $this->assertGreaterThan(0, $caughtCount, 'ReDoS protection should catch at least some dangerous patterns'); - - error_log(sprintf('✅ ReDoS protection caught %d/%d dangerous patterns', $caughtCount, $totalPatterns)); } /** @@ -367,17 +334,10 @@ class ComprehensiveValidationTest extends TestCase } if ($sensitiveTermsFound !== []) { - error_log(sprintf( - "⚠️ Scenario '%s': Sensitive terms still present: ", - $scenario - ) . implode(', ', $sensitiveTermsFound)); - error_log( - ' Full message: ' . $loggedMessage - ); - } else { - error_log(sprintf( - "✅ Scenario '%s': No sensitive terms found in sanitized message", - $scenario + $this->fail(sprintf( + "Scenario '%s': %d sensitive term(s) still present in masked output", + $scenario, + count($sensitiveTermsFound) )); } @@ -424,8 +384,6 @@ class ComprehensiveValidationTest extends TestCase if ($json === false) { $this->fail('RateLimiter::getMemoryStats() returned false'); } - - error_log("✅ Rate limiter statistics: " . $json); } /** @@ -484,19 +442,8 @@ class ComprehensiveValidationTest extends TestCase $memoryIncrease, 'Memory usage should be reasonable for ' . $name ); - - error_log(sprintf( - "✅ Safely processed extreme value '%s' in %ss using %d bytes", - $name, - $processingTime, - $memoryIncrease - )); } catch (Throwable $e) { // Some extreme values might cause controlled exceptions - error_log(sprintf( - "ℹ️ Extreme value '%s' caused controlled exception: ", - $name - ) . $e->getMessage()); $this->assertInstanceOf(Throwable::class, $e); } } @@ -528,8 +475,8 @@ class ComprehensiveValidationTest extends TestCase $processor = $this->createProcessor( patterns: [ '/\b\d{3}-\d{2}-\d{4}\b/' => MaskConstants::MASK_USSSN, - '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/' => MaskConstants::MASK_EMAIL, - '/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/' => MaskConstants::MASK_CC, + TestConstants::PATTERN_EMAIL_SIMPLE => MaskConstants::MASK_EMAIL, + TestConstants::PATTERN_CREDIT_CARD => MaskConstants::MASK_CC, ], fieldPaths: [ TestConstants::FIELD_USER_PASSWORD => FieldMaskConfig::remove(), @@ -618,11 +565,6 @@ class ComprehensiveValidationTest extends TestCase // Rate limiter should provide stats $stats = $rateLimitedLogger->getRateLimitStats(); $this->assertIsArray($stats); - - error_log( - "✅ Complete integration test passed with " - . count($this->auditLog) . " audit log entries" - ); } /** @@ -646,9 +588,6 @@ class ComprehensiveValidationTest extends TestCase PatternValidator::clearCache(); RateLimiter::clearAll(); - // Log final validation summary - error_log("🎯 Comprehensive validation completed successfully"); - parent::tearDown(); } } diff --git a/tests/RegressionTests/CriticalBugRegressionTest.php b/tests/RegressionTests/CriticalBugRegressionTest.php index 910d7e7..b7e3753 100644 --- a/tests/RegressionTests/CriticalBugRegressionTest.php +++ b/tests/RegressionTests/CriticalBugRegressionTest.php @@ -84,7 +84,7 @@ class CriticalBugRegressionTest extends TestCase $testCases = [ 'integer' => 42, 'double' => 3.14, - 'string' => 'test string', + 'string' => TestConstants::MESSAGE_TEST_STRING, 'boolean_true' => true, 'boolean_false' => false, 'null' => null, @@ -378,7 +378,7 @@ class CriticalBugRegressionTest extends TestCase { $safePatterns = [ '/\b\d{3}-\d{2}-\d{4}\b/' => 'SSN', - '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/' => 'EMAIL', + TestConstants::PATTERN_EMAIL_SIMPLE => 'EMAIL', '/\b\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b/' => 'CREDIT_CARD', '/\+?1?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})/' => 'PHONE', ]; @@ -467,23 +467,6 @@ class CriticalBugRegressionTest extends TestCase // Note: Current implementation may not fully sanitize all patterns $this->assertStringContainsString('Rule error:', (string) $errorMessage); - // Test that at least some sanitization occurs (implementation-dependent) - $containsSensitiveInfo = false; - $sensitiveTerms = ['password=secret123', 'user=secret_user', 'host=sensitive.db.com']; - foreach ($sensitiveTerms as $term) { - if (str_contains((string) $errorMessage, $term)) { - $containsSensitiveInfo = true; - break; - } - } - - // If sensitive info is still present, log a warning for future improvement - if ($containsSensitiveInfo) { - error_log( - "Warning: Error message sanitization may need improvement: " . $errorMessage - ); - } - // For now, just ensure the error was logged properly $this->assertNotEmpty($errorMessage); } diff --git a/tests/RegressionTests/SecurityRegressionTest.php b/tests/RegressionTests/SecurityRegressionTest.php index 79f8a21..3feeb15 100644 --- a/tests/RegressionTests/SecurityRegressionTest.php +++ b/tests/RegressionTests/SecurityRegressionTest.php @@ -74,8 +74,8 @@ class SecurityRegressionTest extends TestCase { $redosPatterns = [ // Nested quantifiers - classic ReDoS - '/^(a+)+$/', - '/^(a*)*$/', + TestConstants::PATTERN_REDOS_VULNERABLE, + TestConstants::PATTERN_REDOS_NESTED_STAR, '/^(a+)*$/', // Alternation with overlapping @@ -124,8 +124,8 @@ class SecurityRegressionTest extends TestCase $legitimatePatterns = [ // Common GDPR patterns '/\b\d{3}-\d{2}-\d{4}\b/' => 'SSN', - '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/' => 'EMAIL', - '/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/' => 'CREDIT_CARD', + TestConstants::PATTERN_EMAIL_SIMPLE => MaskConstants::MASK_EMAIL, + TestConstants::PATTERN_CREDIT_CARD => 'CREDIT_CARD', '/\+?1?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})/' => 'PHONE', '/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/' => 'IP_ADDRESS', diff --git a/tests/Retention/RetentionPolicyTest.php b/tests/Retention/RetentionPolicyTest.php index 71f6ec0..9573161 100644 --- a/tests/Retention/RetentionPolicyTest.php +++ b/tests/Retention/RetentionPolicyTest.php @@ -7,6 +7,7 @@ namespace Tests\Retention; use Ivuorinen\MonologGdprFilter\Retention\RetentionPolicy; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; +use Tests\TestConstants; #[CoversClass(RetentionPolicy::class)] final class RetentionPolicyTest extends TestCase @@ -48,9 +49,9 @@ final class RetentionPolicyTest extends TestCase public function testGetFieldsCustom(): void { - $policy = new RetentionPolicy('test', 30, RetentionPolicy::ACTION_DELETE, ['email', 'phone']); + $policy = new RetentionPolicy('test', 30, RetentionPolicy::ACTION_DELETE, [TestConstants::CONTEXT_EMAIL, 'phone']); - $this->assertSame(['email', 'phone'], $policy->getFields()); + $this->assertSame([TestConstants::CONTEXT_EMAIL, 'phone'], $policy->getFields()); } public function testIsWithinRetentionRecent(): void @@ -119,12 +120,12 @@ final class RetentionPolicyTest extends TestCase public function testAnonymizeFactory(): void { - $policy = RetentionPolicy::anonymize('user_data', 90, ['email', 'name']); + $policy = RetentionPolicy::anonymize('user_data', 90, [TestConstants::CONTEXT_EMAIL, 'name']); $this->assertSame('user_data', $policy->getName()); $this->assertSame(90, $policy->getRetentionDays()); $this->assertSame(RetentionPolicy::ACTION_ANONYMIZE, $policy->getAction()); - $this->assertSame(['email', 'name'], $policy->getFields()); + $this->assertSame([TestConstants::CONTEXT_EMAIL, 'name'], $policy->getFields()); } public function testActionConstants(): void diff --git a/tests/SecuritySanitizerTest.php b/tests/SecuritySanitizerTest.php index f162513..58c5af1 100644 --- a/tests/SecuritySanitizerTest.php +++ b/tests/SecuritySanitizerTest.php @@ -6,6 +6,7 @@ namespace Tests; use Ivuorinen\MonologGdprFilter\MaskConstants; use Ivuorinen\MonologGdprFilter\SecuritySanitizer; +use Tests\TestConstants; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; @@ -314,10 +315,10 @@ class SecuritySanitizerTest extends TestCase #[Test] public function preservesPublicIpAddresses(): void { - $message = 'External server at 8.8.8.8 responded'; + $message = 'External server at ' . TestConstants::IP_ADDRESS_PUBLIC . ' responded'; $sanitized = SecuritySanitizer::sanitizeErrorMessage($message); - $this->assertStringContainsString('8.8.8.8', $sanitized); + $this->assertStringContainsString(TestConstants::IP_ADDRESS_PUBLIC, $sanitized); } #[Test] diff --git a/tests/SerializedDataProcessorTest.php b/tests/SerializedDataProcessorTest.php index f2d3d40..718377b 100644 --- a/tests/SerializedDataProcessorTest.php +++ b/tests/SerializedDataProcessorTest.php @@ -43,7 +43,7 @@ final class SerializedDataProcessorTest extends TestCase { $processor = $this->createProcessor(); - $message = 'User data: {"email":"' . TestConstants::EMAIL_JOHN . '","name":"John"}'; + $message = 'User data: {"' . TestConstants::CONTEXT_EMAIL . '":"' . TestConstants::EMAIL_JOHN . '","name":"' . TestConstants::NAME_FIRST . '"}'; $result = $processor->process($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -54,7 +54,7 @@ final class SerializedDataProcessorTest extends TestCase { $processor = $this->createProcessor(); - $message = 'Data: {"id":123,"email":"' . TestConstants::EMAIL_TEST . '"}'; + $message = 'Data: {"id":123,"' . TestConstants::CONTEXT_EMAIL . '":"' . TestConstants::EMAIL_TEST . '"}'; $result = $processor->process($message); // Should still be valid JSON in the message @@ -70,7 +70,7 @@ final class SerializedDataProcessorTest extends TestCase { $processor = $this->createProcessor(); - $message = 'User: {"user":{"contact":{"email":"' . TestConstants::EMAIL_TEST . '"}}}'; + $message = 'User: {"user":{"contact":{"' . TestConstants::CONTEXT_EMAIL . '":"' . TestConstants::EMAIL_TEST . '"}}}'; $result = $processor->process($message); $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); @@ -83,8 +83,8 @@ final class SerializedDataProcessorTest extends TestCase $printROutput = 'Array ( - [name] => John Doe - [email] => ' . TestConstants::EMAIL_JOHN . ' + [name] => ' . TestConstants::NAME_FULL . ' + [' . TestConstants::CONTEXT_EMAIL . '] => ' . TestConstants::EMAIL_JOHN . ' [age] => 30 )'; @@ -92,7 +92,7 @@ final class SerializedDataProcessorTest extends TestCase $this->assertStringContainsString(MaskConstants::MASK_EMAIL, $result); $this->assertStringNotContainsString(TestConstants::EMAIL_JOHN, $result); - $this->assertStringContainsString('John Doe', $result); // Name not masked + $this->assertStringContainsString(TestConstants::NAME_FULL, $result); // Name not masked } public function testProcessPrintROutputWithNestedArrays(): void @@ -119,8 +119,8 @@ PRINT_R; $processor = $this->createProcessor(); $varExportOutput = "array ( - 'name' => 'John Doe', - 'email' => '" . TestConstants::EMAIL_JOHN . "', + 'name' => '" . TestConstants::NAME_FULL . "', + '" . TestConstants::CONTEXT_EMAIL . "' => '" . TestConstants::EMAIL_JOHN . "', 'active' => true, )"; @@ -134,7 +134,7 @@ PRINT_R; { $processor = $this->createProcessor(); - $data = ['email' => TestConstants::EMAIL_TEST, 'name' => 'Test']; + $data = [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST, 'name' => 'Test']; $serialized = serialize($data); $result = $processor->process($serialized); @@ -162,7 +162,7 @@ PRINT_R; { $processor = $this->createProcessor(); - $message = 'Log entry: User {"email":"' . TestConstants::EMAIL_TEST . '"} performed action'; + $message = 'Log entry: User {"' . TestConstants::CONTEXT_EMAIL . '":"' . TestConstants::EMAIL_TEST . '"} performed action'; $result = $processor->process($message); $this->assertStringContainsString('Log entry: User', $result); @@ -179,7 +179,7 @@ PRINT_R; $processor = $this->createProcessor($auditLogger); - $processor->process('{"email":"' . TestConstants::EMAIL_TEST . '"}'); + $processor->process('{"' . TestConstants::CONTEXT_EMAIL . '":"' . TestConstants::EMAIL_TEST . '"}'); $this->assertNotEmpty($logs); $this->assertStringContainsString('json', $logs[0]['path']); @@ -195,7 +195,7 @@ PRINT_R; $processor = $this->createProcessor(); $processor->setAuditLogger($auditLogger); - $processor->process('{"email":"' . TestConstants::EMAIL_TEST . '"}'); + $processor->process('{"' . TestConstants::CONTEXT_EMAIL . '":"' . TestConstants::EMAIL_TEST . '"}'); $this->assertNotEmpty($logs); } @@ -214,7 +214,7 @@ PRINT_R; { $processor = $this->createProcessor(); - $message = 'Users: [{"email":"a@example.com"},{"email":"b@example.com"}]'; + $message = 'Users: [{"' . TestConstants::CONTEXT_EMAIL . '":"a@example.com"},{"' . TestConstants::CONTEXT_EMAIL . '":"b@example.com"}]'; $result = $processor->process($message); $this->assertStringNotContainsString('a@example.com', $result); @@ -237,7 +237,7 @@ PRINT_R; $processor = $this->createProcessor(); $varExportOutput = 'array ( - "email" => "' . TestConstants::EMAIL_JOHN . '", + "' . TestConstants::CONTEXT_EMAIL . '" => "' . TestConstants::EMAIL_JOHN . '", )'; $result = $processor->process($varExportOutput); @@ -249,7 +249,7 @@ PRINT_R; { $processor = $this->createProcessor(); - $message = 'JSON: {"email":"a@example.com"} and serialized: s:16:"b@example.com";'; + $message = 'JSON: {"' . TestConstants::CONTEXT_EMAIL . '":"a@example.com"} and serialized: s:16:"b@example.com";'; $result = $processor->process($message); $this->assertStringNotContainsString('a@example.com', $result); @@ -258,13 +258,13 @@ PRINT_R; public function testProcessWithCustomMasker(): void { - $customMasker = fn(string $value): string => str_replace('secret', '[REDACTED]', $value); + $customMasker = fn(string $value): string => str_replace('secret', TestConstants::MASK_REDACTED_BRACKETS, $value); $processor = new SerializedDataProcessor($customMasker); $message = '{"data":"this is secret information"}'; $result = $processor->process($message); - $this->assertStringContainsString('[REDACTED]', $result); + $this->assertStringContainsString(TestConstants::MASK_REDACTED_BRACKETS, $result); $this->assertStringNotContainsString('secret', $result); } } diff --git a/tests/Strategies/AbstractMaskingStrategyTest.php b/tests/Strategies/AbstractMaskingStrategyTest.php index a9bc5d1..51392ce 100644 --- a/tests/Strategies/AbstractMaskingStrategyTest.php +++ b/tests/Strategies/AbstractMaskingStrategyTest.php @@ -58,7 +58,7 @@ final class AbstractMaskingStrategyTest extends TestCase */ public function getName(): string { - return 'Test Strategy'; + return TestConstants::STRATEGY_TEST; } /** @@ -123,8 +123,8 @@ final class AbstractMaskingStrategyTest extends TestCase #[Test] public function valueToStringConvertsStringAsIs(): void { - $result = $this->strategy->testValueToString('test string'); - $this->assertSame('test string', $result); + $result = $this->strategy->testValueToString(TestConstants::MESSAGE_TEST_STRING); + $this->assertSame(TestConstants::MESSAGE_TEST_STRING, $result); } #[Test] @@ -159,7 +159,7 @@ final class AbstractMaskingStrategyTest extends TestCase public function valueToStringConvertsArray(): void { $result = $this->strategy->testValueToString(['key' => 'value']); - $this->assertSame('{"key":"value"}', $result); + $this->assertSame(TestConstants::JSON_KEY_VALUE, $result); } #[Test] @@ -256,7 +256,7 @@ final class AbstractMaskingStrategyTest extends TestCase $conditions = [ 'level' => 'Error', 'channel' => 'test-channel', - 'message' => TestConstants::MESSAGE_TEST_LOWERCASE, + TestConstants::FIELD_MESSAGE => TestConstants::MESSAGE_TEST_LOWERCASE, TestConstants::CONTEXT_USER_ID => 123, ]; @@ -323,7 +323,7 @@ final class AbstractMaskingStrategyTest extends TestCase public function generateValuePreviewHandlesNonStringValues(): void { $preview = $this->strategy->testGenerateValuePreview(['key' => 'value']); - $this->assertSame('{"key":"value"}', $preview); + $this->assertSame(TestConstants::JSON_KEY_VALUE, $preview); } #[Test] @@ -383,8 +383,8 @@ final class AbstractMaskingStrategyTest extends TestCase #[Test] public function preserveValueTypeConvertsBackToArray(): void { - $result = $this->strategy->testPreserveValueType(['original' => 'value'], '{"masked":"data"}'); - $this->assertSame(['masked' => 'data'], $result); + $result = $this->strategy->testPreserveValueType(['original' => 'value'], '{"' . TestConstants::DATA_MASKED . '":"data"}'); + $this->assertSame([TestConstants::DATA_MASKED => 'data'], $result); $this->assertIsArray($result); } @@ -392,10 +392,10 @@ final class AbstractMaskingStrategyTest extends TestCase public function preserveValueTypeConvertsBackToObject(): void { $original = (object) ['original' => 'value']; - $result = $this->strategy->testPreserveValueType($original, '{"masked":"data"}'); + $result = $this->strategy->testPreserveValueType($original, '{"' . TestConstants::DATA_MASKED . '":"data"}'); $this->assertIsObject($result); - $this->assertEquals((object) ['masked' => 'data'], $result); + $this->assertEquals((object) [TestConstants::DATA_MASKED => 'data'], $result); } #[Test] diff --git a/tests/Strategies/CallbackMaskingStrategyTest.php b/tests/Strategies/CallbackMaskingStrategyTest.php index 6a03cba..99f6af8 100644 --- a/tests/Strategies/CallbackMaskingStrategyTest.php +++ b/tests/Strategies/CallbackMaskingStrategyTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Tests\Strategies; use Ivuorinen\MonologGdprFilter\Exceptions\MaskingOperationFailedException; +use Ivuorinen\MonologGdprFilter\MaskConstants; use Ivuorinen\MonologGdprFilter\Exceptions\RuleExecutionException; use Ivuorinen\MonologGdprFilter\Strategies\CallbackMaskingStrategy; use PHPUnit\Framework\TestCase; @@ -23,9 +24,9 @@ final class CallbackMaskingStrategyTest extends TestCase public function testBasicConstruction(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; - $strategy = new CallbackMaskingStrategy('user.email', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_EMAIL, $callback); - $this->assertSame('user.email', $strategy->getFieldPath()); + $this->assertSame(TestConstants::FIELD_USER_EMAIL, $strategy->getFieldPath()); $this->assertTrue($strategy->isExactMatch()); $this->assertSame(50, $strategy->getPriority()); } @@ -33,10 +34,10 @@ final class CallbackMaskingStrategyTest extends TestCase public function testMaskWithSimpleCallback(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; - $strategy = new CallbackMaskingStrategy('user.email', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_EMAIL, $callback); $record = $this->createLogRecord(); - $result = $strategy->mask('john@example.com', 'user.email', $record); + $result = $strategy->mask(TestConstants::EMAIL_JOHN, TestConstants::FIELD_USER_EMAIL, $record); $this->assertSame(TestConstants::MASK_MASKED_BRACKETS, $result); } @@ -44,10 +45,10 @@ final class CallbackMaskingStrategyTest extends TestCase public function testMaskWithTransformingCallback(): void { $callback = fn(mixed $value): string => strtoupper((string) $value); - $strategy = new CallbackMaskingStrategy('user.name', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_NAME, $callback); $record = $this->createLogRecord(); - $result = $strategy->mask('john', 'user.name', $record); + $result = $strategy->mask('john', TestConstants::FIELD_USER_NAME, $record); $this->assertSame('JOHN', $result); } @@ -57,27 +58,27 @@ final class CallbackMaskingStrategyTest extends TestCase $callback = function (): never { throw new RuleExecutionException('Callback failed'); }; - $strategy = new CallbackMaskingStrategy('user.data', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_DATA, $callback); $record = $this->createLogRecord(); $this->expectException(MaskingOperationFailedException::class); $this->expectExceptionMessage('Callback threw exception'); - $strategy->mask('value', 'user.data', $record); + $strategy->mask('value', TestConstants::FIELD_USER_DATA, $record); } public function testShouldApplyWithExactMatch(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; $strategy = new CallbackMaskingStrategy( - 'user.email', + TestConstants::FIELD_USER_EMAIL, $callback, exactMatch: true ); $record = $this->createLogRecord(); - $this->assertTrue($strategy->shouldApply('value', 'user.email', $record)); - $this->assertFalse($strategy->shouldApply('value', 'user.name', $record)); + $this->assertTrue($strategy->shouldApply('value', TestConstants::FIELD_USER_EMAIL, $record)); + $this->assertFalse($strategy->shouldApply('value', TestConstants::FIELD_USER_NAME, $record)); $this->assertFalse($strategy->shouldApply('value', 'user.email.work', $record)); } @@ -85,32 +86,32 @@ final class CallbackMaskingStrategyTest extends TestCase { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; $strategy = new CallbackMaskingStrategy( - 'user.*', + TestConstants::PATH_USER_WILDCARD, $callback, exactMatch: false ); $record = $this->createLogRecord(); - $this->assertTrue($strategy->shouldApply('value', 'user.email', $record)); - $this->assertTrue($strategy->shouldApply('value', 'user.name', $record)); + $this->assertTrue($strategy->shouldApply('value', TestConstants::FIELD_USER_EMAIL, $record)); + $this->assertTrue($strategy->shouldApply('value', TestConstants::FIELD_USER_NAME, $record)); $this->assertFalse($strategy->shouldApply('value', 'admin.email', $record)); } public function testGetName(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; - $strategy = new CallbackMaskingStrategy('user.email', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_EMAIL, $callback); $name = $strategy->getName(); $this->assertStringContainsString('Callback Masking', $name); - $this->assertStringContainsString('user.email', $name); + $this->assertStringContainsString(TestConstants::FIELD_USER_EMAIL, $name); } public function testValidate(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; - $strategy = new CallbackMaskingStrategy('user.email', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_EMAIL, $callback); $this->assertTrue($strategy->validate()); } @@ -119,7 +120,7 @@ final class CallbackMaskingStrategyTest extends TestCase { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; $strategy = new CallbackMaskingStrategy( - 'user.email', + TestConstants::FIELD_USER_EMAIL, $callback, 75, false @@ -130,7 +131,7 @@ final class CallbackMaskingStrategyTest extends TestCase $this->assertArrayHasKey('field_path', $config); $this->assertArrayHasKey('exact_match', $config); $this->assertArrayHasKey('priority', $config); - $this->assertSame('user.email', $config['field_path']); + $this->assertSame(TestConstants::FIELD_USER_EMAIL, $config['field_path']); $this->assertFalse($config['exact_match']); $this->assertSame(75, $config['priority']); } @@ -138,7 +139,7 @@ final class CallbackMaskingStrategyTest extends TestCase public function testForPathsFactoryMethod(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; - $paths = ['user.email', 'admin.email', 'contact.email']; + $paths = [TestConstants::FIELD_USER_EMAIL, 'admin.email', 'contact.email']; $strategies = CallbackMaskingStrategy::forPaths($paths, $callback); @@ -152,20 +153,20 @@ final class CallbackMaskingStrategyTest extends TestCase public function testConstantFactoryMethod(): void { - $strategy = CallbackMaskingStrategy::constant('user.ssn', '***-**-****'); + $strategy = CallbackMaskingStrategy::constant(TestConstants::FIELD_USER_SSN, MaskConstants::MASK_SSN_PATTERN); $record = $this->createLogRecord(); - $result = $strategy->mask('123-45-6789', 'user.ssn', $record); + $result = $strategy->mask(TestConstants::SSN_US, TestConstants::FIELD_USER_SSN, $record); - $this->assertSame('***-**-****', $result); + $this->assertSame(MaskConstants::MASK_SSN_PATTERN, $result); } public function testHashFactoryMethod(): void { - $strategy = CallbackMaskingStrategy::hash('user.password', 'sha256', 8); + $strategy = CallbackMaskingStrategy::hash(TestConstants::FIELD_USER_PASSWORD, 'sha256', 8); $record = $this->createLogRecord(); - $result = $strategy->mask('secret123', 'user.password', $record); + $result = $strategy->mask('secret123', TestConstants::FIELD_USER_PASSWORD, $record); $this->assertIsString($result); $this->assertSame(11, strlen($result)); @@ -174,24 +175,24 @@ final class CallbackMaskingStrategyTest extends TestCase public function testHashWithNoTruncation(): void { - $strategy = CallbackMaskingStrategy::hash('user.password', 'md5', 0); + $strategy = CallbackMaskingStrategy::hash(TestConstants::FIELD_USER_PASSWORD, 'md5', 0); $record = $this->createLogRecord(); - $result = $strategy->mask('test', 'user.password', $record); + $result = $strategy->mask('test', TestConstants::FIELD_USER_PASSWORD, $record); $this->assertSame(32, strlen((string) $result)); } public function testPartialFactoryMethod(): void { - $strategy = CallbackMaskingStrategy::partial('user.email', 2, 4); + $strategy = CallbackMaskingStrategy::partial(TestConstants::FIELD_USER_EMAIL, 2, 4); $record = $this->createLogRecord(); - $result = $strategy->mask('john@example.com', 'user.email', $record); + $result = $strategy->mask(TestConstants::EMAIL_JOHN, TestConstants::FIELD_USER_EMAIL, $record); $this->assertStringStartsWith('jo', $result); $this->assertStringEndsWith('.com', $result); - $this->assertStringContainsString('***', $result); + $this->assertStringContainsString(MaskConstants::MASK_GENERIC, $result); } public function testPartialWithShortString(): void @@ -201,7 +202,7 @@ final class CallbackMaskingStrategyTest extends TestCase $result = $strategy->mask('abc', 'user.code', $record); - $this->assertSame('***', $result); + $this->assertSame(MaskConstants::MASK_GENERIC, $result); } public function testPartialWithCustomMaskChar(): void @@ -224,29 +225,29 @@ final class CallbackMaskingStrategyTest extends TestCase return TestConstants::MASK_MASKED_BRACKETS; }; - $strategy = new CallbackMaskingStrategy('user.data', $callback); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_DATA, $callback); $record = $this->createLogRecord(); - $strategy->mask(['key' => 'value'], 'user.data', $record); + $strategy->mask(['key' => 'value'], TestConstants::FIELD_USER_DATA, $record); $this->assertSame($receivedValue, ['key' => 'value']); } public function testCallbackCanReturnNonString(): void { - $callback = fn(mixed $value): array => ['masked' => true]; - $strategy = new CallbackMaskingStrategy('user.data', $callback); + $callback = fn(mixed $value): array => [TestConstants::DATA_MASKED => true]; + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_DATA, $callback); $record = $this->createLogRecord(); - $result = $strategy->mask(['key' => 'value'], 'user.data', $record); + $result = $strategy->mask(['key' => 'value'], TestConstants::FIELD_USER_DATA, $record); - $this->assertSame(['masked' => true], $result); + $this->assertSame([TestConstants::DATA_MASKED => true], $result); } public function testCustomPriority(): void { $callback = fn(mixed $value): string => TestConstants::MASK_MASKED_BRACKETS; - $strategy = new CallbackMaskingStrategy('user.email', $callback, 100); + $strategy = new CallbackMaskingStrategy(TestConstants::FIELD_USER_EMAIL, $callback, 100); $this->assertSame(100, $strategy->getPriority()); } diff --git a/tests/Strategies/ConditionalMaskingStrategyComprehensiveTest.php b/tests/Strategies/ConditionalMaskingStrategyComprehensiveTest.php index c466e20..ba367b8 100644 --- a/tests/Strategies/ConditionalMaskingStrategyComprehensiveTest.php +++ b/tests/Strategies/ConditionalMaskingStrategyComprehensiveTest.php @@ -59,7 +59,7 @@ final class ConditionalMaskingStrategyComprehensiveTest extends TestCase public function getName(): string { - return 'Test Strategy'; + return TestConstants::STRATEGY_TEST; } public function validate(): bool diff --git a/tests/Strategies/DataTypeMaskingStrategyComprehensiveTest.php b/tests/Strategies/DataTypeMaskingStrategyComprehensiveTest.php index 0c76648..e3e169e 100644 --- a/tests/Strategies/DataTypeMaskingStrategyComprehensiveTest.php +++ b/tests/Strategies/DataTypeMaskingStrategyComprehensiveTest.php @@ -146,14 +146,14 @@ final class DataTypeMaskingStrategyComprehensiveTest extends TestCase public function testMaskWithObjectValueJsonMask(): void { - $strategy = new DataTypeMaskingStrategy(['object' => '{"masked":"data"}']); + $strategy = new DataTypeMaskingStrategy(['object' => '{"' . TestConstants::DATA_MASKED . '":"data"}']); $record = $this->createLogRecord('Test'); $obj = (object)['original' => 'value']; $result = $strategy->mask($obj, 'field', $record); - $expected = (object)['masked' => 'data']; + $expected = (object)[TestConstants::DATA_MASKED => 'data']; $this->assertEquals($expected, $result); } @@ -411,7 +411,7 @@ final class DataTypeMaskingStrategyComprehensiveTest extends TestCase 'double' => 'D', 'boolean' => '1', // Boolean uses filter_var, so '1' becomes true 'array' => '["MASKED"]', // JSON array - 'object' => '{"masked":"value"}', // JSON object + 'object' => '{"' . TestConstants::DATA_MASKED . '":"value"}', // JSON object 'NULL' => 'N', ]); @@ -422,7 +422,7 @@ final class DataTypeMaskingStrategyComprehensiveTest extends TestCase $this->assertSame('D', $strategy->mask(3.14, 'f', $record)); $this->assertTrue($strategy->mask(true, 'f', $record)); // Boolean conversion $this->assertSame(['MASKED'], $strategy->mask([], 'f', $record)); - $this->assertEquals((object)['masked' => 'value'], $strategy->mask((object)[], 'f', $record)); + $this->assertEquals((object)[TestConstants::DATA_MASKED => 'value'], $strategy->mask((object)[], 'f', $record)); $this->assertSame('N', $strategy->mask(null, 'f', $record)); } } diff --git a/tests/Strategies/DataTypeMaskingStrategyTest.php b/tests/Strategies/DataTypeMaskingStrategyTest.php index 3fb1544..8718fde 100644 --- a/tests/Strategies/DataTypeMaskingStrategyTest.php +++ b/tests/Strategies/DataTypeMaskingStrategyTest.php @@ -70,7 +70,7 @@ final class DataTypeMaskingStrategyTest extends TestCase { $strategy = new DataTypeMaskingStrategy(['string' => MaskConstants::MASK_GENERIC]); - $this->assertTrue($strategy->shouldApply('test string', 'field', $this->logRecord)); + $this->assertTrue($strategy->shouldApply(TestConstants::MESSAGE_TEST_STRING, 'field', $this->logRecord)); } #[Test] @@ -107,11 +107,11 @@ final class DataTypeMaskingStrategyTest extends TestCase #[Test] public function maskAppliesStringMask(): void { - $strategy = new DataTypeMaskingStrategy(['string' => 'REDACTED']); + $strategy = new DataTypeMaskingStrategy(['string' => TestConstants::MASK_REDACTED_PLAIN]); $result = $strategy->mask('sensitive data', 'field', $this->logRecord); - $this->assertSame('REDACTED', $result); + $this->assertSame(TestConstants::MASK_REDACTED_PLAIN, $result); } #[Test] @@ -177,7 +177,7 @@ final class DataTypeMaskingStrategyTest extends TestCase #[Test] public function maskAppliesArrayMaskJsonArray(): void { - $strategy = new DataTypeMaskingStrategy(['array' => '["masked"]']); + $strategy = new DataTypeMaskingStrategy(['array' => '["' . TestConstants::DATA_MASKED . '"]']); $result = $strategy->mask(['original'], 'field', $this->logRecord); @@ -209,13 +209,13 @@ final class DataTypeMaskingStrategyTest extends TestCase #[Test] public function maskAppliesObjectMaskJsonObject(): void { - $strategy = new DataTypeMaskingStrategy(['object' => '{"masked":"data"}']); + $strategy = new DataTypeMaskingStrategy(['object' => '{"' . TestConstants::DATA_MASKED . '":"data"}']); $obj = (object) ['original' => 'value']; $result = $strategy->mask($obj, 'field', $this->logRecord); $this->assertIsObject($result); - $this->assertEquals((object) ['masked' => 'data'], $result); + $this->assertEquals((object) [TestConstants::DATA_MASKED => 'data'], $result); } #[Test] @@ -227,7 +227,7 @@ final class DataTypeMaskingStrategyTest extends TestCase $result = $strategy->mask($obj, 'field', $this->logRecord); $this->assertIsObject($result); - $this->assertEquals((object) ['masked' => 'MASKED'], $result); + $this->assertEquals((object) [TestConstants::DATA_MASKED => 'MASKED'], $result); } #[Test] diff --git a/tests/Strategies/FieldPathMaskingStrategyEnhancedTest.php b/tests/Strategies/FieldPathMaskingStrategyEnhancedTest.php index 89f0e90..939487b 100644 --- a/tests/Strategies/FieldPathMaskingStrategyEnhancedTest.php +++ b/tests/Strategies/FieldPathMaskingStrategyEnhancedTest.php @@ -30,7 +30,7 @@ final class FieldPathMaskingStrategyEnhancedTest extends TestCase $this->expectException(MaskingOperationFailedException::class); $this->expectExceptionMessage('Regex pattern is null'); - $strategy->mask('test value', 'field', $record); + $strategy->mask(TestConstants::VALUE_TEST, 'field', $record); } public function testApplyStaticReplacementWithNullReplacement(): void diff --git a/tests/Strategies/FieldPathMaskingStrategyTest.php b/tests/Strategies/FieldPathMaskingStrategyTest.php index ac4638e..2b27104 100644 --- a/tests/Strategies/FieldPathMaskingStrategyTest.php +++ b/tests/Strategies/FieldPathMaskingStrategyTest.php @@ -138,9 +138,9 @@ final class FieldPathMaskingStrategyTest extends TestCase TestConstants::PATTERN_SSN_FORMAT, MaskConstants::MASK_SSN_PATTERN ); - $strategy = new FieldPathMaskingStrategy(['user.ssn' => $ssnConfig]); + $strategy = new FieldPathMaskingStrategy([TestConstants::FIELD_USER_SSN => $ssnConfig]); - $result = $strategy->mask(TestConstants::SSN_US, 'user.ssn', $this->logRecord); + $result = $strategy->mask(TestConstants::SSN_US, TestConstants::FIELD_USER_SSN, $this->logRecord); $this->assertSame(MaskConstants::MASK_SSN_PATTERN, $result); } @@ -149,12 +149,12 @@ final class FieldPathMaskingStrategyTest extends TestCase public function maskAppliesStaticReplacementFromConfig(): void { $strategy = new FieldPathMaskingStrategy([ - TestConstants::FIELD_USER_NAME => FieldMaskConfig::replace('[REDACTED]'), + TestConstants::FIELD_USER_NAME => FieldMaskConfig::replace(TestConstants::MASK_REDACTED_BRACKETS), ]); $result = $strategy->mask(TestConstants::NAME_FULL, TestConstants::FIELD_USER_NAME, $this->logRecord); - $this->assertSame('[REDACTED]', $result); + $this->assertSame(TestConstants::MASK_REDACTED_BRACKETS, $result); } #[Test] @@ -238,7 +238,7 @@ final class FieldPathMaskingStrategyTest extends TestCase $strategy = new FieldPathMaskingStrategy([ TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL_PATTERN, TestConstants::FIELD_USER_PASSWORD => FieldMaskConfig::remove(), - 'user.ssn' => $ssnConfig, + TestConstants::FIELD_USER_SSN => $ssnConfig, ]); $this->assertTrue($strategy->validate()); @@ -328,7 +328,7 @@ final class FieldPathMaskingStrategyTest extends TestCase public function maskHandlesMultipleReplacementsInSameValue(): void { $strategy = new FieldPathMaskingStrategy([ - 'message' => FieldMaskConfig::regexMask(TestConstants::PATTERN_SSN_FORMAT, MaskConstants::MASK_SSN_PATTERN), + TestConstants::FIELD_MESSAGE => FieldMaskConfig::regexMask(TestConstants::PATTERN_SSN_FORMAT, MaskConstants::MASK_SSN_PATTERN), ]); $input = 'SSNs: 123-45-6789 and 987-65-4321'; diff --git a/tests/Strategies/MaskingStrategiesTest.php b/tests/Strategies/MaskingStrategiesTest.php index be592ae..ab6a680 100644 --- a/tests/Strategies/MaskingStrategiesTest.php +++ b/tests/Strategies/MaskingStrategiesTest.php @@ -127,11 +127,11 @@ class MaskingStrategiesTest extends TestCase $this->assertSame(80, $strategy->getPriority()); // Test shouldApply - $this->assertTrue($strategy->shouldApply('john@example.com', TestConstants::FIELD_USER_EMAIL, $logRecord)); + $this->assertTrue($strategy->shouldApply(TestConstants::EMAIL_JOHN, TestConstants::FIELD_USER_EMAIL, $logRecord)); $this->assertFalse($strategy->shouldApply('some value', 'other.field', $logRecord)); // Test static replacement - $masked = $strategy->mask('john@example.com', TestConstants::FIELD_USER_EMAIL, $logRecord); + $masked = $strategy->mask(TestConstants::EMAIL_JOHN, TestConstants::FIELD_USER_EMAIL, $logRecord); $this->assertEquals(MaskConstants::MASK_EMAIL, $masked); // Test removal (returns null) @@ -336,7 +336,7 @@ class MaskingStrategiesTest extends TestCase #[\Override] public function getName(): string { - return 'Test Strategy'; + return TestConstants::STRATEGY_TEST; } // Expose protected methods for testing diff --git a/tests/Strategies/RegexMaskingStrategyTest.php b/tests/Strategies/RegexMaskingStrategyTest.php index 09a1ea8..9440a01 100644 --- a/tests/Strategies/RegexMaskingStrategyTest.php +++ b/tests/Strategies/RegexMaskingStrategyTest.php @@ -64,7 +64,7 @@ final class RegexMaskingStrategyTest extends TestCase $this->expectException(InvalidRegexPatternException::class); $this->expectExceptionMessage('catastrophic backtracking'); - new RegexMaskingStrategy(['/^(a+)+$/' => MaskConstants::MASK_GENERIC]); + new RegexMaskingStrategy([TestConstants::PATTERN_REDOS_VULNERABLE => MaskConstants::MASK_GENERIC]); } #[Test] @@ -124,7 +124,7 @@ final class RegexMaskingStrategyTest extends TestCase public function maskHandlesArrayValues(): void { $strategy = new RegexMaskingStrategy([ - '/"email":"[^"]+"/' => '"email":"' . MaskConstants::MASK_EMAIL_PATTERN . '"', + '/"' . TestConstants::CONTEXT_EMAIL . '":"[^"]+"/' => '"' . TestConstants::CONTEXT_EMAIL . '":"' . MaskConstants::MASK_EMAIL_PATTERN . '"', ]); $input = [TestConstants::CONTEXT_EMAIL => TestConstants::EMAIL_TEST]; @@ -208,12 +208,12 @@ final class RegexMaskingStrategyTest extends TestCase { $strategy = new RegexMaskingStrategy( patterns: [TestConstants::PATTERN_DIGITS => MaskConstants::MASK_GENERIC], - includePaths: ['user.ssn', 'user.phone'] + includePaths: [TestConstants::FIELD_USER_SSN, 'user.phone'] ); $this->assertTrue($strategy->shouldApply( TestConstants::DATA_NUMBER_STRING, - 'user.ssn', + TestConstants::FIELD_USER_SSN, $this->logRecord )); $this->assertTrue($strategy->shouldApply( @@ -236,7 +236,7 @@ final class RegexMaskingStrategyTest extends TestCase includePaths: [TestConstants::PATH_USER_WILDCARD] ); - $this->assertTrue($strategy->shouldApply(TestConstants::DATA_NUMBER_STRING, 'user.ssn', $this->logRecord)); + $this->assertTrue($strategy->shouldApply(TestConstants::DATA_NUMBER_STRING, TestConstants::FIELD_USER_SSN, $this->logRecord)); $this->assertTrue($strategy->shouldApply(TestConstants::DATA_NUMBER_STRING, 'user.phone', $this->logRecord)); $this->assertFalse($strategy->shouldApply(TestConstants::DATA_NUMBER_STRING, 'admin.id', $this->logRecord)); } @@ -277,7 +277,7 @@ final class RegexMaskingStrategyTest extends TestCase { $strategy = new RegexMaskingStrategy([ TestConstants::PATTERN_SSN_FORMAT => MaskConstants::MASK_SSN_PATTERN, - '/[a-z]+/' => 'REDACTED', + TestConstants::PATTERN_SAFE => TestConstants::MASK_REDACTED_PLAIN, ]); $this->assertTrue($strategy->validate()); @@ -297,7 +297,7 @@ final class RegexMaskingStrategyTest extends TestCase public function getConfigurationReturnsFullConfiguration(): void { $patterns = [TestConstants::PATTERN_DIGITS => MaskConstants::MASK_GENERIC]; - $includePaths = ['user.ssn']; + $includePaths = [TestConstants::FIELD_USER_SSN]; $excludePaths = ['debug.*']; $strategy = new RegexMaskingStrategy( @@ -334,7 +334,7 @@ final class RegexMaskingStrategyTest extends TestCase '/REPLACED/' => 'FINAL', ]); - $result = $strategy->mask('test value', 'field', $this->logRecord); + $result = $strategy->mask(TestConstants::VALUE_TEST, 'field', $this->logRecord); $this->assertSame('FINAL value', $result); } @@ -367,13 +367,13 @@ final class RegexMaskingStrategyTest extends TestCase public function maskHandlesMultilinePatterns(): void { $strategy = new RegexMaskingStrategy([ - '/^line\d+$/m' => 'REDACTED', + '/^line\d+$/m' => TestConstants::MASK_REDACTED_PLAIN, ]); $input = "line1\nother\nline2"; $result = $strategy->mask($input, 'field', $this->logRecord); - $this->assertStringContainsString('REDACTED', $result); + $this->assertStringContainsString(TestConstants::MASK_REDACTED_PLAIN, $result); $this->assertStringContainsString('other', $result); } } diff --git a/tests/Strategies/StrategyEdgeCasesTest.php b/tests/Strategies/StrategyEdgeCasesTest.php index 111d12f..e0029b3 100644 --- a/tests/Strategies/StrategyEdgeCasesTest.php +++ b/tests/Strategies/StrategyEdgeCasesTest.php @@ -17,6 +17,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use Tests\TestConstants; /** * Edge case tests for masking strategies to improve coverage. @@ -35,7 +36,7 @@ final class StrategyEdgeCasesTest extends TestCase datetime: new DateTimeImmutable(), channel: 'test', level: Level::Info, - message: 'Test message', + message: TestConstants::MESSAGE_DEFAULT, context: [], ); } @@ -61,8 +62,8 @@ final class StrategyEdgeCasesTest extends TestCase public static function redosPatternProvider(): array { return [ - 'nested plus quantifier' => ['/^(a+)+$/'], - 'nested star quantifier' => ['/^(a*)*$/'], + 'nested plus quantifier' => [TestConstants::PATTERN_REDOS_VULNERABLE], + 'nested star quantifier' => [TestConstants::PATTERN_REDOS_NESTED_STAR], 'plus with repetition' => ['/^(a+){1,10}$/'], 'star with repetition' => ['/^(a*){1,10}$/'], 'identical alternation with star' => ['/(.*|.*)x/'], @@ -76,9 +77,9 @@ final class StrategyEdgeCasesTest extends TestCase public function regexStrategySafePatternsPasses(): void { $strategy = new RegexMaskingStrategy([ - '/\d{3}-\d{2}-\d{4}/' => '[SSN]', - '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/' => '[EMAIL]', - '/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/' => '[CARD]', + TestConstants::PATTERN_SSN_FORMAT => TestConstants::MASK_SSN_BRACKETS, + TestConstants::PATTERN_EMAIL_SIMPLE => TestConstants::MASK_EMAIL_BRACKETS, + TestConstants::PATTERN_CREDIT_CARD => TestConstants::MASK_CARD_BRACKETS, ]); $this->assertInstanceOf(RegexMaskingStrategy::class, $strategy); @@ -153,7 +154,7 @@ final class StrategyEdgeCasesTest extends TestCase $result = $strategy->mask($obj, 'field', $this->logRecord); $this->assertIsObject($result); - $this->assertEquals((object) ['masked' => '{invalid json'], $result); + $this->assertEquals((object) [TestConstants::DATA_MASKED => '{invalid json'], $result); } #[Test] @@ -165,7 +166,7 @@ final class StrategyEdgeCasesTest extends TestCase $result = $strategy->mask($obj, 'field', $this->logRecord); $this->assertIsObject($result); - $this->assertEquals((object) ['masked' => '["array"]'], $result); + $this->assertEquals((object) [TestConstants::DATA_MASKED => '["array"]'], $result); } #[Test] @@ -256,7 +257,7 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyValidateWithValidStringConfig(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.email' => MaskConstants::MASK_EMAIL_PATTERN, + TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL_PATTERN, ]); $this->assertTrue($strategy->validate()); @@ -266,8 +267,8 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyValidateWithFieldMaskConfig(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.email' => FieldMaskConfig::replace(MaskConstants::MASK_EMAIL_PATTERN), - 'user.ssn' => FieldMaskConfig::remove(), + TestConstants::FIELD_USER_EMAIL => FieldMaskConfig::replace(MaskConstants::MASK_EMAIL_PATTERN), + TestConstants::FIELD_USER_SSN => FieldMaskConfig::remove(), ]); $this->assertTrue($strategy->validate()); @@ -277,7 +278,7 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyValidateWithValidRegexConfig(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.data' => FieldMaskConfig::regexMask('/\d+/', '[MASKED]'), + TestConstants::FIELD_USER_DATA => FieldMaskConfig::regexMask(TestConstants::PATTERN_DIGITS, MaskConstants::MASK_BRACKETS), ]); $this->assertTrue($strategy->validate()); @@ -338,7 +339,7 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyShouldApplyReturnsFalseForMissingPath(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.email' => MaskConstants::MASK_EMAIL_PATTERN, + TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL_PATTERN, ]); $this->assertFalse($strategy->shouldApply('value', 'other.path', $this->logRecord)); @@ -348,11 +349,11 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyShouldApplyReturnsTrueForWildcardMatch(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.*' => MaskConstants::MASK_GENERIC, + TestConstants::PATH_USER_WILDCARD => MaskConstants::MASK_GENERIC, ]); - $this->assertTrue($strategy->shouldApply('value', 'user.email', $this->logRecord)); - $this->assertTrue($strategy->shouldApply('value', 'user.name', $this->logRecord)); + $this->assertTrue($strategy->shouldApply('value', TestConstants::FIELD_USER_EMAIL, $this->logRecord)); + $this->assertTrue($strategy->shouldApply('value', TestConstants::FIELD_USER_NAME, $this->logRecord)); } #[Test] @@ -371,19 +372,19 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyMaskAppliesRegexConfig(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.ssn' => FieldMaskConfig::regexMask('/\d{3}-\d{2}-\d{4}/', '[SSN]'), + TestConstants::FIELD_USER_SSN => FieldMaskConfig::regexMask(TestConstants::PATTERN_SSN_FORMAT, TestConstants::MASK_SSN_BRACKETS), ]); - $result = $strategy->mask('SSN: 123-45-6789', 'user.ssn', $this->logRecord); + $result = $strategy->mask('SSN: 123-45-6789', TestConstants::FIELD_USER_SSN, $this->logRecord); - $this->assertSame('SSN: [SSN]', $result); + $this->assertSame(TestConstants::EXPECTED_SSN_MASKED, $result); } #[Test] public function fieldPathStrategyMaskHandlesArrayValue(): void { $strategy = new FieldPathMaskingStrategy([ - 'data' => FieldMaskConfig::regexMask('/\d+/', '[NUM]'), + 'data' => FieldMaskConfig::regexMask(TestConstants::PATTERN_DIGITS, '[NUM]'), ]); $result = $strategy->mask(['count' => '123 items'], 'data', $this->logRecord); @@ -396,7 +397,7 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyMaskReturnsValueWhenNoConfigMatch(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.email' => MaskConstants::MASK_EMAIL_PATTERN, + TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL_PATTERN, ]); $result = $strategy->mask('original', 'other.field', $this->logRecord); @@ -408,7 +409,7 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyGetNameReturnsCorrectFormat(): void { $strategy = new FieldPathMaskingStrategy([ - 'user.email' => MaskConstants::MASK_EMAIL_PATTERN, + TestConstants::FIELD_USER_EMAIL => MaskConstants::MASK_EMAIL_PATTERN, 'user.phone' => MaskConstants::MASK_PHONE, ]); @@ -421,7 +422,7 @@ final class StrategyEdgeCasesTest extends TestCase public function fieldPathStrategyGetConfigurationReturnsAllSettings(): void { $config = [ - 'user.email' => FieldMaskConfig::replace('[EMAIL]'), + TestConstants::FIELD_USER_EMAIL => FieldMaskConfig::replace(TestConstants::MASK_EMAIL_BRACKETS), ]; $strategy = new FieldPathMaskingStrategy($config); diff --git a/tests/Strategies/StrategyManagerComprehensiveTest.php b/tests/Strategies/StrategyManagerComprehensiveTest.php index 2481568..aadf802 100644 --- a/tests/Strategies/StrategyManagerComprehensiveTest.php +++ b/tests/Strategies/StrategyManagerComprehensiveTest.php @@ -122,9 +122,9 @@ final class StrategyManagerComprehensiveTest extends TestCase $manager = new StrategyManager(); $record = $this->createLogRecord('Test'); - $result = $manager->maskValue('test value', 'field', $record); + $result = $manager->maskValue(TestConstants::VALUE_TEST, 'field', $record); - $this->assertSame('test value', $result); + $this->assertSame(TestConstants::VALUE_TEST, $result); } public function testMaskValueAppliesFirstApplicableStrategy(): void @@ -137,7 +137,7 @@ final class StrategyManagerComprehensiveTest extends TestCase $manager = new StrategyManager([$lowPrio, $highPrio]); $record = $this->createLogRecord('Test'); - $result = $manager->maskValue('secret data', 'field', $record); + $result = $manager->maskValue(TestConstants::MESSAGE_SECRET_DATA, 'field', $record); // High priority strategy should be applied $this->assertStringContainsString('HIGH', $result); @@ -206,7 +206,7 @@ final class StrategyManagerComprehensiveTest extends TestCase $manager = new StrategyManager([$strategy]); $record = $this->createLogRecord('Test'); - $result = $manager->hasApplicableStrategy('secret data', 'field', $record); + $result = $manager->hasApplicableStrategy(TestConstants::MESSAGE_SECRET_DATA, 'field', $record); $this->assertTrue($result); } diff --git a/tests/Streaming/StreamingProcessorTest.php b/tests/Streaming/StreamingProcessorTest.php index f3d6e78..5990c4f 100644 --- a/tests/Streaming/StreamingProcessorTest.php +++ b/tests/Streaming/StreamingProcessorTest.php @@ -25,13 +25,13 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 10); $records = [ - ['message' => 'test message', 'context' => []], + [TestConstants::FIELD_MESSAGE => TestConstants::MESSAGE_TEST_LOWERCASE, 'context' => []], ]; $results = iterator_to_array($processor->processStream($records)); $this->assertCount(1, $results); - $this->assertSame(MaskConstants::MASK_GENERIC . ' message', $results[0]['message']); + $this->assertSame(MaskConstants::MASK_GENERIC . ' message', $results[0][TestConstants::FIELD_MESSAGE]); } public function testProcessStreamMultipleRecords(): void @@ -39,9 +39,9 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 10); $records = [ - ['message' => 'test one', 'context' => []], - ['message' => 'test two', 'context' => []], - ['message' => 'test three', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test one', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test two', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test three', 'context' => []], ]; $results = iterator_to_array($processor->processStream($records)); @@ -54,11 +54,11 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 2); $records = [ - ['message' => 'test 1', 'context' => []], - ['message' => 'test 2', 'context' => []], - ['message' => 'test 3', 'context' => []], - ['message' => 'test 4', 'context' => []], - ['message' => 'test 5', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test 1', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test 2', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test 3', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test 4', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test 5', 'context' => []], ]; $results = iterator_to_array($processor->processStream($records)); @@ -71,12 +71,12 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 10); $records = [ - ['message' => 'message', 'context' => ['key' => 'test value']], + [TestConstants::FIELD_MESSAGE => TestConstants::FIELD_MESSAGE, 'context' => ['key' => TestConstants::VALUE_TEST]], ]; $results = iterator_to_array($processor->processStream($records)); - $this->assertSame(MaskConstants::MASK_GENERIC . ' value', $results[0]['context']['key']); + $this->assertSame(MaskConstants::MASK_GENERIC . TestConstants::VALUE_SUFFIX, $results[0]['context']['key']); } public function testProcessStreamWithGenerator(): void @@ -84,9 +84,9 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 2); $generator = (function () { - yield ['message' => 'test a', 'context' => []]; - yield ['message' => 'test b', 'context' => []]; - yield ['message' => 'test c', 'context' => []]; + yield [TestConstants::FIELD_MESSAGE => 'test a', 'context' => []]; + yield [TestConstants::FIELD_MESSAGE => 'test b', 'context' => []]; + yield [TestConstants::FIELD_MESSAGE => 'test c', 'context' => []]; })(); $results = iterator_to_array($processor->processStream($generator)); @@ -104,7 +104,7 @@ final class StreamingProcessorTest extends TestCase file_put_contents($tempFile, "test line 1\ntest line 2\ntest line 3\n"); try { - $lineParser = fn(string $line): array => ['message' => $line, 'context' => []]; + $lineParser = fn(string $line): array => [TestConstants::FIELD_MESSAGE => $line, 'context' => []]; $results = []; foreach ($processor->processFile($tempFile, $lineParser) as $result) { @@ -112,7 +112,7 @@ final class StreamingProcessorTest extends TestCase } $this->assertCount(3, $results); - $this->assertStringContainsString(MaskConstants::MASK_GENERIC, $results[0]['message']); + $this->assertStringContainsString(MaskConstants::MASK_GENERIC, $results[0][TestConstants::FIELD_MESSAGE]); } finally { unlink($tempFile); } @@ -127,7 +127,7 @@ final class StreamingProcessorTest extends TestCase file_put_contents($tempFile, "test line 1\n\n\ntest line 2\n"); try { - $lineParser = fn(string $line): array => ['message' => $line, 'context' => []]; + $lineParser = fn(string $line): array => [TestConstants::FIELD_MESSAGE => $line, 'context' => []]; $results = iterator_to_array($processor->processFile($tempFile, $lineParser)); @@ -144,7 +144,7 @@ final class StreamingProcessorTest extends TestCase $this->expectException(StreamingOperationFailedException::class); $this->expectExceptionMessage('Cannot open input file for streaming:'); - iterator_to_array($processor->processFile('/nonexistent/path/file.log', fn(string $l): array => ['message' => $l, 'context' => []])); + iterator_to_array($processor->processFile('/nonexistent/path/file.log', fn(string $l): array => [TestConstants::FIELD_MESSAGE => $l, 'context' => []])); } public function testProcessToFile(): void @@ -152,15 +152,15 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 10); $records = [ - ['message' => 'test line 1', 'context' => []], - ['message' => 'test line 2', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test line 1', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test line 2', 'context' => []], ]; $outputFile = tempnam(sys_get_temp_dir(), 'gdpr_output_'); $this->assertIsString($outputFile, 'Failed to create temp file'); try { - $formatter = fn(array $record): string => $record['message']; + $formatter = fn(array $record): string => $record[TestConstants::FIELD_MESSAGE]; $count = $processor->processToFile($records, $outputFile, $formatter); $this->assertSame(2, $count); @@ -188,15 +188,33 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 10); $records = [ - ['message' => 'test masked', 'context' => []], - ['message' => 'no sensitive data', 'context' => []], - ['message' => 'another test here', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'test masked', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'no sensitive data', 'context' => []], + [TestConstants::FIELD_MESSAGE => 'another test here', 'context' => []], ]; $stats = $processor->getStatistics($records); $this->assertSame(3, $stats['processed']); - $this->assertGreaterThan(0, $stats['masked']); // At least some should be masked + $this->assertSame(2, $stats[TestConstants::DATA_MASKED]); + } + + public function testGetStatisticsDoesNotTriggerAuditLogger(): void + { + $auditCalled = false; + $auditLogger = function () use (&$auditCalled): void { + $auditCalled = true; + }; + + $processor = new StreamingProcessor($this->createOrchestrator(), 10, $auditLogger); + + $records = [ + [TestConstants::FIELD_MESSAGE => TestConstants::DATA_TEST_DATA, 'context' => []], + ]; + + $processor->getStatistics($records); + + $this->assertFalse($auditCalled); } public function testSetAuditLogger(): void @@ -209,7 +227,7 @@ final class StreamingProcessorTest extends TestCase $processor = new StreamingProcessor($this->createOrchestrator(), 1); $processor->setAuditLogger($auditLogger); - $records = [['message' => 'test', 'context' => []]]; + $records = [[TestConstants::FIELD_MESSAGE => 'test', 'context' => []]]; iterator_to_array($processor->processStream($records)); $this->assertNotEmpty($logs); @@ -235,7 +253,7 @@ final class StreamingProcessorTest extends TestCase $records = []; for ($i = 1; $i <= 500; $i++) { - $records[] = ['message' => "test record {$i}", 'context' => []]; + $records[] = [TestConstants::FIELD_MESSAGE => "test record {$i}", 'context' => []]; } $count = 0; diff --git a/tests/TestConstants.php b/tests/TestConstants.php index 90949cf..cf1deaa 100644 --- a/tests/TestConstants.php +++ b/tests/TestConstants.php @@ -145,6 +145,8 @@ final class TestConstants public const FIELD_USER_NAME = 'user.name'; public const FIELD_USER_PUBLIC = 'user.public'; public const FIELD_USER_PASSWORD = 'user.password'; + public const FIELD_USER_SSN = 'user.ssn'; + public const FIELD_USER_DATA = 'user.data'; public const FIELD_SYSTEM_LOG = 'system.log'; // Path Patterns @@ -168,20 +170,32 @@ final class TestConstants // Mask placeholders used in tests (bracketed format) public const MASK_REDACTED_BRACKETS = '[REDACTED]'; public const MASK_MASKED_BRACKETS = '[MASKED]'; + public const MASK_SECRET_BRACKETS = '[SECRET]'; + public const MASK_SSN_BRACKETS = '[SSN]'; public const MASK_EMAIL_BRACKETS = '[EMAIL]'; public const MASK_DIGITS_BRACKETS = '[DIGITS]'; public const MASK_INT_BRACKETS = '[INT]'; public const MASK_ALWAYS_THIS = '[ALWAYS_THIS]'; + public const MASK_REDACTED_PLAIN = 'REDACTED'; // Test values public const VALUE_TEST = 'test value'; public const VALUE_SUFFIX = ' value'; + // Expected output strings + public const EXPECTED_SSN_MASKED = 'SSN: [SSN]'; + + // Mask placeholders (bracketed format, additional) + public const MASK_CARD_BRACKETS = '[CARD]'; + // Additional pattern constants + public const PATTERN_EMAIL_SIMPLE = '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/'; public const PATTERN_VALID_SIMPLE = '/^test$/'; public const PATTERN_INVALID_UNCLOSED = '/unclosed'; public const PATTERN_REDOS_VULNERABLE = '/^(a+)+$/'; + public const PATTERN_REDOS_NESTED_STAR = '/^(a*)*$/'; public const PATTERN_SAFE = '/[a-z]+/'; + public const PATTERN_CREDIT_CARD = '/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/'; /** * Prevent instantiation.