Bug 860827 - Add unit tests for ReadSysFile(). r=dhylands, r=BenWa

This commit is contained in:
Vasil Dimov 2013-04-23 13:55:46 -04:00
parent ece29c4cd0
commit 4636e9c5d7
7 changed files with 326 additions and 5 deletions

View File

@ -297,7 +297,7 @@ endif
STATIC_LIBS += thebes gl ycbcr
ifdef MOZ_ENABLE_GTEST
COMPONENT_LIBS += gtest
COMPONENT_LIBS += gtest xpcom_glue_gtest
endif
ifdef MOZ_ENABLE_PROFILER_SPS

View File

@ -130,6 +130,7 @@ if CONFIG['ENABLE_TESTS']:
if CONFIG['MOZ_ENABLE_GTEST']:
add_tier_dir('platform', 'testing/gtest')
add_tier_dir('platform', 'xpcom/glue/tests/gtest')
add_tier_dir('platform', [
'uriloader',

View File

@ -117,7 +117,7 @@ mozilla::fallocate(PRFileDesc *aFD, int64_t aLength)
return false;
}
#ifdef MOZ_WIDGET_GONK
#ifdef ReadSysFile_PRESENT
#undef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(exp) (__extension__({ \
@ -188,7 +188,7 @@ mozilla::ReadSysFile(
return true;
}
#endif /* MOZ_WIDGET_GONK */
#endif /* ReadSysFile_PRESENT */
void
mozilla::ReadAheadLib(nsIFile* aFile)

View File

@ -145,7 +145,14 @@ NS_COM_GLUE void ReadAhead(filedesc_t aFd, const size_t aOffset = 0,
const size_t aCount = SIZE_MAX);
#ifdef MOZ_WIDGET_GONK
/* Define ReadSysFile() only on GONK to avoid unnecessary lubxul bloat.
Also define it in debug builds, so that unit tests for it can be written
and run in non-GONK builds. */
#if (defined(MOZ_WIDGET_GONK) || defined(DEBUG)) && defined(XP_UNIX)
#ifndef ReadSysFile_PRESENT
#define ReadSysFile_PRESENT
#endif /* ReadSysFile_PRESENT */
/**
* Read the contents of a file.
@ -184,7 +191,7 @@ ReadSysFile(
const char* aFilename,
bool* aVal);
#endif /* MOZ_WIDGET_GONK */
#endif /* (MOZ_WIDGET_GONK || DEBUG) && XP_UNIX */
} // namespace mozilla
#endif

View File

@ -0,0 +1,27 @@
# vim:set ts=8 sw=8 sts=8 noet:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE_NAME = xpcom_glue_gtest
LIBRARY_NAME = xpcom_glue_gtest
EXPORT_LIBRARY = 1
LIBXUL_LIBRARY = 1
IS_COMPONENT = 1
LOCAL_INCLUDES = \
-I$(srcdir)/../.. \
$(NULL)
CPPSRCS = \
TestFileUtils.cpp \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,279 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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 <unistd.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 = 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 = 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 = 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", NULL, 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 */
}

View File

@ -0,0 +1,7 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'xpcom_glue_gtest'