Added the non-fatal MaybeReadFileToString() function

Applications which read files to string typically had to previously
die upon encountering an error, which could sometimes be unideal in
the larger scope of the program. A MaybeReadFileToString() function
was added for cases where a program must read from a file, but shouldn't
ever die.

Change-Id: I1877d41276674c12b1f8443a1d0162dc46261a6b
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/util/file_test.cc b/aos/util/file_test.cc
index 712447e..df16d58 100644
--- a/aos/util/file_test.cc
+++ b/aos/util/file_test.cc
@@ -1,6 +1,7 @@
 #include "aos/util/file.h"
 
 #include <cstdlib>
+#include <optional>
 #include <string>
 
 #include "gtest/gtest.h"
@@ -14,20 +15,44 @@
 
 // Basic test of reading a normal file.
 TEST(FileTest, ReadNormalFile) {
-  const ::std::string tmpdir(aos::testing::TestTmpDir());
-  const ::std::string test_file = tmpdir + "/test_file";
+  const std::string tmpdir(aos::testing::TestTmpDir());
+  const std::string test_file = tmpdir + "/test_file";
   ASSERT_EQ(0, system(("echo contents > " + test_file).c_str()));
   EXPECT_EQ("contents\n", ReadFileToStringOrDie(test_file));
 }
 
 // Tests reading a file with 0 size, among other weird things.
 TEST(FileTest, ReadSpecialFile) {
-  const ::std::string stat = ReadFileToStringOrDie("/proc/self/stat");
+  const std::string stat = ReadFileToStringOrDie("/proc/self/stat");
   EXPECT_EQ('\n', stat[stat.size() - 1]);
-  const ::std::string my_pid = ::std::to_string(getpid());
+  const std::string my_pid = ::std::to_string(getpid());
   EXPECT_EQ(my_pid, stat.substr(0, my_pid.size()));
 }
 
+// Basic test of maybe reading a normal file.
+TEST(FileTest, MaybeReadNormalFile) {
+  const std::string tmpdir(aos::testing::TestTmpDir());
+  const std::string test_file = tmpdir + "/test_file";
+  ASSERT_EQ(0, system(("echo contents > " + test_file).c_str()));
+  EXPECT_EQ("contents\n", MaybeReadFileToString(test_file).value());
+}
+
+// Tests maybe reading a file with 0 size, among other weird things.
+TEST(FileTest, MaybeReadSpecialFile) {
+  const std::optional<std::string> stat =
+      MaybeReadFileToString("/proc/self/stat");
+  ASSERT_TRUE(stat.has_value());
+  EXPECT_EQ('\n', (*stat)[stat->size() - 1]);
+  const std::string my_pid = std::to_string(getpid());
+  EXPECT_EQ(my_pid, stat->substr(0, my_pid.size()));
+}
+
+// Tests maybe reading a non-existent file, and not fatally erroring.
+TEST(FileTest, MaybeReadNonexistentFile) {
+  const std::optional<std::string> contents = MaybeReadFileToString("/dne");
+  ASSERT_FALSE(contents.has_value());
+}
+
 // Tests that the PathExists function works under normal conditions.
 TEST(FileTest, PathExistsTest) {
   const std::string tmpdir(aos::testing::TestTmpDir());