1#!/usr/bin/env python3 2# 3# Copyright (C) 2022 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import unittest 18 19import os 20from pathlib import Path 21from tempfile import TemporaryDirectory 22 23from finder import FileFinder 24 25FILENAME = "myfile.json" 26 27 28def _create_file(root: str, rel_dir_path: str, filename: str): 29 """Helper function to create an empty file in a test directory""" 30 if ".." in rel_dir_path: 31 raise Exception(f".. is not allowed in {rel_dir_path}") 32 # Create the directory if it is does not exist 33 dirpath = os.path.join(root, rel_dir_path) 34 os.makedirs(dirpath, exist_ok=True) 35 # Create an empty file in the newly created directory 36 filepath = os.path.join(dirpath, filename) 37 Path(filepath).touch() 38 39 40class TestFileFinder(unittest.TestCase): 41 def test_single_file_match(self): 42 finder = FileFinder(FILENAME) 43 # root dir 44 with TemporaryDirectory() as tmp: 45 _create_file(tmp, "", FILENAME) 46 _create_file(tmp, "", "some_other_file.json") 47 results = list(finder.find(tmp, search_depth=100)) 48 self.assertEqual(1, len(results)) 49 self.assertEqual(f"{tmp}/{FILENAME}", results[0]) 50 # nested dir 51 with TemporaryDirectory() as tmp: 52 _create_file(tmp, "a/b/c", FILENAME) 53 results = list(finder.find(tmp, search_depth=100)) 54 self.assertEqual(1, len(results)) 55 self.assertEqual(f"{tmp}/a/b/c/{FILENAME}", results[0]) 56 57 def test_multiple_file_matches(self): 58 finder = FileFinder(FILENAME) 59 with TemporaryDirectory() as tmp: 60 _create_file(tmp, "a", FILENAME) 61 _create_file(tmp, "a/b", FILENAME) 62 all_results = sorted(list(finder.find(tmp, search_depth=100)), 63 reverse=True) 64 self.assertEqual(2, len(all_results)) 65 self.assertEqual(f"{tmp}/a/{FILENAME}", all_results[0]) 66 self.assertEqual(f"{tmp}/a/b/{FILENAME}", all_results[1]) 67 68 def test_find_does_not_escape_directory(self): 69 finder = FileFinder(FILENAME) 70 with TemporaryDirectory() as tmp: 71 _create_file(tmp, "", FILENAME) 72 _create_file(tmp, "a", FILENAME) 73 _create_file(tmp, "b", FILENAME) 74 search_dir_a_results = list( 75 finder.find(f"{tmp}/a", search_depth=100)) 76 self.assertEqual(1, len(search_dir_a_results)) 77 self.assertEqual(f"{tmp}/a/{FILENAME}", search_dir_a_results[0]) 78 79 def test_depth_pruning(self): 80 finder = FileFinder(FILENAME) 81 with TemporaryDirectory() as tmp: 82 _create_file(tmp, "", FILENAME) 83 _create_file(tmp, "a", FILENAME) 84 _create_file(tmp, "a/b", FILENAME) 85 self.assertEqual(3, len(list(finder.find(tmp, 3)))) 86 self.assertEqual(3, len(list(finder.find(tmp, 2)))) 87 self.assertEqual(2, len(list(finder.find(tmp, 1)))) 88 self.assertEqual(1, len(list(finder.find(tmp, 0)))) 89 90 def test_path_pruning(self): 91 with TemporaryDirectory() as tmp: 92 finder = FileFinder(FILENAME, ignore_paths=[f"{tmp}/out"]) 93 _create_file(tmp, "", FILENAME) 94 _create_file(tmp, "out", 95 FILENAME) # This should not appear in results 96 _create_file( 97 tmp, "a/b/out", 98 FILENAME) # This is "source code", should appear in results 99 results = sorted(list(finder.find(tmp, search_depth=100)), 100 reverse=True) 101 self.assertEqual(2, len(results)) 102 self.assertEqual(f"{tmp}/{FILENAME}", results[0]) 103 self.assertEqual(f"{tmp}/a/b/out/{FILENAME}", results[1]) 104 105 def test_hidden_dir_pruning(self): 106 prune_hidden_dir_finder = FileFinder(FILENAME) 107 all_dir_finder = FileFinder(FILENAME, prune_hidden_dirs=False) 108 with TemporaryDirectory() as tmp: 109 _create_file(tmp, "", FILENAME) 110 _create_file(tmp, ".hidden_dir", FILENAME) 111 _create_file(tmp, "visible_dir", FILENAME) 112 self.assertEqual( 113 2, 114 len(list(prune_hidden_dir_finder.find(tmp, search_depth=100)))) 115 self.assertEqual( 116 3, len(list(all_dir_finder.find(tmp, search_depth=100)))) 117 118 119if __name__ == "__main__": 120 # This unit test assumes that the file separator is / 121 # A generic solution would use os.path.join to join path fragments and make 122 # this test platform agnostic, but would make the test less readable. 123 if os.name != "posix": 124 raise Exception(f"This unit test is not supported on {os.name}") 125 unittest.main() 126