blob: 5d4e689eebc0f5a72f82195d3bc16652bcd780fd [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path lexically_normal() const;
#include "filesystem_include.h"
#include <type_traits>
#include <vector>
#include <iostream>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.h"
#include "filesystem_test_helper.h"
int main(int, char**) {
// clang-format off
struct {
std::string input;
std::string expect;
} TestCases[] = {
{"", ""},
{"/a/b/c", "/a/b/c"},
{"/a/b//c", "/a/b/c"},
{"foo/./bar/..", "foo/"},
{"foo/.///bar/../", "foo/"},
{"/a/b/", "/a/b/"},
{"a/b", "a/b"},
{"a/b/.", "a/b/"},
{"a/b/./", "a/b/"},
{"a/..", "."},
{".", "."},
{"./", "."},
{"./.", "."},
{"./..", ".."},
{"..", ".."},
{"../..", "../.."},
{"/../", "/"},
{"/../..", "/"},
{"/../../", "/"},
{"..", ".."},
{"../", ".."},
{"/a/b/c/../", "/a/b/"},
{"/a/b/./", "/a/b/"},
{"/a/b/c/../d", "/a/b/d"},
{"/a/b/c/../d/", "/a/b/d/"},
{"//a/", "/a/"},
{"//a/b/", "/a/b/"},
{"//a/b/.", "/a/b/"},
{"//a/..", "/"},
///===---------------------------------------------------------------===//
/// Tests specifically for the clauses under [fs.path.generic]p6
///===---------------------------------------------------------------===//
// p1: If the path is empty, stop.
{"", ""},
// p2: Replace each slash character in the root-name with a preferred
// separator.
{"NO_ROOT_NAME_ON_LINUX", "NO_ROOT_NAME_ON_LINUX"},
// p3: Replace each directory-separator with a preferred-separator.
// [ Note: The generic pathname grammar ([fs.path.generic]) defines
// directory-separator as one or more slashes and preferred-separators.
// — end note ]
{"/", "/"},
{"//", "/"},
{"///", "/"},
{"a/b", "a/b"},
{"a//b", "a/b"},
{"a///b", "a/b"},
{"a/b/", "a/b/"},
{"a/b//", "a/b/"},
{"a/b///", "a/b/"},
{"///a////b//////", "/a/b/"},
// p4: Remove each dot filename and any immediately following directory
// separators
{"foo/.", "foo/"},
{"foo/./bar/.", "foo/bar/"},
{"./foo/././bar/./", "foo/bar/"},
{".///foo//.////./bar/.///", "foo/bar/"},
// p5: As long as any appear, remove a non-dot-dot filename immediately
// followed by a directory-separator and a dot-dot filename, along with
// any immediately following directory separator.
{"foo/..", "."},
{"foo/../", "."},
{"foo/bar/..", "foo/"},
{"foo/bar/../", "foo/"},
{"foo/bar/../..", "."},
{"foo/bar/../../", "."},
{"foo/bar/baz/../..", "foo/"},
{"foo/bar/baz/../../", "foo/"},
{"foo/bar/./..", "foo/"},
{"foo/bar/./../", "foo/"},
// p6: If there is a root-directory, remove all dot-dot filenames and any
// directory-separators immediately following them. [ Note: These dot-dot
// filenames attempt to refer to nonexistent parent directories. — end note ]
{"/..", "/"},
{"/../", "/"},
{"/foo/../..", "/"},
{"/../foo", "/foo"},
{"/../foo/../..", "/"},
// p7: If the last filename is dot-dot, remove any trailing
// directory-separator.
{"../", ".."},
{"../../", "../.."},
{"foo/../bar/../..///", ".."},
{"foo/../bar/..//..///../", "../.."},
// p8: If the path is empty, add a dot
{".", "."},
{"./", "."},
{"foo/..", "."}
};
// clang-format on
int ID = 0;
bool Failed = false;
for (auto& TC : TestCases) {
++ID;
fs::path p(TC.input);
const fs::path output = p.lexically_normal();
if (!PathEq(output, TC.expect)) {
Failed = true;
std::cerr << "TEST CASE #" << ID << " FAILED: \n";
std::cerr << " Input: '" << TC.input << "'\n";
std::cerr << " Expected: '" << TC.expect << "'\n";
std::cerr << " Output: '" << output.native() << "'";
std::cerr << std::endl;
}
}
return Failed;
}