blob: e94d4740bd04bfb3d6512ef0a0532e3c5f03bd4c [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define C_LUCY_RAMFOLDER
#define TESTLUCY_USE_SHORT_NAMES
#include "Lucy/Util/ToolSet.h"
#include "Clownfish/Blob.h"
#include "Clownfish/TestHarness/TestBatchRunner.h"
#include "Lucy/Test.h"
#include "Lucy/Test/Store/TestFolder.h"
#include "Lucy/Store/DirHandle.h"
#include "Lucy/Store/FileHandle.h"
#include "Lucy/Store/InStream.h"
#include "Lucy/Store/OutStream.h"
#include "Lucy/Store/RAMFolder.h"
static String *foo = NULL;
static String *bar = NULL;
static String *baz = NULL;
static String *boffo = NULL;
static String *banana = NULL;
static String *foo_bar = NULL;
static String *foo_bar_baz = NULL;
static String *foo_bar_baz_boffo = NULL;
static String *foo_boffo = NULL;
static String *foo_foo = NULL;
static String *nope = NULL;
TestFolder*
TestFolder_new() {
return (TestFolder*)Class_Make_Obj(TESTFOLDER);
}
static void
S_init_strings(void) {
foo = Str_newf("foo");
bar = Str_newf("bar");
baz = Str_newf("baz");
boffo = Str_newf("boffo");
banana = Str_newf("banana");
foo_bar = Str_newf("foo/bar");
foo_bar_baz = Str_newf("foo/bar/baz");
foo_bar_baz_boffo = Str_newf("foo/bar/baz/boffo");
foo_boffo = Str_newf("foo/boffo");
foo_foo = Str_newf("foo/foo");
nope = Str_newf("nope");
}
static void
S_destroy_strings(void) {
DECREF(foo);
DECREF(bar);
DECREF(baz);
DECREF(boffo);
DECREF(banana);
DECREF(foo_bar);
DECREF(foo_bar_baz);
DECREF(foo_bar_baz_boffo);
DECREF(foo_boffo);
DECREF(foo_foo);
DECREF(nope);
}
static void
test_Exists(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
fh = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
fh = Folder_Open_FileHandle(folder, foo_boffo,
FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
TEST_TRUE(runner, Folder_Exists(folder, foo), "Dir exists");
TEST_TRUE(runner, Folder_Exists(folder, boffo), "File exists");
TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
"Nested dir exists");
TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
"Nested file exists");
TEST_FALSE(runner, Folder_Exists(folder, banana),
"Non-existent entry");
TEST_FALSE(runner, Folder_Exists(folder, foo_foo),
"Non-existent nested entry");
DECREF(folder);
}
static void
test_Set_Path_and_Get_Path(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(foo);
TEST_TRUE(runner, Str_Equals(Folder_Get_Path(folder), (Obj*)foo),
"Get_Path");
Folder_Set_Path(folder, bar);
TEST_TRUE(runner, Str_Equals(Folder_Get_Path(folder), (Obj*)bar),
"Set_Path");
DECREF(folder);
}
static void
test_MkDir_and_Is_Directory(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
TEST_FALSE(runner, Folder_Is_Directory(folder, foo),
"Is_Directory() false for non-existent entry");
TEST_TRUE(runner, Folder_MkDir(folder, foo),
"MkDir returns true on success");
TEST_TRUE(runner, Folder_Is_Directory(folder, foo),
"Is_Directory() true for local folder");
TEST_FALSE(runner, Folder_Is_Directory(folder, foo_bar_baz),
"Is_Directory() false for non-existent deeply nested dir");
Err_set_error(NULL);
TEST_FALSE(runner, Folder_MkDir(folder, foo_bar_baz),
"MkDir for deeply nested dir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"MkDir for deeply nested dir sets global error");
TEST_TRUE(runner, Folder_MkDir(folder, foo_bar),
"MkDir for nested dir");
TEST_TRUE(runner, Folder_Is_Directory(folder, foo_bar),
"Is_Directory() true for nested dir");
Err_set_error(NULL);
TEST_FALSE(runner, Folder_MkDir(folder, foo_bar),
"Overwrite dir with MkDir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Overwrite dir with MkDir sets global error");
fh = Folder_Open_FileHandle(folder, foo_boffo,
FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
Err_set_error(NULL);
TEST_FALSE(runner, Folder_MkDir(folder, foo_boffo),
"Overwrite file with MkDir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Overwrite file with MkDir sets global error");
TEST_FALSE(runner, Folder_Is_Directory(folder, foo_boffo),
"Is_Directory() false for nested file");
DECREF(folder);
}
static void
test_Enclosing_Folder_and_Find_Folder(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
Folder_MkDir(folder, foo_bar_baz);
fh = Folder_Open_FileHandle(folder, foo_bar_baz_boffo,
FH_CREATE | FH_WRITE_ONLY);
{
Folder *encloser = Folder_Enclosing_Folder(folder, (String*)nope);
Folder *found = Folder_Find_Folder(folder, (String*)nope);
TEST_TRUE(runner, encloser == folder,
"Enclosing_Folder() - non-existent entry yields parent");
TEST_TRUE(runner, found == NULL,
"Find_Folder() - non-existent entry yields NULL");
}
{
Folder *encloser = Folder_Enclosing_Folder(folder, foo_bar);
Folder *found = Folder_Find_Folder(folder, foo_bar);
TEST_TRUE(runner,
encloser
&& Folder_is_a(encloser, FOLDER)
&& Str_Ends_With(Folder_Get_Path(encloser), foo),
"Enclosing_Folder() - find one directory down");
TEST_TRUE(runner,
found
&& Folder_is_a(found, FOLDER)
&& Str_Ends_With(Folder_Get_Path(found), bar),
"Find_Folder() - 'foo/bar'");
}
{
Folder *encloser = Folder_Enclosing_Folder(folder, foo_bar_baz);
Folder *found = Folder_Find_Folder(folder, foo_bar_baz);
TEST_TRUE(runner,
encloser
&& Folder_is_a(encloser, FOLDER)
&& Str_Ends_With(Folder_Get_Path(encloser), bar),
"Find two directories down");
TEST_TRUE(runner,
found
&& Folder_is_a(found, FOLDER)
&& Str_Ends_With(Folder_Get_Path(found), baz),
"Find_Folder() - 'foo/bar/baz'");
}
{
Folder *encloser
= Folder_Enclosing_Folder(folder, foo_bar_baz_boffo);
Folder *found = Folder_Find_Folder(folder, foo_bar_baz_boffo);
TEST_TRUE(runner,
encloser
&& Folder_is_a(encloser, FOLDER)
&& Str_Ends_With(Folder_Get_Path(encloser), baz),
"Recurse to find a directory containing a real file");
TEST_TRUE(runner, found == NULL,
"Find_Folder() - file instead of folder yields NULL");
}
DECREF(fh);
DECREF(folder);
}
static void
test_List(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
Vector *list;
String *elem;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
Folder_MkDir(folder, foo_bar_baz);
fh = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
fh = Folder_Open_FileHandle(folder, banana, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
list = Folder_List(folder, NULL);
Vec_Sort(list);
TEST_UINT_EQ(runner, Vec_Get_Size(list), 3, "List");
elem = (String*)DOWNCAST(Vec_Fetch(list, 0), STRING);
TEST_TRUE(runner, elem && Str_Equals(elem, (Obj*)banana),
"List first file");
elem = (String*)DOWNCAST(Vec_Fetch(list, 1), STRING);
TEST_TRUE(runner, elem && Str_Equals(elem, (Obj*)boffo),
"List second file");
elem = (String*)DOWNCAST(Vec_Fetch(list, 2), STRING);
TEST_TRUE(runner, elem && Str_Equals(elem, (Obj*)foo), "List dir");
DECREF(list);
list = Folder_List(folder, foo_bar);
TEST_UINT_EQ(runner, Vec_Get_Size(list), 1, "List subdirectory contents");
elem = (String*)DOWNCAST(Vec_Fetch(list, 0), STRING);
TEST_TRUE(runner, elem && Str_Equals(elem, (Obj*)baz),
"Just the filename");
DECREF(list);
DECREF(folder);
}
static void
test_Open_Dir(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
DirHandle *dh;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
dh = Folder_Open_Dir(folder, foo);
TEST_TRUE(runner, dh && DH_is_a(dh, DIRHANDLE), "Open_Dir");
DECREF(dh);
dh = Folder_Open_Dir(folder, foo_bar);
TEST_TRUE(runner, dh && DH_is_a(dh, DIRHANDLE), "Open_Dir nested dir");
DECREF(dh);
Err_set_error(NULL);
dh = Folder_Open_Dir(folder, bar);
TEST_TRUE(runner, dh == NULL,
"Open_Dir on non-existent entry fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_Dir on non-existent entry sets global error");
Err_set_error(NULL);
dh = Folder_Open_Dir(folder, foo_foo);
TEST_TRUE(runner, dh == NULL,
"Open_Dir on non-existent nested entry fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_Dir on non-existent nested entry sets global error");
DECREF(folder);
}
static void
test_Open_FileHandle(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
Folder_MkDir(folder, foo);
fh = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE), "Open_FileHandle");
DECREF(fh);
fh = Folder_Open_FileHandle(folder, foo_boffo,
FH_CREATE | FH_WRITE_ONLY);
TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE),
"Open_FileHandle for nested file");
DECREF(fh);
Err_set_error(NULL);
fh = Folder_Open_FileHandle(folder, foo, FH_CREATE | FH_WRITE_ONLY);
TEST_TRUE(runner, fh == NULL,
"Open_FileHandle on existing dir path fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_FileHandle on existing dir name sets global error");
Err_set_error(NULL);
fh = Folder_Open_FileHandle(folder, foo_bar_baz_boffo,
FH_CREATE | FH_WRITE_ONLY);
TEST_TRUE(runner, fh == NULL,
"Open_FileHandle for entry within non-existent dir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_FileHandle for entry within non-existent dir sets global error");
DECREF(folder);
}
static void
test_Open_Out(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
OutStream *outstream;
Folder_MkDir(folder, foo);
outstream = Folder_Open_Out(folder, boffo);
TEST_TRUE(runner, outstream && OutStream_is_a(outstream, OUTSTREAM),
"Open_Out");
DECREF(outstream);
outstream = Folder_Open_Out(folder, foo_boffo);
TEST_TRUE(runner, outstream && OutStream_is_a(outstream, OUTSTREAM),
"Open_Out for nested file");
DECREF(outstream);
Err_set_error(NULL);
outstream = Folder_Open_Out(folder, boffo);
TEST_TRUE(runner, outstream == NULL,
"Open_OutStream on existing file fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_Out on existing file sets global error");
Err_set_error(NULL);
outstream = Folder_Open_Out(folder, foo);
TEST_TRUE(runner, outstream == NULL,
"Open_OutStream on existing dir path fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_Out on existing dir name sets global error");
Err_set_error(NULL);
outstream = Folder_Open_Out(folder, foo_bar_baz_boffo);
TEST_TRUE(runner, outstream == NULL,
"Open_Out for entry within non-existent dir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_Out for entry within non-existent dir sets global error");
DECREF(folder);
}
static void
test_Open_In(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
InStream *instream;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
fh = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
fh = Folder_Open_FileHandle(folder, foo_boffo, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
instream = Folder_Open_In(folder, boffo);
TEST_TRUE(runner, instream && InStream_is_a(instream, INSTREAM),
"Open_In");
DECREF(instream);
instream = Folder_Open_In(folder, foo_boffo);
TEST_TRUE(runner, instream && InStream_is_a(instream, INSTREAM),
"Open_In for nested file");
DECREF(instream);
Err_set_error(NULL);
instream = Folder_Open_In(folder, foo);
TEST_TRUE(runner, instream == NULL,
"Open_InStream on existing dir path fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_In on existing dir name sets global error");
Err_set_error(NULL);
instream = Folder_Open_In(folder, foo_bar_baz_boffo);
TEST_TRUE(runner, instream == NULL,
"Open_In for entry within non-existent dir fails");
TEST_TRUE(runner, Err_get_error() != NULL,
"Open_In for entry within non-existent dir sets global error");
DECREF(folder);
}
static void
test_Delete(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
bool result;
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
fh = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
fh = Folder_Open_FileHandle(folder, foo_boffo,
FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
Err_set_error(NULL);
result = Folder_Delete(folder, banana);
TEST_FALSE(runner, result, "Delete on non-existent entry returns false");
Err_set_error(NULL);
result = Folder_Delete(folder, foo);
TEST_FALSE(runner, result, "Delete on non-empty dir returns false");
TEST_TRUE(runner, Folder_Delete(folder, foo_boffo),
"Delete nested file");
TEST_FALSE(runner, Folder_Exists(folder, foo_boffo),
"File is really gone");
TEST_TRUE(runner, Folder_Delete(folder, foo_bar),
"Delete nested dir");
TEST_FALSE(runner, Folder_Exists(folder, foo_bar),
"Dir is really gone");
TEST_TRUE(runner, Folder_Delete(folder, foo), "Delete empty dir");
TEST_FALSE(runner, Folder_Exists(folder, foo), "Dir is really gone");
DECREF(folder);
}
static void
test_Delete_Tree(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh;
bool result;
// Create tree to be deleted.
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
Folder_MkDir(folder, foo_bar_baz);
fh = Folder_Open_FileHandle(folder, foo_bar_baz_boffo,
FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
// Create bystanders.
Folder_MkDir(folder, bar);
fh = Folder_Open_FileHandle(folder, baz, FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
result = Folder_Delete_Tree(folder, foo);
TEST_TRUE(runner, result, "Delete_Tree() succeeded");
TEST_FALSE(runner, Folder_Exists(folder, foo), "Tree really gone");
TEST_TRUE(runner, Folder_Exists(folder, bar),
"local dir with same name as nested dir left intact");
TEST_TRUE(runner, Folder_Exists(folder, baz),
"local file with same name as nested dir left intact");
// Kill off the bystanders.
result = Folder_Delete_Tree(folder, bar);
TEST_TRUE(runner, result, "Delete_Tree() on empty dir");
result = Folder_Delete_Tree(folder, baz);
TEST_TRUE(runner, result, "Delete_Tree() on file");
// Create new tree to be deleted.
Folder_MkDir(folder, foo);
Folder_MkDir(folder, foo_bar);
Folder_MkDir(folder, foo_bar_baz);
fh = Folder_Open_FileHandle(folder, foo_bar_baz_boffo,
FH_CREATE | FH_WRITE_ONLY);
DECREF(fh);
// Remove tree in subdir.
result = Folder_Delete_Tree(folder, foo_bar);
TEST_TRUE(runner, result, "Delete_Tree() of subdir succeeded");
TEST_FALSE(runner, Folder_Exists(folder, foo_bar),
"subdir really gone");
TEST_TRUE(runner, Folder_Exists(folder, foo),
"enclosing dir left intact");
DECREF(folder);
}
static void
test_Slurp_File(TestBatchRunner *runner) {
Folder *folder = (Folder*)RAMFolder_new(NULL);
FileHandle *fh = Folder_Open_FileHandle(folder, foo,
FH_CREATE | FH_WRITE_ONLY);
Blob *contents;
FH_Write(fh, "stuff", 5);
FH_Close(fh);
DECREF(fh);
contents = Folder_Slurp_File(folder, foo);
TEST_TRUE(runner, Blob_Equals_Bytes(contents, "stuff", 5), "Slurp_File");
DECREF(contents);
DECREF(folder);
}
void
TestFolder_Run_IMP(TestFolder *self, TestBatchRunner *runner) {
TestBatchRunner_Plan(runner, (TestBatch*)self, 79);
S_init_strings();
test_Exists(runner);
test_Set_Path_and_Get_Path(runner);
test_MkDir_and_Is_Directory(runner);
test_Enclosing_Folder_and_Find_Folder(runner);
test_List(runner);
test_Open_Dir(runner);
test_Open_FileHandle(runner);
test_Open_Out(runner);
test_Open_In(runner);
test_Delete(runner);
test_Delete_Tree(runner);
test_Slurp_File(runner);
S_destroy_strings();
}