libbase_test: win32: get some tests working

* Get it building on Win32 by implementing mkstemp() and mkdtemp().

* Run StringPrintf %z test on Windows because it passes because we build
with __USE_MINGW_ANSI_STDIO which implements %z.

Change-Id: Ia01f94e8258503381a1df6d3da6e40de59e57125
Signed-off-by: Spencer Low <CompareAndSwap@gmail.com>
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index dceb8b7..b0c5a12 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include "base/logging.h"
 #include "base/test_utils.h"
+#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
 
 #include <fcntl.h>
 #include <stdio.h>
@@ -24,17 +26,47 @@
 
 #if defined(_WIN32)
 #include <windows.h>
+#include <direct.h>
 #endif
 
 #include <string>
 
+#ifdef _WIN32
+int mkstemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return -1;
+  }
+  // Use open() to match the close() that TemporaryFile's destructor does.
+  // Note that on Windows, this does CR/LF translation and _setmode() should
+  // be used to change that if appropriate.
+  return open(template_name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+}
+
+char* mkdtemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return nullptr;
+  }
+  if (_mkdir(template_name) == -1) {
+    return nullptr;
+  }
+  return template_name;
+}
+#endif
+
 static std::string GetSystemTempDir() {
 #if defined(__ANDROID__)
   return "/data/local/tmp";
 #elif defined(_WIN32)
-  char wd[MAX_PATH] = {};
-  _getcwd(wd, sizeof(wd));
-  return wd;
+  char tmp_dir[MAX_PATH];
+  DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
+  CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
+  CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
+
+  // GetTempPath() returns a path with a trailing slash, but init()
+  // does not expect that, so remove it.
+  CHECK_EQ(tmp_dir[result - 1], '\\');
+  tmp_dir[result - 1] = '\0';
+  return tmp_dir;
 #else
   return "/tmp";
 #endif
@@ -50,21 +82,11 @@
 }
 
 void TemporaryFile::init(const std::string& tmp_dir) {
-  snprintf(path, sizeof(path), "%s/TemporaryFile-XXXXXX", tmp_dir.c_str());
-#if !defined(_WIN32)
+  snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
+           OS_PATH_SEPARATOR);
   fd = mkstemp(path);
-#else
-  // Windows doesn't have mkstemp, and tmpfile creates the file in the root
-  // directory, requiring root (?!) permissions. We have to settle for mktemp.
-  if (mktemp(path) == nullptr) {
-    abort();
-  }
-
-  fd = open(path, O_RDWR | O_NOINHERIT | O_CREAT, _S_IREAD | _S_IWRITE);
-#endif
 }
 
-#if !defined(_WIN32)
 TemporaryDir::TemporaryDir() {
   init(GetSystemTempDir());
 }
@@ -74,7 +96,7 @@
 }
 
 bool TemporaryDir::init(const std::string& tmp_dir) {
-  snprintf(path, sizeof(path), "%s/TemporaryDir-XXXXXX", tmp_dir.c_str());
+  snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
+           OS_PATH_SEPARATOR);
   return (mkdtemp(path) != nullptr);
 }
-#endif