file: Update design and create a new unit test
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
parent
3359cbae6f
commit
336024bae9
24
DESIGN
24
DESIGN
|
@ -132,18 +132,13 @@ Callbacks: (lib/callback.cpp)
|
|||
|
||||
On-disk files: (lib/file.cpp)
|
||||
Data will be stored in the user's home directory according to the
|
||||
XDG / freedesktop.org specification. This means storing data in
|
||||
$XDG_DATA_HOME/ocarina{-debug|-test}/ and storing configuration in
|
||||
$XDG_CONFIG_HOME/ocarina{-debug|-test}/. In addition, I will support
|
||||
importing data from Ocarina 5.10 for conversion to the new format.
|
||||
XDG / freedesktop.org specification. This means data will be stored
|
||||
in a subdirectory of $XDG_DATA_HOME.
|
||||
|
||||
In theory my file format will not change often, so it should be
|
||||
possible to use multiple Ocarina versions with the same data. However,
|
||||
should the format need to change I will only support forward
|
||||
compatibility. This means that downgrades will not be possible after
|
||||
a file format change. To keep the code even cleaner, I will only
|
||||
support updating from the previous file format version. This means
|
||||
that legacy support will be removed after the first file format change.
|
||||
The filse class will support reading and writing files in the users
|
||||
$XDG_CONFIG_HOME/ocarina{-debug|test}. In addition, Ocarina 6.0 will
|
||||
support reading library files from the Ocarina 5.10 directory:
|
||||
$HOME/.ocarina{-debug}.
|
||||
|
||||
Items should be written to a file with either a space or new line
|
||||
separating multiple values.
|
||||
|
@ -156,7 +151,6 @@ On-disk files: (lib/file.cpp)
|
|||
|
||||
- Hint where the file is located:
|
||||
enum FileLocHint {
|
||||
FILE_TYPE_CONFIG,
|
||||
FILE_TYPE_DATA,
|
||||
FILE_TYPE_LEGACY,
|
||||
FILE_TYPE_INVALID,
|
||||
|
@ -195,9 +189,9 @@ On-disk files: (lib/file.cpp)
|
|||
- API:
|
||||
File :: File(string filepath, FileLocHint hint);
|
||||
Resolve filepath to one of:
|
||||
XDG_{CONFIG|DATA}_HOME/ocarina/filepath
|
||||
XDG_{CONFIG|DATA}_HOME/ocarina-debug/filepath
|
||||
XDG_{CONFIG|DATA}_HOME/ocarina-test/filepath
|
||||
XDG_DATA_HOME/ocarina/filepath
|
||||
XDG_DATA_HOME/ocarina-debug/filepath
|
||||
XDG_DATA_HOME/ocarina-test/filepath
|
||||
$HOME/.ocarina/
|
||||
$HOME/.ocarina-debug/
|
||||
$HOME/.ocarina-test/
|
||||
|
|
1
config
1
config
|
@ -26,6 +26,7 @@ Export("env", "use_package", "CONFIG_DEBUG", "CONFIG_VERSION")
|
|||
include = SConscript("include/Sconscript")
|
||||
|
||||
lib = SConscript("lib/Sconscript")
|
||||
Export("lib")
|
||||
|
||||
tests = SConscript("tests/Sconscript")
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#define FILE_VERSION 0
|
||||
|
||||
enum FileLocHint {
|
||||
FILE_TYPE_CONFIG,
|
||||
FILE_TYPE_DATA,
|
||||
FILE_TYPE_LEGACY,
|
||||
FILE_TYPE_INVALID,
|
||||
|
@ -29,7 +28,7 @@ private:
|
|||
std::string filepath;
|
||||
unsigned int version;
|
||||
|
||||
void find_dir(std::string &);
|
||||
std::string find_dir();
|
||||
void open_read();
|
||||
void open_write();
|
||||
|
||||
|
|
94
lib/file.cpp
94
lib/file.cpp
|
@ -15,49 +15,16 @@
|
|||
#define OCARINA_DIR "ocarina"
|
||||
#endif
|
||||
|
||||
void File :: find_dir(std::string &res)
|
||||
{
|
||||
if (hint == FILE_TYPE_INVALID)
|
||||
return;
|
||||
|
||||
switch (hint) {
|
||||
case FILE_TYPE_CONFIG:
|
||||
res = g_get_user_config_dir();
|
||||
break;
|
||||
case FILE_TYPE_DATA:
|
||||
res = g_get_user_data_dir();
|
||||
break;
|
||||
default: /* FILE_TYPE_LEGACY */
|
||||
res = g_get_home_dir();
|
||||
break;
|
||||
}
|
||||
|
||||
res += "/";
|
||||
switch (hint) {
|
||||
case FILE_TYPE_CONFIG:
|
||||
case FILE_TYPE_DATA:
|
||||
res += OCARINA_DIR;
|
||||
break;
|
||||
default: /* FILE_TYPE_LEGACY */
|
||||
res += ".";
|
||||
res += OCARINA_DIR;
|
||||
res += "/library";
|
||||
}
|
||||
}
|
||||
|
||||
File :: File(const std::string &path, FileLocHint file_hint)
|
||||
: mode(NOT_OPEN), hint(file_hint)
|
||||
: mode(NOT_OPEN), hint(file_hint), version(FILE_VERSION)
|
||||
{
|
||||
std::string dir;
|
||||
|
||||
if (path == "") {
|
||||
if (path.size() == 0)
|
||||
hint = FILE_TYPE_INVALID;
|
||||
filepath = "INVALID";
|
||||
return;
|
||||
}
|
||||
|
||||
find_dir(dir);
|
||||
filepath = dir + "/" + path;
|
||||
if (hint == FILE_TYPE_INVALID)
|
||||
filepath = "INVALID";
|
||||
else
|
||||
filepath = find_dir() + "/" + path;
|
||||
}
|
||||
|
||||
File :: ~File()
|
||||
|
@ -80,16 +47,34 @@ bool File :: exists()
|
|||
return g_file_test(filepath.c_str(), G_FILE_TEST_EXISTS);
|
||||
}
|
||||
|
||||
std::string File :: find_dir()
|
||||
{
|
||||
std::string res;
|
||||
|
||||
if (hint == FILE_TYPE_DATA) {
|
||||
res = g_get_user_data_dir();
|
||||
res += "/";
|
||||
res += OCARINA_DIR;
|
||||
} else /* FILE_TYPE_LEGACY */ {
|
||||
res = g_get_home_dir();
|
||||
res += "/.";
|
||||
res += OCARINA_DIR;
|
||||
res += "/library";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void File :: open_read()
|
||||
{
|
||||
if (!exists()) {
|
||||
dprint("ERROR: File does not exist (%s)\n", filepath.c_str());
|
||||
dprint("ERROR: File does not exist\n");
|
||||
throw -E_EXIST;
|
||||
}
|
||||
|
||||
std::fstream::open(filepath.c_str(), std::fstream::in);
|
||||
if (std::fstream::fail()) {
|
||||
dprint("ERROR: Could not open file for reading (%s)\n", filepath.c_str());
|
||||
dprint("ERROR: File could not be opened for reading\n");
|
||||
throw -E_IO;
|
||||
}
|
||||
|
||||
|
@ -100,21 +85,20 @@ void File :: open_read()
|
|||
|
||||
void File :: open_write()
|
||||
{
|
||||
std::string dir;
|
||||
if (hint == FILE_TYPE_LEGACY) {
|
||||
dprint("ERROR: Cannot write to legacy files (%s)\n", filepath.c_str());
|
||||
dprint("ERROR: Cannot write to legacy files\n");
|
||||
throw -E_IO;
|
||||
}
|
||||
|
||||
find_dir(dir);
|
||||
std::string dir = find_dir();
|
||||
if (g_mkdir_with_parents(dir.c_str(), 0755) != 0) {
|
||||
dprint("ERROR: Could not make directory (%s)\n", dir.c_str());
|
||||
dprint("ERROR: Could not make directory\n");
|
||||
throw -E_IO;
|
||||
}
|
||||
|
||||
std::fstream::open(filepath.c_str(), std::fstream::out);
|
||||
if (std::fstream::fail()) {
|
||||
dprint("ERROR: Could not open file for writing (%s)\n", filepath.c_str());
|
||||
dprint("ERROR: Could not open file for writing\n");
|
||||
throw -E_IO;
|
||||
}
|
||||
|
||||
|
@ -124,18 +108,18 @@ void File :: open_write()
|
|||
|
||||
void File :: open(OpenMode m)
|
||||
{
|
||||
if (mode != NOT_OPEN) {
|
||||
dprint("ERROR: File is already open (%s)\n", filepath.c_str());
|
||||
if (hint == FILE_TYPE_INVALID) {
|
||||
dprint("ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened\n");
|
||||
throw -E_INVAL;
|
||||
} else if (m == NOT_OPEN) {
|
||||
dprint("ERROR: NOT_OPEN is not a legal OpenMode\n");
|
||||
throw -E_INVAL;
|
||||
} else if (mode != NOT_OPEN) {
|
||||
dprint("ERROR: File is already open\n");
|
||||
throw -E_IO;
|
||||
}
|
||||
|
||||
if (m == NOT_OPEN) {
|
||||
dprint("ERROR: NOT_OPEN is not a legal OpenMode (%s)\n", filepath.c_str());
|
||||
throw -E_INVAL;
|
||||
} else if (hint == FILE_TYPE_INVALID) {
|
||||
dprint("ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened\n");
|
||||
throw -E_INVAL;
|
||||
} else if (m == OPEN_READ)
|
||||
else if (m == OPEN_READ)
|
||||
open_read();
|
||||
else /* m == OPEN_WRITE */
|
||||
open_write();
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
#!/usr/bin/python
|
||||
Import("env")
|
||||
|
||||
env.Append( CCFLAGS = [ "-DCONFIG_TEST" ] )
|
||||
src = SConscript("src/Sconscript")
|
||||
|
||||
tests = [ "version" ]
|
||||
|
||||
|
||||
def Test(name):
|
||||
return Command("%s.out" % name, [], "./tests/%s" % name)
|
||||
|
||||
for test in tests:
|
||||
t = Test(test)
|
||||
Depends(t, src)
|
||||
AlwaysBuild(t)
|
||||
|
||||
#AlwaysBuild(test)
|
||||
#Depends(test, src)
|
||||
|
||||
tests = [ "version", "file" ]
|
||||
#scripts = [ "print", "file", "database", "index", "filter", "idle", "playlist",
|
||||
# "library", "playqueue", "deck", "audio", "gui" ]
|
||||
|
||||
prev = None
|
||||
|
||||
for test in tests:
|
||||
t = Command("%s.out" % test, [], "./tests/%s" % test)
|
||||
|
||||
if prev:
|
||||
Depends(t, prev)
|
||||
Depends(t, src)
|
||||
AlwaysBuild(t)
|
||||
prev = t
|
||||
|
|
|
@ -16,18 +16,51 @@ function config_debug
|
|||
read_config CONFIG_DEBUG
|
||||
}
|
||||
|
||||
function test_success
|
||||
CUR_TEST=0
|
||||
function new_test
|
||||
{
|
||||
echo "Success!"
|
||||
exit 0
|
||||
echo "$1"
|
||||
CUR_TEST=0
|
||||
}
|
||||
|
||||
function test_failed
|
||||
function start_test
|
||||
{
|
||||
echo "FAILED =("
|
||||
on_failed
|
||||
exit 1
|
||||
echo -n " $CUR_TEST: "
|
||||
let CUR_TEST=($CUR_TEST + 1)
|
||||
}
|
||||
|
||||
function assert_equal
|
||||
{
|
||||
if [ "$1" == "$2" ]; then
|
||||
echo "Success!"
|
||||
return 0
|
||||
else
|
||||
echo "FAILED =("
|
||||
echo " Expected: $2"
|
||||
echo " Actual: $1"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function test_equal
|
||||
{
|
||||
start_test
|
||||
assert_equal "$($1)" "$2"
|
||||
}
|
||||
|
||||
function on_exit
|
||||
{
|
||||
ret=$?
|
||||
echo
|
||||
return $ret
|
||||
}; trap "on_exit" EXIT
|
||||
|
||||
[ -z $HOME ] && HOME=$(cat /etc/passwd | grep $(whoami) | awk -F: '{print $6}')
|
||||
[ -z $XDG_DATA_HOME] && XDG_DATA_HOME="$HOME/.local/share"
|
||||
DATA_DIR="$XDG_DATA_HOME/ocarina-test"
|
||||
LEGACY_DIR="$HOME/.ocarina-test/library"
|
||||
|
||||
rm -rf $DATA_DIR 2>/dev/null || true
|
||||
|
||||
set -e
|
||||
cd $(dirname $0)
|
||||
echo -n "Testing $(basename $0) ... "
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
#!/bin/bash
|
||||
# Copyright 2014 (c) Anna Schumaker
|
||||
|
||||
. $(dirname $0)/_functions
|
||||
|
||||
function test_file
|
||||
{
|
||||
test_equal "./src/file $1" "$2"
|
||||
}
|
||||
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Test filepaths
|
||||
#
|
||||
|
||||
new_test "Filepath Test"
|
||||
|
||||
test_file -D INVALID
|
||||
test_file -L INVALID
|
||||
test_file "-D file.txt" "$DATA_DIR/file.txt"
|
||||
test_file "-L file.txt" "$LEGACY_DIR/file.txt"
|
||||
test_file "file.txt" INVALID
|
||||
test_file "-D -v file.txt" "0"
|
||||
test_file "-L -v file.txt" "0"
|
||||
|
||||
if [ -d $DATA_DIR ]; then
|
||||
echo "ERROR: $DATA_DIR should not exist!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Test opening files
|
||||
#
|
||||
|
||||
echo
|
||||
new_test "File Open Test"
|
||||
|
||||
# Generic open testing
|
||||
test_file "-o N file.txt" "ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened"
|
||||
test_file "-D -o N file.txt" "ERROR: NOT_OPEN is not a legal OpenMode"
|
||||
test_file "-D -o W -O file.txt" "ERROR: File is already open" # This test creates a file
|
||||
test_file "-D -o R -O file.txt" "ERROR: File is already open"
|
||||
rm $DATA_DIR/*
|
||||
|
||||
# Test opening for read
|
||||
test_file "-D -o R file.txt" "ERROR: File does not exist"
|
||||
|
||||
touch $DATA_DIR/file.txt
|
||||
chmod -r $DATA_DIR/file.txt
|
||||
test_file "-D -o R file.txt" "ERROR: File could not be opened for reading"
|
||||
rm -r $DATA_DIR
|
||||
|
||||
# Test opening for write
|
||||
test_file "-L -o W file.txt" "ERROR: Cannot write to legacy files"
|
||||
|
||||
touch $DATA_DIR
|
||||
test_file "-D -o W file.txt" "ERROR: Could not make directory"
|
||||
|
||||
rm $DATA_DIR
|
||||
mkdir -p $DATA_DIR
|
||||
touch $DATA_DIR/file.txt
|
||||
chmod -w $DATA_DIR/file.txt
|
||||
test_file "-D -o W file.txt" "ERROR: Could not open file for writing"
|
||||
rm -rf $DATA_DIR
|
||||
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Test closing files
|
||||
#
|
||||
|
||||
echo
|
||||
new_test "File Close Test"
|
||||
test_file "-D -c file.txt" ""
|
||||
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Test FILE IO
|
||||
#
|
||||
|
||||
data="ABCDE FGHIJ KLMNO PQRST UVWXYZ"
|
||||
echo
|
||||
new_test "File IO Test"
|
||||
|
||||
# Write to file
|
||||
./src/file -D -w file.txt "$data"
|
||||
start_test
|
||||
assert_equal "$(cat $DATA_DIR/file.txt)" "0
|
||||
$data"
|
||||
|
||||
# Read data back from file
|
||||
test_file "-D -r file.txt" "ABCDE
|
||||
FGHIJ
|
||||
KLMNO
|
||||
PQRST
|
||||
UVWXYZ"
|
||||
|
||||
# Write different data to file
|
||||
./src/file -D -w file.txt " $data"
|
||||
start_test
|
||||
assert_equal "$(cat $DATA_DIR/file.txt)" "0
|
||||
$data"
|
||||
|
||||
# Read data back in a single line
|
||||
test_file "-D -r -g file.txt" "$data"
|
|
@ -1,6 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
Import("Test", "CONFIG")
|
||||
|
||||
CONFIG.FILE = True
|
||||
|
||||
Test("file", "file.cpp")
|
|
@ -1,287 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 (c) Anna Schumaker.
|
||||
*/
|
||||
#include <error.h>
|
||||
#include <file.h>
|
||||
#include <print.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
bool test_result(bool passed, bool print_spaces)
|
||||
{
|
||||
if (print_spaces)
|
||||
print(" ");
|
||||
if (passed == true)
|
||||
print("Passed\n");
|
||||
else
|
||||
print("Failed\n");
|
||||
return passed;
|
||||
}
|
||||
|
||||
File *get_file(int testno, char subtest, bool valid, FileLocHint hint)
|
||||
{
|
||||
std::stringstream s;
|
||||
std::string path = "";
|
||||
if (valid == true) {
|
||||
path = "file.";
|
||||
s << testno;
|
||||
path += s.str() + subtest;
|
||||
}
|
||||
print("Test %d%c: ", testno, subtest);
|
||||
return new File(path, hint);
|
||||
}
|
||||
|
||||
static inline bool inval_or_legacy(bool valid, FileLocHint hint)
|
||||
{
|
||||
return (valid == false) || (hint == FILE_TYPE_LEGACY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check how filepath is expanded
|
||||
* An empty filepath == INVALID
|
||||
*/
|
||||
void test_a(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
File *f = get_file(testno, 'a', valid, hint);
|
||||
print("File path is %s\n", f->get_filepath());
|
||||
}
|
||||
|
||||
/*
|
||||
* NOT_OPEN is not a valid openmode
|
||||
*/
|
||||
void test_b(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
int status = 0;
|
||||
File *f = get_file(testno, 'b', valid, hint);
|
||||
try {
|
||||
f->open(NOT_OPEN);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
test_result(status == -E_INVAL, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a file doesn't exist, it can't be opened for reading
|
||||
*/
|
||||
void test_c(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
int status = 0;
|
||||
File *f = get_file(testno, 'c', valid, hint);
|
||||
try {
|
||||
f->open(OPEN_READ);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (valid == false)
|
||||
test_result(status == -E_INVAL, true);
|
||||
else
|
||||
test_result(status == -E_EXIST, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writing to FILE_TYPE_LEGACY is not supported
|
||||
*/
|
||||
void test_d(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
int status = 0;
|
||||
File *f = get_file(testno, 'd', valid, hint);
|
||||
|
||||
try {
|
||||
f->open(OPEN_WRITE);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
|
||||
if (valid == false)
|
||||
test_result(status == -E_INVAL, true);
|
||||
else if (hint == FILE_TYPE_LEGACY)
|
||||
test_result(status == -E_IO, true);
|
||||
else
|
||||
test_result(status == 0, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to close a file that was never opened
|
||||
*/
|
||||
void test_e(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
int status = 0;
|
||||
File *f = get_file(testno, 'e', valid, hint);
|
||||
try {
|
||||
f->close();
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
test_result(status == 0, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open for writing, then for reading
|
||||
*/
|
||||
void test_f(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
File *f;
|
||||
int status = 0;
|
||||
|
||||
if (inval_or_legacy(valid, hint))
|
||||
return;
|
||||
|
||||
f = get_file(testno, 'f', valid, hint);
|
||||
|
||||
try {
|
||||
f->open(OPEN_WRITE);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
test_result(status == 0, false);
|
||||
print(" ");
|
||||
|
||||
status = 0;
|
||||
try {
|
||||
f->open(OPEN_READ);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
test_result(status == -E_IO, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a file, then open for reading
|
||||
*/
|
||||
void test_g(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
File *f;
|
||||
int status = 0;
|
||||
|
||||
if (inval_or_legacy(valid, hint))
|
||||
return;
|
||||
|
||||
f = get_file(testno, 'g', valid, hint);
|
||||
|
||||
try {
|
||||
f->open(OPEN_WRITE);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (!test_result(status == 0, false))
|
||||
return;
|
||||
|
||||
try {
|
||||
f->close();
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (!test_result(status == 0, true))
|
||||
return;
|
||||
|
||||
try {
|
||||
f->open(OPEN_READ);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (!test_result(status == 0, true))
|
||||
return;
|
||||
|
||||
f->close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test doing IO to a file
|
||||
*/
|
||||
void test_h(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
File *f;
|
||||
int a, b, c, d, e, status = 0;
|
||||
|
||||
if (inval_or_legacy(valid, hint))
|
||||
return;
|
||||
f = get_file(testno, 'h', valid, hint);
|
||||
|
||||
/*
|
||||
* Write data to file
|
||||
*/
|
||||
try {
|
||||
f->open(OPEN_WRITE);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (!test_result(status == 0, false))
|
||||
return;
|
||||
|
||||
(*f) << "Hello, World!" << std::endl;
|
||||
(*f) << "This is a multi-line file =)" << std::endl;
|
||||
(*f) << "1 2 3 4 5" << std::endl;
|
||||
|
||||
try {
|
||||
f->close();
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (!test_result(status == 0, true))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Read data back from disk
|
||||
*/
|
||||
try {
|
||||
f->open(OPEN_READ);
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
if (!test_result(status == 0, true))
|
||||
return;
|
||||
|
||||
print(" File version is: %u\n", f->get_version());
|
||||
print(" \"%s\"\n", f->getline().c_str());
|
||||
if (!test_result(f->good(), true))
|
||||
return;
|
||||
print(" \"%s\"\n", f->getline().c_str());
|
||||
if (!test_result(f->good(), true))
|
||||
return;
|
||||
|
||||
(*f) >> a >> b >> c >> d >> e;
|
||||
if (!test_result(f->good(), true))
|
||||
return;
|
||||
print(" a: %d, b: %d, c: %d, d: %d, e: %d\n", a, b, c, d, e);
|
||||
|
||||
/*
|
||||
* Close file
|
||||
*/
|
||||
try {
|
||||
f->close();
|
||||
} catch (int error) {
|
||||
status = error;
|
||||
}
|
||||
test_result(status == 0, true);
|
||||
}
|
||||
|
||||
static void(*tests[])(int, bool, FileLocHint) = {
|
||||
test_a,
|
||||
test_b,
|
||||
test_c,
|
||||
test_d,
|
||||
test_e,
|
||||
test_f,
|
||||
test_g,
|
||||
test_h,
|
||||
};
|
||||
static unsigned int num_tests = sizeof(tests) / sizeof(void (*)(int, bool, FileLocHint));
|
||||
|
||||
void run_test(int testno, bool valid, FileLocHint hint)
|
||||
{
|
||||
for (unsigned int i = 0; i < num_tests; i++)
|
||||
tests[i](testno, valid, hint);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
run_test(1, true, FILE_TYPE_CONFIG);
|
||||
run_test(2, false, FILE_TYPE_CONFIG);
|
||||
run_test(3, true, FILE_TYPE_DATA);
|
||||
run_test(4, false, FILE_TYPE_DATA);
|
||||
run_test(5, true, FILE_TYPE_LEGACY);
|
||||
run_test(6, false, FILE_TYPE_LEGACY);
|
||||
return 0;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
Test 1a: File path is /home/anna/.config/ocarina-test/file.1a
|
||||
Test 1b: ERROR: NOT_OPEN is not a legal OpenMode (/home/anna/.config/ocarina-test/file.1b)
|
||||
Passed
|
||||
Test 1c: ERROR: File does not exist (/home/anna/.config/ocarina-test/file.1c)
|
||||
Passed
|
||||
Test 1d: Passed
|
||||
Test 1e: Passed
|
||||
Test 1f: Passed
|
||||
ERROR: File is already open (/home/anna/.config/ocarina-test/file.1f)
|
||||
Passed
|
||||
Test 1g: Passed
|
||||
Passed
|
||||
Passed
|
||||
Test 1h: Passed
|
||||
Passed
|
||||
Passed
|
||||
File version is: 0
|
||||
"Hello, World!"
|
||||
Passed
|
||||
"This is a multi-line file =)"
|
||||
Passed
|
||||
Passed
|
||||
a: 1, b: 2, c: 3, d: 4, e: 5
|
||||
Passed
|
||||
|
||||
Test 2a: File path is INVALID
|
||||
Test 2b: ERROR: NOT_OPEN is not a legal OpenMode (INVALID)
|
||||
Passed
|
||||
Test 2c: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened
|
||||
Passed
|
||||
Test 2d: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened
|
||||
Passed
|
||||
Test 2e: Passed
|
||||
|
||||
Test 3a: File path is /home/anna/.local/share/ocarina-test/file.3a
|
||||
Test 3b: ERROR: NOT_OPEN is not a legal OpenMode (/home/anna/.local/share/ocarina-test/file.3b)
|
||||
Passed
|
||||
Test 3c: ERROR: File does not exist (/home/anna/.local/share/ocarina-test/file.3c)
|
||||
Passed
|
||||
Test 3d: Passed
|
||||
Test 3e: Passed
|
||||
Test 3f: Passed
|
||||
ERROR: File is already open (/home/anna/.local/share/ocarina-test/file.3f)
|
||||
Passed
|
||||
Test 3g: Passed
|
||||
Passed
|
||||
Passed
|
||||
Test 3h: Passed
|
||||
Passed
|
||||
Passed
|
||||
File version is: 0
|
||||
"Hello, World!"
|
||||
Passed
|
||||
"This is a multi-line file =)"
|
||||
Passed
|
||||
Passed
|
||||
a: 1, b: 2, c: 3, d: 4, e: 5
|
||||
Passed
|
||||
|
||||
Test 4a: File path is INVALID
|
||||
Test 4b: ERROR: NOT_OPEN is not a legal OpenMode (INVALID)
|
||||
Passed
|
||||
Test 4c: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened
|
||||
Passed
|
||||
Test 4d: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened
|
||||
Passed
|
||||
Test 4e: Passed
|
||||
|
||||
Test 5a: File path is /home/anna/.ocarina-test/library/file.5a
|
||||
Test 5b: ERROR: NOT_OPEN is not a legal OpenMode (/home/anna/.ocarina-test/library/file.5b)
|
||||
Passed
|
||||
Test 5c: ERROR: File does not exist (/home/anna/.ocarina-test/library/file.5c)
|
||||
Passed
|
||||
Test 5d: ERROR: Cannot write to legacy files (/home/anna/.ocarina-test/library/file.5d)
|
||||
Passed
|
||||
Test 5e: Passed
|
||||
|
||||
Test 6a: File path is INVALID
|
||||
Test 6b: ERROR: NOT_OPEN is not a legal OpenMode (INVALID)
|
||||
Passed
|
||||
Test 6c: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened
|
||||
Passed
|
||||
Test 6d: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened
|
||||
Passed
|
||||
Test 6e: Passed
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
#!/usr/bin/python
|
||||
Import("env")
|
||||
Import("env", "lib")
|
||||
|
||||
def compile_utility(name):
|
||||
return env.Program(name, "%s.cpp" % name)
|
||||
build = []
|
||||
for f in Glob("*.cpp"):
|
||||
src = str(f)
|
||||
name = src.split(".")[0]
|
||||
build += [ env.Program(name, [src] + lib) ]
|
||||
|
||||
build = compile_utility("version")
|
||||
Return("build")
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright 2014 (c) Anna Schumaker.
|
||||
* Do stuff with files
|
||||
*
|
||||
* Usage: files -D|-L [-c -g -o {R, W, N} -O -r -v -w] name [DATA]
|
||||
*
|
||||
* -D: FILE_TYPE_DATA
|
||||
* -L: FILE_TYPE_LEGACY
|
||||
*
|
||||
* -c: Test closing the file
|
||||
* -g: Read file using getline()
|
||||
* -o: Open the file for READ, WRITE, or NOT_OPEN
|
||||
* -O: Open the file a second time
|
||||
* -r: Read data from file
|
||||
* -v: Print version and exit
|
||||
* -w: Write data to file
|
||||
*
|
||||
*/
|
||||
#include <file.h>
|
||||
#include <print.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
enum action_t { CLOSE, OPEN, PATHS, READ, VERSION, WRITE };
|
||||
|
||||
int print_version(File &f)
|
||||
{
|
||||
print("%u\n", f.get_version());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int print_filepath(File &f)
|
||||
{
|
||||
print("%s\n", f.get_filepath());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_file(File &f, OpenMode mode)
|
||||
{
|
||||
try {
|
||||
f.open(mode);
|
||||
return 0;
|
||||
} catch (int err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, ret;
|
||||
action_t action = PATHS;
|
||||
FileLocHint hint = FILE_TYPE_INVALID;
|
||||
OpenMode mode = NOT_OPEN;
|
||||
bool second_open = false;
|
||||
bool getline = false;
|
||||
std::string file;
|
||||
std::string data;
|
||||
|
||||
while ((c = getopt(argc, argv, "cDgLo:Orvw")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
action = CLOSE;
|
||||
break;
|
||||
case 'D':
|
||||
hint = FILE_TYPE_DATA;
|
||||
break;
|
||||
case 'g':
|
||||
getline = true;
|
||||
break;
|
||||
case 'L':
|
||||
hint = FILE_TYPE_LEGACY;
|
||||
break;
|
||||
case 'o':
|
||||
action = OPEN;
|
||||
switch (optarg[0]) {
|
||||
case 'R':
|
||||
mode = OPEN_READ;
|
||||
break;
|
||||
case 'W':
|
||||
mode = OPEN_WRITE;
|
||||
break;
|
||||
case 'N':
|
||||
mode = NOT_OPEN;
|
||||
break;
|
||||
default:
|
||||
print("Invalid open mode\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
second_open = true;
|
||||
break;
|
||||
case 'r':
|
||||
action = READ;
|
||||
break;
|
||||
case 'v':
|
||||
action = VERSION;
|
||||
break;
|
||||
case 'w':
|
||||
action = WRITE;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
file = argv[optind++];
|
||||
if (optind < argc)
|
||||
data = argv[optind++];
|
||||
|
||||
File f(file, hint);
|
||||
switch (action) {
|
||||
case CLOSE:
|
||||
ret = open_file(f, OPEN_WRITE);
|
||||
if (ret == 0) {
|
||||
f.close();
|
||||
ret = open_file(f, OPEN_WRITE);
|
||||
}
|
||||
return ret;
|
||||
case OPEN:
|
||||
ret = open_file(f, mode);
|
||||
if ((ret == 0) && (second_open == true))
|
||||
ret = open_file(f, mode);
|
||||
return ret;
|
||||
case PATHS:
|
||||
return print_filepath(f);
|
||||
case READ:
|
||||
ret = open_file(f, OPEN_READ);
|
||||
if (ret == 0) {
|
||||
do {
|
||||
if (getline == true)
|
||||
data = f.getline();
|
||||
else
|
||||
f >> data;
|
||||
if (f.good() == false)
|
||||
break;
|
||||
print("%s\n", data.c_str());
|
||||
} while (true);
|
||||
}
|
||||
return ret;
|
||||
case VERSION:
|
||||
return print_version(f);
|
||||
case WRITE:
|
||||
ret = open_file(f, OPEN_WRITE);
|
||||
if (ret == 0)
|
||||
f << data << std::endl;
|
||||
return ret;
|
||||
}
|
||||
}
|
Binary file not shown.
Loading…
Reference in New Issue