diff --git a/tools/lint/lint.py b/tools/lint/lint.py index d8fb9fc35ef38d..6645e99e4f9f8a 100644 --- a/tools/lint/lint.py +++ b/tools/lint/lint.py @@ -396,6 +396,20 @@ def check_unique_testharness_basenames(repo_root, paths): return errors +def check_unique_case_insensitive_paths(repo_root, paths): + # type: (Text, List[Text]) -> List[rules.Error] + seen = {} # type: Dict[Text, Text] + errors = [] + for path in paths: + lower_path = path.lower() + if lower_path in seen: + context = (seen[lower_path],) + errors.append(rules.DuplicatePathCaseInsensitive.error(path, context)) + else: + seen[lower_path] = path + return errors + + def parse_ignorelist(f): # type: (IO[Text]) -> Tuple[Ignorelist, Set[Text]] """ @@ -1107,7 +1121,8 @@ def process_errors(errors): path_lints = [check_file_type, check_path_length, check_worker_collision, check_ahem_copy, check_mojom_js, check_tentative_directories, check_gitignore_file] -all_paths_lints = [check_css_globally_unique, check_unique_testharness_basenames] +all_paths_lints = [check_css_globally_unique, check_unique_testharness_basenames, + check_unique_case_insensitive_paths] file_lints = [check_regexp_line, check_parsed, check_python_ast, check_script_metadata, check_ahem_system_font] diff --git a/tools/lint/rules.py b/tools/lint/rules.py index e9bb30b59cff07..125adb07d7f884 100644 --- a/tools/lint/rules.py +++ b/tools/lint/rules.py @@ -359,6 +359,14 @@ class DuplicateBasenamePath(Rule): to_fix = "rename files so they have unique basename paths" +class DuplicatePathCaseInsensitive(Rule): + name = "DUPLICATE-CASE-INSENSITIVE-PATH" + description = collapse(""" + Path differs from path %s only in case + """) + to_fix = "rename files so they are unique irrespective of case" + + class TentativeDirectoryName(Rule): name = "TENTATIVE-DIRECTORY-NAME" description = "Directories for tentative tests must be named exactly 'tentative'" diff --git a/tools/lint/tests/test_path_lints.py b/tools/lint/tests/test_path_lints.py index 9fefb7a1d7e061..3706a952c61f6a 100644 --- a/tools/lint/tests/test_path_lints.py +++ b/tools/lint/tests/test_path_lints.py @@ -3,7 +3,7 @@ import mock import os -from ..lint import check_path +from ..lint import check_path, check_unique_case_insensitive_paths from .base import check_errors import pytest @@ -153,3 +153,15 @@ def test_gitignore_negative(path): errors = check_path("/foo/", path) assert errors == [] + + +@pytest.mark.parametrize("paths,errors", + [(["a/b.html", "a/B.html"], ["a/B.html"]), + (["A/b.html", "a/b.html"], ["a/b.html"]), + (["a/b.html", "a/c.html"], [])]) +def test_unique_case_insensitive_paths(paths, errors): + got_errors = check_unique_case_insensitive_paths(None, paths) + assert len(got_errors) == len(errors) + for (name, _, path, _), expected_path in zip(got_errors, errors): + assert name == "DUPLICATE-CASE-INSENSITIVE-PATH" + assert path == expected_path