-
Notifications
You must be signed in to change notification settings - Fork 3.4k
memoize wp_normalize_path #10770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
memoize wp_normalize_path #10770
Changes from 9 commits
12fde07
8b21f23
0f68954
b16350b
9369fd0
9664f3b
9c85c8b
0d12856
3e306c2
c243205
1bb3064
8b9d7e1
49a4a73
39df60c
3188ab4
ca34f0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -222,6 +222,145 @@ | |
| array( 'php://input', 'php://input' ), | ||
| array( 'http://example.com//path.ext', 'http://example.com/path.ext' ), | ||
| array( 'file://c:\\www\\path\\', 'file://C:/www/path/' ), | ||
|
|
||
| // Edge cases. | ||
| array( '', '' ), // Empty string should return empty string. | ||
| array( 123, '123' ), // Integer should be cast to string. | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that wp_normalize_path() works with objects that have __toString(). | ||
| * | ||
| * This is important because the function uses a static cache, and the input | ||
| * must be cast to string before being used as an array key. | ||
| * | ||
| * @ticket 64538 | ||
| */ | ||
| public function test_wp_normalize_path_with_stringable_object() { | ||
| $stringable = new class() { | ||
| public function __toString() { | ||
| return '/var/www/html\\test'; | ||
| } | ||
| }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a more representative test might be an SplFileInfo instance, since that is actually used in Core. as discovered in #10781 we can fix that currently-improper call in another patch.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no particular preference there. I will update the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated. |
||
|
|
||
| $this->assertSame( '/var/www/html/test', wp_normalize_path( $stringable ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that wp_normalize_path() returns consistent results on repeated calls. | ||
| * | ||
| * The function uses a static cache, so this verifies cache behavior. | ||
| * | ||
| * @ticket 64538 | ||
| */ | ||
| public function test_wp_normalize_path_returns_consistent_results() { | ||
| $path = 'C:\\www\\path\\'; | ||
|
|
||
| $first_call = wp_normalize_path( $path ); | ||
| $second_call = wp_normalize_path( $path ); | ||
| $third_call = wp_normalize_path( $path ); | ||
|
|
||
| $this->assertSame( $first_call, $second_call, 'Second call should return same result as first.' ); | ||
| $this->assertSame( $second_call, $third_call, 'Third call should return same result as second.' ); | ||
| $this->assertSame( 'C:/www/path/', $first_call, 'Normalized path should match expected value.' ); | ||
| } | ||
|
josephscott marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Tests that wp_normalize_path() cache rotation works correctly. | ||
| * | ||
| * The function uses a two-tier cache (hot/warm) with max 100 entries in hot. | ||
| * This verifies that after exceeding the cache size, both old and new paths | ||
| * still return correct results. | ||
| * | ||
| * @ticket 64538 | ||
| */ | ||
| public function test_wp_normalize_path_cache_rotation() { | ||
| $paths = array(); | ||
| $expected = array(); | ||
|
|
||
| // Generate 150 unique paths to exceed the 100-entry hot cache limit. | ||
| for ( $i = 0; $i < 150; $i++ ) { | ||
|
josephscott marked this conversation as resolved.
Outdated
|
||
| $paths[ $i ] = "/var/www/test-{$i}\\subdir\\"; | ||
| $expected[ $i ] = "/var/www/test-{$i}/subdir/"; | ||
| } | ||
|
|
||
| // First pass: normalize all paths (fills hot, triggers rotation to warm). | ||
| $results_first_pass = array(); | ||
| foreach ( $paths as $i => $path ) { | ||
| $results_first_pass[ $i ] = wp_normalize_path( $path ); | ||
| } | ||
|
|
||
| // Verify all first pass results are correct. | ||
| foreach ( $results_first_pass as $i => $result ) { | ||
| $this->assertSame( | ||
| $expected[ $i ], | ||
| $result, | ||
| "First pass: Path {$i} should be normalized correctly." | ||
| ); | ||
| } | ||
|
|
||
| // Second pass: verify old paths (now in warm) still return correct results. | ||
| // Access early paths which should have rotated to warm cache. | ||
| for ( $i = 0; $i < 50; $i++ ) { | ||
| $this->assertSame( | ||
| $expected[ $i ], | ||
| wp_normalize_path( $paths[ $i ] ), | ||
| "Second pass: Early path {$i} should still return correct result from warm cache." | ||
| ); | ||
| } | ||
|
|
||
| // Verify recent paths (should be in hot cache) also work. | ||
| for ( $i = 100; $i < 150; $i++ ) { | ||
| $this->assertSame( | ||
| $expected[ $i ], | ||
| wp_normalize_path( $paths[ $i ] ), | ||
| "Second pass: Recent path {$i} should return correct result from hot cache." | ||
| ); | ||
| } | ||
|
josephscott marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| /** | ||
| * Tests that wp_normalize_path() cache segments do not exceed the maximum size. | ||
| * | ||
| * The function uses a two-tier cache with a max of 100 entries per segment. | ||
| * This verifies the cache remains bounded after processing many unique paths. | ||
| * | ||
| * @ticket 64538 | ||
| */ | ||
| public function test_wp_normalize_path_cache_segment_limits() { | ||
| // Generate 250 unique paths to ensure multiple cache rotations. | ||
| for ( $i = 0; $i < 250; $i++ ) { | ||
| wp_normalize_path( "/unique/path/number-{$i}\\file.php" ); | ||
| } | ||
|
|
||
| // Use reflection to inspect the static cache variables. | ||
| $reflection = new ReflectionFunction( 'wp_normalize_path' ); | ||
| $static_vars = $reflection->getStaticVariables(); | ||
| $hot_count = count( $static_vars['hot'] ); | ||
| $warm_count = count( $static_vars['warm'] ); | ||
| $max = $static_vars['max']; | ||
|
|
||
| // Verify hot cache does not exceed max. | ||
| $this->assertLessThanOrEqual( | ||
| $max, | ||
| $hot_count, | ||
| "Hot cache ({$hot_count} entries) should not exceed max ({$max})." | ||
| ); | ||
|
|
||
| // Verify warm cache does not exceed max. | ||
| $this->assertLessThanOrEqual( | ||
| $max, | ||
| $warm_count, | ||
| "Warm cache ({$warm_count} entries) should not exceed max ({$max})." | ||
| ); | ||
|
|
||
| // Verify total cached entries is bounded (at most 2x max). | ||
| $total = $hot_count + $warm_count; | ||
| $this->assertLessThanOrEqual( | ||
| $max * 2, | ||
| $total, | ||
| "Total cache ({$total} entries) should not exceed 2x max (" . ( $max * 2 ) . ').' | ||
| ); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.