summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji <binji@chromium.org>2015-03-19 10:25:43 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-19 17:26:34 +0000
commitfea846358e7c2efe04bdeb4b01ecccee6efe7759 (patch)
tree1aa2f9f8be62b5c885d23afa4324108edc6c329f /native_client_sdk
parent821dbcff61cfb0ab1d602ef505b9545599a86410 (diff)
downloadchromium_src-fea846358e7c2efe04bdeb4b01ecccee6efe7759.zip
chromium_src-fea846358e7c2efe04bdeb4b01ecccee6efe7759.tar.gz
chromium_src-fea846358e7c2efe04bdeb4b01ecccee6efe7759.tar.bz2
[NaCl SDK] Rewrite nacl_io::Path to avoid STL.
Path used to be a std::vector<std::string>. Now it is just a C array of size PATH_MAX. The code has a lot of nasty edge cases because it is trying to match the previous behavior. Really, all this code should be axed -- it is incorrect to handle paths the way nacl_io does currently. AFAICT, the only place that should have to handle paths is the path lookup routine. Fixing that is a much larger change. BUG=none R=sbc@chromium.org Review URL: https://codereview.chromium.org/1016873004 Cr-Commit-Position: refs/heads/master@{#321386}
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/libraries/nacl_io/path.cc286
-rw-r--r--native_client_sdk/src/libraries/nacl_io/path.h34
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/path_test.cc402
3 files changed, 369 insertions, 353 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/path.cc b/native_client_sdk/src/libraries/nacl_io/path.cc
index c524bfa..2196560 100644
--- a/native_client_sdk/src/libraries/nacl_io/path.cc
+++ b/native_client_sdk/src/libraries/nacl_io/path.cc
@@ -4,6 +4,7 @@
#include "nacl_io/path.h"
+#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <string>
@@ -12,8 +13,13 @@
namespace nacl_io {
+Path::Path() : len_(0) {
+ path_[0] = 0;
+}
+
Path::Path(const Path& path) {
- paths_ = path.paths_;
+ len_ = path.len_;
+ strcpy(path_, path.path_);
}
Path::Path(const std::string& path) {
@@ -21,24 +27,54 @@ Path::Path(const std::string& path) {
}
bool Path::IsAbsolute() const {
- return !paths_.empty() && paths_[0] == "/";
+ return path_[0] == '/';
}
-const std::string& Path::Part(size_t index) const {
- return paths_[index];
+std::string Path::Part(size_t index) const {
+ if (IsAbsolute() && index == 0) {
+ return std::string("/");
+ }
+
+ const char* start = &path_[0];
+ size_t slashes = 0;
+ const char* p;
+ for (p = &path_[0]; *p; p++) {
+ if (*p == '/') {
+ if (++slashes == index + 1)
+ break;
+
+ start = p + 1;
+ }
+ }
+
+ return std::string(start, p - start);
}
size_t Path::Size() const {
- return paths_.size();
+ if (len_ == 0)
+ return 0;
+
+ const char* p = &path_[0];
+ if (len_ == 1 && *p == '/') {
+ return 1;
+ }
+
+ size_t count = 1;
+ for (; *p; p++) {
+ if (*p == '/')
+ count++;
+ }
+ return count;
}
bool Path::IsRoot() const {
- return paths_.empty() || (paths_.size() == 1 && paths_[0] == "/");
+ return strcmp(path_, "/") == 0;
}
Path& Path::MakeRelative() {
if (IsAbsolute()) {
- paths_.erase(paths_.begin());
+ memmove(&path_[0], &path_[1], PATH_MAX - 1);
+ len_--;
}
return *this;
}
@@ -47,14 +83,19 @@ Path& Path::Append(const Path& path) {
// Appending an absolute path effectivly sets the path, ignoring
// the current contents.
if (path.IsAbsolute()) {
- paths_ = path.paths_;
+ strcpy(path_, path.path_);
} else {
- for (size_t index = 0; index < path.paths_.size(); index++) {
- paths_.push_back(path.paths_[index]);
+ strncat(path_, "/", PATH_MAX - len_ - 1);
+ len_++;
+ strncat(path_, path.path_, PATH_MAX - len_ - 1);
+ len_ += path.len_;
+
+ if (len_ >= PATH_MAX - 1) {
+ len_ = PATH_MAX - 1;
}
}
- paths_ = Normalize(paths_);
+ Normalize();
return *this;
}
@@ -62,142 +103,157 @@ Path& Path::Append(const std::string& path) {
return Append(Path(path));
}
-Path& Path::Set(const StringArray_t path) {
- paths_ = Normalize(path);
- return *this;
-}
-
Path& Path::Set(const std::string& path) {
- return Set(Split(path));
+ strncpy(path_, path.c_str(), PATH_MAX - 1);
+ path_[PATH_MAX - 1] = 0;
+ len_ = path.length();
+ if (len_ > PATH_MAX - 1)
+ len_ = PATH_MAX - 1;
+ Normalize();
+ return *this;
}
Path Path::Parent() const {
- Path out;
- out.paths_ = paths_;
- if (out.paths_.size())
- out.paths_.pop_back();
- return out;
+ const char* last_slash = strrchr(path_, '/');
+ if (last_slash) {
+ Path out;
+ if (last_slash == &path_[0]) {
+ out.len_ = 1;
+ strcpy(out.path_, "/");
+ } else {
+ out.len_ = last_slash - &path_[0];
+ strncpy(out.path_, path_, out.len_);
+ out.path_[out.len_] = 0;
+ }
+
+ return out;
+ }
+
+ return Path(*this);
}
std::string Path::Basename() const {
- if (paths_.size())
- return paths_.back();
- return std::string();
-}
+ if (IsRoot())
+ return std::string(path_);
-std::string Path::Join() const {
- return Range(paths_, 0, paths_.size());
-}
+ const char* last_slash = strrchr(path_, '/');
+ if (last_slash)
+ return std::string(last_slash + 1, path_ + len_ - (last_slash + 1));
-std::string Path::Range(size_t start, size_t end) const {
- return Range(paths_, start, end);
+ return std::string(path_);
}
-StringArray_t Path::Split() const {
- return paths_;
+std::string Path::Join() const {
+ return std::string(path_);
}
-// static
-StringArray_t Path::Normalize(const StringArray_t& paths) {
- StringArray_t path_out;
-
- for (size_t index = 0; index < paths.size(); index++) {
- const std::string& curr = paths[index];
-
- // Check if '/' was used excessively in the path.
- // For example, in cd Desktop/////
- if (curr == "/" && index != 0)
- continue;
+std::string Path::Range(size_t start, size_t end) const {
+ assert(start <= end);
- // Check for '.' in the path and remove it
- if (curr == ".")
- continue;
+ const char* pstart = &path_[0];
+ const char* pend = &path_[len_];
- // Check for '..'
- if (curr == "..") {
- // If the path is empty, or "..", then add ".."
- if (path_out.empty() || path_out.back() == "..") {
- path_out.push_back(curr);
- continue;
- }
+ if (IsAbsolute() && start == 0 && end == 1)
+ return std::string("/");
- // If the path is at root, "/.." = "/"
- if (path_out.back() == "/") {
- continue;
- }
+ size_t slashes = 0;
+ for (const char* p = &path_[0]; *p; p++) {
+ if (*p == '/') {
+ ++slashes;
+ if (slashes == start)
+ pstart = p + 1;
- // if we are already at root, then stay there (root/.. -> root)
- if (path_out.back() == "/") {
- continue;
+ if (slashes == end) {
+ pend = p;
+ break;
}
-
- // otherwise, pop off the top path component
- path_out.pop_back();
- continue;
}
-
- // By now, we should have handled end cases so just append.
- path_out.push_back(curr);
}
- // If the path was valid, but now it's empty, return self
- if (path_out.empty())
- path_out.push_back(".");
-
- return path_out;
-}
+ if (pstart > pend)
+ return std::string();
-// static
-std::string Path::Join(const StringArray_t& paths) {
- return Range(paths, 0, paths.size());
+ return std::string(pstart, pend - pstart);
}
-// static
-std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) {
- std::string out_path;
- size_t index = start;
-
- if (end > paths.size())
- end = paths.size();
+void Path::Normalize() {
+ char* outp = &path_[0];
+ const char* start = outp;
+ const char* part_start = start;
+ const char* next_slash;
+ bool is_absolute = false;
- // If this is an absolute path, paths[0] == "/". In this case, we don't want
- // to add an additional / separator.
- if (start == 0 && end > 0 && paths[0] == "/") {
- out_path += "/";
- index++;
+ if (IsAbsolute()) {
+ // Absolute path. Append the slash, then continue the algorithm as if the
+ // path were relative.
+ start++;
+ outp++;
+ part_start++;
+ is_absolute = true;
}
- for (; index < end; index++) {
- out_path += paths[index];
- if (index < end - 1)
- out_path += "/";
- }
+ do {
+ next_slash = strchr(part_start, '/');
+ const char* part_end = next_slash;
+ if (!part_end)
+ part_end = part_start + strlen(part_start);
+
+ size_t part_len = part_end - part_start;
+
+ bool should_append = true;
+ if (part_len == 0) {
+ // Don't append if the part is empty.
+ should_append = false;
+ } else if (part_len == 1 && part_start[0] == '.') {
+ // Don't append "."
+ should_append = false;
+ } else if (part_len == 2 && part_start[0] == '.' && part_start[1] == '.') {
+ // If part is "..", only append if the output is empty or already has
+ // ".." at the end.
+ if (outp == start ||
+ (outp - start >= 2 && outp[-1] == '.' && outp[-2] == '.')) {
+ should_append = !is_absolute;
+ } else {
+ should_append = false;
+ // Move outp backward to the one past the previous slash, or to the
+ // beginning of the string. Unless outp == start, outp[-1] is a '/'.
+ if (outp > start)
+ --outp;
+ while (outp > start && outp[0] != '/')
+ --outp;
+ }
+ }
- return out_path;
-}
+ if (should_append) {
+ // Append [part_start, part_end) to outp.
+ if (outp != start) {
+ // Append slash to separate from previous path.
+ *outp++ = '/';
+ }
-// static
-StringArray_t Path::Split(const std::string& path) {
- StringArray_t path_split;
- StringArray_t components;
+ // Only need to copy bytes when the pointers are different.
+ if (outp != part_start) {
+ memmove(outp, part_start, part_len);
+ }
- sdk_util::SplitString(path, '/', &path_split);
+ outp += part_len;
+ }
- if (path[0] == '/')
- components.push_back("/");
+ part_start = next_slash + 1;
+ } while (next_slash);
- // Copy path_split to components, removing empty path segments.
- for (StringArray_t::const_iterator it = path_split.begin();
- it != path_split.end();
- ++it) {
- if (!it->empty())
- components.push_back(*it);
+ // Return '.' instead of an empty path.
+ if (outp == start && !is_absolute) {
+ *outp++ = '.';
}
- return components;
+
+ *outp = 0;
+ len_ = outp - &path_[0];
}
Path& Path::operator=(const Path& p) {
- paths_ = p.paths_;
+ len_ = p.len_;
+ strcpy(path_, p.path_);
return *this;
}
@@ -205,4 +261,12 @@ Path& Path::operator=(const std::string& p) {
return Set(p);
}
+bool Path::operator==(const Path& other) {
+ return len_ == other.len_ && strncmp(path_, other.path_, len_) == 0;
+}
+
+bool Path::operator!=(const Path& other) {
+ return !operator==(other);
+}
+
} // namespace nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/path.h b/native_client_sdk/src/libraries/nacl_io/path.h
index ff90113..737e8f1 100644
--- a/native_client_sdk/src/libraries/nacl_io/path.h
+++ b/native_client_sdk/src/libraries/nacl_io/path.h
@@ -5,6 +5,8 @@
#ifndef LIBRARIES_NACL_IO_PATH_H_
#define LIBRARIES_NACL_IO_PATH_H_
+#include <limits.h>
+
#include <string>
#include <vector>
@@ -12,16 +14,10 @@
namespace nacl_io {
-typedef std::vector<std::string> StringArray_t;
-
class Path {
public:
- Path() {}
+ Path();
Path(const Path& path);
-
- // This constructor splits path by '/' as a starting point for this Path.
- // If the path begins with the character '/', the path is considered
- // to be absolute.
explicit Path(const std::string& path);
// Return true of the first path item is '/'.
@@ -31,7 +27,7 @@ class Path {
bool IsRoot() const;
// Return a part of the path
- const std::string& Part(size_t index) const;
+ std::string Part(size_t index) const;
// Return the number of path parts
size_t Size() const;
@@ -41,7 +37,6 @@ class Path {
Path& Append(const std::string& path);
Path& Set(const std::string& path);
Path& MakeRelative();
- Path& Set(const StringArray_t path);
// Return the parent path.
Path Parent() const;
@@ -49,26 +44,19 @@ class Path {
std::string Join() const;
std::string Range(size_t start, size_t end) const;
- StringArray_t Split() const;
- // Collapse the string list removing extraneous '.', '..' path components
- static StringArray_t Normalize(const StringArray_t& paths);
- static std::string Join(const StringArray_t& paths);
- static std::string Range(const StringArray_t& paths,
- size_t start,
- size_t end);
- static StringArray_t Split(const std::string& paths);
// Operator versions
Path& operator=(const Path& p);
Path& operator=(const std::string& str);
- bool operator==(const Path& other) { return Split() == other.Split(); }
- bool operator!=(const Path& other) { return !operator==(other); }
+ bool operator==(const Path& other);
+ bool operator!=(const Path& other);
private:
- // Internal representation of the path stored an array of string representing
- // the directory traversal. The first string is a "/" if this is an absolute
- // path.
- StringArray_t paths_;
+ // Collapse the string list removing extraneous '.', '..' path components
+ void Normalize();
+
+ size_t len_;
+ char path_[PATH_MAX];
};
} // namespace nacl_io
diff --git a/native_client_sdk/src/tests/nacl_io_test/path_test.cc b/native_client_sdk/src/tests/nacl_io_test/path_test.cc
index 9cdaa682..b7b82cc 100644
--- a/native_client_sdk/src/tests/nacl_io_test/path_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/path_test.cc
@@ -11,253 +11,217 @@
using namespace nacl_io;
-TEST(PathTest, SanityChecks) {
- // can we construct and delete?
- Path ph1(".");
- Path *ph2 = new Path(".");
- delete ph2;
-
- Path p1(".");
- EXPECT_FALSE(p1.IsAbsolute());
- EXPECT_EQ(".", p1.Join());
- Path p2("/");
- EXPECT_TRUE(p2.IsAbsolute());
- EXPECT_EQ("/", p2.Join());
+TEST(PathTest, Empty) {
+ Path p;
+ EXPECT_FALSE(p.IsAbsolute());
+ EXPECT_FALSE(p.IsRoot());
+ EXPECT_EQ(0, p.Size());
+ EXPECT_EQ("", p.Basename());
+ EXPECT_EQ("", p.Join());
+ EXPECT_EQ("", p.Range(0, 0));
+ EXPECT_EQ("", p.Parent().Join());
}
-TEST(PathTest, Assignment) {
- Path empty;
- Path dot(".");
- Path root("/");
- Path abs_str("/abs/from/string");
- Path rel_str("rel/from/string");
- Path self_str("./rel/from/string");
-
- EXPECT_EQ(0, empty.Size());
- EXPECT_FALSE(empty.IsAbsolute());
- EXPECT_EQ("", empty.Join());
-
- EXPECT_EQ(1, dot.Size());
- EXPECT_FALSE(dot.IsAbsolute());
- EXPECT_EQ(".", dot.Join());
-
- EXPECT_EQ(1, root.Size());
- EXPECT_TRUE(root.IsAbsolute());
- EXPECT_EQ("/", root.Join());
-
- EXPECT_EQ(4, abs_str.Size());
- EXPECT_TRUE(abs_str.IsAbsolute());
- EXPECT_EQ("/abs/from/string", abs_str.Join());
-
- EXPECT_EQ(3, rel_str.Size());
- EXPECT_FALSE(rel_str.IsAbsolute());
- EXPECT_EQ("rel/from/string", rel_str.Join());
-
- EXPECT_EQ(3, self_str.Size());
- EXPECT_FALSE(self_str.IsAbsolute());
- EXPECT_EQ("rel/from/string", self_str.Join());
-
- empty = "";
- dot = ".";
- root = "/";
- abs_str = "/abs/from/assign";
- rel_str = "rel/from/assign";
- self_str = "./rel/from/assign";
-
- EXPECT_EQ(1, empty.Size());
- EXPECT_FALSE(empty.IsAbsolute());
- EXPECT_EQ(".", empty.Join());
-
- EXPECT_EQ(1, dot.Size());
- EXPECT_FALSE(dot.IsAbsolute());
- EXPECT_EQ(".", dot.Join());
-
- EXPECT_EQ(1, root.Size());
- EXPECT_TRUE(root.IsAbsolute());
- EXPECT_EQ("/", root.Join());
-
- EXPECT_EQ(4, abs_str.Size());
- EXPECT_TRUE(abs_str.IsAbsolute());
- EXPECT_EQ("/abs/from/assign", abs_str.Join());
-
- EXPECT_EQ(3, rel_str.Size());
- EXPECT_FALSE(rel_str.IsAbsolute());
- EXPECT_EQ("rel/from/assign", rel_str.Join());
-
- EXPECT_EQ(3, self_str.Size());
- EXPECT_FALSE(self_str.IsAbsolute());
- EXPECT_EQ("rel/from/assign", self_str.Join());
-
- Path cpy_str;
- cpy_str = empty;
- EXPECT_EQ(1, cpy_str.Size());
- EXPECT_FALSE(cpy_str.IsAbsolute());
- EXPECT_EQ(".", cpy_str.Join());
-
- cpy_str = dot;
- EXPECT_EQ(1, cpy_str.Size());
- EXPECT_FALSE(cpy_str.IsAbsolute());
- EXPECT_EQ(".", cpy_str.Join());
-
- cpy_str = root;
- EXPECT_EQ(1, cpy_str.Size());
- EXPECT_TRUE(cpy_str.IsAbsolute());
- EXPECT_EQ("/", cpy_str.Join());
-
- cpy_str = abs_str;
- EXPECT_EQ(4, cpy_str.Size());
- EXPECT_TRUE(cpy_str.IsAbsolute());
- EXPECT_EQ("/abs/from/assign", cpy_str.Join());
-
- cpy_str = rel_str;
- EXPECT_EQ(3, cpy_str.Size());
- EXPECT_FALSE(cpy_str.IsAbsolute());
- EXPECT_EQ("rel/from/assign", cpy_str.Join());
-
- cpy_str = self_str;
- EXPECT_EQ(3, cpy_str.Size());
- EXPECT_FALSE(cpy_str.IsAbsolute());
- EXPECT_EQ("rel/from/assign", cpy_str.Join());
+TEST(PathTest, Dot) {
+ Path p(".");
+ EXPECT_FALSE(p.IsAbsolute());
+ EXPECT_FALSE(p.IsRoot());
+ EXPECT_EQ(1, p.Size());
+ EXPECT_EQ(".", p.Part(0));
+ EXPECT_EQ(".", p.Basename());
+ EXPECT_EQ(".", p.Join());
+ EXPECT_EQ(".", p.Range(0, 1));
+ EXPECT_EQ(".", p.Parent().Join()); // TODO(binji): this is unexpected.
}
+TEST(PathTest, Root) {
+ Path p("/");
+ EXPECT_TRUE(p.IsAbsolute());
+ EXPECT_TRUE(p.IsRoot());
+ EXPECT_EQ(1, p.Size());
+ EXPECT_EQ("/", p.Part(0));
+ EXPECT_EQ("/", p.Basename());
+ EXPECT_EQ("/", p.Join());
+ EXPECT_EQ("/", p.Range(0, 1));
+ EXPECT_EQ("/", p.Parent().Join());
+}
-TEST(PathTest, Collapse) {
- StringArray_t path_components;
-
- Path p1("/simple/splitter/test");
- path_components = p1.Split();
- EXPECT_EQ("/", path_components[0]);
- EXPECT_EQ("/", p1.Part(0));
-
- EXPECT_EQ("simple", path_components[1]);
- EXPECT_EQ("simple", p1.Part(1));
-
- EXPECT_EQ("splitter",path_components[2]);
- EXPECT_EQ("splitter",p1.Part(2));
-
- EXPECT_EQ("test", path_components[3]);
- EXPECT_EQ("test", p1.Part(3));
-
- Path p2("///simple//splitter///test/");
- path_components = p2.Split();
- EXPECT_EQ(4, static_cast<int>(path_components.size()));
- EXPECT_EQ(4, static_cast<int>(p2.Size()));
- EXPECT_EQ("/", path_components[0]);
- EXPECT_EQ("simple", path_components[1]);
- EXPECT_EQ("splitter", path_components[2]);
- EXPECT_EQ("test", path_components[3]);
-
- Path p3("sim/ple//spli/tter/te/st/");
- path_components = p3.Split();
- EXPECT_EQ(6, static_cast<int>(path_components.size()));
- EXPECT_FALSE(p3.IsAbsolute());
- EXPECT_EQ("sim", path_components[0]);
- EXPECT_EQ("ple", path_components[1]);
- EXPECT_EQ("spli", path_components[2]);
- EXPECT_EQ("tter", path_components[3]);
- EXPECT_EQ("te", path_components[4]);
- EXPECT_EQ("st", path_components[5]);
-
- Path p4("");
- path_components = p4.Split();
- EXPECT_EQ(1, static_cast<int>(path_components.size()));
-
- Path p5("/");
- path_components = p5.Split();
- EXPECT_EQ(1, static_cast<int>(path_components.size()));
+TEST(PathTest, OnePart_Relative) {
+ Path p("foo");
+ EXPECT_FALSE(p.IsAbsolute());
+ EXPECT_FALSE(p.IsRoot());
+ EXPECT_EQ(1, p.Size());
+ EXPECT_EQ("foo", p.Part(0));
+ EXPECT_EQ("foo", p.Basename());
+ EXPECT_EQ("foo", p.Join());
+ EXPECT_EQ("foo", p.Range(0, 1));
+ EXPECT_EQ("foo", p.Parent().Join());
}
-TEST(PathTest, AppendAndJoin) {
- Path ph1("/usr/local/hi/there");
-
- EXPECT_EQ("/usr/local/hi/there", ph1.Join());
- ph1 = ph1.Append("..");
- EXPECT_EQ("/usr/local/hi", ph1.Join());
- ph1 = ph1.Append(".././././hi/there/../.././././");
- EXPECT_EQ("/usr/local", ph1.Join());
- ph1 = ph1.Append("../../../../../../../../././../");
- EXPECT_EQ("/", ph1.Join());
- ph1 = ph1.Append("usr/lib/../bin/.././etc/../local/../share");
- EXPECT_EQ("/usr/share", ph1.Join());
-
- Path ph2("./");
- EXPECT_EQ(".", ph2.Join());
-
- Path ph3("/");
- EXPECT_EQ("/", ph3.Join());
- ph3 = ph3.Append("");
- EXPECT_EQ("/", ph3.Join());
- ph3 = ph3.Append("USR/local/SHARE");
- EXPECT_EQ("/USR/local/SHARE", ph3.Join());
-
- Path ph4("..");
- EXPECT_EQ("..", ph4.Join());
- ph4 = ph4.Append("node1/node3/../../node1/./");
- EXPECT_EQ("../node1", ph4.Join());
- ph4 = ph4.Append("node4/../../node1/./node5");
- EXPECT_EQ("../node1/node5", ph4.Join());
+TEST(PathTest, OnePart_Absolute) {
+ Path p("/foo");
+ EXPECT_TRUE(p.IsAbsolute());
+ EXPECT_FALSE(p.IsRoot());
+ EXPECT_EQ(2, p.Size());
+ EXPECT_EQ("/", p.Part(0));
+ EXPECT_EQ("foo", p.Part(1));
+ EXPECT_EQ("foo", p.Basename());
+ EXPECT_EQ("/foo", p.Join());
+ EXPECT_EQ("/", p.Range(0, 1));
+ EXPECT_EQ("foo", p.Range(1, 2));
+ EXPECT_EQ("/foo", p.Range(0, 2));
+ EXPECT_EQ("/", p.Parent().Join());
}
-TEST(PathTest, AppendAbsolute) {
- Path path("/usr/local");
- path.Append("/foo");
- EXPECT_EQ("/foo", path.Join());
+TEST(PathTest, TwoPart_Relative) {
+ Path p("foo/bar");
+ EXPECT_FALSE(p.IsAbsolute());
+ EXPECT_FALSE(p.IsRoot());
+ EXPECT_EQ(2, p.Size());
+ EXPECT_EQ("foo", p.Part(0));
+ EXPECT_EQ("bar", p.Part(1));
+ EXPECT_EQ("bar", p.Basename());
+ EXPECT_EQ("foo/bar", p.Join());
+ EXPECT_EQ("foo", p.Range(0, 1));
+ EXPECT_EQ("bar", p.Range(1, 2));
+ EXPECT_EQ("foo/bar", p.Range(0, 2));
+ EXPECT_EQ("foo", p.Parent().Join());
}
-TEST(PathTest, Invalid) {
- Path absolute("/usr/local");
- Path current("./usr/local");
- Path relative("usr/local");
+TEST(PathTest, MakeRelative) {
+ EXPECT_EQ("", Path("/").MakeRelative().Join());
+ EXPECT_EQ("foo/bar/baz", Path("/foo/bar/baz").MakeRelative().Join());
+ EXPECT_EQ("foo/bar/baz", Path("foo/bar/baz").MakeRelative().Join());
+}
- Path test;
+TEST(PathTest, Normalize_EmptyComponent) {
+ EXPECT_EQ("foo/bar", Path("foo//bar").Join());
+ EXPECT_EQ("/blah", Path("//blah").Join());
+ EXPECT_EQ("/a/b/c", Path("//a//b//c").Join());
+ EXPECT_EQ("path/to/dir", Path("path/to/dir/").Join());
+}
- test = absolute;
- test.Append("../..");
- EXPECT_EQ("/", test.Join());
+TEST(PathTest, Normalize_Dot) {
+ EXPECT_EQ(".", Path(".").Join());
+ EXPECT_EQ("foo", Path("foo/.").Join());
+ EXPECT_EQ("foo/bar", Path("foo/./bar").Join());
+ EXPECT_EQ("blah", Path("./blah").Join());
+ EXPECT_EQ("stuff", Path("stuff/./.").Join());
+ EXPECT_EQ("/", Path("/.").Join());
+}
- test = absolute;
- test.Append("../../..");
- EXPECT_EQ("/", test.Join());
+TEST(PathTest, Normalize_DotDot_Relative) {
+ EXPECT_EQ("..", Path("..").Join());
+ EXPECT_EQ("../..", Path("../..").Join());
+ EXPECT_EQ(".", Path("foo/..").Join());
+ EXPECT_EQ("foo", Path("foo/bar/..").Join());
+ EXPECT_EQ("bar", Path("foo/../bar").Join());
+ EXPECT_EQ("foo/baz", Path("foo/bar/../baz").Join());
+}
- test = absolute;
- test.Append("../../../foo");
- EXPECT_EQ("/foo", test.Join());
+TEST(PathTest, Normalize_DotDot_Absolute) {
+ EXPECT_EQ("/", Path("/..").Join());
+ EXPECT_EQ("/", Path("/../..").Join());
+ EXPECT_EQ("/", Path("/foo/..").Join());
+ EXPECT_EQ("/foo", Path("/foo/bar/..").Join());
+ EXPECT_EQ("/bar", Path("/foo/../bar").Join());
+ EXPECT_EQ("/foo/baz", Path("/foo/bar/../baz").Join());
+}
+
+TEST(PathTest, Append) {
+ EXPECT_EQ(".", Path("").Append(Path("")).Join());
+ EXPECT_EQ("foo", Path("").Append(Path("foo")).Join());
+ EXPECT_EQ(".", Path(".").Append(Path("")).Join());
+ EXPECT_EQ("foo", Path(".").Append(Path("foo")).Join());
+ EXPECT_EQ("foo/bar", Path(".").Append(Path("foo/bar")).Join());
+ EXPECT_EQ("foo", Path("foo").Append(Path("")).Join());
+ EXPECT_EQ("foo/bar", Path("foo").Append(Path("bar")).Join());
+ EXPECT_EQ("foo/bar/quux", Path("foo").Append(Path("bar/quux")).Join());
+ EXPECT_EQ("foo/and", Path("foo/and/more").Append(Path("..")).Join());
+}
- test = current;
- test.Append("../..");
- EXPECT_EQ(".", test.Join());
+TEST(PathTest, Append_Absolute) {
+ EXPECT_EQ("/", Path("").Append(Path("/")).Join());
+ EXPECT_EQ("/hello/world", Path("").Append(Path("/hello/world")).Join());
+ EXPECT_EQ("/", Path(".").Append(Path("/")).Join());
+ EXPECT_EQ("/goodbye", Path(".").Append(Path("/goodbye")).Join());
+ EXPECT_EQ("/foo/bar/baz", Path("/a/b").Append(Path("/foo/bar/baz")).Join());
+}
- test = current;
- test.Append("../../..");
- EXPECT_EQ("..", test.Join());
+TEST(PathTest, Append_Overflow) {
+ std::string big(PATH_MAX - 5, 'A');
+ Path p(big.c_str());
+ p.Append(Path("0123456789"));
+
+ std::string part(p.Join());
+ EXPECT_EQ(PATH_MAX - 1, part.size());
+}
+
+TEST(PathTest, Set) {
+ Path p("/random/path");
+ EXPECT_EQ("something/else", p.Set("something/else").Join());
+ // Set should change p, not just return a copy.
+ EXPECT_EQ("something/else", p.Join());
+}
+
+TEST(PathTest, Set_Overflow) {
+ std::string big(PATH_MAX * 2, 'A');
+ Path p(big.c_str());
+ EXPECT_EQ(PATH_MAX - 1, p.Part(0).size());
+}
+
+TEST(PathTest, Range_Empty) {
+ EXPECT_EQ("", Path("/").Range(1, 1));
+}
- test = current;
- test.Append("../../../foo");
- EXPECT_EQ("../foo", test.Join());
+TEST(PathTest, Range_Relative) {
+ Path p("a/relative/path");
- test = relative;
- test.Append("../..");
- EXPECT_EQ(".", test.Join());
+ EXPECT_EQ("a", p.Range(0, 1));
+ EXPECT_EQ("a/relative", p.Range(0, 2));
+ EXPECT_EQ("a/relative/path", p.Range(0, 3));
- test = relative;
- test.Append("../../..");
- EXPECT_EQ("..", test.Join());
+ EXPECT_EQ("relative", p.Range(1, 2));
+ EXPECT_EQ("relative/path", p.Range(1, 3));
- test = relative;
- test.Append("../../../foo");
- EXPECT_EQ("../foo", test.Join());
+ EXPECT_EQ("path", p.Range(2, 3));
}
-TEST(PathTest, Range) {
+TEST(PathTest, Range_Absolute) {
Path p("/an/absolute/path");
- // p's parts should be ["/", "an", "absolute", "path"].
+ EXPECT_EQ("/", p.Range(0, 1));
+ EXPECT_EQ("/an", p.Range(0, 2));
+ EXPECT_EQ("/an/absolute", p.Range(0, 3));
EXPECT_EQ("/an/absolute/path", p.Range(0, 4));
+
+ EXPECT_EQ("an", p.Range(1, 2));
+ EXPECT_EQ("an/absolute", p.Range(1, 3));
EXPECT_EQ("an/absolute/path", p.Range(1, 4));
+
+ EXPECT_EQ("absolute", p.Range(2, 3));
EXPECT_EQ("absolute/path", p.Range(2, 4));
+
EXPECT_EQ("path", p.Range(3, 4));
+}
- EXPECT_EQ("/an/absolute", p.Range(0, 3));
- EXPECT_EQ("an/absolute", p.Range(1, 3));
- EXPECT_EQ("absolute", p.Range(2, 3));
+TEST(PathTest, Assign) {
+ Path p;
+
+ p = "foo/bar";
+ EXPECT_EQ("foo/bar", p.Join());
+
+ // Should normalize.
+ p = "/foo/../bar";
+ EXPECT_EQ("/bar", p.Join());
+
+ p = Path("hi/planet");
+ EXPECT_EQ("hi/planet", p.Join());
+}
+
+TEST(PathTest, Equals) {
+ EXPECT_TRUE(Path("/foo") == Path("/foo"));
+ EXPECT_TRUE(Path("foo/../bar") == Path("bar"));
+ EXPECT_TRUE(Path("one/path") != Path("another/path"));
}
+