# # # patch "paths.cc" # from [739c98e9f973a674309edcab5f596aec4c130992] # to [e11b32810ac1b029fe63d8faf7d9fa054dfded65] # # patch "tests/listing_workspace_manifests/__driver__.lua" # from [2a0a4649b1e147bfe14eb15666ce1ff47aa77a23] # to [7366ca38f9de3a2a3a0d0636e714c66b5e63c614] # # patch "tests/ls_unknown_in_subdir/__driver__.lua" # from [2d2da6ec91b788419c052f7f8e9168253269589a] # to [5a6c9bfa9fede61c1d1a5949b8c1f7fc515f5cf6] # # patch "tests/revert_--missing_in_subdir/__driver__.lua" # from [09a2b97131c6bde5a6eb952074f413d1fbba00a8] # to [475edca519499f39558e229bf5c9f8bbf0167b3e] # # patch "tests/subdirectory_restrictions/__driver__.lua" # from [1e4ce8ba438a4d1fd2e5725bb77d51bd44b5f28f] # to [5b95ef7f9f71d0c7fe442677550f244dd66fcd34] # # patch "tests/two_parent_workspace_list/__driver__.lua" # from [65c50373573076490512bf8852e35bb671f34ff7] # to [864b67fd31928331c5f849129f9bdb8e2448f22f] # ============================================================ --- paths.cc 739c98e9f973a674309edcab5f596aec4c130992 +++ paths.cc e11b32810ac1b029fe63d8faf7d9fa054dfded65 @@ -151,7 +151,7 @@ has_bad_component_chars(string const & p return true; } return false; - + } static bool @@ -298,7 +298,7 @@ normalize_path(string const & in) } } #endif - + I(!is_absolute_here(inT)); if (inT.size() == 0) return leader; @@ -587,7 +587,7 @@ file_path::dirname_basename(file_path & dir = file_path(); base = path_component(s, 0); } - else + else { I(sep < s.size() - 1); // last component must have at least one char dir = file_path(s, 0, sep); @@ -635,13 +635,15 @@ file_path::as_relative() const string file_path::as_relative() const { - I(initial_rel_path.initialized); + + if (!initial_rel_path.initialized) + return as_internal(); string base = initial_rel_path.get_but_unused(); string::size_type prefix = 0; - while (prefix < data.length() && - prefix < base.length() && + while (prefix < data.length() && + prefix < base.length() && data[prefix] == base[prefix]) ++prefix; @@ -649,19 +651,19 @@ file_path::as_relative() const { // possible match, back up to the last / character while (prefix > 0 && (base[prefix] != '/' || data[prefix] != '/')) - --prefix; + --prefix; } else if (prefix >= data.length() && prefix < base.length()) { // base path below this path while (prefix > 0 && base[prefix] != '/') - --prefix; + --prefix; } else if (prefix < data.length() && prefix >= base.length()) { // this path below base path while (prefix > 0 && data[prefix] != '/') - --prefix; + --prefix; } // else exact match of entire string @@ -686,21 +688,21 @@ file_path::as_relative() const if (base_suffix < base.length()) relative.append(".."); for (string::size_type i = base_suffix; i < base.length(); i++) - if (base[i] == '/') + if (base[i] == '/') relative.append("/.."); // down into this path's directories if (data_suffix < data.length()) { - if (!relative.empty()) + if (!relative.empty()) relative.append("/"); relative.append(data.substr(data_suffix)); } // special case for the root directory - if (relative.empty()) + if (relative.empty()) relative.append("."); // FIXME: this should probably return a string in the user's charset @@ -928,7 +930,7 @@ find_bookdir(system_path const & root, p goto found; } return false; - + found: // check for _MTN/. and _MTN/.. to see if mt dir is readable try @@ -991,7 +993,7 @@ find_and_go_to_workspace(string const & F("search root '%s' does not exist") % root, F("search root '%s' is not a directory") % root); } - + // first look for the current name of the bookkeeping directory. // if we don't find it, look for it under the old name, so that // migration has a chance to work. @@ -1056,7 +1058,7 @@ UNIT_TEST(paths, path_component) "_MTN", 0 }; - + for (char const * const * c = baddies; *c; ++c) { // the comparison prevents the compiler from eliminating the @@ -1072,8 +1074,8 @@ UNIT_TEST(paths, path_component) UNIT_TEST_CHECK_THROW(file_path_internal("foo") / path_component(), logic_error); } - + UNIT_TEST(paths, file_path_internal) { char const * const baddies[] = {"/foo", @@ -1388,7 +1390,7 @@ UNIT_TEST(paths, basename) FL("basename('%s') = '%s' (expect '%s')") % p->in % pc % p->out); } - + UNIT_TEST_CHECKPOINT("bookkeeping_path basenames"); for (struct t const *p = bp_cases; p->in; p++) { @@ -1404,7 +1406,7 @@ UNIT_TEST(paths, basename) initial_abs_path.unset(); initial_abs_path.set(system_path("/a/b"), true); - + for (struct t const *p = sp_cases; p->in; p++) { system_path fp(p->in); @@ -1491,7 +1493,7 @@ UNIT_TEST(paths, dirname) }; initial_abs_path.unset(); - + UNIT_TEST_CHECKPOINT("file_path dirnames"); for (struct t const *p = fp_cases; p->in; p++) { @@ -1838,7 +1840,7 @@ UNIT_TEST(paths, ordering_random) do b = rng.uniform(0x7f - 0x20) + 0x20; while (b == 0x5c || b == 0x2f || b == 0x2e); // '\\', '/', '.' - + do c = rng.uniform(0x7f - 0x20) + 0x20; while (c == 0x5c || c == 0x2f || c == 0x2e); // '\\', '/', '.' @@ -1871,8 +1873,8 @@ UNIT_TEST(paths, ordering_random) do d = rng.uniform(0x7f - 0x20) + 0x20; while (d == 0x5c || d == 0x2f || d == 0x2e); // '\\', '/', '.' - + x[0] = a; x[1] = b; y[0] = c; @@ -1886,7 +1888,7 @@ UNIT_TEST(paths, ordering_random) test_path_less_than(y, x); } - + UNIT_TEST_CHECKPOINT("a/b and c/d"); x[1] = '/'; for (i = 0; i < ntrials; i++) @@ -1896,7 +1898,7 @@ UNIT_TEST(paths, ordering_random) do b = rng.uniform(0x7f - 0x20) + 0x20; while (b == 0x5c || b == 0x2f || b == 0x2e); // '\\', '/', '.' - + do c = rng.uniform(0x7f - 0x20) + 0x20; while (c == 0x5c || c == 0x2f || c == 0x2e); // '\\', '/', '.' @@ -2003,6 +2005,50 @@ UNIT_TEST(paths, test_external_string_is ::external_string_is_bookkeeping_path(utf8(std::string(*c)))); } +static void +check_relative_path(string const & path, string const & base, string const & expected) +{ + initial_rel_path.set(string(base), true); + file_path test = file_path_internal(path); + string actual = test.as_relative(); + + UNIT_TEST_CHECK_MSG(test.as_relative() == expected, + FL("'%s' relative to '%s' was '%s' expected '%s'") + % path + % base + % test.as_relative() + % expected); + +} + +UNIT_TEST(paths, relative) +{ + // exact matches + check_relative_path("", "", "."); + check_relative_path("a", "a", "."); + check_relative_path("a/b", "a/b", "."); + + // data below base + check_relative_path("a", "", "a"); + check_relative_path("a/b/c", "a", "b/c"); + check_relative_path("a/b/c", "a/b", "c"); + check_relative_path("a/b/c", "a/b/c", "."); + + // data above base + check_relative_path("", "a/b/c", "../../.."); + check_relative_path("a", "a/b/c", "../.."); + check_relative_path("a/b", "a/b/c", ".."); + check_relative_path("a/b/c", "a/b/c", "."); + + check_relative_path("hello", "goodbye", "../hello"); + check_relative_path("foobarbaz", "foobar/baz", "../../foobarbaz"); + check_relative_path("a/b/c/d/e/f", "a/b/c/d/e/x", "../f"); + check_relative_path("a/b/c", "a/y/z", "../../b/c"); + check_relative_path("a/b/c", "x/y/z", "../../../a/b/c"); + check_relative_path("foo/bar/baz", "foo/bar/fud", "../baz"); +} + + #endif // BUILD_UNIT_TESTS // Local Variables: ============================================================ --- tests/listing_workspace_manifests/__driver__.lua 2a0a4649b1e147bfe14eb15666ce1ff47aa77a23 +++ tests/listing_workspace_manifests/__driver__.lua 7366ca38f9de3a2a3a0d0636e714c66b5e63c614 @@ -8,7 +8,7 @@ check(mtn("ls", "known"), 0, true) check(mtn("add", "foo", "bar"), 0, false, false) check(mtn("ls", "known"), 0, true) -check(sort("stdout"), 0, "bar\nfoo\n") +check(sort("stdout"), 0, ".\nbar\nfoo\n") mkdir("dir") writefile("dir/foo", "the foo file") @@ -16,16 +16,16 @@ check(mtn("ls", "known"), 0, true) check(mtn("add", "dir/foo", "dir/bar"), 0, false, false) check(mtn("ls", "known"), 0, true) -check(sort("stdout"), 0, "bar\ndir\ndir/bar\ndir/foo\nfoo\n") +check(sort("stdout"), 0, ".\nbar\ndir\ndir/bar\ndir/foo\nfoo\n") check(mtn("--branch=testbranch", "commit", "--message=committed"), 0, false, false) check(mtn("ls", "known"), 0, true) -check(sort("stdout"), 0, "bar\ndir\ndir/bar\ndir/foo\nfoo\n") +check(sort("stdout"), 0, ".\nbar\ndir\ndir/bar\ndir/foo\nfoo\n") check(mtn("drop", "--bookkeep-only", "foo"), 0, false, false) check(mtn("rename", "dir", "dir2"), 0, false, false) check(mtn("rename", "bar", "baz"), 0, false, false) check(mtn("ls", "known"), 0, true) +check(sort("stdout"), 0, ".\nbaz\ndir2\ndir2/bar\ndir2/foo\n") -check(sort("stdout"), 0, "baz\ndir2\ndir2/bar\ndir2/foo\n") ============================================================ --- tests/ls_unknown_in_subdir/__driver__.lua 2d2da6ec91b788419c052f7f8e9168253269589a +++ tests/ls_unknown_in_subdir/__driver__.lua 5a6c9bfa9fede61c1d1a5949b8c1f7fc515f5cf6 @@ -11,7 +11,7 @@ check(indir("foo", mtn("ls", "unknown")) check(not qgrep('foo/b$', "stdout")) check(indir("foo", mtn("ls", "unknown")), 0, true, false) -check(qgrep('foo$', "stdout")) -check(not qgrep('foo/a$', "stdout")) -check(not qgrep('foo/b$', "stdout")) +check(qgrep('^\.$', "stdout")) +check(not qgrep('^a$', "stdout")) +check(not qgrep('^b$', "stdout")) ============================================================ --- tests/revert_--missing_in_subdir/__driver__.lua 09a2b97131c6bde5a6eb952074f413d1fbba00a8 +++ tests/revert_--missing_in_subdir/__driver__.lua 475edca519499f39558e229bf5c9f8bbf0167b3e @@ -11,7 +11,7 @@ check(mtn("ls", "missing"), 0, true, fal remove("testdir/testfile2") chdir("testdir") check(mtn("ls", "missing"), 0, true, false) -check(samelines("stdout", {"testdir/testfile2", "testfile1"})) +check(samelines("stdout", {"../testfile1", "testfile2"})) check(mtn("revert", "--missing", "."), 0, false, false) check(not exists("../testfile1")) ============================================================ --- tests/subdirectory_restrictions/__driver__.lua 1e4ce8ba438a4d1fd2e5725bb77d51bd44b5f28f +++ tests/subdirectory_restrictions/__driver__.lua 5b95ef7f9f71d0c7fe442677550f244dd66fcd34 @@ -30,30 +30,30 @@ check(mtn("--norc", "status"), 0, true) chdir("foo") check(mtn("--norc", "status"), 0, true) -check(qgrep("foo/foo", "stdout")) -check(qgrep("bar/bar", "stdout")) +check(qgrep("foo", "stdout")) +check(qgrep("../bar/bar", "stdout")) check(mtn("--norc", "status", "."), 0, true) -check(qgrep("foo/foo", "stdout")) +check(qgrep("foo", "stdout")) check(not qgrep("bar/bar", "stdout")) check(mtn("--norc", "status", ".."), 0, true) -check(qgrep("foo/foo", "stdout")) -check(qgrep("bar/bar", "stdout")) +check(qgrep("foo", "stdout")) +check(qgrep("../bar/bar", "stdout")) chdir("..") chdir("bar") check(mtn("--norc", "status"), 0, true) -check(qgrep("foo/foo", "stdout")) -check(qgrep("bar/bar", "stdout")) +check(qgrep("../foo/foo", "stdout")) +check(qgrep("bar", "stdout")) check(mtn("--norc", "status", "."), 0, true) -check(not qgrep("foo/foo", "stdout")) -check(qgrep("bar/bar", "stdout")) +check(not qgrep("foo", "stdout")) +check(qgrep("bar", "stdout")) check(mtn("--norc", "status", ".."), 0, true) -check(qgrep("foo/foo", "stdout")) -check(qgrep("bar/bar", "stdout")) +check(qgrep("../foo/foo", "stdout")) +check(qgrep("bar", "stdout")) chdir("..") -- TODO: test a.c a.h a/foo.c a/foo.h from inside and outside of a ============================================================ --- tests/two_parent_workspace_list/__driver__.lua 65c50373573076490512bf8852e35bb671f34ff7 +++ tests/two_parent_workspace_list/__driver__.lua 864b67fd31928331c5f849129f9bdb8e2448f22f @@ -23,7 +23,7 @@ check(mtn("ls", "changed"), 0, "file1\nf check(mtn("merge_into_workspace", left), 0, false, false) check(mtn("ls", "changed"), 0, "file1\nfile2\nfile3\n", nil) -check(mtn("ls", "known"), 0, "file1\nfile2\nfile3\nfile4\n", nil) +check(mtn("ls", "known"), 0, ".\nfile1\nfile2\nfile3\nfile4\n", nil) -- these rely on the precise set of junk files that the test suite -- dumps into the current directory, and on the fact that it doesn't