1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "utils/source_path_utils.h"
16
17 #include <android-base/file.h>
18 #include <gtest/gtest.h>
19
20 #include <filesystem>
21 #include <vector>
22
23 namespace header_checker {
24 namespace utils {
25
TEST(SourcePathUtilsTest,CollectAllExportedHeaders)26 TEST(SourcePathUtilsTest, CollectAllExportedHeaders) {
27 TemporaryDir temp_dir;
28 std::error_code ec;
29 // Prepare a header directory containing links, hidden files, etc.
30 const std::filesystem::path header_dir =
31 std::filesystem::path(temp_dir.path) / "include";
32 ASSERT_TRUE(std::filesystem::create_directory(header_dir, ec));
33 ASSERT_FALSE(ec);
34
35 const std::filesystem::path header = header_dir / "header.h";
36 ASSERT_TRUE(android::base::WriteStringToFile("// test", header));
37
38 const std::filesystem::path no_ext_header = header_dir / "header";
39 ASSERT_TRUE(android::base::WriteStringToFile("// test", no_ext_header));
40
41 const std::filesystem::path subdir = header_dir / "subdir";
42 ASSERT_TRUE(std::filesystem::create_directory(subdir, ec));
43 ASSERT_FALSE(ec);
44
45 const std::filesystem::path subdir_link = header_dir / "subdir_link";
46 std::filesystem::create_directory_symlink(subdir, subdir_link, ec);
47 ASSERT_FALSE(ec);
48
49 const std::filesystem::path hidden_subdir_link = header_dir / ".subdir_link";
50 std::filesystem::create_directory_symlink(subdir, hidden_subdir_link, ec);
51 ASSERT_FALSE(ec);
52
53 const std::filesystem::path header_link = subdir / "header_link.h";
54 std::filesystem::create_symlink(header, header_link, ec);
55 ASSERT_FALSE(ec);
56
57 const std::filesystem::path hidden_header_link = subdir / ".header_link.h";
58 std::filesystem::create_symlink(header, hidden_header_link, ec);
59 ASSERT_FALSE(ec);
60
61 const std::filesystem::path non_header_link = subdir / "header_link.txt";
62 std::filesystem::create_symlink(header, non_header_link, ec);
63 ASSERT_FALSE(ec);
64 // Prepare a header directory like libc++.
65 const std::filesystem::path libcxx_dir =
66 std::filesystem::path(temp_dir.path) / "libcxx" / "include";
67 ASSERT_TRUE(std::filesystem::create_directories(libcxx_dir, ec));
68 ASSERT_FALSE(ec);
69
70 const std::filesystem::path libcxx_header = libcxx_dir / "array";
71 ASSERT_TRUE(android::base::WriteStringToFile("// test", libcxx_header));
72 // Test the function.
73 std::vector<std::string> exported_header_dirs{header_dir, libcxx_dir};
74 std::vector<RootDir> root_dirs{{header_dir, "include"},
75 {libcxx_dir, "libcxx"}};
76 std::set<std::string> headers =
77 CollectAllExportedHeaders(exported_header_dirs, root_dirs);
78
79 std::set<std::string> expected_headers{
80 "include/header.h", "include/subdir/header_link.h",
81 "include/subdir_link/header_link.h", "libcxx/array"};
82 ASSERT_EQ(headers, expected_headers);
83 }
84
TEST(SourcePathUtilsTest,NormalizeAbsolutePaths)85 TEST(SourcePathUtilsTest, NormalizeAbsolutePaths) {
86 const std::vector<std::string> args{"/root/dir"};
87 const RootDirs root_dirs = ParseRootDirs(args);
88 ASSERT_EQ(1, root_dirs.size());
89 ASSERT_EQ("/root/dir", root_dirs[0].path);
90 ASSERT_EQ("", root_dirs[0].replacement);
91
92 EXPECT_EQ("", NormalizePath("/root/dir", root_dirs));
93 EXPECT_EQ("test", NormalizePath("/root/dir/test", root_dirs));
94 EXPECT_EQ("/root/unit/test",
95 NormalizePath("/root/dir/../unit/test", root_dirs));
96 }
97
98
TEST(SourcePathUtilsTest,NormalizeCwdPaths)99 TEST(SourcePathUtilsTest, NormalizeCwdPaths) {
100 const RootDirs cwd = ParseRootDirs(std::vector<std::string>());
101 ASSERT_EQ(1, cwd.size());
102 ASSERT_NE("", cwd[0].path);
103 ASSERT_EQ("", cwd[0].replacement);
104
105 EXPECT_EQ("", NormalizePath("", cwd));
106 EXPECT_EQ("unit/test", NormalizePath("./unit/test/.", cwd));
107 EXPECT_EQ("unit/test", NormalizePath("unit//test//", cwd));
108 EXPECT_EQ("test", NormalizePath("unit/../test", cwd));
109 EXPECT_EQ("unit/test", NormalizePath(cwd[0].path + "/unit/test", cwd));
110 EXPECT_EQ('/', NormalizePath("../unit/test", cwd)[0]);
111 }
112
113
TEST(SourcePathUtilsTest,NormalizePathsWithMultipleRootDirs)114 TEST(SourcePathUtilsTest, NormalizePathsWithMultipleRootDirs) {
115 const std::vector<std::string> args{"/before:/", "/before/dir:after"};
116 const RootDirs root_dirs = ParseRootDirs(args);
117 ASSERT_EQ(2, root_dirs.size());
118 ASSERT_EQ("/before/dir", root_dirs[0].path);
119 ASSERT_EQ("after", root_dirs[0].replacement);
120 ASSERT_EQ("/before", root_dirs[1].path);
121 ASSERT_EQ("/", root_dirs[1].replacement);
122
123 EXPECT_EQ("/directory", NormalizePath("/before/directory", root_dirs));
124 EXPECT_EQ("after", NormalizePath("/before/dir", root_dirs));
125 }
126
127
TEST(SourcePathUtilsTest,NormalizeRelativePaths)128 TEST(SourcePathUtilsTest, NormalizeRelativePaths) {
129 const std::vector<std::string> args{"../before/.:..//after/."};
130 const RootDirs root_dirs = ParseRootDirs(args);
131 ASSERT_EQ(1, root_dirs.size());
132 ASSERT_EQ('/', root_dirs[0].path[0]);
133 ASSERT_EQ("../after", root_dirs[0].replacement);
134
135 EXPECT_EQ("../after", NormalizePath("../before", root_dirs));
136 }
137
138
139 } // namespace utils
140 } // namespace header_checker
141