[C++] Improve NormalizePath

So now NormalizePath("../foo") will be "../foo" and "/../foo"
will be "/foo".
diff --git a/ninja_test.cc b/ninja_test.cc
index f1fb522..5fc410e 100644
--- a/ninja_test.cc
+++ b/ninja_test.cc
@@ -18,25 +18,10 @@
 
 #include "log.h"
 #include "ninja.h"
+#include "testutil.h"
 
 namespace {
 
-#define ASSERT_EQ(a, b)                                                 \
-  do {                                                                  \
-    if ((a) != (b)) {                                                   \
-      fprintf(stderr,                                                   \
-              "Assertion failure at %s:%d: %s (which is \"%s\") vs %s\n", \
-              __FILE__, __LINE__, #a, c_str(a), #b);                    \
-    }                                                                   \
-  } while(0)
-
-const char* c_str(const string& s) { return s.c_str(); }
-const char* c_str(size_t v) {
-  static char buf[64];
-  sprintf(buf, "%zd", v);
-  return buf;
-}
-
 string GetDepfile(string cmd, string* new_cmd) {
   new_cmd->clear();
   string r;
@@ -90,4 +75,5 @@
   g_log_no_exit = true;
   TestGetDepfile();
   TestGetGomaccPosForAndroidCompileCommand();
+  assert(!g_failed);
 }
diff --git a/strutil.cc b/strutil.cc
index 7afe743..ea5d633 100644
--- a/strutil.cc
+++ b/strutil.cc
@@ -266,7 +266,12 @@
   return s.substr(0, found);
 }
 
-void NormalizePath(string* o, size_t start_index) {
+void NormalizePath(string* o) {
+  if (o->empty())
+    return;
+  size_t start_index = 0;
+  if ((*o)[0] == '/')
+    start_index++;
   size_t j = start_index;
   size_t prev_start = start_index;
   for (size_t i = start_index; i <= o->size(); i++) {
@@ -280,13 +285,18 @@
     StringPiece prev_dir = StringPiece(o->data() + prev_start, j - prev_start);
     if (prev_dir == ".") {
       j--;
-    } else if (prev_dir == "..") {
-      j -= 4;
-      j = o->rfind('/', j);
-      if (j == string::npos) {
+    } else if (prev_dir == ".." && j != 2 /* .. */) {
+      if (j == 3) {
+        // /..
         j = start_index;
       } else {
-        j++;
+        j -= 4;
+        j = o->rfind('/', j);
+        if (j == string::npos) {
+          j = start_index;
+        } else {
+          j++;
+        }
       }
     } else if (!prev_dir.empty()) {
       if (c) {
@@ -316,7 +326,7 @@
     *o += '/';
   }
   AppendString(s, o);
-  NormalizePath(o, 1);
+  NormalizePath(o);
 }
 
 template<typename Cond>
diff --git a/strutil.h b/strutil.h
index 2dd229c..8c47f1c 100644
--- a/strutil.h
+++ b/strutil.h
@@ -118,7 +118,7 @@
 StringPiece Basename(StringPiece s);
 StringPiece GetExt(StringPiece s);
 StringPiece StripExt(StringPiece s);
-void NormalizePath(string* o, size_t start_index = 0);
+void NormalizePath(string* o);
 void AbsPath(StringPiece s, string* o);
 
 size_t FindOutsideParen(StringPiece s, char c);
diff --git a/strutil_test.cc b/strutil_test.cc
index b9c5580..048a974 100644
--- a/strutil_test.cc
+++ b/strutil_test.cc
@@ -22,18 +22,21 @@
 #include <vector>
 
 #include "string_piece.h"
+#include "testutil.h"
 
 using namespace std;
 
+namespace {
+
 void TestWordScanner() {
   vector<StringPiece> ss;
   for (StringPiece tok : WordScanner("foo bar baz")) {
     ss.push_back(tok);
   }
   assert(ss.size() == 3LU);
-  assert(ss[0] == "foo");
-  assert(ss[1] == "bar");
-  assert(ss[2] == "baz");
+  ASSERT_EQ(ss[0], "foo");
+  ASSERT_EQ(ss[1], "bar");
+  ASSERT_EQ(ss[2], "baz");
 }
 
 void TestHasPrefix() {
@@ -57,14 +60,14 @@
 }
 
 void TestSubstPattern() {
-  assert(SubstPattern("x.c", "%.c", "%.o") == "x.o");
-  assert(SubstPattern("c.x", "c.%", "o.%") == "o.x");
-  assert(SubstPattern("x.c.c", "%.c", "%.o") == "x.c.o");
-  assert(SubstPattern("x.x y.c", "%.c", "%.o") == "x.x y.o");
-  assert(SubstPattern("x.%.c", "%.%.c", "OK") == "OK");
-  assert(SubstPattern("x.c", "x.c", "OK") == "OK");
-  assert(SubstPattern("x.c.c", "x.c", "XX") == "x.c.c");
-  assert(SubstPattern("x.x.c", "x.c", "XX") == "x.x.c");
+  ASSERT_EQ(SubstPattern("x.c", "%.c", "%.o"), "x.o");
+  ASSERT_EQ(SubstPattern("c.x", "c.%", "o.%"), "o.x");
+  ASSERT_EQ(SubstPattern("x.c.c", "%.c", "%.o"), "x.c.o");
+  ASSERT_EQ(SubstPattern("x.x y.c", "%.c", "%.o"), "x.x y.o");
+  ASSERT_EQ(SubstPattern("x.%.c", "%.%.c", "OK"), "OK");
+  ASSERT_EQ(SubstPattern("x.c", "x.c", "OK"), "OK");
+  ASSERT_EQ(SubstPattern("x.c.c", "x.c", "XX"), "x.c.c");
+  ASSERT_EQ(SubstPattern("x.x.c", "x.c", "XX"), "x.x.c");
 }
 
 void TestNoLineBreak() {
@@ -84,6 +87,32 @@
   assert(!HasWord("foo bar baz", "fo"));
 }
 
+static string NormalizePath(string s) {
+  ::NormalizePath(&s);
+  return s;
+}
+
+void TestNormalizePath() {
+  ASSERT_EQ(NormalizePath(""), "");
+  ASSERT_EQ(NormalizePath("."), "");
+  ASSERT_EQ(NormalizePath("/"), "/");
+  ASSERT_EQ(NormalizePath("/tmp"), "/tmp");
+  ASSERT_EQ(NormalizePath("////tmp////"), "/tmp");
+  ASSERT_EQ(NormalizePath("a////b"), "a/b");
+  ASSERT_EQ(NormalizePath("a//.//b"), "a/b");
+  ASSERT_EQ(NormalizePath("a////b//../c/////"), "a/c");
+  ASSERT_EQ(NormalizePath("../foo"), "../foo");
+  ASSERT_EQ(NormalizePath("./foo"), "foo");
+  ASSERT_EQ(NormalizePath("x/y/..//../foo"), "foo");
+  ASSERT_EQ(NormalizePath("x/../../foo"), "../foo");
+  ASSERT_EQ(NormalizePath("/../foo"), "/foo");
+  ASSERT_EQ(NormalizePath("/../../foo"), "/foo");
+  ASSERT_EQ(NormalizePath("/a/../../foo"), "/foo");
+  ASSERT_EQ(NormalizePath("/a/b/.."), "/a");
+}
+
+}  // namespace
+
 int main() {
   TestWordScanner();
   TestHasPrefix();
@@ -91,4 +120,6 @@
   TestSubstPattern();
   TestNoLineBreak();
   TestHasWord();
+  TestNormalizePath();
+  assert(!g_failed);
 }
diff --git a/testutil.h b/testutil.h
new file mode 100644
index 0000000..7036409
--- /dev/null
+++ b/testutil.h
@@ -0,0 +1,36 @@
+// Copyright 2015 Google Inc. All rights reserved
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <assert.h>
+
+#include "string_piece.h"
+
+bool g_failed;
+
+#define ASSERT_EQ(a, b)                                                 \
+  do {                                                                  \
+    if ((a) != (b)) {                                                   \
+      fprintf(stderr,                                                   \
+              "Assertion failure at %s:%d: %s (which is \"%.*s\") vs %s\n", \
+              __FILE__, __LINE__, #a, SPF(GetStringPiece(a)), #b);      \
+      g_failed = true;                                                  \
+    }                                                                   \
+  } while(0)
+
+StringPiece GetStringPiece(StringPiece s) { return s; }
+StringPiece GetStringPiece(size_t v) {
+  static char buf[64];
+  sprintf(buf, "%zd", v);
+  return buf;
+}