Skip to content

Commit

Permalink
✨ New PathHelper class
Browse files Browse the repository at this point in the history
... with utility functions for handling file paths.

It is expected that this class will move to PHPCSUtils in the foreseeable future (sooner rather than later).

Includes unit tests.
  • Loading branch information
jrfnl committed Nov 19, 2023
1 parent c89e9f6 commit b09ea19
Show file tree
Hide file tree
Showing 3 changed files with 526 additions and 1 deletion.
387 changes: 387 additions & 0 deletions Yoast/Tests/Utils/PathHelperTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,387 @@
<?php

namespace YoastCS\Yoast\Tests\Utils;

use PHPUnit\Framework\TestCase;
use YoastCS\Yoast\Utils\PathHelper;

/**
* Tests for the YoastCS\Yoast\Utils\PathHelper class.
*
* @coversDefaultClass \YoastCS\Yoast\Utils\PathHelper
*
* @since 3.0.0
*/
final class PathHelperTest extends TestCase {

/**
* Test normalizing a directory path.
*
* @dataProvider data_normalize_path
* @covers ::normalize_path
*
* @param string $input The input string.
* @param string $expected The expected function output.
*
* @return void
*/
public function test_normalize_path( $input, $expected ) {
$this->assertSame( $expected, PathHelper::normalize_path( $input ) );
}

/**
* Data provider.
*
* @see test_normalize_path() For the array format.
*
* @return array<string, array<string, string>>
*/
public static function data_normalize_path() {
return [
'path is dot' => [
'input' => '.',
'expected' => './',
],
'path containing forward slashes only with trailing slash' => [
'input' => 'my/path/to/',
'expected' => 'my/path/to/',
],
'path containing forward slashes only without trailing slash' => [
'input' => 'my/path/to',
'expected' => 'my/path/to/',
],
'path containing forward slashes only with leading and trailing slash' => [
'input' => '/my/path/to/',
'expected' => 'my/path/to/',
],
'path containing back-slashes only with trailing slash' => [
'input' => 'my\path\to\\',
'expected' => 'my/path/to/',
],
'path containing back-slashes only without trailing slash' => [
'input' => 'my\path\to',
'expected' => 'my/path/to/',
],
'path containing back-slashes only with leading, no trailing slash' => [
'input' => '\my\path\to',
'expected' => 'my/path/to/',
],
'path containing a mix of forward and backslashes with leading and trailing slash' => [
'input' => '/my\path/to\\',
'expected' => 'my/path/to/',
],
'path containing a mix of forward and backslashes without trailing slash' => [
'input' => 'my\path/to',
'expected' => 'my/path/to/',
],
];
}

/**
* Test normalizing the directory separators in a path.
*
* @dataProvider data_normalize_directory_separators
* @covers ::normalize_directory_separators
*
* @param string $input The input string.
* @param string $expected The expected function output.
*
* @return void
*/
public function test_normalize_directory_separators( $input, $expected ) {
$this->assertSame( $expected, PathHelper::normalize_directory_separators( $input ) );
}

/**
* Data provider.
*
* @see test_normalize_directory_separators() For the array format.
*
* @return array<string, array<string, string>>
*/
public static function data_normalize_directory_separators() {
return [
'path is dot' => [
'input' => '.',
'expected' => '.',
],
'path containing forward slashes only' => [
'input' => 'my/path/to/',
'expected' => 'my/path/to/',
],
'path containing back-slashes only' => [
'input' => 'my\path\to\\',
'expected' => 'my/path/to/',
],
'path containing a mix of forward and backslashes' => [
'input' => 'my\path/to\\',
'expected' => 'my/path/to/',
],
];
}

/**
* Test ensuring that a directory path does not start with a leading slash.
*
* @dataProvider data_remove_leading_slash
* @covers ::remove_leading_slash
*
* @param string $input The input string.
* @param string $expected The expected function output.
*
* @return void
*/
public function test_remove_leading_slash( $input, $expected ) {
$this->assertSame( $expected, PathHelper::remove_leading_slash( $input ) );
}

/**
* Data provider.
*
* @see test_remove_leading_slash() For the array format.
*
* @return array<string, array<string, string>>
*/
public static function data_remove_leading_slash() {
return [
'path is dot' => [
'input' => '.',
'expected' => '.',
],
'path with leading forward slash' => [
'input' => '/my/path/to/',
'expected' => 'my/path/to/',
],
'path with leading back slash' => [
'input' => '\my\path\to',
'expected' => 'my\path\to',
],
'path without leading slash' => [
'input' => 'my/path/to',
'expected' => 'my/path/to',
],
'path to a file with leading slash' => [
'input' => '/file.ext',
'expected' => 'file.ext',
],
];
}

/**
* Test ensuring that a directory path ends on a trailing slash.
*
* @dataProvider data_trailingslashit
* @covers ::trailingslashit
*
* @param string|bool $input The input string.
* @param string $expected The expected function output.
*
* @return void
*/
public function test_trailingslashit( $input, $expected ) {
$this->assertSame( $expected, PathHelper::trailingslashit( $input ) );
}

/**
* Data provider.
*
* @see test_trailingslashit() For the array format.
*
* @return array<string, array<string, string|bool>>
*/
public static function data_trailingslashit() {
return [
'path is non-string' => [
'input' => false,
'expected' => '',
],
'path is empty string' => [
'input' => '',
'expected' => '',
],
'path is dot' => [
'input' => '.',
'expected' => './',
],
'path with trailing forward slash' => [
'input' => 'my/path/to/',
'expected' => 'my/path/to/',
],
'path with trailing back slash' => [
'input' => 'my\path\to\\',
'expected' => 'my\path\to/',
],
'path without trailing slash' => [
'input' => 'my/path/to',
'expected' => 'my/path/to/',
],
'path to a file with an extension' => [
'input' => 'my/path/to/filename.ext',
'expected' => 'my/path/to/filename.ext',
],
'path to a dot file' => [
'input' => 'my/path/to/.gitignore',
'expected' => 'my/path/to/.gitignore',
],
'path ending on a dot' => [
'input' => 'my/path/to/dot.',
'expected' => 'my/path/to/dot./',
],
'path with trailing forward slash and the last dir contains a dot' => [
'input' => 'my/path/to.ext/',
'expected' => 'my/path/to.ext/',
],
];
}

/**
* Test stripping one path from the start of another path.
*
* @dataProvider data_strip_basepath
* @covers ::strip_basepath
*
* @param string $path The path of the file.
* @param string $basepath The base path to remove.
* @param string $expected The expected function output.
*
* @return void
*/
public function test_strip_basepath( $path, $basepath, $expected ) {
$this->assertSame( $expected, PathHelper::strip_basepath( $path, $basepath ) );
}

/**
* Data provider.
*
* @see test_strip_basepath() For the array format.
*
* @return array<string, array<string, string>>
*/
public static function data_strip_basepath() {
return [
'basepath is empty' => [
'path' => '/my/path/too/',
'basepath' => '',
'expected' => '/my/path/too/',
],
'path NOT starting with other path' => [
'path' => '/my/path/too/',
'basepath' => '/my/path/to/',
'expected' => '/my/path/too/',
],
'path equal to other path, forward slashes' => [
'path' => '/my/path/to/',
'basepath' => '/my/path/to/',
'expected' => '.',
],
'path starting with other path, forward slashes' => [
'path' => '/my/path/to/some/sub/directory',
'basepath' => '/my/path/to/',
'expected' => 'some/sub/directory',
],
'path equal to other path, forward slashes, basepath does not end on slash' => [
'path' => '/my/path/to/',
'basepath' => '/my/path/to',
'expected' => '.',
],
'path starting with other path, forward slashes, basepath does not end on slash' => [
'path' => '/my/path/to/some/sub/file.ext',
'basepath' => '/my/path/to',
'expected' => 'some/sub/file.ext',
],
'path equal to other path, back slashes' => [
'path' => 'C:\my\path\to\\',
'basepath' => 'C:\my\path\to\\',
'expected' => '.',
],
'path starting with other path, back slashes' => [
'path' => 'C:\my\path\to\some\sub\directory',
'basepath' => 'C:\my\path\to\\',
'expected' => 'some\sub\directory',
],
'path equal to other path, back slashes, basepath does not end on slash' => [
'path' => 'C:\my\path\to\\',
'basepath' => 'C:\my\path\to',
'expected' => '.',
],
'path starting with other path, back slashes, basepath does not end on slash' => [
'path' => 'C:\my\path\to\some\sub\directory',
'basepath' => 'C:\my\path\to',
'expected' => 'some\sub\directory',
],
];
}

/**
* Test verifying whether a certain path starts with another path.
*
* @dataProvider data_path_starts_with
* @covers ::path_starts_with
*
* @param string $haystack Directory path to search in.
* @param string $needle Path the haystack path should start with.
* @param string $expected The expected function output.
*
* @return void
*/
public function test_path_starts_with( $haystack, $needle, $expected ) {
$this->assertSame( $expected, PathHelper::path_starts_with( $haystack, $needle ) );
}

/**
* Data provider.
*
* @see test_path_starts_with() For the array format.
*
* @return array<string, array<string, string|bool>>
*/
public static function data_path_starts_with() {
return [
'path equal to other path, forward slashes' => [
'haystack' => '/my/path/to/',
'needle' => '/my/path/to/',
'expected' => true,
],
'path starting with other path, forward slashes' => [
'haystack' => '/my/path/to/some/sub/directory',
'needle' => '/my/path/to/',
'expected' => true,
],
'path equal to other path, back slashes' => [
'haystack' => 'C:\my\path\to\\',
'needle' => 'C:\my\path\to\\',
'expected' => true,
],
'path starting with other path, back slashes' => [
'haystack' => 'C:\my\path\to\some\sub\directory',
'needle' => 'C:\my\path\to\\',
'expected' => true,
],
'path starting with other path, but slashes are different' => [
'haystack' => '\my\path\to\some\sub\directory',
'needle' => '/my/path/to/',
'expected' => false,
],
'path starting with other path, but case is different' => [
'haystack' => '/My/path/To/some/Sub/directory',
'needle' => '/my/path/to/',
'expected' => false,
],
'path NOT starting with other path, forward slashes' => [
'haystack' => '/my/path/too/some/sub/directory',
'needle' => '/my/path/to/',
'expected' => false,
],
'path NOT starting with other path, back slashes' => [
'haystack' => 'C:\my\path\too\some\sub\directory',
'needle' => 'C:\my\path\to\\',
'expected' => false,
],
'completely different paths' => [
'haystack' => '/your/subdir/',
'needle' => 'my/path/to/',
'expected' => false,
],
];
}
}
Loading

0 comments on commit b09ea19

Please sign in to comment.