Start the work on a default replay (regression) engine used for executing a corpus or set of tests (#98)

* Start the work on a default replay (regression) engine used for executing a corpus or set of tests.

This change imports the necessary dependencies (ABSL and gTest) and adds a small library for producing absl::Status values from errno values.

* Added include guards.

* Make ErrnoStatus return OK when errno is zero.
diff --git a/.gitignore b/.gitignore
index e3582ca..f7b2d3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,7 @@
 
 # Visual Studio Code configuration.
 /.vscode
+
+# IntelliSense configuration generated by
+# https://github.com/grailbio/bazel-compilation-database
+compile_commands.json
diff --git a/WORKSPACE b/WORKSPACE
index 54823c9..72c8f98 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -43,3 +43,10 @@
     strip_prefix = "re2-2020-11-01",
     url = "https://github.com/google/re2/archive/2020-11-01.tar.gz",
 )
+
+http_archive(
+    name = "com_google_googletest",
+    sha256 = "763e20249e76417bed7ebc44aa85fedf5fbac6f9fb6d30bddb628ab07ebf04f5",
+    strip_prefix = "googletest-389cb68b87193358358ae87cc56d257fd0d80189",
+    urls = ["https://github.com/google/googletest/archive/389cb68b87193358358ae87cc56d257fd0d80189.zip"],
+)
diff --git a/fuzzing/replay/BUILD b/fuzzing/replay/BUILD
new file mode 100644
index 0000000..e35454e
--- /dev/null
+++ b/fuzzing/replay/BUILD
@@ -0,0 +1,45 @@
+# Copyright 2020 Google LLC
+#
+# 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
+#
+#    https://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.
+
+# Tools for replaying test files.
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+
+package(default_visibility = ["//fuzzing:__subpackages__"])
+
+# Libraries.
+############
+
+cc_library(
+    name = "status_util",
+    srcs = ["status_util.cc"],
+    hdrs = ["status_util.h"],
+    deps = [
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/strings",
+    ],
+)
+
+# Tests.
+########
+
+cc_test(
+    name = "status_util_test",
+    size = "small",
+    srcs = ["status_util_test.cc"],
+    deps = [
+        ":status_util",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/fuzzing/replay/status_util.cc b/fuzzing/replay/status_util.cc
new file mode 100644
index 0000000..6c50185
--- /dev/null
+++ b/fuzzing/replay/status_util.cc
@@ -0,0 +1,55 @@
+// Copyright 2020 Google LLC
+//
+// 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
+//
+//    https://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 "fuzzing/replay/status_util.h"
+
+#include <cstring>
+#include <string>
+
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
+
+namespace fuzzing {
+
+namespace {
+
+constexpr size_t kMaxErrorStringSize = 128;
+
+std::string StrError(int errno_value) {
+  char error_str_buf[kMaxErrorStringSize];
+#if (_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE
+  const int result =
+      strerror_r(errno_value, error_str_buf, sizeof(error_str_buf));
+  if (result) {
+    return absl::StrCat("Unknown error ", errno_value);
+  } else {
+    return error_str_buf;
+  }
+#else
+  return strerror_r(errno_value, error_str_buf, sizeof(error_str_buf));
+#endif
+}
+
+}  // namespace
+
+absl::Status ErrnoStatus(absl::string_view message, int errno_value) {
+  if (errno_value == 0) {
+    return absl::OkStatus();
+  } else {
+    return absl::UnknownError(
+        absl::StrCat(message, " (", StrError(errno_value), ")"));
+  }
+}
+
+}  // namespace fuzzing
diff --git a/fuzzing/replay/status_util.h b/fuzzing/replay/status_util.h
new file mode 100644
index 0000000..8bcc1d0
--- /dev/null
+++ b/fuzzing/replay/status_util.h
@@ -0,0 +1,31 @@
+// Copyright 2020 Google LLC
+//
+// 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
+//
+//    https://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.
+
+// Utilities for working with absl::Status values.
+
+#ifndef FUZZING_REPLAY_STATUS_UTIL_H_
+#define FUZZING_REPLAY_STATUS_UTIL_H_
+
+#include "absl/status/status.h"
+#include "absl/strings/string_view.h"
+
+namespace fuzzing {
+
+// Creates an error status value that includes the given `message` and a
+// description of the `errno_value`. Returns OK if `errno_value` is zero.
+absl::Status ErrnoStatus(absl::string_view message, int errno_value);
+
+}  // namespace fuzzing
+
+#endif  // FUZZING_REPLAY_STATUS_UTIL_H_
diff --git a/fuzzing/replay/status_util_test.cc b/fuzzing/replay/status_util_test.cc
new file mode 100644
index 0000000..c559e44
--- /dev/null
+++ b/fuzzing/replay/status_util_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2020 Google LLC
+//
+// 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
+//
+//    https://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 "fuzzing/replay/status_util.h"
+
+#include <cerrno>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace fuzzing {
+
+namespace {
+
+using ::testing::StrEq;
+
+TEST(StatusUtilTest, EmptyMessage) {
+  const absl::Status status = ErrnoStatus("", ENOENT);
+  EXPECT_EQ(status.code(), absl::StatusCode::kUnknown);
+  EXPECT_THAT(status.message(), StrEq(" (No such file or directory)"));
+}
+
+TEST(StatusUtilTest, NonemptyMessage) {
+  const absl::Status status = ErrnoStatus("could not open file", ENOENT);
+  EXPECT_EQ(status.code(), absl::StatusCode::kUnknown);
+  EXPECT_THAT(status.message(),
+              StrEq("could not open file (No such file or directory)"));
+}
+
+TEST(StatusUtilTest, SuccessfulErrno) {
+  const absl::Status status = ErrnoStatus("no error", 0);
+  EXPECT_TRUE(status.ok());
+}
+
+TEST(StatusUtilTest, UnknownErrno) {
+  const absl::Status status = ErrnoStatus("some error", 123456);
+  EXPECT_EQ(status.code(), absl::StatusCode::kUnknown);
+  EXPECT_THAT(status.message(), StrEq("some error (Unknown error 123456)"));
+}
+
+}  // namespace
+
+}  // namespace fuzzing
diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl
index a181ca2..cf7db2b 100644
--- a/fuzzing/repositories.bzl
+++ b/fuzzing/repositories.bzl
@@ -37,6 +37,14 @@
         sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c",
     )
 
+    maybe(
+        http_archive,
+        name = "com_google_absl",
+        urls = ["https://github.com/abseil/abseil-cpp/archive/4611a601a7ce8d5aad169417092e3d5027aa8403.zip"],
+        strip_prefix = "abseil-cpp-4611a601a7ce8d5aad169417092e3d5027aa8403",
+        sha256 = "f4f2d3d01c3cc99eebc9f370ea626c43a54b386913aef393bf8201b2c42a9e2f",
+    )
+
     # TODO(sbucur): Since Honggfuzz has its own set of dependencies, look into
     # making them optional, so developers only import them if they decide to
     # use Honggfuzz.