blob: 17b66e5754ae6190161ac29fd564ed724da1aceb [file] [log] [blame]
/*
* Copyright (c) 2011 The Native Client 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 <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define PRINT_HEADER 0
#define TEXT_LINE_SIZE 1024
/*
* global text for text file generation and
* testing. table is NULL terminated.
*/
static const char *gText[] = {
"Text output test\n",
"This is test text for text IO\n",
"Duplicate line\n",
"Duplicate line\n",
"Same as above\n",
"0123456789~!@#$%^&*()_+\n",
NULL
};
/*
* function failed(testname, msg)
* print failure message and exit with a return code of -1
*/
bool failed(const char *testname, const char *msg) {
printf("TEST FAILED: %s: %s\n", testname, msg);
return false;
}
/*
* function passed(testname, msg)
* print success message
*/
bool passed(const char *testname, const char *msg) {
printf("TEST PASSED: %s: %s\n", testname, msg);
return true;
}
/*
* function createBinaryTestData(testname)
* Create binary 'testdata256' file.
* This file contains bytes 0..255
* It is exactly 256 bytes in size.
* returns true if test passed
*/
bool fopen_createBinaryFile(const char *testname) {
// create and write 0..255 into binary testdata file
FILE *f = fopen("testdata256", "wb");
if (NULL == f) {
return failed(testname, "failed on fopen()");
}
for (int i = 0; i < 256; ++i) {
unsigned char c = (unsigned char)i;
size_t j = fwrite(&c, 1, 1, f);
if (1 != j) {
fclose(f);
return failed(testname, "can't fwrite(&c, 1, 1, f)");
}
}
fclose(f);
return passed(testname, "fopen_createBinaryFile()");
}
/*
* function fread_bytes(testname, filename)
* Read and compare expected bytes from binary filename.
* Read is done byte at a time.
* The testdata256 file is exactly 256 bytes in length.
* We expect to find 0, 1, 2... 253, 254, 255.
* returns true if test passed
*/
bool fread_bytes(const char *testname, const char *filename) {
FILE *f = fopen(filename, "rb");
if (NULL == f) {
return failed(testname, "failed on fopen()");
}
for (int i = 0; i < 256; ++i) {
unsigned char c;
size_t j = fread(&c, 1, 1, f);
if (1 != j) {
fclose(f);
return failed(testname, "couldn't fread(&c, 1, 1, f)");
}
if (c != (unsigned char)i) {
fclose(f);
return failed(testname, "read bytes don't match");
}
}
fclose(f);
return passed(testname, "fread(&c, 1, 1, f) x 256");
}
/*
* function fopen_fail(testname)
* Attempt to fopen a file that isn't there.
* This should fail(!)
* returns true if test passed (fopen failed)
*/
bool fopen_fail(const char *testname) {
FILE *f = fopen("noexist.abc", "rb");
if (NULL != f) {
fclose(f);
return failed(testname, "fopen() succeeded on non-existant file!");
}
if (errno != ENOENT) {
return failed(testname, "fopen() wrong error on non-existant file!");
}
return passed(testname, "fopen_fail() on non-existant file");
}
/*
* function fread_256x1_block(testname)
* read and compare expected bytes from binary file
* read as one 256x1 chunk
* The testdata256 file is exactly 256 bytes in length.
* We expect to find 0, 1, 2... 253, 254, 255.
* returns true if test passed
*/
bool fread_256x1_block(const char *testname) {
FILE *f = fopen("testdata256", "rb");
if (NULL == f) {
return failed(testname, "failed on fopen()");
}
unsigned char c[256];
memset(c, 0, sizeof(unsigned char) * 256);
// read as 256x1 chunk
size_t j = fread(&c, 256, 1, f);
fclose(f);
if (1 != j) {
return failed(testname, "couldn't fread(&c, 256, 1, f)");
}
for (int i = 0; i < 256; ++i) {
if (c[i] != (unsigned char)i) {
return failed(testname, "read bytes don't match");
}
}
return passed(testname, "fread_256x1_block()");
}
/*
* function fread_1x256_block(testname)
* read and compare expected bytes from binary file
* read as one 1x256 chunks
* The testdata256 file is exactly 256 bytes in length.
* We expect to find 0, 1, 2... 253, 254, 255.
* returns true if test passed
*/
bool fread_1x256_block(const char *testname) {
FILE *f = fopen("testdata256", "rb");
if (NULL == f) {
return failed(testname, "failed on fopen()");
}
unsigned char c[256];
memset(c, 0, sizeof(unsigned char) * 256);
// read as 1x256 chunk
size_t j = fread(&c, 1, 256, f);
fclose(f);
if (256 != j) {
return failed(testname, "couldn't fread(&c, 1, 256, f)");
}
for (int i = 0; i < 256; ++i) {
if (c[i] != (unsigned char)i) {
return failed(testname, "read bytes don't match");
}
}
return passed(testname, "fread_1x256_block()");
}
/*
* function fopen_createTextFile(testname)
* create and write text file
* Uses 'gText' NULL terminated array to populate text file
* returns true if test passed
*/
bool fopen_createTextFile(const char *testname) {
FILE *f = fopen("testdata.txt", "wt");
if (NULL == f) {
return failed(testname, "fopen() testdata.txt (wt)");
}
for (int i = 0; NULL != gText[i]; ++i) {
int numWritten = fprintf(f, "%s", gText[i]);
if (numWritten < 0) {
fclose(f);
return failed(testname, "fprintf() returned a negative value.");
}
}
fclose(f);
return passed(testname, "fopen_createTextFile()");
}
/*
* function fgets_readText(testname)
* Read and compare expected text from test file.
* The test file should contain the same text as
* the 'gText' NULL terminated array.
* returns true if test passed
*/
bool fgets_readText(const char *testname) {
FILE *f = fopen("testdata.txt", "rt");
if (NULL == f) {
return failed(testname, "Unable to open file");
}
char buffer[TEXT_LINE_SIZE];
int index;
memset(buffer, 0, sizeof(char) * TEXT_LINE_SIZE);
for (index = 0; NULL != fgets(buffer, TEXT_LINE_SIZE - 1, f); ++index) {
if (NULL == gText[index]) {
fclose(f);
return failed(testname, "unexpected mismatch");
}
if (0 != strcmp(buffer, gText[index])) {
fclose(f);
return failed(testname, "read text does not match");
}
}
fclose(f);
if (NULL != gText[index]) {
return failed(testname, "unexpected eof() encountered");
}
return passed(testname, "fgets_readText()");
}
/*
* function fseek_filesize256(testname)
* Use fseek to determine expected filesize of test file filedata256.
* It is expected to be exactly 256 bytes in size.
* returns true if test passed
*/
bool fseek_filesize256(const char *testname) {
FILE *f = fopen("testdata256", "rb");
if (NULL == f) {
return failed(testname, "fopen failed");
}
int x = fseek(f, 0, SEEK_END);
if (0 == x) {
int p = ftell(f);
if (256 != p) {
fclose(f);
return failed(testname, "ftell mismatch");
}
fclose(f);
} else {
fclose(f);
return failed(testname, "fseek failed");
}
return passed(testname, "fseek_filesize256()");
}
/*
* function fseek_simple_testdata256(testname)
* Verify a simple combination of fseek & fread.
* The testdata256 file is exactly 256 bytes in length,
* and consists of 0, 1, 2... 253, 254, 255.
* If we seek to the Nth byte, we expect to find
* the value N there.
* returns true if test passed
*/
bool fseek_simple_testdata256(const char *testname) {
// test simple file seeking within testdata256
FILE *f = fopen("testdata256", "rb");
if (NULL == f) {
return failed(testname, "fseek_simple_testdata256() could not fopen()");
}
// seek to offset 1 from start of file
int x = fseek(f, 1, SEEK_SET);
if (x != 0) {
fclose(f);
return failed(testname, "fseek(1, SEEK_SET) failed");
}
unsigned char c = 0;
fread(&c, 1, 1, f);
if (1 != c) {
fclose(f);
return failed(testname, "fread(f, 1, 1, &c) at SEEK_SET+1 mismatch");
}
x = fseek(f, -2, SEEK_END);
if (0 != x) {
fclose(f);
return failed(testname, "fseek(-1, SEEK_END) failed");
}
fread(&c, 1, 1, f);
if (254 != c) {
fclose(f);
return failed(testname, "fread(f, 1, 1, &c) at SEEK_END-1 mismatch");
}
x = fseek(f, 2, SEEK_SET);
if (0 != x) {
fclose(f);
return failed(testname, "fseek(2, SEEK_SET) failed");
}
x = fseek(f, 1, SEEK_CUR);
if (0 != x) {
fclose(f);
return failed(testname, "fseek(1, SEEK_CUR) failed");
}
fread(&c, 1, 1, f);
if (3 != c) {
fclose(f);
return failed(testname, "fseek(f, 1, 1, &c) at SEEK_CUR+1 mismatch");
}
return passed(testname, "fseek_simple_testdata256()");
}
/*
* function fgets_filesize(testname)
* Determine the length of a text file using fgets & strlen
* This value should match the length of gText[]
* returns true if test passed
*/
bool fgets_filesize(const char *testname) {
size_t charcount = 0;
size_t filecharcount = 0;
// count chars in gText[]
for (int i = 0; NULL != gText[i]; ++i) {
charcount += strlen(gText[i]);
}
FILE *f = fopen("testdata.txt", "r");
if (NULL == f) {
return failed(testname, "fgets_filesize() failed on fopen()");
}
char buffer[TEXT_LINE_SIZE];
memset(buffer, 0, sizeof(char) * TEXT_LINE_SIZE);
while(NULL != fgets(buffer, TEXT_LINE_SIZE - 1, f)) {
filecharcount += strlen(buffer);
}
fclose(f);
if (charcount != filecharcount) {
return failed(testname, "fgets_filesize() mismatch");
}
return passed(testname, "fgets_filesize()");
}
/*
* function fopen_appendBinaryFile(testname)
* First create half a binary test file.
* Then re-open it for binary append, and add the other half.
* The intention is for testdata256 to contain 0, 1, 2... 253, 254, 255.
* returns true if test passed
*/
bool fopen_appendBinaryFile(const char *testname)
{
// first half: create a small file
// write 0..99
FILE *f = fopen("testdata256", "wb");
if (NULL == f) {
return failed(testname, "failed on fopen()\n");
}
for (int i = 0; i < 100; ++i) {
unsigned char c = (unsigned char)i;
size_t j = fwrite(&c, 1, 1, f);
if (1 != j) {
fclose(f);
return failed(testname, "can't fwrite(&c, 1, 1, f)");
}
}
fclose(f);
// second half: re-open and append the rest
// write 99..255
f = fopen("testdata256", "ab");
if (NULL == f) {
return failed(testname, "fopen() testdata256 (ab)");
}
for (int i = 100; i < 256; ++i) {
unsigned char c = (unsigned char)i;
size_t j = fwrite(&c, 1, 1, f);
if (1 != j) {
fclose(f);
return failed(testname, "can't fwrite(&c, 1, 1, f)");
}
}
fclose(f);
return passed(testname, "fopen_appendBinaryFile()");
}
/*
* function fopen_appendTextFile(testname)
* First create a text file with first 2 lines.
* Then re-open it for append, and add the remaining lines.
* The intention is for testdata to contain gText[].
* returns true if test passed
*/
bool fopen_appendTextFile(const char *testname) {
// create & write first 2 lines of gText[]
FILE *f = fopen("testdata.txt", "w");
int i = 0;
if (NULL == f) {
return failed(testname, "fopen() testdata.txt (w+)");
}
if ((gText[0]) && (gText[1])) {
// write first two lines
fprintf(f, "%s", gText[i++]);
fprintf(f, "%s", gText[i++]);
} else {
failed(testname, "gText table is too small!");
}
fclose(f);
// re-open and append the rest of gText[]
f = fopen("testdata.txt", "a");
if (NULL == f) {
return failed(testname, "fopen() testdata.txt (w+)");
}
while (gText[i]) {
fprintf(f, "%s", gText[i]);
i++;
}
fclose(f);
return passed(testname, "fopen_appendTextFile()");
}
/*
* function test*()
*
* Simple tests follow below. Each test may call one or more
* of the functions above. They all have a boolean return value
* to indicate success (all tests passed) or failure (one or more
* tests failed) Order matters - the parent should call
* test1() before test2(), and so on.
*/
bool test1()
{
// test the creation of a binary file
return fopen_createBinaryFile("test1");
}
bool test2()
{
// test the creation of a text file
return fopen_createTextFile("test2");
}
bool test3()
{
// test reading bytes from binary file
return fread_bytes("test3", "testdata256");
}
bool test4()
{
// test reading block from binary file
return fread_256x1_block("test4");
}
bool test5()
{
// test reading block from binary file
return fread_1x256_block("test5");
}
bool test6()
{
// test reading from text file
return fgets_readText("test6");
}
bool test7()
{
// test binary file size
return fseek_filesize256("test7");
}
bool test8()
{
// test text file size
return fgets_filesize("test8");
}
bool test9()
{
// create binary file twice
bool ret = true;
ret &= fopen_createBinaryFile("test7a");
ret &= fopen_createBinaryFile("test7b");
return ret;
}
bool test10()
{
// create text file twice
bool ret = true;
ret &= fopen_createTextFile("test8a");
ret &= fopen_createTextFile("test8b");
return ret;
}
bool test11()
{
// verify binary file size again
return fseek_filesize256("test11");
}
bool test12()
{
// verify test file size again
return fgets_filesize("test12");
}
bool test13()
{
// verify seeks followed by reads
return fseek_simple_testdata256("test13");
}
bool test14()
{
// create and then append to binary file
// then verify contents & filesize
bool ret = true;
ret &= fopen_appendBinaryFile("test14a");
ret &= fread_bytes("test14b", "testdata256");
ret &= fseek_filesize256("test14c");
return ret;
}
bool test15()
{
// create and then append to a text file
// then verify contents & filesize
bool ret = true;
ret &= fopen_appendTextFile("test15a");
ret &= fgets_readText("test15b");
ret &= fgets_filesize("test15c");
return ret;
}
bool test16()
{
// try a slightly different path
bool ret = true;
ret &= fread_bytes("test16", "./testdata256");
return ret;
}
bool test17()
{
// try a slightly different path
bool ret = true;
ret &= fread_bytes("test17", ".././file/testdata256");
return ret;
}
bool test18()
{
bool ret = true;
ret &= fopen_fail("test18");
return ret;
}
/*
* function testSuite()
*
* Run through a complete sequence of file tests.
*
* returns true if all tests succeed. false if one or more fail.
*/
bool testSuite()
{
bool ret = true;
// The order of executing these tests matters!
ret &= test1();
ret &= test2();
ret &= test3();
ret &= test4();
ret &= test5();
ret &= test6();
ret &= test7();
ret &= test8();
ret &= test9();
ret &= test10();
ret &= test11();
ret &= test12();
ret &= test13();
ret &= test14();
ret &= test15();
ret &= test16();
ret &= test17();
ret &= test18();
return ret;
}
/*
* function remove_testfiles()
*
* cleanup and remove all testfiles here.
* (at the moment, nacl cannot remove files, so this function
* will do nothing in a nacl nexe. It will function as expected
* when the test suite is built as a non-nacl executable. The
* NaCl version of the test suite uses a python script to remove
* the testfiles.)
*/
void remove_testfiles()
{
#if !defined(__native_client__)
remove("testdata256");
remove("testdata.txt");
#endif
}
/*
* main entry point.
*
* run all tests and call system exit with appropriate value
* 0 - success, all tests passed.
* -1 - one or more tests failed.
*/
int main(const int argc, const char *argv[])
{
bool passed;
// remove test files from previous runs
remove_testfiles();
// run the full test suite
passed = testSuite();
// remove test files that were created.
remove_testfiles();
if (passed) {
printf("All tests PASSED\n");
exit(0);
} else {
printf("One or more tests FAILED\n");
exit(-1);
}
}