1# Copyright 2017 The Bazel Authors. All rights reserved. 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"""Unit tests for paths.bzl.""" 16 17load("//lib:paths.bzl", "paths") 18load("//lib:unittest.bzl", "asserts", "unittest") 19 20def _basename_test(ctx): 21 """Unit tests for paths.basename.""" 22 env = unittest.begin(ctx) 23 24 # Verify some degenerate cases. 25 asserts.equals(env, "", paths.basename("")) 26 asserts.equals(env, "", paths.basename("/")) 27 asserts.equals(env, "bar", paths.basename("foo///bar")) 28 29 # Verify some realistic cases. 30 asserts.equals(env, "foo", paths.basename("foo")) 31 asserts.equals(env, "foo", paths.basename("/foo")) 32 asserts.equals(env, "foo", paths.basename("bar/foo")) 33 asserts.equals(env, "foo", paths.basename("/bar/foo")) 34 35 # Verify that we correctly duplicate Python's os.path.basename behavior, 36 # where a trailing slash means the basename is empty. 37 asserts.equals(env, "", paths.basename("foo/")) 38 asserts.equals(env, "", paths.basename("/foo/")) 39 40 return unittest.end(env) 41 42basename_test = unittest.make(_basename_test) 43 44def _dirname_test(ctx): 45 """Unit tests for paths.dirname.""" 46 env = unittest.begin(ctx) 47 48 # Verify some degenerate cases. 49 asserts.equals(env, "", paths.dirname("")) 50 asserts.equals(env, "/", paths.dirname("/")) 51 asserts.equals(env, "foo", paths.dirname("foo///bar")) 52 53 # Verify some realistic cases. 54 asserts.equals(env, "", paths.dirname("foo")) 55 asserts.equals(env, "/", paths.dirname("/foo")) 56 asserts.equals(env, "bar", paths.dirname("bar/foo")) 57 asserts.equals(env, "/bar", paths.dirname("/bar/foo")) 58 59 # Verify that we correctly duplicate Python's os.path.dirname behavior, 60 # where a trailing slash means the dirname is the same as the original 61 # path (without the trailing slash). 62 asserts.equals(env, "foo", paths.dirname("foo/")) 63 asserts.equals(env, "/foo", paths.dirname("/foo/")) 64 65 return unittest.end(env) 66 67dirname_test = unittest.make(_dirname_test) 68 69def _is_absolute_test(ctx): 70 """Unit tests for paths.is_absolute.""" 71 env = unittest.begin(ctx) 72 73 # Try a degenerate case. 74 asserts.false(env, paths.is_absolute("")) 75 76 # Try some relative paths. 77 asserts.false(env, paths.is_absolute("foo")) 78 asserts.false(env, paths.is_absolute("foo/")) 79 asserts.false(env, paths.is_absolute("foo/bar")) 80 81 # Try some Linux absolute paths. 82 asserts.true(env, paths.is_absolute("/")) 83 asserts.true(env, paths.is_absolute("/foo")) 84 asserts.true(env, paths.is_absolute("/foo/")) 85 asserts.true(env, paths.is_absolute("/foo/bar")) 86 87 # Try some Windows absolute paths. 88 asserts.true(env, paths.is_absolute("D:\\")) 89 asserts.true(env, paths.is_absolute("C:\\")) 90 asserts.true(env, paths.is_absolute("C:\\foo")) 91 asserts.true(env, paths.is_absolute("C:\\foo\\bar")) 92 93 return unittest.end(env) 94 95is_absolute_test = unittest.make(_is_absolute_test) 96 97def _join_test(ctx): 98 """Unit tests for paths.join.""" 99 env = unittest.begin(ctx) 100 101 # Try a degenerate case. 102 asserts.equals(env, "", paths.join("")) 103 104 # Try some basic paths. 105 asserts.equals(env, "foo", paths.join("foo")) 106 asserts.equals(env, "foo/bar", paths.join("foo", "bar")) 107 asserts.equals(env, "foo/bar/baz", paths.join("foo", "bar", "baz")) 108 109 # Make sure an initially absolute path stays absolute. 110 asserts.equals(env, "/foo", paths.join("/foo")) 111 asserts.equals(env, "/foo/bar", paths.join("/foo", "bar")) 112 113 # Make sure an absolute path later in the list resets the result. 114 asserts.equals(env, "/baz", paths.join("foo", "bar", "/baz")) 115 asserts.equals(env, "/baz", paths.join("foo", "/bar", "/baz")) 116 asserts.equals(env, "/bar/baz", paths.join("foo", "/bar", "baz")) 117 asserts.equals(env, "/bar", paths.join("/foo", "/bar")) 118 119 # Make sure a leading empty segment doesn't make it absolute. 120 asserts.equals(env, "foo", paths.join("", "foo")) 121 122 # Try some trailing slash scenarios. 123 asserts.equals(env, "foo/", paths.join("foo", "")) 124 asserts.equals(env, "foo/", paths.join("foo/")) 125 asserts.equals(env, "foo/", paths.join("foo/", "")) 126 asserts.equals(env, "foo//", paths.join("foo//", "")) 127 asserts.equals(env, "foo//", paths.join("foo//")) 128 asserts.equals(env, "foo/bar/baz/", paths.join("foo/", "bar/", "baz", "")) 129 asserts.equals(env, "foo/bar/baz/", paths.join("foo/", "bar/", "baz/")) 130 asserts.equals(env, "foo/bar/baz/", paths.join("foo/", "bar/", "baz/", "")) 131 132 # Make sure that adjacent empty segments don't add extra path separators. 133 asserts.equals(env, "foo/", paths.join("foo", "", "")) 134 asserts.equals(env, "foo", paths.join("", "", "foo")) 135 asserts.equals(env, "foo/bar", paths.join("foo", "", "", "bar")) 136 137 return unittest.end(env) 138 139join_test = unittest.make(_join_test) 140 141def _normalize_test(ctx): 142 """Unit tests for paths.normalize.""" 143 env = unittest.begin(ctx) 144 145 # Try the most basic case. 146 asserts.equals(env, ".", paths.normalize("")) 147 148 # Try some basic adjacent-slash removal. 149 asserts.equals(env, "foo/bar", paths.normalize("foo//bar")) 150 asserts.equals(env, "foo/bar", paths.normalize("foo////bar")) 151 152 # Try some "." removal. 153 asserts.equals(env, "foo/bar", paths.normalize("foo/./bar")) 154 asserts.equals(env, "foo/bar", paths.normalize("./foo/bar")) 155 asserts.equals(env, "foo/bar", paths.normalize("foo/bar/.")) 156 asserts.equals(env, "/", paths.normalize("/.")) 157 158 # Try some ".." removal. 159 asserts.equals(env, "bar", paths.normalize("foo/../bar")) 160 asserts.equals(env, "foo", paths.normalize("foo/bar/..")) 161 asserts.equals(env, ".", paths.normalize("foo/..")) 162 asserts.equals(env, ".", paths.normalize("foo/bar/../..")) 163 asserts.equals(env, "..", paths.normalize("foo/../..")) 164 asserts.equals(env, "/", paths.normalize("/foo/../..")) 165 asserts.equals(env, "../../c", paths.normalize("a/b/../../../../c/d/..")) 166 167 # Make sure one or two initial slashes are preserved, but three or more are 168 # collapsed to a single slash. 169 asserts.equals(env, "/foo", paths.normalize("/foo")) 170 asserts.equals(env, "//foo", paths.normalize("//foo")) 171 asserts.equals(env, "/foo", paths.normalize("///foo")) 172 173 # Trailing slashes should be removed unless the entire path is a trailing 174 # slash. 175 asserts.equals(env, "/", paths.normalize("/")) 176 asserts.equals(env, "foo", paths.normalize("foo/")) 177 asserts.equals(env, "foo/bar", paths.normalize("foo/bar/")) 178 179 return unittest.end(env) 180 181normalize_test = unittest.make(_normalize_test) 182 183def _is_normalized_test(ctx): 184 """Unit tests for paths.is_normalized.""" 185 env = unittest.begin(ctx) 186 187 # Try the most basic cases. 188 asserts.true(env, paths.is_normalized("")) 189 asserts.false(env, paths.is_normalized(".")) 190 asserts.true(env, paths.is_normalized("/")) 191 asserts.true(env, paths.is_normalized("/tmp")) 192 asserts.true(env, paths.is_normalized("tmp")) 193 asserts.true(env, paths.is_normalized("c:/")) 194 asserts.false(env, paths.is_normalized("../a")) 195 asserts.false(env, paths.is_normalized("a/..")) 196 197 # Try some basic adjacent-slash removal. 198 asserts.true(env, paths.is_normalized("foo//bar")) 199 asserts.true(env, paths.is_normalized("foo////bar")) 200 201 # Try some "." removal. 202 asserts.false(env, paths.is_normalized("foo/./bar")) 203 asserts.false(env, paths.is_normalized("./foo/bar")) 204 asserts.false(env, paths.is_normalized("foo/bar/.")) 205 asserts.false(env, paths.is_normalized("/.")) 206 207 # Try some ".." removal. 208 asserts.false(env, paths.is_normalized("foo/../bar")) 209 asserts.false(env, paths.is_normalized("foo/bar/..")) 210 asserts.false(env, paths.is_normalized("foo/..")) 211 asserts.false(env, paths.is_normalized("foo/bar/../..")) 212 asserts.false(env, paths.is_normalized("foo/../..")) 213 asserts.false(env, paths.is_normalized("/foo/../..")) 214 asserts.false(env, paths.is_normalized("a/b/../../../../c/d/..")) 215 216 # Make sure one or two initial slashes are preserved, but three or more are 217 # collapsed to a single slash. 218 asserts.true(env, paths.is_normalized("/foo")) 219 asserts.true(env, paths.is_normalized("//foo")) 220 asserts.true(env, paths.is_normalized("///foo")) 221 222 # Trailing slashes should be removed unless the entire path is a trailing 223 # slash. 224 asserts.true(env, paths.is_normalized("/")) 225 asserts.true(env, paths.is_normalized("foo/")) 226 asserts.true(env, paths.is_normalized("foo/bar/")) 227 228 return unittest.end(env) 229 230is_normalized_test = unittest.make(_is_normalized_test) 231 232def _relativize_test(ctx): 233 """Unit tests for paths.relativize.""" 234 env = unittest.begin(ctx) 235 236 # Make sure that relative-to-current-directory works in all forms. 237 asserts.equals(env, "foo", paths.relativize("foo", "")) 238 asserts.equals(env, "foo", paths.relativize("foo", ".")) 239 240 # Try some regular cases. 241 asserts.equals(env, "bar", paths.relativize("foo/bar", "foo")) 242 asserts.equals(env, "baz", paths.relativize("foo/bar/baz", "foo/bar")) 243 asserts.equals(env, "bar/baz", paths.relativize("foo/bar/baz", "foo")) 244 245 # Try a case where a parent directory is normalized away. 246 asserts.equals(env, "baz", paths.relativize("foo/bar/../baz", "foo")) 247 248 # Relative paths work, as long as they share a common start. 249 asserts.equals(env, "file", paths.relativize("../foo/bar/baz/file", "../foo/bar/baz")) 250 asserts.equals(env, "baz/file", paths.relativize("../foo/bar/baz/file", "../foo/bar")) 251 252 # TODO(allevato): Test failure cases, once that is possible. 253 254 return unittest.end(env) 255 256relativize_test = unittest.make(_relativize_test) 257 258def _replace_extension_test(ctx): 259 """Unit tests for paths.replace_extension.""" 260 env = unittest.begin(ctx) 261 262 # Try some degenerate cases. 263 asserts.equals(env, ".foo", paths.replace_extension("", ".foo")) 264 asserts.equals(env, "/.foo", paths.replace_extension("/", ".foo")) 265 asserts.equals(env, "foo.bar", paths.replace_extension("foo", ".bar")) 266 267 # Try a directory with an extension and basename that doesn't have one. 268 asserts.equals( 269 env, 270 "foo.bar/baz.quux", 271 paths.replace_extension("foo.bar/baz", ".quux"), 272 ) 273 274 # Now try some things with legit extensions. 275 asserts.equals(env, "a.z", paths.replace_extension("a.b", ".z")) 276 asserts.equals(env, "a.b.z", paths.replace_extension("a.b.c", ".z")) 277 asserts.equals(env, "a/b.z", paths.replace_extension("a/b.c", ".z")) 278 asserts.equals(env, "a.b/c.z", paths.replace_extension("a.b/c.d", ".z")) 279 asserts.equals(env, ".a/b.z", paths.replace_extension(".a/b.c", ".z")) 280 asserts.equals(env, ".a.z", paths.replace_extension(".a.b", ".z")) 281 282 # Verify that we don't insert a period on the extension if none is provided. 283 asserts.equals(env, "foobaz", paths.replace_extension("foo.bar", "baz")) 284 285 return unittest.end(env) 286 287replace_extension_test = unittest.make(_replace_extension_test) 288 289def _split_extension_test(ctx): 290 """Unit tests for paths.split_extension.""" 291 env = unittest.begin(ctx) 292 293 # Try some degenerate cases. 294 asserts.equals(env, ("", ""), paths.split_extension("")) 295 asserts.equals(env, ("/", ""), paths.split_extension("/")) 296 asserts.equals(env, ("foo", ""), paths.split_extension("foo")) 297 298 # Try some paths whose basenames start with ".". 299 asserts.equals(env, (".", ""), paths.split_extension(".")) 300 asserts.equals(env, (".bashrc", ""), paths.split_extension(".bashrc")) 301 asserts.equals(env, ("foo/.bashrc", ""), paths.split_extension("foo/.bashrc")) 302 asserts.equals( 303 env, 304 (".foo/.bashrc", ""), 305 paths.split_extension(".foo/.bashrc"), 306 ) 307 308 # Try some directories with extensions with basenames that don't have one. 309 asserts.equals(env, ("foo.bar/baz", ""), paths.split_extension("foo.bar/baz")) 310 asserts.equals( 311 env, 312 ("foo.bar/.bashrc", ""), 313 paths.split_extension("foo.bar/.bashrc"), 314 ) 315 316 # Now try some things that will actually get split. 317 asserts.equals(env, ("a", ".b"), paths.split_extension("a.b")) 318 asserts.equals(env, ("a.b", ".c"), paths.split_extension("a.b.c")) 319 asserts.equals(env, ("a/b", ".c"), paths.split_extension("a/b.c")) 320 asserts.equals(env, ("a.b/c", ".d"), paths.split_extension("a.b/c.d")) 321 asserts.equals(env, (".a/b", ".c"), paths.split_extension(".a/b.c")) 322 asserts.equals(env, (".a", ".b"), paths.split_extension(".a.b")) 323 324 return unittest.end(env) 325 326split_extension_test = unittest.make(_split_extension_test) 327 328def _starts_with_test(ctx): 329 """Unit tests for paths.starts_with.""" 330 env = unittest.begin(ctx) 331 332 # Make sure that relative-to-current-directory works in all forms. 333 asserts.true(env, paths.starts_with("foo", "")) 334 asserts.false(env, paths.starts_with("foo", ".")) 335 336 # Try some regular cases. 337 asserts.true(env, paths.starts_with("foo/bar", "foo")) 338 asserts.false(env, paths.starts_with("foo/bar", "fo")) 339 asserts.true(env, paths.starts_with("foo/bar/baz", "foo/bar")) 340 asserts.true(env, paths.starts_with("foo/bar/baz", "foo")) 341 342 # Try a case where a parent directory is normalized away. 343 asserts.true(env, paths.starts_with("foo/bar/../baz", "foo")) 344 345 # Relative paths work, as long as they share a common start. 346 asserts.true(env, paths.starts_with("../foo/bar/baz/file", "../foo/bar/baz")) 347 asserts.true(env, paths.starts_with("../foo/bar/baz/file", "../foo/bar")) 348 349 return unittest.end(env) 350 351starts_with_test = unittest.make(_starts_with_test) 352 353def paths_test_suite(): 354 """Creates the test targets and test suite for paths.bzl tests.""" 355 unittest.suite( 356 "paths_tests", 357 basename_test, 358 dirname_test, 359 is_absolute_test, 360 join_test, 361 normalize_test, 362 is_normalized_test, 363 relativize_test, 364 replace_extension_test, 365 split_extension_test, 366 starts_with_test, 367 ) 368