Skip to content

Commit 6c6060c

Browse files
committed
feat: Add case sensitivity option for path matching
1 parent 1144d33 commit 6c6060c

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,12 @@ $path->match('file?.txt'); // matches file1.txt, fileA.txt, etc.
9797
$path->match('file[123].txt'); // matches file1.txt, file2.txt, file3.txt
9898
$path->match('test/*/*.php'); // matches test/any/file.php
9999

100-
// Case sensitivity depends on the operating system
101-
// Windows: case-insensitive (File.TXT matches *.txt)
102-
// Unix/Linux: case-sensitive (File.TXT does NOT match *.txt)
100+
// Control case sensitivity with optional parameter
101+
$file = Path::create('File.TXT');
102+
$file->match('*.txt'); // OS default (case-insensitive on Windows, case-sensitive on Unix)
103+
$file->match('*.txt', false); // case-insensitive (matches on any OS)
104+
$file->match('*.txt', true); // case-sensitive (won't match - different case)
105+
$file->match('*.TXT', true); // case-sensitive (matches - exact case)
103106
```
104107

105108
## Edge cases and special handling

src/Path.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,21 @@ public function absolute(): self
203203
*
204204
* @param non-empty-string|self $pattern The pattern to match against. Can be a string path or Path object.
205205
* Will be converted to absolute path before matching.
206+
* @param bool|null $caseSensitive Whether the match should be case-sensitive. If null, uses OS default:
207+
* case-insensitive on Windows, case-sensitive on Unix/Linux.
206208
*
207209
* @return bool True if the path matches the pattern, false otherwise.
208210
*/
209-
public function match(string|self $pattern): bool
211+
public function match(string|self $pattern, ?bool $caseSensitive = null): bool
210212
{
213+
// Use OS default: case-insensitive on Windows, case-sensitive on Unix
214+
$caseSensitive ??= \DIRECTORY_SEPARATOR !== '\\';
215+
211216
\is_string($pattern) and $pattern = self::create($pattern);
212-
return \fnmatch((string) $pattern->absolute(), $this->absolute()->path, \FNM_NOESCAPE);
217+
218+
$flags = $caseSensitive ? \FNM_NOESCAPE : \FNM_NOESCAPE | \FNM_CASEFOLD;
219+
220+
return \fnmatch((string) $pattern->absolute(), $this->absolute()->path, $flags);
213221
}
214222

215223
/**

tests/Unit/PathTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,4 +535,66 @@ public function testMatchCaseSensitive(): void
535535
Assert::false($result, 'On Unix, match should be case-sensitive');
536536
}
537537
}
538+
539+
public function testMatchWithCaseSensitiveFlag(): void
540+
{
541+
// Arrange
542+
$path = Path::create('Test/File.TXT')->absolute();
543+
$pattern = 'test/file.txt';
544+
545+
// Act & Assert - case-sensitive matching
546+
Assert::false($path->match($pattern, true), 'Should not match when case-sensitive is true');
547+
548+
// Act & Assert - case-insensitive matching
549+
Assert::true($path->match($pattern, false), 'Should match when case-sensitive is false');
550+
}
551+
552+
public function testMatchWithCaseSensitiveFlagExactCase(): void
553+
{
554+
// Arrange
555+
$path = Path::create('Test/File.TXT')->absolute();
556+
$patternExact = 'Test/File.TXT';
557+
$patternLower = 'test/file.txt';
558+
559+
// Act & Assert - exact case with case-sensitive flag
560+
Assert::true($path->match($patternExact, true), 'Should match exact case with case-sensitive flag');
561+
562+
// Act & Assert - different case with case-sensitive flag
563+
Assert::false($path->match($patternLower, true), 'Should not match different case with case-sensitive flag');
564+
}
565+
566+
public function testMatchCaseInsensitiveOnAllOS(): void
567+
{
568+
// Arrange
569+
$path = Path::create('Documents/FILE.txt')->absolute();
570+
571+
// Act & Assert - force case-insensitive on any OS
572+
Assert::true($path->match('*/file.TXT', false), 'Should match with case-insensitive flag');
573+
Assert::true($path->match('*/FILE.txt', false), 'Should match with case-insensitive flag');
574+
Assert::true($path->match('*/FiLe.TxT', false), 'Should match with case-insensitive flag');
575+
}
576+
577+
public function testMatchCaseSensitiveOnAllOS(): void
578+
{
579+
// Arrange
580+
$path = Path::create('Documents/report.PDF')->absolute();
581+
582+
// Act & Assert - force case-sensitive on any OS
583+
Assert::true($path->match('*/report.PDF', true), 'Should match exact case');
584+
Assert::false($path->match('*/report.pdf', true), 'Should not match different case');
585+
Assert::false($path->match('*/REPORT.PDF', true), 'Should not match different case');
586+
}
587+
588+
public function testMatchWithWildcardsAndCaseFlag(): void
589+
{
590+
// Arrange
591+
$path = Path::create('src/Controller/UserController.php')->absolute();
592+
593+
// Act & Assert - wildcards with case-insensitive
594+
Assert::true($path->match('*/controller/*.PHP', false), 'Wildcard should match case-insensitive');
595+
596+
// Act & Assert - wildcards with case-sensitive
597+
Assert::false($path->match('*/controller/*.php', true), 'Should not match - Controller != controller');
598+
Assert::true($path->match('*/Controller/*.php', true), 'Should match with correct case');
599+
}
538600
}

0 commit comments

Comments
 (0)