]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Use UpperCamelCase instead of snake_case for namespaces
authorJoel Rosdahl <joel@rosdahl.net>
Wed, 25 Sep 2019 18:33:15 +0000 (20:33 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 5 Oct 2019 21:16:46 +0000 (23:16 +0200)
This makes Foo::bar work for both a namespace Foo and a class Foo.

19 files changed:
CONTRIBUTING.md
Makefile.in
dev.mk.in
src/AtomicFile.cpp
src/CacheFile.cpp
src/Config.cpp
src/Util.cpp [new file with mode: 0644]
src/Util.hpp [moved from src/util.hpp with 99% similarity]
src/ccache.cpp
src/cleanup.cpp
src/cleanup.hpp
src/compress.cpp
src/compress.hpp
src/legacy_util.cpp [moved from src/util.cpp with 86% similarity]
src/lockfile.cpp
unittest/framework.cpp
unittest/test_Config.cpp
unittest/test_Util.cpp [new file with mode: 0644]
unittest/test_util.cpp [deleted file]

index 6b7573a0a71d61016488198bae3c56cd546cf797..8832c6dafe96f53635229078012007115d064cb8 100644 (file)
@@ -64,9 +64,9 @@ can install the [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
 
 Regarding naming:
 
-* Use UpperCamelCase for types (e.g. classes and structs).
-* Use snake_case for namespaces, functions and variables.
+* Use UpperCamelCase for types (e.g. classes and structs) and namespaces.
+* Use UPPER_CASE names for macros.
+* Use snake_case for other names (functions, variables, enum values, etc.).
 * Use an "m_" prefix for non-public member variables.
 * Use a "g_" prefix for global mutable variables.
 * Use a "k_" prefix for global constants.
-* Use UPPER_CASE names for macros.
index 0b58e3e3a77b6bd7649a59f39d53bd6a6613d9a3..f2c61294e672455245fc65e646b5300cbe4d3a18 100644 (file)
@@ -35,6 +35,7 @@ non_third_party_sources = \
     src/CacheFile.cpp \
     src/Config.cpp \
     src/ProgressBar.cpp \
+    src/Util.cpp \
     src/args.cpp \
     src/ccache.cpp \
     src/cleanup.cpp \
@@ -52,12 +53,12 @@ non_third_party_sources = \
     src/hash.cpp \
     src/hashutil.cpp \
     src/language.cpp \
+    src/legacy_util.cpp \
     src/lockfile.cpp \
     src/manifest.cpp \
     src/result.cpp \
     src/stats.cpp \
-    src/unify.cpp \
-    src/util.cpp
+    src/unify.cpp
 generated_sources = \
     src/version.cpp
 third_party_sources = \
@@ -75,6 +76,7 @@ ccache_objs = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(ccache_sources)))
 
 test_suites += unittest/test_Checksum.cpp
 test_suites += unittest/test_Config.cpp
+test_suites += unittest/test_Util.cpp
 test_suites += unittest/test_args.cpp
 test_suites += unittest/test_argument_processing.cpp
 test_suites += unittest/test_compopt.cpp
@@ -86,7 +88,6 @@ test_suites += unittest/test_hashutil.cpp
 test_suites += unittest/test_legacy_util.cpp
 test_suites += unittest/test_lockfile.cpp
 test_suites += unittest/test_stats.cpp
-test_suites += unittest/test_util.cpp
 
 test_sources += unittest/catch2_tests.cpp
 test_sources += unittest/framework.cpp
index 4399297fe63039eabf5a8e1c9501d306ab91c0cf..2e78f1613dd2417507d28e5eb9a5b1089a97fec4 100644 (file)
--- a/dev.mk.in
+++ b/dev.mk.in
@@ -41,6 +41,7 @@ non_third_party_headers = \
     src/Config.hpp \
     src/Error.hpp \
     src/ProgressBar.hpp \
+    src/Util.hpp \
     src/ccache.hpp \
     src/cleanup.hpp \
     src/common_header.hpp \
@@ -57,7 +58,6 @@ non_third_party_headers = \
     src/result.hpp \
     src/system.hpp \
     src/unify.hpp \
-    src/util.hpp \
     unittest/framework.hpp \
     unittest/util.hpp
 third_party_headers = \
index 401968267f14dd59569dec922231b5de68f95804..4063c21ca378ba0f3e42c529461471f945cb1686 100644 (file)
@@ -19,6 +19,7 @@
 #include "AtomicFile.hpp"
 
 #include "Error.hpp"
+#include "Util.hpp"
 #include "ccache.hpp"
 
 #include <cassert>
@@ -28,7 +29,7 @@
 
 AtomicFile::AtomicFile(const std::string& path, Mode mode) : m_path(path)
 {
-  auto fd_and_path = util::create_temp_fd(path);
+  auto fd_and_path = Util::create_temp_fd(path);
   m_stream = fdopen(fd_and_path.first, mode == Mode::binary ? "w+b" : "w+");
   m_tmp_path = std::move(fd_and_path.second);
 }
index 4a301031e18c017ee43b8ec0d43b3e775c25b03b..8022b2fb56ea0169fd2f3b3ca1f598b8ee4e2207 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "CacheFile.hpp"
 
-#include "util.hpp"
+#include "Util.hpp"
 
 const struct stat&
 CacheFile::stat() const
@@ -50,9 +50,9 @@ CacheFile::stat() const
 CacheFile::Type
 CacheFile::type() const
 {
-  if (util::ends_with(m_path, ".manifest")) {
+  if (Util::ends_with(m_path, ".manifest")) {
     return Type::manifest;
-  } else if (util::ends_with(m_path, ".result")) {
+  } else if (Util::ends_with(m_path, ".result")) {
     return Type::result;
   } else {
     return Type::unknown;
index 3a6d019a88b6203452d0a162d38a6a500b2a0030..622ad11d3c7730d6058e1f1f0100714fde584370 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "AtomicFile.hpp"
 #include "Error.hpp"
-#include "util.hpp"
+#include "Util.hpp"
 
 #include <algorithm>
 #include <cassert>
@@ -164,7 +164,7 @@ parse_bool(const std::string& value, bool from_env_variable, bool negate)
     // Previously any value meant true, but this was surprising to users, who
     // might do something like CCACHE_DISABLE=0 and expect ccache to be
     // enabled.
-    std::string lower_value = util::to_lowercase(value);
+    std::string lower_value = Util::to_lowercase(value);
     if (value == "0" || lower_value == "false" || lower_value == "disable"
         || lower_value == "no") {
       throw Error(fmt::format(
@@ -245,7 +245,7 @@ parse_sloppiness(const std::string& value)
   while (end != std::string::npos) {
     end = value.find_first_of(", ", start);
     std::string token =
-      util::strip_whitespace(value.substr(start, end - start));
+      Util::strip_whitespace(value.substr(start, end - start));
     if (token == "file_macro") {
       result |= SLOPPY_FILE_MACRO;
     } else if (token == "file_stat_matches") {
@@ -371,7 +371,7 @@ parse_line(const std::string& line,
            std::string* value,
            std::string* error_message)
 {
-  std::string stripped_line = util::strip_whitespace(line);
+  std::string stripped_line = Util::strip_whitespace(line);
   if (stripped_line.empty() || stripped_line[0] == '#') {
     return true;
   }
@@ -382,8 +382,8 @@ parse_line(const std::string& line,
   }
   *key = stripped_line.substr(0, equal_pos);
   *value = stripped_line.substr(equal_pos + 1);
-  *key = util::strip_whitespace(*key);
-  *value = util::strip_whitespace(*value);
+  *key = Util::strip_whitespace(*key);
+  *value = Util::strip_whitespace(*value);
   return true;
 }
 
@@ -439,7 +439,7 @@ Config::update_from_environment()
   for (char** env = environ; *env; ++env) {
     std::string setting = *env;
     const std::string prefix = "CCACHE_";
-    if (!util::starts_with(setting, prefix)) {
+    if (!Util::starts_with(setting, prefix)) {
       continue;
     }
     size_t equal_pos = setting.find('=');
@@ -449,7 +449,7 @@ Config::update_from_environment()
 
     std::string key = setting.substr(prefix.size(), equal_pos - prefix.size());
     std::string value = setting.substr(equal_pos + 1);
-    bool negate = util::starts_with(key, "NO");
+    bool negate = Util::starts_with(key, "NO");
     if (negate) {
       key = key.substr(2);
     }
@@ -685,7 +685,7 @@ Config::set_item(const std::string& key,
     break;
 
   case ConfigItem::compression_level: {
-    auto level = util::parse_int(value);
+    auto level = Util::parse_int(value);
     if (level < -128 || level > 127) {
       throw Error("compression level must be between -128 and 127");
     }
diff --git a/src/Util.cpp b/src/Util.cpp
new file mode 100644 (file)
index 0000000..e33af70
--- /dev/null
@@ -0,0 +1,239 @@
+// Copyright (C) 2019 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "Util.hpp"
+
+#include "ccache.hpp"
+#include "util.hpp"
+
+#include <algorithm>
+#include <fstream>
+
+namespace {
+
+void
+get_cache_files_internal(const std::string& dir,
+                         uint8_t level,
+                         const Util::ProgressReceiver& progress_receiver,
+                         std::vector<std::shared_ptr<CacheFile>>& files)
+{
+  DIR* d = opendir(dir.c_str());
+  if (!d) {
+    return;
+  }
+
+  std::vector<std::string> directories;
+  dirent* de;
+  while ((de = readdir(d))) {
+    std::string name = de->d_name;
+    if (name == "" || name == "." || name == ".." || name == "CACHEDIR.TAG"
+        || name == "stats" || Util::starts_with(name, ".nfs")) {
+      continue;
+    }
+
+    if (name.length() == 1) {
+      directories.push_back(name);
+    } else {
+      files.push_back(
+        std::make_shared<CacheFile>(fmt::format("{}/{}", dir, name)));
+    }
+  }
+  closedir(d);
+
+  if (level == 1) {
+    progress_receiver(1.0 / (directories.size() + 1));
+  }
+
+  for (size_t i = 0; i < directories.size(); ++i) {
+    get_cache_files_internal(
+      dir + "/" + directories[i], level + 1, progress_receiver, files);
+    if (level == 1) {
+      progress_receiver(1.0 * (i + 1) / (directories.size() + 1));
+    }
+  }
+}
+
+} // namespace
+
+namespace Util {
+
+std::string
+base_name(const std::string& path)
+{
+  size_t n = path.rfind('/');
+#ifdef _WIN32
+  size_t n2 = path.rfind('\\');
+  if (n2 != std::string::npos && n2 > n) {
+    n = n2;
+  }
+#endif
+  return n == std::string::npos ? path : path.substr(n + 1);
+}
+
+bool
+create_dir(const std::string& dir)
+{
+  struct stat st;
+  if (stat(dir.c_str(), &st) == 0) {
+    if (S_ISDIR(st.st_mode)) {
+      return true;
+    } else {
+      errno = ENOTDIR;
+      return false;
+    }
+  } else {
+    if (!create_dir(Util::dir_name(dir))) {
+      return false;
+    }
+    int result = mkdir(dir.c_str(), 0777);
+    // Treat an already existing directory as OK since the file system could
+    // have changed in between calling stat and actually creating the
+    // directory. This can happen when there are multiple instances of ccache
+    // running and trying to create the same directory chain, which usually is
+    // the case when the cache root does not initially exist. As long as one of
+    // the processes creates the directories then our condition is satisfied
+    // and we avoid a race condition.
+    return result == 0 || errno == EEXIST;
+  }
+}
+
+std::pair<int, std::string>
+create_temp_fd(const std::string& path_prefix)
+{
+  char* tmp_path = x_strdup(path_prefix.c_str());
+  int fd = create_tmp_fd(&tmp_path);
+  std::string actual_path = tmp_path;
+  free(tmp_path);
+  return {fd, actual_path};
+}
+
+std::string
+dir_name(const std::string& path)
+{
+  size_t n = path.rfind('/');
+#ifdef _WIN32
+  size_t n2 = path.rfind('\\');
+  if (n2 != std::string::npos && n2 > n) {
+    n = n2;
+  }
+#endif
+  if (n == std::string::npos) {
+    return ".";
+  }
+  return n == 0 ? "/" : path.substr(0, n);
+}
+
+bool
+ends_with(const std::string& string, const std::string& suffix)
+{
+  return suffix.length() <= string.length()
+         && string.compare(
+              string.length() - suffix.length(), suffix.length(), suffix)
+              == 0;
+}
+
+void
+for_each_level_1_subdir(const std::string& cache_dir,
+                        const SubdirVisitor& subdir_visitor,
+                        const ProgressReceiver& progress_receiver)
+{
+  for (int i = 0; i <= 0xF; i++) {
+    double progress = 1.0 * i / 16;
+    progress_receiver(progress);
+    std::string subdir_path = fmt::format("{}/{:x}", cache_dir, i);
+    subdir_visitor(subdir_path, [&](double inner_progress) {
+      progress_receiver(progress + inner_progress / 16);
+    });
+  }
+  progress_receiver(1.0);
+}
+
+void
+get_level_1_files(const std::string& dir,
+                  const ProgressReceiver& progress_receiver,
+                  std::vector<std::shared_ptr<CacheFile>>& files)
+{
+  get_cache_files_internal(dir, 1, progress_receiver, files);
+}
+
+int
+parse_int(const std::string& value)
+{
+  size_t end;
+  long result;
+  bool failed = false;
+  try {
+    result = std::stol(value, &end, 10);
+  } catch (std::exception&) {
+    failed = true;
+  }
+  if (failed || end != value.size() || result < std::numeric_limits<int>::min()
+      || result > std::numeric_limits<int>::max()) {
+    throw Error(fmt::format("invalid integer: \"{}\"", value));
+  }
+  return result;
+}
+
+std::string
+read_file(const std::string& path)
+{
+  std::ifstream file(path);
+  if (!file) {
+    throw Error(fmt::format("{}: {}", path, strerror(errno)));
+  }
+  return std::string(std::istreambuf_iterator<char>(file),
+                     std::istreambuf_iterator<char>());
+}
+
+bool
+starts_with(const std::string& string, const std::string& prefix)
+{
+  return prefix.length() <= string.length()
+         && string.compare(0, prefix.length(), prefix) == 0;
+}
+
+std::string
+strip_whitespace(const std::string& string)
+{
+  auto is_space = [](int ch) { return std::isspace(ch); };
+  auto start = std::find_if_not(string.begin(), string.end(), is_space);
+  auto end = std::find_if_not(string.rbegin(), string.rend(), is_space).base();
+  return start < end ? std::string(start, end) : std::string();
+}
+
+std::string
+to_lowercase(const std::string& string)
+{
+  std::string result = string;
+  std::transform(result.begin(), result.end(), result.begin(), tolower);
+  return result;
+}
+
+// Write file data from a string.
+void
+write_file(const std::string& path, const std::string& data, bool binary)
+{
+  std::ofstream file(path,
+                     binary ? std::ios::out | std::ios::binary : std::ios::out);
+  if (!file) {
+    throw Error(fmt::format("{}: {}", path, strerror(errno)));
+  }
+  file << data;
+}
+
+} // namespace Util
similarity index 99%
rename from src/util.hpp
rename to src/Util.hpp
index caf24e5a1635c7719b634a9eda35855e2f27a43b..21eca35380a0b6570e1fb5aa7008bb27850f296b 100644 (file)
@@ -28,7 +28,7 @@
 #include <utility>
 #include <vector>
 
-namespace util {
+namespace Util {
 
 typedef std::function<void(double)> ProgressReceiver;
 typedef std::function<void(std::shared_ptr<CacheFile>)> CacheFileVisitor;
@@ -117,4 +117,4 @@ void write_file(const std::string& path,
                 const std::string& data,
                 bool binary = false);
 
-} // namespace util
+} // namespace Util
index f5834204f47ae1f5cef26a87a8d54f665382dfb7..737cfd803e1ef6113aee9dccf831dea8a55ca6ab 100644 (file)
@@ -21,9 +21,9 @@
 
 #include "Error.hpp"
 #include "ProgressBar.hpp"
+#include "Util.hpp"
 #include "cleanup.hpp"
 #include "compopt.hpp"
-#include "util.hpp"
 
 #include <fmt/core.h>
 #include <limits>
@@ -1636,7 +1636,7 @@ hash_compiler(struct hash* hash,
     hash_delimiter(hash, "cc_mtime");
     hash_int(hash, st->st_size);
     hash_int(hash, st->st_mtime);
-  } else if (util::starts_with(g_config.compiler_check(), "string:")) {
+  } else if (Util::starts_with(g_config.compiler_check(), "string:")) {
     hash_delimiter(hash, "cc_hash");
     hash_string(hash, g_config.compiler_check().c_str() + strlen("string:"));
   } else if (g_config.compiler_check() == "content" || !allow_command) {
@@ -3451,7 +3451,7 @@ out:
 static void
 create_initial_config_file(const char* path)
 {
-  if (!util::create_dir(util::dir_name(path))) {
+  if (!Util::create_dir(Util::dir_name(path))) {
     return;
   }
 
index 88956f15aa37bb78f6e977b9dd02dee5a6417771..5062742278554bd26e6958dfd831769039044332 100644 (file)
@@ -50,12 +50,12 @@ void
 clean_up_dir(const std::string& subdir,
              uint64_t max_size,
              uint32_t max_files,
-             const util::ProgressReceiver& progress_receiver)
+             const Util::ProgressReceiver& progress_receiver)
 {
   cc_log("Cleaning up cache directory %s", subdir.c_str());
 
   std::vector<std::shared_ptr<CacheFile>> files;
-  util::get_level_1_files(
+  Util::get_level_1_files(
     subdir, [&](double progress) { progress_receiver(progress / 3); }, files);
 
   uint64_t cache_size = 0;
@@ -73,7 +73,7 @@ clean_up_dir(const std::string& subdir,
 
     // Delete any tmp files older than 1 hour right away.
     if (file->stat().st_mtime + 3600 < current_time
-        && util::base_name(file->path()).find(".tmp.") != std::string::npos) {
+        && Util::base_name(file->path()).find(".tmp.") != std::string::npos) {
       x_unlink(file->path().c_str());
       continue;
     }
@@ -109,7 +109,7 @@ clean_up_dir(const std::string& subdir,
       break;
     }
 
-    if (util::ends_with(file->path(), ".stderr")) {
+    if (Util::ends_with(file->path(), ".stderr")) {
       // In order to be nice to legacy ccache versions, make sure that the .o
       // file is deleted before .stderr, because if the ccache process gets
       // killed after deleting the .stderr but before deleting the .o, the
@@ -148,12 +148,12 @@ clean_up_dir(const std::string& subdir,
 // Clean up all cache subdirectories.
 void
 clean_up_all(const Config& config,
-             const util::ProgressReceiver& progress_receiver)
+             const Util::ProgressReceiver& progress_receiver)
 {
-  util::for_each_level_1_subdir(
+  Util::for_each_level_1_subdir(
     config.cache_dir(),
     [&](const std::string& subdir,
-        const util::ProgressReceiver& sub_progress_receiver) {
+        const Util::ProgressReceiver& sub_progress_receiver) {
       clean_up_dir(subdir,
                    config.max_size() / 16,
                    config.max_files() / 16,
@@ -165,12 +165,12 @@ clean_up_all(const Config& config,
 // Wipe one cache subdirectory.
 static void
 wipe_dir(const std::string& subdir,
-         const util::ProgressReceiver& progress_receiver)
+         const Util::ProgressReceiver& progress_receiver)
 {
   cc_log("Clearing out cache directory %s", subdir.c_str());
 
   std::vector<std::shared_ptr<CacheFile>> files;
-  util::get_level_1_files(
+  Util::get_level_1_files(
     subdir, [&](double progress) { progress_receiver(progress / 2); }, files);
 
   for (size_t i = 0; i < files.size(); ++i) {
@@ -188,8 +188,8 @@ wipe_dir(const std::string& subdir,
 
 // Wipe all cached files in all subdirectories.
 void
-wipe_all(const Config& config, const util::ProgressReceiver& progress_receiver)
+wipe_all(const Config& config, const Util::ProgressReceiver& progress_receiver)
 {
-  util::for_each_level_1_subdir(
+  Util::for_each_level_1_subdir(
     config.cache_dir(), wipe_dir, progress_receiver);
 }
index 7fce9005a1b7e4a5355b099226aebdea60ae13ca..ac81e8fc912f6396cf4b2bddb956d161c713de3d 100644 (file)
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include "util.hpp"
+#include "Util.hpp"
 
 #include <string>
 
@@ -27,10 +27,10 @@ class Config;
 void clean_up_dir(const std::string& subdir,
                   uint64_t max_size,
                   uint32_t max_files,
-                  const util::ProgressReceiver& progress_receiver);
+                  const Util::ProgressReceiver& progress_receiver);
 
 void clean_up_all(const Config& config,
-                  const util::ProgressReceiver& progress_receiver);
+                  const Util::ProgressReceiver& progress_receiver);
 
 void wipe_all(const Config& config,
-              const util::ProgressReceiver& progress_receiver);
+              const Util::ProgressReceiver& progress_receiver);
index 3ae295aab495bf4d118d4175d80767c63f776a19..21e9d1d6473dcf9a8e11e1af334ba86e982a6560 100644 (file)
@@ -50,19 +50,19 @@ get_content_size(const std::string& path,
 
 void
 compress_stats(const Config& config,
-               const util::ProgressReceiver& progress_receiver)
+               const Util::ProgressReceiver& progress_receiver)
 {
   uint64_t on_disk_size = 0;
   uint64_t compr_size = 0;
   uint64_t compr_orig_size = 0;
   uint64_t incompr_size = 0;
 
-  util::for_each_level_1_subdir(
+  Util::for_each_level_1_subdir(
     config.cache_dir(),
     [&](const std::string& subdir,
-        const util::ProgressReceiver& sub_progress_receiver) {
+        const Util::ProgressReceiver& sub_progress_receiver) {
       std::vector<std::shared_ptr<CacheFile>> files;
-      util::get_level_1_files(
+      Util::get_level_1_files(
         subdir,
         [&](double progress) { sub_progress_receiver(progress / 2); },
         files);
index 459258c7f42cdabf2b13189357269487c05c9f9c..58f6e2b4d2d6db639da2ed23e2affeb552cd2e58 100644 (file)
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "Config.hpp"
-#include "util.hpp"
+#include "Util.hpp"
 
 void compress_stats(const Config& config,
-                    const util::ProgressReceiver& progress_receiver);
+                    const Util::ProgressReceiver& progress_receiver);
similarity index 86%
rename from src/util.cpp
rename to src/legacy_util.cpp
index d066a90e70c946dce9dcc816b5580cdcd9196cba..90e10c838762f64a77354c33a583bfc3c08080ff 100644 (file)
 
 #include "Config.hpp"
 #include "Error.hpp"
+#include "Util.hpp"
 #include "ccache.hpp"
 
-#include <algorithm>
 #include <fmt/core.h>
-#include <fstream>
 #include <string>
 
 #ifdef HAVE_PWD_H
@@ -1176,7 +1175,7 @@ create_tmp_fd(char** fname)
   char* tmpl = format("%s.%s", *fname, tmp_string());
   int fd = mkstemp(tmpl);
   if (fd == -1 && errno == ENOENT) {
-    if (!util::create_dir(util::dir_name(*fname))) {
+    if (!Util::create_dir(Util::dir_name(*fname))) {
       fatal("Failed to create directory %s: %s",
             x_dirname(*fname),
             strerror(errno));
@@ -1710,217 +1709,3 @@ time_seconds(void)
   return (double)time(NULL);
 #endif
 }
-
-namespace {
-
-void
-get_cache_files_internal(const std::string& dir,
-                         uint8_t level,
-                         const util::ProgressReceiver& progress_receiver,
-                         std::vector<std::shared_ptr<CacheFile>>& files)
-{
-  DIR* d = opendir(dir.c_str());
-  if (!d) {
-    return;
-  }
-
-  std::vector<std::string> directories;
-  dirent* de;
-  while ((de = readdir(d))) {
-    std::string name = de->d_name;
-    if (name == "" || name == "." || name == ".." || name == "CACHEDIR.TAG"
-        || name == "stats" || util::starts_with(name, ".nfs")) {
-      continue;
-    }
-
-    if (name.length() == 1) {
-      directories.push_back(name);
-    } else {
-      files.push_back(
-        std::make_shared<CacheFile>(fmt::format("{}/{}", dir, name)));
-    }
-  }
-  closedir(d);
-
-  if (level == 1) {
-    progress_receiver(1.0 / (directories.size() + 1));
-  }
-
-  for (size_t i = 0; i < directories.size(); ++i) {
-    get_cache_files_internal(
-      dir + "/" + directories[i], level + 1, progress_receiver, files);
-    if (level == 1) {
-      progress_receiver(1.0 * (i + 1) / (directories.size() + 1));
-    }
-  }
-}
-
-} // namespace
-
-namespace util {
-
-std::string
-base_name(const std::string& path)
-{
-  size_t n = path.rfind('/');
-#ifdef _WIN32
-  size_t n2 = path.rfind('\\');
-  if (n2 != std::string::npos && n2 > n) {
-    n = n2;
-  }
-#endif
-  return n == std::string::npos ? path : path.substr(n + 1);
-}
-
-bool
-create_dir(const std::string& dir)
-{
-  struct stat st;
-  if (stat(dir.c_str(), &st) == 0) {
-    if (S_ISDIR(st.st_mode)) {
-      return true;
-    } else {
-      errno = ENOTDIR;
-      return false;
-    }
-  } else {
-    if (!create_dir(util::dir_name(dir))) {
-      return false;
-    }
-    int result = mkdir(dir.c_str(), 0777);
-    // Treat an already existing directory as OK since the file system could
-    // have changed in between calling stat and actually creating the
-    // directory. This can happen when there are multiple instances of ccache
-    // running and trying to create the same directory chain, which usually is
-    // the case when the cache root does not initially exist. As long as one of
-    // the processes creates the directories then our condition is satisfied
-    // and we avoid a race condition.
-    return result == 0 || errno == EEXIST;
-  }
-}
-
-std::pair<int, std::string>
-create_temp_fd(const std::string& path_prefix)
-{
-  char* tmp_path = x_strdup(path_prefix.c_str());
-  int fd = create_tmp_fd(&tmp_path);
-  std::string actual_path = tmp_path;
-  free(tmp_path);
-  return {fd, actual_path};
-}
-
-std::string
-dir_name(const std::string& path)
-{
-  size_t n = path.rfind('/');
-#ifdef _WIN32
-  size_t n2 = path.rfind('\\');
-  if (n2 != std::string::npos && n2 > n) {
-    n = n2;
-  }
-#endif
-  if (n == std::string::npos) {
-    return ".";
-  }
-  return n == 0 ? "/" : path.substr(0, n);
-}
-
-bool
-ends_with(const std::string& string, const std::string& suffix)
-{
-  return suffix.length() <= string.length()
-         && string.compare(
-              string.length() - suffix.length(), suffix.length(), suffix)
-              == 0;
-}
-
-void
-for_each_level_1_subdir(const std::string& cache_dir,
-                        const SubdirVisitor& subdir_visitor,
-                        const ProgressReceiver& progress_receiver)
-{
-  for (int i = 0; i <= 0xF; i++) {
-    double progress = 1.0 * i / 16;
-    progress_receiver(progress);
-    std::string subdir_path = fmt::format("{}/{:x}", cache_dir, i);
-    subdir_visitor(subdir_path, [&](double inner_progress) {
-      progress_receiver(progress + inner_progress / 16);
-    });
-  }
-  progress_receiver(1.0);
-}
-
-void
-get_level_1_files(const std::string& dir,
-                  const ProgressReceiver& progress_receiver,
-                  std::vector<std::shared_ptr<CacheFile>>& files)
-{
-  get_cache_files_internal(dir, 1, progress_receiver, files);
-}
-
-int
-parse_int(const std::string& value)
-{
-  size_t end;
-  long result;
-  bool failed = false;
-  try {
-    result = std::stol(value, &end, 10);
-  } catch (std::exception&) {
-    failed = true;
-  }
-  if (failed || end != value.size() || result < std::numeric_limits<int>::min()
-      || result > std::numeric_limits<int>::max()) {
-    throw Error(fmt::format("invalid integer: \"{}\"", value));
-  }
-  return result;
-}
-
-std::string
-read_file(const std::string& path)
-{
-  std::ifstream file(path);
-  if (!file) {
-    throw Error(fmt::format("{}: {}", path, strerror(errno)));
-  }
-  return std::string(std::istreambuf_iterator<char>(file),
-                     std::istreambuf_iterator<char>());
-}
-
-bool
-starts_with(const std::string& string, const std::string& prefix)
-{
-  return prefix.length() <= string.length()
-         && string.compare(0, prefix.length(), prefix) == 0;
-}
-
-std::string
-strip_whitespace(const std::string& string)
-{
-  auto is_space = [](int ch) { return std::isspace(ch); };
-  auto start = std::find_if_not(string.begin(), string.end(), is_space);
-  auto end = std::find_if_not(string.rbegin(), string.rend(), is_space).base();
-  return start < end ? std::string(start, end) : std::string();
-}
-
-std::string
-to_lowercase(const std::string& string)
-{
-  std::string result = string;
-  std::transform(result.begin(), result.end(), result.begin(), tolower);
-  return result;
-}
-
-// Write file data from a string.
-void
-write_file(const std::string& path, const std::string& data, bool binary)
-{
-  std::ofstream file(path,
-                     binary ? std::ios::out | std::ios::binary : std::ios::out);
-  if (!file) {
-    throw Error(fmt::format("{}: {}", path, strerror(errno)));
-  }
-  file << data;
-}
-
-} // namespace util
index bc9d1745352154cdb5bf8ec811ae69ee911924ee..a93be8e339fcce66bfa2b55d95b9718a320c18f7 100644 (file)
@@ -16,8 +16,8 @@
 // this program; if not, write to the Free Software Foundation, Inc., 51
 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
+#include "Util.hpp"
 #include "ccache.hpp"
-#include "util.hpp"
 
 // This function acquires a lockfile for the given path. Returns true if the
 // lock was acquired, otherwise false. If the lock has been considered stale
@@ -50,7 +50,7 @@ lockfile_acquire(const char* path, unsigned staleness_limit)
       cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno));
       if (saved_errno == ENOENT) {
         // Directory doesn't exist?
-        if (util::create_dir(util::dir_name(lockfile))) {
+        if (Util::create_dir(Util::dir_name(lockfile))) {
           // OK. Retry.
           continue;
         }
@@ -105,7 +105,7 @@ lockfile_acquire(const char* path, unsigned staleness_limit)
     cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(saved_errno));
     if (saved_errno == ENOENT) {
       // Directory doesn't exist?
-      if (util::create_dir(util::dir_name(lockfile))) {
+      if (Util::create_dir(Util::dir_name(lockfile))) {
         // OK. Retry.
         continue;
       }
index 07e0b6f13dcd22cf39b7b390977ef16f6b8ca96f..8dee463b22b327de578176cb03bf083da9a362a7 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "framework.hpp"
 
-#include "../src/util.hpp"
+#include "../src/Util.hpp"
 #include "util.hpp"
 
 #include <float.h>
@@ -110,7 +110,7 @@ cct_suite_begin(const char* name)
     printf("=== SUITE: %s ===\n", name);
   }
   dir_before_suite = gnu_getcwd();
-  util::create_dir(name);
+  Util::create_dir(name);
   cct_chdir(name);
   current_suite = name;
 }
@@ -131,7 +131,7 @@ cct_test_begin(const char* name)
     printf("--- TEST: %s ---\n", name);
   }
   dir_before_test = gnu_getcwd();
-  util::create_dir(name);
+  Util::create_dir(name);
   cct_chdir(name);
   current_test = name;
 
index 9b6602454108c17a0b7af5f8cd20e88015fdc690..f32ceabd6efb5db2d70622f74e9a25f87a884d6e 100644 (file)
@@ -18,8 +18,8 @@
 
 #include "../src/Config.hpp"
 #include "../src/Error.hpp"
+#include "../src/Util.hpp"
 #include "../src/ccache.hpp"
-#include "../src/util.hpp"
 
 #include <catch.hpp>
 #include <fmt/core.h>
@@ -80,7 +80,7 @@ TEST_CASE("Config::update_from_file")
   std::string base_dir = fmt::format("C:/{0}/foo/{0}", user);
 #endif
 
-  util::write_file(
+  Util::write_file(
     "ccache.conf",
     "base_dir = " + base_dir + "\n"
     "cache_dir=\n"
@@ -173,72 +173,72 @@ TEST_CASE("Config::update_from_file, error handling")
 
   SECTION("missing equal sign")
   {
-    util::write_file("ccache.conf", "no equal sign");
+    Util::write_file("ccache.conf", "no equal sign");
     REQUIRE_THROWS_WITH(config.update_from_file("ccache.conf"),
                         Equals("ccache.conf:1: missing equal sign"));
   }
 
   SECTION("unknown key")
   {
-    util::write_file("ccache.conf", "# Comment\nfoo = bar");
+    Util::write_file("ccache.conf", "# Comment\nfoo = bar");
     CHECK(config.update_from_file("ccache.conf"));
   }
 
   SECTION("invalid bool")
   {
-    util::write_file("ccache.conf", "disable=");
+    Util::write_file("ccache.conf", "disable=");
     REQUIRE_THROWS_WITH(config.update_from_file("ccache.conf"),
                         Equals("ccache.conf:1: not a boolean value: \"\""));
 
-    util::write_file("ccache.conf", "disable=foo");
+    Util::write_file("ccache.conf", "disable=foo");
     REQUIRE_THROWS_WITH(config.update_from_file("ccache.conf"),
                         Equals("ccache.conf:1: not a boolean value: \"foo\""));
   }
 
   SECTION("invalid variable reference")
   {
-    util::write_file("ccache.conf", "base_dir = ${foo");
+    Util::write_file("ccache.conf", "base_dir = ${foo");
     REQUIRE_THROWS_WITH(
       config.update_from_file("ccache.conf"),
       Equals("ccache.conf:1: syntax error: missing '}' after \"foo\""));
-    // Other cases tested in test_util.c.
+    // Other cases tested in test_Util.c.
   }
 
   SECTION("empty umask")
   {
-    util::write_file("ccache.conf", "umask = ");
+    Util::write_file("ccache.conf", "umask = ");
     CHECK(config.update_from_file("ccache.conf"));
     CHECK(config.umask() == std::numeric_limits<uint32_t>::max());
   }
 
   SECTION("invalid size")
   {
-    util::write_file("ccache.conf", "max_size = foo");
+    Util::write_file("ccache.conf", "max_size = foo");
     REQUIRE_THROWS_WITH(config.update_from_file("ccache.conf"),
                         Equals("ccache.conf:1: invalid size: \"foo\""));
-    // Other cases tested in test_util.c.
+    // Other cases tested in test_Util.c.
   }
 
   SECTION("invalid sloppiness")
   {
-    util::write_file("ccache.conf", "sloppiness = file_macro, foo");
+    Util::write_file("ccache.conf", "sloppiness = file_macro, foo");
     REQUIRE_THROWS_WITH(config.update_from_file("ccache.conf"),
                         Equals("ccache.conf:1: unknown sloppiness: \"foo\""));
   }
 
   SECTION("invalid unsigned")
   {
-    util::write_file("ccache.conf", "max_files =");
+    Util::write_file("ccache.conf", "max_files =");
     REQUIRE_THROWS_WITH(
       config.update_from_file("ccache.conf"),
       Equals("ccache.conf:1: invalid unsigned integer: \"\""));
 
-    util::write_file("ccache.conf", "max_files = -42");
+    Util::write_file("ccache.conf", "max_files = -42");
     REQUIRE_THROWS_WITH(
       config.update_from_file("ccache.conf"),
       Equals("ccache.conf:1: invalid unsigned integer: \"-42\""));
 
-    util::write_file("ccache.conf", "max_files = foo");
+    Util::write_file("ccache.conf", "max_files = foo");
     REQUIRE_THROWS_WITH(
       config.update_from_file("ccache.conf"),
       Equals("ccache.conf:1: invalid unsigned integer: \"foo\""));
@@ -251,18 +251,18 @@ TEST_CASE("Config::update_from_file, error handling")
 
   SECTION("relative base dir")
   {
-    util::write_file("ccache.conf", "base_dir = relative/path");
+    Util::write_file("ccache.conf", "base_dir = relative/path");
     REQUIRE_THROWS_WITH(
       config.update_from_file("ccache.conf"),
       Equals("ccache.conf:1: not an absolute path: \"relative/path\""));
 
-    util::write_file("ccache.conf", "base_dir =");
+    Util::write_file("ccache.conf", "base_dir =");
     CHECK(config.update_from_file("ccache.conf"));
   }
 
   SECTION("bad dir levels")
   {
-    util::write_file("ccache.conf", "cache_dir_levels = 0");
+    Util::write_file("ccache.conf", "cache_dir_levels = 0");
     try {
       config.update_from_file("ccache.conf");
       CHECK(false);
@@ -271,7 +271,7 @@ TEST_CASE("Config::update_from_file, error handling")
             == "ccache.conf:1: cache directory levels must be between 1 and 8");
     }
 
-    util::write_file("ccache.conf", "cache_dir_levels = 9");
+    Util::write_file("ccache.conf", "cache_dir_levels = 9");
     try {
       config.update_from_file("ccache.conf");
       CHECK(false);
@@ -301,23 +301,23 @@ TEST_CASE("Config::set_value_in_file")
 {
   SECTION("set new value")
   {
-    util::write_file("ccache.conf", "path = vanilla\n");
+    Util::write_file("ccache.conf", "path = vanilla\n");
     Config::set_value_in_file("ccache.conf", "compiler", "chocolate");
-    std::string content = util::read_file("ccache.conf");
+    std::string content = Util::read_file("ccache.conf");
     CHECK(content == "path = vanilla\ncompiler = chocolate\n");
   }
 
   SECTION("existing value")
   {
-    util::write_file("ccache.conf", "path = chocolate\nstats = chocolate\n");
+    Util::write_file("ccache.conf", "path = chocolate\nstats = chocolate\n");
     Config::set_value_in_file("ccache.conf", "path", "vanilla");
-    std::string content = util::read_file("ccache.conf");
+    std::string content = Util::read_file("ccache.conf");
     CHECK(content == "path = vanilla\nstats = chocolate\n");
   }
 
   SECTION("unknown option")
   {
-    util::write_file("ccache.conf", "path = chocolate\nstats = chocolate\n");
+    Util::write_file("ccache.conf", "path = chocolate\nstats = chocolate\n");
     try {
       Config::set_value_in_file("ccache.conf", "foo", "bar");
       CHECK(false);
@@ -325,7 +325,7 @@ TEST_CASE("Config::set_value_in_file")
       CHECK(std::string(e.what()) == "unknown configuration option \"foo\"");
     }
 
-    std::string content = util::read_file("ccache.conf");
+    std::string content = Util::read_file("ccache.conf");
     CHECK(content == "path = chocolate\nstats = chocolate\n");
   }
 }
@@ -353,7 +353,7 @@ TEST_CASE("Config::get_string_value")
 
 TEST_CASE("Config::visit_items")
 {
-  util::write_file(
+  Util::write_file(
     "test.conf",
     "base_dir = /bd\n"
     "cache_dir = cd\n"
diff --git a/unittest/test_Util.cpp b/unittest/test_Util.cpp
new file mode 100644 (file)
index 0000000..a9fcfd2
--- /dev/null
@@ -0,0 +1,216 @@
+// Copyright (C) 2019 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../src/Util.hpp"
+
+#include <catch.hpp>
+
+using Catch::Equals;
+
+TEST_CASE("Util::base_name")
+{
+  CHECK(Util::base_name("") == "");
+  CHECK(Util::base_name(".") == ".");
+  CHECK(Util::base_name("foo") == "foo");
+  CHECK(Util::base_name("/") == "");
+  CHECK(Util::base_name("/foo") == "foo");
+  CHECK(Util::base_name("/foo/bar/f.txt") == "f.txt");
+}
+
+TEST_CASE("Util::create_dir")
+{
+  CHECK(Util::create_dir("/"));
+
+  CHECK(Util::create_dir("create/dir"));
+  struct stat st;
+  CHECK(stat("create/dir", &st) == 0);
+  CHECK(S_ISDIR(st.st_mode));
+
+  Util::write_file("create/dir/file", "");
+  CHECK(!Util::create_dir("create/dir/file"));
+}
+
+TEST_CASE("Util::dir_name")
+{
+  CHECK(Util::dir_name("") == ".");
+  CHECK(Util::dir_name(".") == ".");
+  CHECK(Util::dir_name("foo") == ".");
+  CHECK(Util::dir_name("/") == "/");
+  CHECK(Util::dir_name("/foo") == "/");
+  CHECK(Util::dir_name("/foo/bar/f.txt") == "/foo/bar");
+}
+
+TEST_CASE("Util::ends_with")
+{
+  CHECK(Util::ends_with("", ""));
+  CHECK(Util::ends_with("x", ""));
+  CHECK(Util::ends_with("x", "x"));
+  CHECK(Util::ends_with("xy", ""));
+  CHECK(Util::ends_with("xy", "y"));
+  CHECK(Util::ends_with("xy", "xy"));
+  CHECK(Util::ends_with("xyz", ""));
+  CHECK(Util::ends_with("xyz", "z"));
+  CHECK(Util::ends_with("xyz", "yz"));
+  CHECK(Util::ends_with("xyz", "xyz"));
+
+  CHECK_FALSE(Util::ends_with("", "x"));
+  CHECK_FALSE(Util::ends_with("x", "y"));
+  CHECK_FALSE(Util::ends_with("x", "xy"));
+}
+
+TEST_CASE("Util::for_each_level_1_subdir")
+{
+  std::vector<std::string> actual;
+  Util::for_each_level_1_subdir(
+    "cache_dir",
+    [&](const std::string& subdir, const Util::ProgressReceiver&) {
+      actual.push_back(subdir);
+    },
+    [](double) {});
+
+  std::vector<std::string> expected = {
+    "cache_dir/0",
+    "cache_dir/1",
+    "cache_dir/2",
+    "cache_dir/3",
+    "cache_dir/4",
+    "cache_dir/5",
+    "cache_dir/6",
+    "cache_dir/7",
+    "cache_dir/8",
+    "cache_dir/9",
+    "cache_dir/a",
+    "cache_dir/b",
+    "cache_dir/c",
+    "cache_dir/d",
+    "cache_dir/e",
+    "cache_dir/f",
+  };
+  CHECK(actual == expected);
+}
+
+TEST_CASE("Util::get_level_1_files")
+{
+  Util::create_dir("e/m/p/t/y");
+
+  Util::create_dir("0/1");
+  Util::create_dir("0/f/c");
+  Util::write_file("0/file_a", "");
+  Util::write_file("0/1/file_b", "1");
+  Util::write_file("0/1/file_c", "12");
+  Util::write_file("0/f/c/file_d", "123");
+
+  std::vector<std::shared_ptr<CacheFile>> files;
+  auto null_receiver = [](double) {};
+
+  SECTION("nonexistent subdirectory")
+  {
+    Util::get_level_1_files("2", null_receiver, files);
+    CHECK(files.empty());
+  }
+
+  SECTION("empty subdirectory")
+  {
+    Util::get_level_1_files("e", null_receiver, files);
+    CHECK(files.empty());
+  }
+
+  SECTION("simple case")
+  {
+    Util::get_level_1_files("0", null_receiver, files);
+    REQUIRE(files.size() == 4);
+
+    // Files within a level are in arbitrary order, sort them to be able to
+    // verify them.
+    std::sort(files.begin(),
+              files.end(),
+              [](const std::shared_ptr<CacheFile>& f1,
+                 const std::shared_ptr<CacheFile>& f2) {
+                return f1->path() < f2->path();
+              });
+
+    CHECK(files[0]->path() == "0/1/file_b");
+    CHECK(files[0]->stat().st_size == 1);
+    CHECK(files[1]->path() == "0/1/file_c");
+    CHECK(files[1]->stat().st_size == 2);
+    CHECK(files[2]->path() == "0/f/c/file_d");
+    CHECK(files[2]->stat().st_size == 3);
+    CHECK(files[3]->path() == "0/file_a");
+    CHECK(files[3]->stat().st_size == 0);
+  }
+}
+
+TEST_CASE("Util::parse_int")
+{
+  CHECK(Util::parse_int("0") == 0);
+  CHECK(Util::parse_int("2") == 2);
+  CHECK(Util::parse_int("-17") == -17);
+  CHECK(Util::parse_int("42") == 42);
+  CHECK(Util::parse_int("0666") == 666);
+  CHECK(Util::parse_int(" 777") == 777);
+
+  CHECK_THROWS_WITH(Util::parse_int(""), Equals("invalid integer: \"\""));
+  CHECK_THROWS_WITH(Util::parse_int("x"), Equals("invalid integer: \"x\""));
+  CHECK_THROWS_WITH(Util::parse_int("0x"), Equals("invalid integer: \"0x\""));
+  CHECK_THROWS_WITH(Util::parse_int("0x4"), Equals("invalid integer: \"0x4\""));
+  CHECK_THROWS_WITH(Util::parse_int("0 "), Equals("invalid integer: \"0 \""));
+}
+
+TEST_CASE("Util::read_file and Util::write_file")
+{
+  Util::write_file("test", "foo\nbar\n");
+  std::string data = Util::read_file("test");
+  CHECK(data == "foo\nbar\n");
+}
+
+TEST_CASE("Util::starts_with")
+{
+  CHECK(Util::starts_with("", ""));
+  CHECK(Util::starts_with("x", ""));
+  CHECK(Util::starts_with("x", "x"));
+  CHECK(Util::starts_with("xy", ""));
+  CHECK(Util::starts_with("xy", "x"));
+  CHECK(Util::starts_with("xy", "xy"));
+  CHECK(Util::starts_with("xyz", ""));
+  CHECK(Util::starts_with("xyz", "x"));
+  CHECK(Util::starts_with("xyz", "xy"));
+  CHECK(Util::starts_with("xyz", "xyz"));
+
+  CHECK_FALSE(Util::starts_with("", "x"));
+  CHECK_FALSE(Util::starts_with("x", "y"));
+  CHECK_FALSE(Util::starts_with("x", "xy"));
+}
+
+TEST_CASE("Util::strip_whitespace")
+{
+  CHECK(Util::strip_whitespace("") == "");
+  CHECK(Util::strip_whitespace("x") == "x");
+  CHECK(Util::strip_whitespace(" x") == "x");
+  CHECK(Util::strip_whitespace("x ") == "x");
+  CHECK(Util::strip_whitespace(" x ") == "x");
+  CHECK(Util::strip_whitespace(" \n\tx \n\t") == "x");
+  CHECK(Util::strip_whitespace("  x  y  ") == "x  y");
+}
+
+TEST_CASE("Util::to_lowercase")
+{
+  CHECK(Util::to_lowercase("") == "");
+  CHECK(Util::to_lowercase("x") == "x");
+  CHECK(Util::to_lowercase("X") == "x");
+  CHECK(Util::to_lowercase(" x_X@") == " x_x@");
+}
diff --git a/unittest/test_util.cpp b/unittest/test_util.cpp
deleted file mode 100644 (file)
index 89d505b..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (C) 2019 Joel Rosdahl and other contributors
-//
-// See doc/AUTHORS.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#include "../src/util.hpp"
-
-#include <catch.hpp>
-
-using Catch::Equals;
-
-TEST_CASE("util::base_name")
-{
-  CHECK(util::base_name("") == "");
-  CHECK(util::base_name(".") == ".");
-  CHECK(util::base_name("foo") == "foo");
-  CHECK(util::base_name("/") == "");
-  CHECK(util::base_name("/foo") == "foo");
-  CHECK(util::base_name("/foo/bar/f.txt") == "f.txt");
-}
-
-TEST_CASE("util::create_dir")
-{
-  CHECK(util::create_dir("/"));
-
-  CHECK(util::create_dir("create/dir"));
-  struct stat st;
-  CHECK(stat("create/dir", &st) == 0);
-  CHECK(S_ISDIR(st.st_mode));
-
-  util::write_file("create/dir/file", "");
-  CHECK(!util::create_dir("create/dir/file"));
-}
-
-TEST_CASE("util::dir_name")
-{
-  CHECK(util::dir_name("") == ".");
-  CHECK(util::dir_name(".") == ".");
-  CHECK(util::dir_name("foo") == ".");
-  CHECK(util::dir_name("/") == "/");
-  CHECK(util::dir_name("/foo") == "/");
-  CHECK(util::dir_name("/foo/bar/f.txt") == "/foo/bar");
-}
-
-TEST_CASE("util::ends_with")
-{
-  CHECK(util::ends_with("", ""));
-  CHECK(util::ends_with("x", ""));
-  CHECK(util::ends_with("x", "x"));
-  CHECK(util::ends_with("xy", ""));
-  CHECK(util::ends_with("xy", "y"));
-  CHECK(util::ends_with("xy", "xy"));
-  CHECK(util::ends_with("xyz", ""));
-  CHECK(util::ends_with("xyz", "z"));
-  CHECK(util::ends_with("xyz", "yz"));
-  CHECK(util::ends_with("xyz", "xyz"));
-
-  CHECK_FALSE(util::ends_with("", "x"));
-  CHECK_FALSE(util::ends_with("x", "y"));
-  CHECK_FALSE(util::ends_with("x", "xy"));
-}
-
-TEST_CASE("util::for_each_level_1_subdir")
-{
-  std::vector<std::string> actual;
-  util::for_each_level_1_subdir(
-    "cache_dir",
-    [&](const std::string& subdir, const util::ProgressReceiver&) {
-      actual.push_back(subdir);
-    },
-    [](double) {});
-
-  std::vector<std::string> expected = {
-    "cache_dir/0",
-    "cache_dir/1",
-    "cache_dir/2",
-    "cache_dir/3",
-    "cache_dir/4",
-    "cache_dir/5",
-    "cache_dir/6",
-    "cache_dir/7",
-    "cache_dir/8",
-    "cache_dir/9",
-    "cache_dir/a",
-    "cache_dir/b",
-    "cache_dir/c",
-    "cache_dir/d",
-    "cache_dir/e",
-    "cache_dir/f",
-  };
-  CHECK(actual == expected);
-}
-
-TEST_CASE("util::get_level_1_files")
-{
-  util::create_dir("e/m/p/t/y");
-
-  util::create_dir("0/1");
-  util::create_dir("0/f/c");
-  util::write_file("0/file_a", "");
-  util::write_file("0/1/file_b", "1");
-  util::write_file("0/1/file_c", "12");
-  util::write_file("0/f/c/file_d", "123");
-
-  std::vector<std::shared_ptr<CacheFile>> files;
-  auto null_receiver = [](double) {};
-
-  SECTION("nonexistent subdirectory")
-  {
-    util::get_level_1_files("2", null_receiver, files);
-    CHECK(files.empty());
-  }
-
-  SECTION("empty subdirectory")
-  {
-    util::get_level_1_files("e", null_receiver, files);
-    CHECK(files.empty());
-  }
-
-  SECTION("simple case")
-  {
-    util::get_level_1_files("0", null_receiver, files);
-    REQUIRE(files.size() == 4);
-
-    // Files within a level are in arbitrary order, sort them to be able to
-    // verify them.
-    std::sort(files.begin(),
-              files.end(),
-              [](const std::shared_ptr<CacheFile>& f1,
-                 const std::shared_ptr<CacheFile>& f2) {
-                return f1->path() < f2->path();
-              });
-
-    CHECK(files[0]->path() == "0/1/file_b");
-    CHECK(files[0]->stat().st_size == 1);
-    CHECK(files[1]->path() == "0/1/file_c");
-    CHECK(files[1]->stat().st_size == 2);
-    CHECK(files[2]->path() == "0/f/c/file_d");
-    CHECK(files[2]->stat().st_size == 3);
-    CHECK(files[3]->path() == "0/file_a");
-    CHECK(files[3]->stat().st_size == 0);
-  }
-}
-
-TEST_CASE("util::parse_int")
-{
-  CHECK(util::parse_int("0") == 0);
-  CHECK(util::parse_int("2") == 2);
-  CHECK(util::parse_int("-17") == -17);
-  CHECK(util::parse_int("42") == 42);
-  CHECK(util::parse_int("0666") == 666);
-  CHECK(util::parse_int(" 777") == 777);
-
-  CHECK_THROWS_WITH(util::parse_int(""), Equals("invalid integer: \"\""));
-  CHECK_THROWS_WITH(util::parse_int("x"), Equals("invalid integer: \"x\""));
-  CHECK_THROWS_WITH(util::parse_int("0x"), Equals("invalid integer: \"0x\""));
-  CHECK_THROWS_WITH(util::parse_int("0x4"), Equals("invalid integer: \"0x4\""));
-  CHECK_THROWS_WITH(util::parse_int("0 "), Equals("invalid integer: \"0 \""));
-}
-
-TEST_CASE("util::read_file and util::write_file")
-{
-  util::write_file("test", "foo\nbar\n");
-  std::string data = util::read_file("test");
-  CHECK(data == "foo\nbar\n");
-}
-
-TEST_CASE("util::starts_with")
-{
-  CHECK(util::starts_with("", ""));
-  CHECK(util::starts_with("x", ""));
-  CHECK(util::starts_with("x", "x"));
-  CHECK(util::starts_with("xy", ""));
-  CHECK(util::starts_with("xy", "x"));
-  CHECK(util::starts_with("xy", "xy"));
-  CHECK(util::starts_with("xyz", ""));
-  CHECK(util::starts_with("xyz", "x"));
-  CHECK(util::starts_with("xyz", "xy"));
-  CHECK(util::starts_with("xyz", "xyz"));
-
-  CHECK_FALSE(util::starts_with("", "x"));
-  CHECK_FALSE(util::starts_with("x", "y"));
-  CHECK_FALSE(util::starts_with("x", "xy"));
-}
-
-TEST_CASE("util::strip_whitespace")
-{
-  CHECK(util::strip_whitespace("") == "");
-  CHECK(util::strip_whitespace("x") == "x");
-  CHECK(util::strip_whitespace(" x") == "x");
-  CHECK(util::strip_whitespace("x ") == "x");
-  CHECK(util::strip_whitespace(" x ") == "x");
-  CHECK(util::strip_whitespace(" \n\tx \n\t") == "x");
-  CHECK(util::strip_whitespace("  x  y  ") == "x  y");
-}
-
-TEST_CASE("util::to_lowercase")
-{
-  CHECK(util::to_lowercase("") == "");
-  CHECK(util::to_lowercase("x") == "x");
-  CHECK(util::to_lowercase("X") == "x");
-  CHECK(util::to_lowercase(" x_X@") == " x_x@");
-}