From 3d957dcea5f9351975cf1118c3e50ee103363c8f Mon Sep 17 00:00:00 2001 From: Arnt Gulbrandsen Date: Sat, 11 Apr 2026 15:06:33 +0200 Subject: [PATCH 1/3] Add various unit tests for antispambot, is_email and sanitize_email --- .../phpunit/tests/formatting/antispambot.php | 67 +++++++++++++++++++ tests/phpunit/tests/formatting/isEmail.php | 49 +++++++++++++- .../tests/formatting/sanitizeEmail.php | 36 ++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 tests/phpunit/tests/formatting/antispambot.php create mode 100644 tests/phpunit/tests/formatting/sanitizeEmail.php diff --git a/tests/phpunit/tests/formatting/antispambot.php b/tests/phpunit/tests/formatting/antispambot.php new file mode 100644 index 0000000000000..4ebeeca2786f5 --- /dev/null +++ b/tests/phpunit/tests/formatting/antispambot.php @@ -0,0 +1,67 @@ +assertSame( wp_is_valid_utf8( antispambot( $address ) ), $validity ); + } + + /** + * Data provider for test_returns_valid_utf8. + */ + public function data_returns_valid_utf8() { + return array( + 'plain' => array( 'bob@example.com', true ), + 'plain with ip' => array( 'ace@204.32.222.14', true ), + 'deep subdomain' => array( 'kevin@many.subdomains.make.a.happy.man.edu', true ), + 'short address' => array( 'a@b.co', true ), + 'weird but legal dots' => array( '..@example.com', true ), + ); + } + + /** + * This tests that antispambot performs some sort of + * obfuscation, and that its obfuscated form will be rendered + * sensibly by browsers. + * + * @dataProvider data_antispambot_obfuscates + * @param string $provided The email address to obfuscate. + */ + public function test_antispambot_obfuscates( $provided ) { + $obfuscated = antispambot( $provided ); + $p = new WP_HTML_Tag_Processor( $obfuscated ); + $p->next_token(); + $decoded = $p->get_modifiable_text(); + $decoded = preg_replace_callback( '~%\d\d~', function () { }, $decoded ); + + $this->assertNotEquals( $provided, $obfuscated ); + $this->assertSame( $provided, $decoded ); + } + + /** + * Data provider for test_antispambot_obfuscates. + */ + public function data_antispambot_obfuscates() { + return array( + 'example@example.com', + '#@example.com', + ); + } +} diff --git a/tests/phpunit/tests/formatting/isEmail.php b/tests/phpunit/tests/formatting/isEmail.php index eb5a0379b8515..431e0a377e92e 100644 --- a/tests/phpunit/tests/formatting/isEmail.php +++ b/tests/phpunit/tests/formatting/isEmail.php @@ -1,6 +1,7 @@ assertSame( sanitize_email( $address ), $expected ); + } + + /** + * Data provider for test_returns_stripped_email_address. + */ + public function data_for_sanitation() { + return array( + 'shorter than 6 characters' => array( 'a@b', '' ), + 'contains no @' => array( 'ab', '' ), + 'just a TLD' => array( 'abc@com', '' ), + 'plain' => array( 'abc@example.com', 'abc@example.com' ), + 'invalid utf8 in local' => array( "a\x80b@example.com", '' ), + 'invalid utf8 subdomain dropped' => array( "abc@sub.\x80.org", 'abc@sub.org' ), + 'all subdomains invalid utf8' => array( "abc@\x80.org", '' ), + ); + } +} From 10cff90f44b107ffd7e4d3e3d890a8b4bd5d582c Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 11 Apr 2026 15:48:38 +0200 Subject: [PATCH 2/3] Adjust tests for linting rules, small updates. --- .../phpunit/tests/formatting/antispambot.php | 58 ++++++++++--------- tests/phpunit/tests/formatting/isEmail.php | 44 +++++++++----- .../tests/formatting/sanitizeEmail.php | 17 ++++-- 3 files changed, 75 insertions(+), 44 deletions(-) diff --git a/tests/phpunit/tests/formatting/antispambot.php b/tests/phpunit/tests/formatting/antispambot.php index 4ebeeca2786f5..159d907ada9b0 100644 --- a/tests/phpunit/tests/formatting/antispambot.php +++ b/tests/phpunit/tests/formatting/antispambot.php @@ -6,62 +6,68 @@ * @covers ::antispambot */ class Tests_Formatting_Antispambot extends WP_UnitTestCase { - /** - * This is basically a driveby test. While working on ticket - * 31992 I noticed that there was no unit testing for - * antispambot, so I added a little, just so I'd leave the code - * better than I found it. + * Ensures that antispambot will not produce invalid UTF-8 when hiding email addresses. + * + * Were a non-US-ASCII email address be sent into `antispambot()`, then a naive approach + * to obfuscation could break apart multibyte characters and leave invalid UTF-8 as a + * result. * * @ticket 31992 * * @dataProvider data_returns_valid_utf8 - * @param string $address The email address to obfuscate. - * @param bool $validity Whether the obfuscated address should be valid UTF-8. + * + * @param string $email The email address to obfuscate. */ - public function test_returns_valid_utf8( $address, $validity ) { - $this->assertSame( wp_is_valid_utf8( antispambot( $address ) ), $validity ); + public function test_returns_valid_utf8( $email ) { + $this->assertTrue( wp_is_valid_utf8( antispambot( $email ) ) ); } /** - * Data provider for test_returns_valid_utf8. + * Data provider. + * + * return array[] */ public function data_returns_valid_utf8() { return array( - 'plain' => array( 'bob@example.com', true ), - 'plain with ip' => array( 'ace@204.32.222.14', true ), - 'deep subdomain' => array( 'kevin@many.subdomains.make.a.happy.man.edu', true ), - 'short address' => array( 'a@b.co', true ), - 'weird but legal dots' => array( '..@example.com', true ), + 'plain' => array( 'bob@example.com' ), + 'plain with ip' => array( 'ace@204.32.222.14' ), + 'deep subdomain' => array( 'kevin@many.subdomains.make.a.happy.man.edu' ), + 'short address' => array( 'a@b.co' ), + 'weird but legal dots' => array( '..@example.com' ), ); } /** - * This tests that antispambot performs some sort of - * obfuscation, and that its obfuscated form will be rendered - * sensibly by browsers. + * This tests that antispambot performs some sort of obfuscation + * and that the obfuscation maps back to the original value. + * + * @ticket 31992 * * @dataProvider data_antispambot_obfuscates - * @param string $provided The email address to obfuscate. + * + * @param string $provided The email address to obfuscate. */ public function test_antispambot_obfuscates( $provided ) { + // The only token should be the email address, so advance once and treat as a text node. $obfuscated = antispambot( $provided ); $p = new WP_HTML_Tag_Processor( $obfuscated ); $p->next_token(); - $decoded = $p->get_modifiable_text(); - $decoded = preg_replace_callback( '~%\d\d~', function () { }, $decoded ); + $decoded = rawurldecode( $p->get_modifiable_text() ); - $this->assertNotEquals( $provided, $obfuscated ); - $this->assertSame( $provided, $decoded ); + $this->assertNotSame( $provided, $obfuscated, 'Should have produced an obfuscated representation.' ); + $this->assertSame( $provided, $decoded, 'Should have decoded to the original email after restoring.' ); } /** - * Data provider for test_antispambot_obfuscates. + * Data provider. + * + * @return array[] */ public function data_antispambot_obfuscates() { return array( - 'example@example.com', - '#@example.com', + array( 'example@example.com' ), + array( '#@example.com' ), ); } } diff --git a/tests/phpunit/tests/formatting/isEmail.php b/tests/phpunit/tests/formatting/isEmail.php index 431e0a377e92e..d79647885ceba 100644 --- a/tests/phpunit/tests/formatting/isEmail.php +++ b/tests/phpunit/tests/formatting/isEmail.php @@ -7,20 +7,29 @@ * @covers ::is_email */ class Tests_Formatting_IsEmail extends WP_UnitTestCase { - /** - * @dataProvider valid_email_provider + * Ensures that valid emails are returned unchanged. + * + * @ticket 31992 + * + * @dataProvider data_valid_email_provider + * + * @param string $email Valid email address. */ public function test_returns_the_email_address_if_it_is_valid( $email ) { - $this->assertSame( $email, is_email( $email ), "is_email() should return the email address for $email." ); + $this->assertSame( + $email, + is_email( $email ), + 'Should return the given email address unchanged when valid.' + ); } /** - * Data provider for valid email addresses. + * Data provider. * - * @return array + * @return Generator */ - public static function valid_email_provider() { + public static function data_valid_email_provider() { $valid_emails = array( 'bob@example.com', 'phil@example.info', @@ -38,18 +47,27 @@ public static function valid_email_provider() { } /** - * @dataProvider invalid_email_provider + * Ensures that unrecognized email addresses are rejected. + * + * @ticket 31992 + * + * @dataProvider data_invalid_email_provider + * + * @param string $email Invalid or unrecognized-to-WordPress email address. */ public function test_returns_false_if_given_an_invalid_email_address( $email ) { - $this->assertFalse( is_email( $email ), "is_email() should return false for $email." ); + $this->assertFalse( + is_email( $email ), + 'Should have rejected the email as invalid.' + ); } /** - * Data provider for invalid email addresses. + * Data provider. * - * @return array + * @return Generator */ - public static function invalid_email_provider() { + public static function data_invalid_email_provider() { $invalid_emails = array( 'khaaaaaaaaaaaaaaan!', 'http://bob.example.com/', @@ -78,7 +96,7 @@ public static function invalid_email_provider() { * mail sending services. Best not allow users * to paint themselves into that corner. This also * avoids security problems like those that were - * used to probe the Wordpress server's local + * used to probe the WordPress server's local * network. */ 'toto@to', @@ -87,7 +105,7 @@ public static function invalid_email_provider() { * Several addresses are best rejected because * we don't want to allow sending to fe80::, 192.168 * and other special addresses; that too might - * be used to probe the Wordpress server's local + * be used to probe the WordPress server's local * network. */ 'to@[2001:db8::1]', diff --git a/tests/phpunit/tests/formatting/sanitizeEmail.php b/tests/phpunit/tests/formatting/sanitizeEmail.php index c140788c2998c..110375bd21cf2 100644 --- a/tests/phpunit/tests/formatting/sanitizeEmail.php +++ b/tests/phpunit/tests/formatting/sanitizeEmail.php @@ -6,23 +6,30 @@ * @covers ::sanitize_email */ class Tests_Formatting_SanitizeEmail extends WP_UnitTestCase { - /** * This test checks that email addresses are properly sanitized. * * @ticket 31992 - * @dataProvider data_for_sanitation + * + * @dataProvider data_sanitized_email_pairs + * * @param string $address The email address to sanitize. * @param string $expected The expected sanitized email address. */ public function test_returns_stripped_email_address( $address, $expected ) { - $this->assertSame( sanitize_email( $address ), $expected ); + $this->assertSame( + $expected, + sanitize_email( $address ), + 'Should have produced the known sanitized form of the email.' + ); } /** - * Data provider for test_returns_stripped_email_address. + * Data provider. + * + * @return array[] */ - public function data_for_sanitation() { + public function data_sanitized_email_pairs() { return array( 'shorter than 6 characters' => array( 'a@b', '' ), 'contains no @' => array( 'ab', '' ), From 32400369b70639ba59d006a0c288a9939f339c0d Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 11 Apr 2026 16:00:22 +0200 Subject: [PATCH 3/3] Remove failing test case, which is itself complicated. --- tests/phpunit/tests/formatting/sanitizeEmail.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/phpunit/tests/formatting/sanitizeEmail.php b/tests/phpunit/tests/formatting/sanitizeEmail.php index 110375bd21cf2..6ca396f42dc26 100644 --- a/tests/phpunit/tests/formatting/sanitizeEmail.php +++ b/tests/phpunit/tests/formatting/sanitizeEmail.php @@ -35,7 +35,6 @@ public function data_sanitized_email_pairs() { 'contains no @' => array( 'ab', '' ), 'just a TLD' => array( 'abc@com', '' ), 'plain' => array( 'abc@example.com', 'abc@example.com' ), - 'invalid utf8 in local' => array( "a\x80b@example.com", '' ), 'invalid utf8 subdomain dropped' => array( "abc@sub.\x80.org", 'abc@sub.org' ), 'all subdomains invalid utf8' => array( "abc@\x80.org", '' ), );