summaryrefslogtreecommitdiffstats
path: root/xpcom/glue/tests/gtest/TestFileUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/glue/tests/gtest/TestFileUtils.cpp')
-rw-r--r--xpcom/glue/tests/gtest/TestFileUtils.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/xpcom/glue/tests/gtest/TestFileUtils.cpp b/xpcom/glue/tests/gtest/TestFileUtils.cpp
new file mode 100644
index 000000000..55106c6c5
--- /dev/null
+++ b/xpcom/glue/tests/gtest/TestFileUtils.cpp
@@ -0,0 +1,283 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* Test ReadSysFile() */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "FileUtils.h"
+
+#include "gtest/gtest.h"
+
+namespace mozilla {
+
+#ifdef ReadSysFile_PRESENT
+
+/**
+ * Create a file with the specified contents.
+ */
+static bool
+WriteFile(
+ const char* aFilename,
+ const void* aContents,
+ size_t aContentsLen)
+{
+ int fd;
+ ssize_t ret;
+ size_t offt;
+
+ fd = MOZ_TEMP_FAILURE_RETRY(
+ open(aFilename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (fd == -1) {
+ fprintf(stderr, "open(): %s: %s\n", aFilename, strerror(errno));
+ return false;
+ }
+
+ offt = 0;
+ do {
+ ret = MOZ_TEMP_FAILURE_RETRY(
+ write(fd, (char*)aContents + offt, aContentsLen - offt));
+ if (ret == -1) {
+ fprintf(stderr, "write(): %s: %s\n", aFilename, strerror(errno));
+ close(fd);
+ return false;
+ }
+ offt += ret;
+ } while (offt < aContentsLen);
+
+ ret = MOZ_TEMP_FAILURE_RETRY(close(fd));
+ if (ret == -1) {
+ fprintf(stderr, "close(): %s: %s\n", aFilename, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+TEST(ReadSysFile, Nonexistent) {
+ bool ret;
+ int errno_saved;
+
+ ret = ReadSysFile("/nonexistent", nullptr, 0);
+ errno_saved = errno;
+
+ ASSERT_FALSE(ret);
+ ASSERT_EQ(errno_saved, ENOENT);
+}
+
+TEST(ReadSysFile, Main) {
+ /* Use a different file name for each test since different tests could be
+ executed concurrently. */
+ static const char* fn = "TestReadSysFileMain";
+ /* If we have a file which contains "abcd" and we read it with ReadSysFile(),
+ providing a buffer of size 10 bytes, we would expect 5 bytes to be written
+ to that buffer: "abcd\0". */
+ struct
+ {
+ /* input (file contents), e.g. "abcd" */
+ const char* input;
+ /* pretended output buffer size, e.g. 10; the actual buffer is larger
+ and we check if anything was written past the end of the allowed length */
+ size_t output_size;
+ /* expected number of bytes written to the output buffer, including the
+ terminating '\0', e.g. 5 */
+ size_t output_len;
+ /* expected output buffer contents, e.g. "abcd\0", the first output_len
+ bytes of the output buffer should match the first 'output_len' bytes from
+ 'output', the rest of the output buffer should be untouched. */
+ const char* output;
+ } tests[] = {
+ /* No new lines */
+ {"", 0, 0, ""},
+ {"", 1, 1, "\0"}, /* \0 is redundant, but we write it for clarity */
+ {"", 9, 1, "\0"},
+
+ {"a", 0, 0, ""},
+ {"a", 1, 1, "\0"},
+ {"a", 2, 2, "a\0"},
+ {"a", 9, 2, "a\0"},
+
+ {"abcd", 0, 0, ""},
+ {"abcd", 1, 1, "\0"},
+ {"abcd", 2, 2, "a\0"},
+ {"abcd", 3, 3, "ab\0"},
+ {"abcd", 4, 4, "abc\0"},
+ {"abcd", 5, 5, "abcd\0"},
+ {"abcd", 9, 5, "abcd\0"},
+
+ /* A single trailing new line */
+ {"\n", 0, 0, ""},
+ {"\n", 1, 1, "\0"},
+ {"\n", 2, 1, "\0"},
+ {"\n", 9, 1, "\0"},
+
+ {"a\n", 0, 0, ""},
+ {"a\n", 1, 1, "\0"},
+ {"a\n", 2, 2, "a\0"},
+ {"a\n", 3, 2, "a\0"},
+ {"a\n", 9, 2, "a\0"},
+
+ {"abcd\n", 0, 0, ""},
+ {"abcd\n", 1, 1, "\0"},
+ {"abcd\n", 2, 2, "a\0"},
+ {"abcd\n", 3, 3, "ab\0"},
+ {"abcd\n", 4, 4, "abc\0"},
+ {"abcd\n", 5, 5, "abcd\0"},
+ {"abcd\n", 6, 5, "abcd\0"},
+ {"abcd\n", 9, 5, "abcd\0"},
+
+ /* Multiple trailing new lines */
+ {"\n\n", 0, 0, ""},
+ {"\n\n", 1, 1, "\0"},
+ {"\n\n", 2, 2, "\n\0"},
+ {"\n\n", 3, 2, "\n\0"},
+ {"\n\n", 9, 2, "\n\0"},
+
+ {"a\n\n", 0, 0, ""},
+ {"a\n\n", 1, 1, "\0"},
+ {"a\n\n", 2, 2, "a\0"},
+ {"a\n\n", 3, 3, "a\n\0"},
+ {"a\n\n", 4, 3, "a\n\0"},
+ {"a\n\n", 9, 3, "a\n\0"},
+
+ {"abcd\n\n", 0, 0, ""},
+ {"abcd\n\n", 1, 1, "\0"},
+ {"abcd\n\n", 2, 2, "a\0"},
+ {"abcd\n\n", 3, 3, "ab\0"},
+ {"abcd\n\n", 4, 4, "abc\0"},
+ {"abcd\n\n", 5, 5, "abcd\0"},
+ {"abcd\n\n", 6, 6, "abcd\n\0"},
+ {"abcd\n\n", 7, 6, "abcd\n\0"},
+ {"abcd\n\n", 9, 6, "abcd\n\0"},
+
+ /* New line in the middle */
+ {"ab\ncd", 9, 6, "ab\ncd\0"},
+ };
+
+ for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ ASSERT_TRUE(WriteFile(fn, tests[i].input, strlen(tests[i].input)));
+ /* Leave the file to exist if some of the assertions fail. */
+
+ char buf[128];
+ static const char unmodified = 'X';
+
+ memset(buf, unmodified, sizeof(buf));
+
+ ASSERT_TRUE(ReadSysFile(fn, buf, tests[i].output_size));
+
+ if (tests[i].output_size == 0) {
+ /* The buffer must be unmodified. We check only the first byte. */
+ ASSERT_EQ(unmodified, buf[0]);
+ } else {
+ ASSERT_EQ(tests[i].output_len, strlen(buf) + 1);
+ ASSERT_STREQ(tests[i].output, buf);
+ /* Check that the first byte after the trailing '\0' has not been
+ modified. */
+ ASSERT_EQ(unmodified, buf[tests[i].output_len]);
+ }
+ }
+
+ unlink(fn);
+}
+
+TEST(ReadSysFile, Int) {
+ static const char* fn = "TestReadSysFileInt";
+ struct
+ {
+ /* input (file contents), e.g. "5" */
+ const char* input;
+ /* expected return value, if false, then the output is not checked */
+ bool ret;
+ /* expected result */
+ int output;
+ } tests[] = {
+ {"0", true, 0},
+ {"00", true, 0},
+ {"1", true, 1},
+ {"5", true, 5},
+ {"55", true, 55},
+
+ {" 123", true, 123},
+ {"123 ", true, 123},
+ {" 123 ", true, 123},
+ {"123\n", true, 123},
+
+ {"", false, 0},
+ {" ", false, 0},
+ {"a", false, 0},
+
+ {"-1", true, -1},
+ {" -456 ", true, -456},
+ {" -78.9 ", true, -78},
+ };
+
+ for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ ASSERT_TRUE(WriteFile(fn, tests[i].input, strlen(tests[i].input)));
+ /* Leave the file to exist if some of the assertions fail. */
+
+ bool ret;
+ int output = 424242;
+
+ ret = ReadSysFile(fn, &output);
+
+ ASSERT_EQ(tests[i].ret, ret);
+
+ if (ret) {
+ ASSERT_EQ(tests[i].output, output);
+ }
+ }
+
+ unlink(fn);
+}
+
+TEST(ReadSysFile, Bool) {
+ static const char* fn = "TestReadSysFileBool";
+ struct
+ {
+ /* input (file contents), e.g. "1" */
+ const char* input;
+ /* expected return value */
+ bool ret;
+ /* expected result */
+ bool output;
+ } tests[] = {
+ {"0", true, false},
+ {"00", true, false},
+ {"1", true, true},
+ {"5", true, true},
+ {"23", true, true},
+ {"-1", true, true},
+
+ {"", false, true /* unused */},
+ };
+
+ for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ ASSERT_TRUE(WriteFile(fn, tests[i].input, strlen(tests[i].input)));
+ /* Leave the file to exist if some of the assertions fail. */
+
+ bool ret;
+ bool output;
+
+ ret = ReadSysFile(fn, &output);
+
+ ASSERT_EQ(tests[i].ret, ret);
+
+ if (ret) {
+ ASSERT_EQ(tests[i].output, output);
+ }
+ }
+
+ unlink(fn);
+}
+
+#endif /* ReadSysFile_PRESENT */
+
+} // namespace mozilla