Add hex file parsing functionality to file_util.
This is to be used to parse the file containing the secret API key.
Also add tests for all of file_util.
Bug: 36537
Change-Id: Iba1fd2e2903363aa9973a0c1e1dcfd1b1442f0da
diff --git a/src/lib/util/BUILD.gn b/src/lib/util/BUILD.gn
index 102599a..33776a0 100644
--- a/src/lib/util/BUILD.gn
+++ b/src/lib/util/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/test.gni")
import("//third_party/protobuf/proto_library.gni")
source_set("clock") {
@@ -121,6 +122,34 @@
"$cobalt_root/src:logging",
"$cobalt_root/src/lib/crypto_util",
"$cobalt_root/third_party/statusor",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+test("file_util_test") {
+ testonly = true
+ sources = [
+ "file_util_test.cc",
+ ]
+ configs += [ "$cobalt_root:cobalt_config" ]
+ deps = [
+ ":file_util",
+ ":file_util_test_files",
+ "$cobalt_root/src:logging",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/googletest:gtest",
+ ]
+}
+
+copy("file_util_test_files") {
+ sources = [
+ "test_data/deadbeef",
+ "test_data/empty",
+ "test_data/hex_too_short",
+ "test_data/hex_wrong_char",
+ ]
+ outputs = [
+ "$root_out_dir/tests/cpp/file_util_test_files/{{source_file_part}}",
]
}
@@ -238,6 +267,7 @@
":consistent_proto_store_test",
":datetime_util_test",
":encrypted_message_util_test",
+ ":file_util_test",
":protected_fields_test",
":sleeper_test",
]
diff --git a/src/lib/util/file_util.cc b/src/lib/util/file_util.cc
index 329ab4f..27b1a47 100644
--- a/src/lib/util/file_util.cc
+++ b/src/lib/util/file_util.cc
@@ -10,6 +10,8 @@
#include "src/lib/util/status.h"
#include "src/lib/util/status_codes.h"
#include "src/logging.h"
+#include "third_party/abseil-cpp/absl/strings/ascii.h"
+#include "third_party/abseil-cpp/absl/strings/escaping.h"
namespace cobalt::util {
@@ -65,4 +67,32 @@
return read_file_result;
}
+statusor::StatusOr<std::string> ReadHexFile(const std::string& file_path) {
+ auto read_file_result = ReadNonEmptyTextFile(file_path);
+ if (!read_file_result.ok()) {
+ return read_file_result;
+ }
+
+ auto hex = absl::StripAsciiWhitespace(read_file_result.ValueOrDie());
+ if (hex.size() % 2 == 1) {
+ return Status(FAILED_PRECONDITION, "Hex file has invalid size: " + file_path);
+ }
+
+ if (std::find_if_not(hex.begin(), hex.end(), absl::ascii_isxdigit) != hex.end()) {
+ return Status(FAILED_PRECONDITION, "Hex file has non-hex characters: " + file_path);
+ }
+
+ return absl::HexStringToBytes(hex);
+}
+
+std::string ReadHexFileOrDefault(const std::string& file_path, const std::string& default_string) {
+ auto read_hex_file_result = ReadHexFile(file_path);
+ if (!read_hex_file_result.ok()) {
+ VLOG(1) << "Failed to read hex file: " << read_hex_file_result.status().error_message();
+ return default_string;
+ }
+
+ return read_hex_file_result.ValueOrDie();
+}
+
} // namespace cobalt::util
diff --git a/src/lib/util/file_util.h b/src/lib/util/file_util.h
index 2da7b1e..9748494 100644
--- a/src/lib/util/file_util.h
+++ b/src/lib/util/file_util.h
@@ -15,6 +15,10 @@
statusor::StatusOr<std::string> ReadNonEmptyTextFile(const std::string& file_path);
+statusor::StatusOr<std::string> ReadHexFile(const std::string& file_path);
+
+std::string ReadHexFileOrDefault(const std::string& file_path, const std::string& default_string);
+
} // namespace util
} // namespace cobalt
#endif // COBALT_SRC_LIB_UTIL_FILE_UTIL_H_
diff --git a/src/lib/util/file_util_test.cc b/src/lib/util/file_util_test.cc
new file mode 100644
index 0000000..f588c0d
--- /dev/null
+++ b/src/lib/util/file_util_test.cc
@@ -0,0 +1,137 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/lib/util/file_util.h"
+
+#include "glog/logging.h"
+#include "third_party/abseil-cpp/absl/strings/str_cat.h"
+#include "third_party/googletest/googletest/include/gtest/gtest.h"
+
+namespace {
+
+// Directory in which the test files can be found.
+const char* kTestFilesDir;
+
+// Test file names.
+const char* kDeadbeefFile = "deadbeef";
+const char* kEmptyFile = "empty";
+const char* kNonExistentFile = "non_existent";
+const char* kHexTooShortFile = "hex_too_short";
+const char* kHexWrongCharFile = "hex_wrong_char";
+
+const char* kDeadbeef = "\xde\xad\xbe\xef";
+
+TEST(ReadTextFile, ReadFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kDeadbeefFile);
+ auto read_result = cobalt::util::ReadTextFile(path);
+ ASSERT_TRUE(read_result.ok());
+ EXPECT_EQ(read_result.ValueOrDie(), "deadbeef\n");
+}
+
+TEST(ReadTextFile, ReadEmptyFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kEmptyFile);
+ auto read_result = cobalt::util::ReadTextFile(path);
+ ASSERT_TRUE(read_result.ok());
+ EXPECT_EQ(read_result.ValueOrDie(), "");
+}
+
+TEST(ReadTextFile, ReadNonExistentFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kNonExistentFile);
+ auto read_result = cobalt::util::ReadTextFile(path);
+ ASSERT_FALSE(read_result.ok());
+}
+
+TEST(ReadNonEmptyTextFile, ReadFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kDeadbeefFile);
+ auto read_result = cobalt::util::ReadNonEmptyTextFile(path);
+ ASSERT_TRUE(read_result.ok());
+ EXPECT_EQ(read_result.ValueOrDie(), "deadbeef\n");
+}
+
+TEST(ReadNonEmptyTextFile, ReadEmptyFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kEmptyFile);
+ auto read_result = cobalt::util::ReadNonEmptyTextFile(path);
+ EXPECT_FALSE(read_result.ok());
+}
+
+TEST(ReadNonEmtpyTextFile, ReadNonExistentFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kNonExistentFile);
+ auto read_result = cobalt::util::ReadNonEmptyTextFile(path);
+ EXPECT_FALSE(read_result.ok());
+}
+
+TEST(ReadHexFile, ReadHexFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kDeadbeefFile);
+ auto read_result = cobalt::util::ReadHexFile(path);
+ ASSERT_TRUE(read_result.ok());
+ EXPECT_EQ(read_result.ValueOrDie(), kDeadbeef);
+}
+
+TEST(ReadHexFile, ReadEmptyFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kEmptyFile);
+ auto read_result = cobalt::util::ReadHexFile(path);
+ EXPECT_FALSE(read_result.ok());
+}
+
+TEST(ReadHexFile, ReadNonExistentFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kNonExistentFile);
+ auto read_result = cobalt::util::ReadHexFile(path);
+ EXPECT_FALSE(read_result.ok());
+}
+
+TEST(ReadHexFile, ReadHexTooShortFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kHexTooShortFile);
+ auto read_result = cobalt::util::ReadHexFile(path);
+ EXPECT_FALSE(read_result.ok());
+}
+
+TEST(ReadHexFile, ReadHexWrongCharFile) {
+ std::string path = absl::StrCat(kTestFilesDir, kHexWrongCharFile);
+ auto read_result = cobalt::util::ReadHexFile(path);
+ EXPECT_FALSE(read_result.ok());
+}
+
+TEST(ReadHexFileOrDefault, ReadHexFile) {
+ const std::string kDefault = "default";
+ std::string path = absl::StrCat(kTestFilesDir, kDeadbeefFile);
+ EXPECT_EQ(cobalt::util::ReadHexFileOrDefault(path, kDefault), kDeadbeef);
+}
+
+TEST(ReadHexFileOrDefault, ReadEmptyFile) {
+ const std::string kDefault = "default";
+ std::string path = absl::StrCat(kTestFilesDir, kEmptyFile);
+ EXPECT_EQ(cobalt::util::ReadHexFileOrDefault(path, kDefault), kDefault);
+}
+
+TEST(ReadHexFileOrDefault, ReadNonExistentFile) {
+ const std::string kDefault = "default";
+ std::string path = absl::StrCat(kTestFilesDir, kNonExistentFile);
+ EXPECT_EQ(cobalt::util::ReadHexFileOrDefault(path, kDefault), kDefault);
+}
+
+TEST(ReadHexFileOrDefault, ReadHexTooShortFile) {
+ const std::string kDefault = "default";
+ std::string path = absl::StrCat(kTestFilesDir, kHexTooShortFile);
+ EXPECT_EQ(cobalt::util::ReadHexFileOrDefault(path, kDefault), kDefault);
+}
+
+TEST(ReadHexFileOrDefault, ReadHexWrongCharFile) {
+ const std::string kDefault = "default";
+ std::string path = absl::StrCat(kTestFilesDir, kHexWrongCharFile);
+ EXPECT_EQ(cobalt::util::ReadHexFileOrDefault(path, kDefault), kDefault);
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ // Compute the path where keys are stored in the output directory.
+ std::string path(argv[0]);
+ auto slash = path.find_last_of('/');
+ CHECK(slash != std::string::npos);
+ path = path.substr(0, slash) + "/file_util_test_files/";
+ kTestFilesDir = path.c_str();
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/lib/util/test_data/deadbeef b/src/lib/util/test_data/deadbeef
new file mode 100644
index 0000000..5ca31d5
--- /dev/null
+++ b/src/lib/util/test_data/deadbeef
@@ -0,0 +1 @@
+deadbeef
diff --git a/src/lib/util/test_data/empty b/src/lib/util/test_data/empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/lib/util/test_data/empty
diff --git a/src/lib/util/test_data/hex_file.hex b/src/lib/util/test_data/hex_file.hex
new file mode 100644
index 0000000..5ca31d5
--- /dev/null
+++ b/src/lib/util/test_data/hex_file.hex
@@ -0,0 +1 @@
+deadbeef
diff --git a/src/lib/util/test_data/hex_too_short b/src/lib/util/test_data/hex_too_short
new file mode 100644
index 0000000..aa8eac6
--- /dev/null
+++ b/src/lib/util/test_data/hex_too_short
@@ -0,0 +1 @@
+dea
diff --git a/src/lib/util/test_data/hex_wrong_char b/src/lib/util/test_data/hex_wrong_char
new file mode 100644
index 0000000..b4b74dd
--- /dev/null
+++ b/src/lib/util/test_data/hex_wrong_char
@@ -0,0 +1 @@
+deadbeeg