teak-llvm/lldb/unittests/Utility/FileSpecTest.cpp
Pavel Labath 841bea933b Breakpad: auto-detect path style of file entries
Summary:
This adds support for auto-detection of path style to SymbolFileBreakpad
(similar to how r351328 did the same for DWARF). We guess each file
entry separately, as we have no idea which file came from which compile
units (and different compile units can have different path styles). The
breakpad generates should have already converted the paths to absolute
ones, so this guess should be reasonable accurate, but as always with
these kinds of things, it is hard to give guarantees about anything.

In an attempt to bring some unity to the path guessing logic, I move the
guessing logic from inside SymbolFileDWARF into the FileSpec class and
have both symbol files use it to implent their desired behavior.

Reviewers: clayborg, lemo, JDevlieghere

Subscribers: aprantl, markmentovai, lldb-commits

Differential Revision: https://reviews.llvm.org/D57895

llvm-svn: 353702
2019-02-11 14:11:00 +00:00

382 lines
14 KiB
C++

//===-- FileSpecTest.cpp ----------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
#include "lldb/Utility/FileSpec.h"
using namespace lldb_private;
TEST(FileSpecTest, FileAndDirectoryComponents) {
FileSpec fs_posix("/foo/bar", FileSpec::Style::posix);
EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
FileSpec fs_windows("F:\\bar", FileSpec::Style::windows);
EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
// EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString()); // It returns
// "F:/"
EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
FileSpec fs_posix_root("/", FileSpec::Style::posix);
EXPECT_STREQ("/", fs_posix_root.GetCString());
EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
FileSpec fs_net_drive("//net", FileSpec::Style::posix);
EXPECT_STREQ("//net", fs_net_drive.GetCString());
EXPECT_EQ(nullptr, fs_net_drive.GetDirectory().GetCString());
EXPECT_STREQ("//net", fs_net_drive.GetFilename().GetCString());
FileSpec fs_net_root("//net/", FileSpec::Style::posix);
EXPECT_STREQ("//net/", fs_net_root.GetCString());
EXPECT_STREQ("//net", fs_net_root.GetDirectory().GetCString());
EXPECT_STREQ("/", fs_net_root.GetFilename().GetCString());
FileSpec fs_windows_drive("F:", FileSpec::Style::windows);
EXPECT_STREQ("F:", fs_windows_drive.GetCString());
EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
FileSpec fs_windows_root("F:\\", FileSpec::Style::windows);
EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
// EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It
// returns "/"
FileSpec fs_posix_long("/foo/bar/baz", FileSpec::Style::posix);
EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString());
EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString());
FileSpec fs_windows_long("F:\\bar\\baz", FileSpec::Style::windows);
EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
// EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It
// returns "F:/bar"
EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
FileSpec fs_posix_trailing_slash("/foo/bar/", FileSpec::Style::posix);
EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetCString());
EXPECT_STREQ("/foo", fs_posix_trailing_slash.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_posix_trailing_slash.GetFilename().GetCString());
FileSpec fs_windows_trailing_slash("F:\\bar\\", FileSpec::Style::windows);
EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetCString());
EXPECT_STREQ("bar", fs_windows_trailing_slash.GetFilename().GetCString());
}
TEST(FileSpecTest, AppendPathComponent) {
FileSpec fs_posix("/foo", FileSpec::Style::posix);
fs_posix.AppendPathComponent("bar");
EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
FileSpec fs_posix_2("/foo", FileSpec::Style::posix);
fs_posix_2.AppendPathComponent("//bar/baz");
EXPECT_STREQ("/foo/bar/baz", fs_posix_2.GetCString());
EXPECT_STREQ("/foo/bar", fs_posix_2.GetDirectory().GetCString());
EXPECT_STREQ("baz", fs_posix_2.GetFilename().GetCString());
FileSpec fs_windows("F:\\bar", FileSpec::Style::windows);
fs_windows.AppendPathComponent("baz");
EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
// EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It
// returns "F:/bar"
EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
FileSpec fs_posix_root("/", FileSpec::Style::posix);
fs_posix_root.AppendPathComponent("bar");
EXPECT_STREQ("/bar", fs_posix_root.GetCString());
EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
FileSpec fs_windows_root("F:\\", FileSpec::Style::windows);
fs_windows_root.AppendPathComponent("bar");
EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
// EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It
// returns "F:/"
EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
}
TEST(FileSpecTest, CopyByAppendingPathComponent) {
FileSpec fs = FileSpec("/foo", FileSpec::Style::posix)
.CopyByAppendingPathComponent("bar");
EXPECT_STREQ("/foo/bar", fs.GetCString());
EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs.GetFilename().GetCString());
}
TEST(FileSpecTest, PrependPathComponent) {
FileSpec fs_posix("foo", FileSpec::Style::posix);
fs_posix.PrependPathComponent("/bar");
EXPECT_STREQ("/bar/foo", fs_posix.GetCString());
FileSpec fs_posix_2("foo/bar", FileSpec::Style::posix);
fs_posix_2.PrependPathComponent("/baz");
EXPECT_STREQ("/baz/foo/bar", fs_posix_2.GetCString());
FileSpec fs_windows("baz", FileSpec::Style::windows);
fs_windows.PrependPathComponent("F:\\bar");
EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
FileSpec fs_posix_root("bar", FileSpec::Style::posix);
fs_posix_root.PrependPathComponent("/");
EXPECT_STREQ("/bar", fs_posix_root.GetCString());
FileSpec fs_windows_root("bar", FileSpec::Style::windows);
fs_windows_root.PrependPathComponent("F:\\");
EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
}
TEST(FileSpecTest, EqualSeparator) {
FileSpec backward("C:\\foo\\bar", FileSpec::Style::windows);
FileSpec forward("C:/foo/bar", FileSpec::Style::windows);
EXPECT_EQ(forward, backward);
}
TEST(FileSpecTest, EqualDotsWindows) {
std::pair<const char *, const char *> tests[] = {
{R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"},
{R"(C:\bar\baz)", R"(C:\foo\..\bar\baz)"},
{R"(C:\bar\baz)", R"(C:/foo/../bar/baz)"},
{R"(C:/bar/baz)", R"(C:\foo\..\bar\baz)"},
{R"(C:\bar)", R"(C:\foo\..\bar)"},
{R"(C:\foo\bar)", R"(C:\foo\.\bar)"},
{R"(C:\foo\bar)", R"(C:\foo\bar\.)"},
};
for (const auto &test : tests) {
FileSpec one(test.first, FileSpec::Style::windows);
FileSpec two(test.second, FileSpec::Style::windows);
EXPECT_EQ(one, two);
}
}
TEST(FileSpecTest, EqualDotsPosix) {
std::pair<const char *, const char *> tests[] = {
{R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"},
{R"(/bar/baz)", R"(/foo/../bar/baz)"},
{R"(/bar)", R"(/foo/../bar)"},
{R"(/foo/bar)", R"(/foo/./bar)"},
{R"(/foo/bar)", R"(/foo/bar/.)"},
};
for (const auto &test : tests) {
FileSpec one(test.first, FileSpec::Style::posix);
FileSpec two(test.second, FileSpec::Style::posix);
EXPECT_EQ(one, two);
}
}
TEST(FileSpecTest, EqualDotsPosixRoot) {
std::pair<const char *, const char *> tests[] = {
{R"(/)", R"(/..)"},
{R"(/)", R"(/.)"},
{R"(/)", R"(/foo/..)"},
};
for (const auto &test : tests) {
FileSpec one(test.first, FileSpec::Style::posix);
FileSpec two(test.second, FileSpec::Style::posix);
EXPECT_EQ(one, two);
}
}
TEST(FileSpecTest, GuessPathStyle) {
EXPECT_EQ(FileSpec::Style::posix, FileSpec::GuessPathStyle("/foo/bar.txt"));
EXPECT_EQ(FileSpec::Style::posix, FileSpec::GuessPathStyle("//net/bar.txt"));
EXPECT_EQ(FileSpec::Style::windows,
FileSpec::GuessPathStyle(R"(C:\foo.txt)"));
EXPECT_EQ(FileSpec::Style::windows,
FileSpec::GuessPathStyle(R"(\\net\foo.txt)"));
EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo.txt"));
EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo/bar.txt"));
}
TEST(FileSpecTest, GetNormalizedPath) {
std::pair<const char *, const char *> posix_tests[] = {
{"/foo/.././bar", "/bar"},
{"/foo/./../bar", "/bar"},
{"/foo/../bar", "/bar"},
{"/foo/./bar", "/foo/bar"},
{"/foo/..", "/"},
{"/foo/.", "/foo"},
{"/foo//bar", "/foo/bar"},
{"/foo//bar/baz", "/foo/bar/baz"},
{"/foo//bar/./baz", "/foo/bar/baz"},
{"/./foo", "/foo"},
{"/", "/"},
{"//", "/"},
{"//net", "//net"},
{"/..", "/"},
{"/.", "/"},
{"..", ".."},
{".", "."},
{"../..", "../.."},
{"foo/..", "."},
{"foo/../bar", "bar"},
{"../foo/..", ".."},
{"./foo", "foo"},
{"././foo", "foo"},
{"../foo", "../foo"},
{"../../foo", "../../foo"},
};
for (auto test : posix_tests) {
SCOPED_TRACE(llvm::Twine("test.first = ") + test.first);
EXPECT_EQ(test.second,
FileSpec(test.first, FileSpec::Style::posix).GetPath());
}
std::pair<const char *, const char *> windows_tests[] = {
{R"(c:\bar\..\bar)", R"(c:\bar)"},
{R"(c:\bar\.\bar)", R"(c:\bar\bar)"},
{R"(c:\bar\..)", R"(c:\)"},
{R"(c:\bar\.)", R"(c:\bar)"},
{R"(c:\.\bar)", R"(c:\bar)"},
{R"(\)", R"(\)"},
{R"(\\)", R"(\)"},
{R"(\\net)", R"(\\net)"},
{R"(c:\..)", R"(c:\)"},
{R"(c:\.)", R"(c:\)"},
// TODO: fix llvm::sys::path::remove_dots() to return "\" below.
{R"(\..)", R"(\..)"},
// {R"(c:..)", R"(c:..)"},
{R"(..)", R"(..)"},
{R"(.)", R"(.)"},
// TODO: fix llvm::sys::path::remove_dots() to return "c:\" below.
{R"(c:..\..)", R"(c:\..\..)"},
{R"(..\..)", R"(..\..)"},
{R"(foo\..)", R"(.)"},
{R"(foo\..\bar)", R"(bar)"},
{R"(..\foo\..)", R"(..)"},
{R"(.\foo)", R"(foo)"},
{R"(.\.\foo)", R"(foo)"},
{R"(..\foo)", R"(..\foo)"},
{R"(..\..\foo)", R"(..\..\foo)"},
};
for (auto test : windows_tests) {
EXPECT_EQ(test.second,
FileSpec(test.first, FileSpec::Style::windows).GetPath())
<< "Original path: " << test.first;
}
}
TEST(FileSpecTest, FormatFileSpec) {
auto win = FileSpec::Style::windows;
FileSpec F;
EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str());
EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str());
F = FileSpec("C:\\foo\\bar.txt", win);
EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str());
EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str());
EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
F = FileSpec("foo\\bar.txt", win);
EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str());
EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str());
EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
F = FileSpec("foo", win);
EXPECT_EQ("foo", llvm::formatv("{0}", F).str());
EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str());
EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
}
TEST(FileSpecTest, IsRelative) {
llvm::StringRef not_relative[] = {
"/",
"/a",
"/a/",
"/a/b",
"/a/b/",
"//",
"//a/",
"//a/b",
"//a/b/",
"~",
"~/",
"~/a",
"~/a/",
"~/a/b"
"~/a/b/",
"/foo/.",
"/foo/..",
"/foo/../",
"/foo/../.",
};
for (const auto &path: not_relative) {
FileSpec spec(path, FileSpec::Style::posix);
EXPECT_FALSE(spec.IsRelative());
}
llvm::StringRef is_relative[] = {
".",
"./",
".///",
"a",
"./a",
"./a/",
"./a/",
"./a/b",
"./a/b/",
"../foo",
"foo/bar.c",
"./foo/bar.c"
};
for (const auto &path: is_relative) {
FileSpec spec(path, FileSpec::Style::posix);
EXPECT_TRUE(spec.IsRelative());
}
}
TEST(FileSpecTest, RemoveLastPathComponent) {
FileSpec fs_posix("/foo/bar/baz", FileSpec::Style::posix);
EXPECT_STREQ("/foo/bar/baz", fs_posix.GetCString());
EXPECT_TRUE(fs_posix.RemoveLastPathComponent());
EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
EXPECT_TRUE(fs_posix.RemoveLastPathComponent());
EXPECT_STREQ("/foo", fs_posix.GetCString());
EXPECT_TRUE(fs_posix.RemoveLastPathComponent());
EXPECT_STREQ("/", fs_posix.GetCString());
EXPECT_FALSE(fs_posix.RemoveLastPathComponent());
EXPECT_STREQ("/", fs_posix.GetCString());
FileSpec fs_posix_relative("./foo/bar/baz", FileSpec::Style::posix);
EXPECT_STREQ("foo/bar/baz", fs_posix_relative.GetCString());
EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent());
EXPECT_STREQ("foo/bar", fs_posix_relative.GetCString());
EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent());
EXPECT_STREQ("foo", fs_posix_relative.GetCString());
EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent());
EXPECT_STREQ("foo", fs_posix_relative.GetCString());
FileSpec fs_posix_relative2("./", FileSpec::Style::posix);
EXPECT_STREQ(".", fs_posix_relative2.GetCString());
EXPECT_FALSE(fs_posix_relative2.RemoveLastPathComponent());
EXPECT_STREQ(".", fs_posix_relative2.GetCString());
EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent());
EXPECT_STREQ(".", fs_posix_relative2.GetCString());
FileSpec fs_windows("C:\\foo\\bar\\baz", FileSpec::Style::windows);
EXPECT_STREQ("C:\\foo\\bar\\baz", fs_windows.GetCString());
EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
EXPECT_STREQ("C:\\foo\\bar", fs_windows.GetCString());
EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
EXPECT_STREQ("C:\\foo", fs_windows.GetCString());
EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
EXPECT_STREQ("C:\\", fs_windows.GetCString());
EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
EXPECT_STREQ("C:", fs_windows.GetCString());
EXPECT_FALSE(fs_windows.RemoveLastPathComponent());
EXPECT_STREQ("C:", fs_windows.GetCString());
}