http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestFolder.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestFolder.c b/test/Lucy/Test/Store/TestFolder.c new file mode 100644 index 0000000..e94d474 --- /dev/null +++ b/test/Lucy/Test/Store/TestFolder.c @@ -0,0 +1,540 @@ +/* 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(); +} +
http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestFolder.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestFolder.cfh b/test/Lucy/Test/Store/TestFolder.cfh new file mode 100644 index 0000000..6a5ecf4 --- /dev/null +++ b/test/Lucy/Test/Store/TestFolder.cfh @@ -0,0 +1,29 @@ +/* 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. + */ + +parcel TestLucy; + +class Lucy::Test::Store::TestFolder + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestFolder* + new(); + + void + Run(TestFolder *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestFolderCommon.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestFolderCommon.c b/test/Lucy/Test/Store/TestFolderCommon.c new file mode 100644 index 0000000..07a9850 --- /dev/null +++ b/test/Lucy/Test/Store/TestFolderCommon.c @@ -0,0 +1,562 @@ +/* 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 TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Lucy/Test.h" +#include "Lucy/Test/Store/TestFolderCommon.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Store/Folder.h" +#include "Lucy/Store/DirHandle.h" +#include "Lucy/Store/FileHandle.h" +#include "Lucy/Store/InStream.h" +#include "Lucy/Store/OutStream.h" + +#define set_up_t LUCY_TestFolderCommon_Set_Up_t +#define tear_down_t LUCY_TestFolderCommon_Tear_Down_t + +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_boffo = NULL; +static String *foo_boffo = NULL; +static String *foo_foo = NULL; +static String *nope = NULL; +static String *nope_nyet = NULL; + +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_boffo = Str_newf("foo/bar/boffo"); + foo_boffo = Str_newf("foo/boffo"); + foo_foo = Str_newf("foo/foo"); + nope = Str_newf("nope"); + nope_nyet = Str_newf("nope/nyet"); +} + +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_boffo); + DECREF(foo_boffo); + DECREF(foo_foo); + DECREF(nope); + DECREF(nope_nyet); +} + +static void +test_Local_Exists(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + OutStream *outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + Folder_Local_MkDir(folder, foo); + outstream = Folder_Open_Out(folder, foo_boffo); + DECREF(outstream); + + TEST_TRUE(runner, Folder_Local_Exists(folder, boffo), + "Local_Exists() returns true for file"); + TEST_TRUE(runner, Folder_Local_Exists(folder, foo), + "Local_Exists() returns true for dir"); + TEST_FALSE(runner, Folder_Local_Exists(folder, foo_boffo), + "Local_Exists() returns false for nested entry"); + TEST_FALSE(runner, Folder_Local_Exists(folder, bar), + "Local_Exists() returns false for non-existent entry"); + + Folder_Delete(folder, foo_boffo); + Folder_Delete(folder, foo); + Folder_Delete(folder, boffo); + DECREF(folder); + tear_down(); +} + +static void +test_Local_Is_Directory(TestBatchRunner *runner, set_up_t set_up, + tear_down_t tear_down) { + Folder *folder = set_up(); + OutStream *outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + Folder_Local_MkDir(folder, foo); + + TEST_FALSE(runner, Folder_Local_Is_Directory(folder, boffo), + "Local_Is_Directory() returns false for file"); + TEST_TRUE(runner, Folder_Local_Is_Directory(folder, foo), + "Local_Is_Directory() returns true for dir"); + TEST_FALSE(runner, Folder_Local_Is_Directory(folder, bar), + "Local_Is_Directory() returns false for non-existent entry"); + + Folder_Delete(folder, boffo); + Folder_Delete(folder, foo); + DECREF(folder); + tear_down(); +} + +static void +test_Local_Find_Folder(TestBatchRunner *runner, set_up_t set_up, + tear_down_t tear_down) { + Folder *folder = set_up(); + Folder *local; + OutStream *outstream; + + Folder_MkDir(folder, foo); + Folder_MkDir(folder, foo_bar); + outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + outstream = Folder_Open_Out(folder, foo_boffo); + DECREF(outstream); + + local = Folder_Local_Find_Folder(folder, nope); + TEST_TRUE(runner, local == NULL, "Non-existent entry yields NULL"); + + String *empty = SSTR_BLANK(); + local = Folder_Local_Find_Folder(folder, empty); + TEST_TRUE(runner, local == NULL, "Empty string yields NULL"); + + local = Folder_Local_Find_Folder(folder, foo_bar); + TEST_TRUE(runner, local == NULL, "nested folder yields NULL"); + + local = Folder_Local_Find_Folder(folder, foo_boffo); + TEST_TRUE(runner, local == NULL, "nested file yields NULL"); + + local = Folder_Local_Find_Folder(folder, boffo); + TEST_TRUE(runner, local == NULL, "local file yields NULL"); + + local = Folder_Local_Find_Folder(folder, bar); + TEST_TRUE(runner, local == NULL, "name of nested folder yields NULL"); + + local = Folder_Local_Find_Folder(folder, foo); + TEST_TRUE(runner, + local + && Folder_is_a(local, FOLDER) + && Str_Ends_With(Folder_Get_Path(local), foo), + "Find local directory"); + + Folder_Delete(folder, foo_bar); + Folder_Delete(folder, foo_boffo); + Folder_Delete(folder, foo); + Folder_Delete(folder, boffo); + DECREF(folder); + tear_down(); +} + +static void +test_Local_MkDir(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + bool result; + + result = Folder_Local_MkDir(folder, foo); + TEST_TRUE(runner, result, "Local_MkDir succeeds and returns true"); + + Err_set_error(NULL); + result = Folder_Local_MkDir(folder, foo); + TEST_FALSE(runner, result, + "Local_MkDir returns false when a dir already exists"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Local_MkDir sets global error when a dir already exists"); + TEST_TRUE(runner, Folder_Exists(folder, foo), + "Existing dir untouched after failed Local_MkDir"); + + OutStream *outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + Err_set_error(NULL); + result = Folder_Local_MkDir(folder, foo); + TEST_FALSE(runner, result, + "Local_MkDir returns false when a file already exists"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Local_MkDir sets global error when a file already exists"); + TEST_TRUE(runner, Folder_Exists(folder, boffo) && + !Folder_Local_Is_Directory(folder, boffo), + "Existing file untouched after failed Local_MkDir"); + + Folder_Delete(folder, foo); + Folder_Delete(folder, boffo); + DECREF(folder); + tear_down(); +} + +static void +test_Local_Open_Dir(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + DirHandle *dh = Folder_Local_Open_Dir(folder); + TEST_TRUE(runner, dh && DH_is_a(dh, DIRHANDLE), + "Local_Open_Dir returns an DirHandle"); + DECREF(dh); + DECREF(folder); + tear_down(); +} + +static void +test_Local_Open_FileHandle(TestBatchRunner *runner, set_up_t set_up, + tear_down_t tear_down) { + Folder *folder = set_up(); + FileHandle *fh; + + fh = Folder_Local_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE); + TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE), + "opened FileHandle"); + DECREF(fh); + + fh = Folder_Local_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE), + "opened FileHandle for append"); + DECREF(fh); + + Err_set_error(NULL); + fh = Folder_Local_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE); + TEST_TRUE(runner, fh == NULL, "FH_EXLUSIVE flag prevents clobber"); + TEST_TRUE(runner, Err_get_error() != NULL, + "failure due to FH_EXLUSIVE flag sets global error"); + + fh = Folder_Local_Open_FileHandle(folder, boffo, FH_READ_ONLY); + TEST_TRUE(runner, fh && FH_is_a(fh, FILEHANDLE), + "opened FileHandle for reading"); + DECREF(fh); + + Err_set_error(NULL); + fh = Folder_Local_Open_FileHandle(folder, nope, FH_READ_ONLY); + TEST_TRUE(runner, fh == NULL, + "Can't open non-existent file for reading"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Opening non-existent file for reading sets global error"); + + Folder_Delete(folder, boffo); + DECREF(folder); + tear_down(); +} + +static void +test_Local_Delete(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + OutStream *outstream; + + outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + TEST_TRUE(runner, Folder_Local_Delete(folder, boffo), + "Local_Delete on file succeeds"); + TEST_FALSE(runner, Folder_Exists(folder, boffo), + "File is really gone"); + + Folder_Local_MkDir(folder, foo); + outstream = Folder_Open_Out(folder, foo_boffo); + DECREF(outstream); + + Err_set_error(NULL); + TEST_FALSE(runner, Folder_Local_Delete(folder, foo), + "Local_Delete on non-empty dir fails"); + + Folder_Delete(folder, foo_boffo); + TEST_TRUE(runner, Folder_Local_Delete(folder, foo), + "Local_Delete on empty dir succeeds"); + // FIXME: This test sometimes fails on Windows. + TEST_FALSE(runner, Folder_Exists(folder, foo), + "Dir is really gone"); + + DECREF(folder); + tear_down(); +} + +static void +test_Rename(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + OutStream *outstream; + bool result; + + Folder_MkDir(folder, foo); + Folder_MkDir(folder, foo_bar); + outstream = Folder_Open_Out(folder, boffo); + OutStream_Close(outstream); + DECREF(outstream); + + // Move files. + + result = Folder_Rename(folder, boffo, banana); + TEST_TRUE(runner, result, "Rename succeeds and returns true"); + TEST_TRUE(runner, Folder_Exists(folder, banana), + "File exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, boffo), + "File no longer exists at old path"); + + result = Folder_Rename(folder, banana, foo_bar_boffo); + TEST_TRUE(runner, result, "Rename to file in nested dir"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo), + "File exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, banana), + "File no longer exists at old path"); + + result = Folder_Rename(folder, foo_bar_boffo, boffo); + TEST_TRUE(runner, result, "Rename from file in nested dir"); + TEST_TRUE(runner, Folder_Exists(folder, boffo), + "File exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, foo_bar_boffo), + "File no longer exists at old path"); + + outstream = Folder_Open_Out(folder, foo_boffo); + OutStream_Close(outstream); + DECREF(outstream); + result = Folder_Rename(folder, boffo, foo_boffo); + if (result) { + PASS(runner, "Rename clobbers on this system"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, boffo), + "File no longer exists at old path"); + } + else { + PASS(runner, "Rename does not clobber on this system"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File exists at new path"); + TEST_TRUE(runner, Folder_Exists(folder, boffo), + "File still exists at old path"); + Folder_Delete(folder, boffo); + } + + // Move Dirs. + + Folder_MkDir(folder, baz); + result = Folder_Rename(folder, baz, boffo); + TEST_TRUE(runner, result, "Rename dir"); + TEST_TRUE(runner, Folder_Exists(folder, boffo), + "Folder exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, baz), + "Folder no longer exists at old path"); + + result = Folder_Rename(folder, boffo, foo_foo); + TEST_TRUE(runner, result, "Rename dir into nested subdir"); + TEST_TRUE(runner, Folder_Exists(folder, foo_foo), + "Folder exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, boffo), + "Folder no longer exists at old path"); + + result = Folder_Rename(folder, foo_foo, foo_bar_baz); + TEST_TRUE(runner, result, "Rename dir from nested subdir"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar_baz), + "Folder exists at new path"); + TEST_FALSE(runner, Folder_Exists(folder, foo_foo), + "Folder no longer exists at old path"); + + // Test failed clobbers. + + Err_set_error(NULL); + result = Folder_Rename(folder, foo_boffo, foo_bar); + TEST_FALSE(runner, result, "Rename file clobbering dir fails"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Failed rename sets global error"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File still exists at old path"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar), + "Dir still exists after failed clobber"); + + Err_set_error(NULL); + result = Folder_Rename(folder, foo_bar, foo_boffo); + TEST_FALSE(runner, result, "Rename dir clobbering file fails"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Failed rename sets global error"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar), + "Dir still exists at old path"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File still exists after failed clobber"); + + // Test that "renaming" succeeds where to and from are the same. + + result = Folder_Rename(folder, foo_boffo, foo_boffo); + TEST_TRUE(runner, result, "Renaming file to itself succeeds"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File still exists"); + + result = Folder_Rename(folder, foo_bar, foo_bar); + // FIXME: This test sometimes fails on Windows with "Permission denied". + TEST_TRUE(runner, result, "Renaming dir to itself succeeds"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar), + "Dir still exists"); + + // Invalid filepaths. + + Err_set_error(NULL); + result = Folder_Rename(folder, foo_boffo, nope_nyet); + TEST_FALSE(runner, result, "Rename into non-existent subdir fails"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Renaming into non-existent subdir sets global error"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "Entry still exists at old path"); + + Err_set_error(NULL); + result = Folder_Rename(folder, nope_nyet, boffo); + TEST_FALSE(runner, result, "Rename non-existent file fails"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Renaming non-existent source file sets global error"); + + Folder_Delete(folder, foo_bar_baz); + Folder_Delete(folder, foo_bar); + Folder_Delete(folder, foo_boffo); + Folder_Delete(folder, foo); + DECREF(folder); + tear_down(); +} + +static void +test_Hard_Link(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + OutStream *outstream; + bool result; + + Folder_MkDir(folder, foo); + Folder_MkDir(folder, foo_bar); + outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + + // Link files. + + result = Folder_Hard_Link(folder, boffo, banana); + TEST_TRUE(runner, result, "Hard_Link succeeds and returns true"); + TEST_TRUE(runner, Folder_Exists(folder, banana), + "File exists at new path"); + TEST_TRUE(runner, Folder_Exists(folder, boffo), + "File still exists at old path"); + Folder_Delete(folder, boffo); + + result = Folder_Hard_Link(folder, banana, foo_bar_boffo); + TEST_TRUE(runner, result, "Hard_Link to target within nested dir"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo), + "File exists at new path"); + TEST_TRUE(runner, Folder_Exists(folder, banana), + "File still exists at old path"); + Folder_Delete(folder, banana); + + result = Folder_Hard_Link(folder, foo_bar_boffo, foo_boffo); + TEST_TRUE(runner, result, "Hard_Link from file in nested dir"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File exists at new path"); + TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo), + "File still exists at old path"); + Folder_Delete(folder, foo_bar_boffo); + + // Invalid clobbers. + + outstream = Folder_Open_Out(folder, boffo); + DECREF(outstream); + result = Folder_Hard_Link(folder, foo_boffo, boffo); + TEST_FALSE(runner, result, "Clobber of file fails"); + TEST_TRUE(runner, Folder_Exists(folder, boffo), + "File still exists at new path"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File still exists at old path"); + Folder_Delete(folder, boffo); + + Folder_MkDir(folder, baz); + result = Folder_Hard_Link(folder, foo_boffo, baz); + TEST_FALSE(runner, result, "Clobber of dir fails"); + TEST_TRUE(runner, Folder_Exists(folder, baz), + "Dir still exists at new path"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File still exists at old path"); + Folder_Delete(folder, baz); + + // Invalid Hard_Link of dir. + + Folder_MkDir(folder, baz); + result = Folder_Hard_Link(folder, baz, banana); + TEST_FALSE(runner, result, "Hard_Link dir fails"); + TEST_FALSE(runner, Folder_Exists(folder, banana), + "Nothing at new path"); + // FIXME: This test sometimes fails on Windows. + TEST_TRUE(runner, Folder_Exists(folder, baz), + "Folder still exists at old path"); + Folder_Delete(folder, baz); + + // Test that linking to yourself fails. + + result = Folder_Hard_Link(folder, foo_boffo, foo_boffo); + TEST_FALSE(runner, result, "Hard_Link file to itself fails"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "File still exists"); + + // Invalid filepaths. + + Err_set_error(NULL); + result = Folder_Rename(folder, foo_boffo, nope_nyet); + TEST_FALSE(runner, result, "Hard_Link into non-existent subdir fails"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Hard_Link into non-existent subdir sets global error"); + TEST_TRUE(runner, Folder_Exists(folder, foo_boffo), + "Entry still exists at old path"); + + Err_set_error(NULL); + result = Folder_Rename(folder, nope_nyet, boffo); + TEST_FALSE(runner, result, "Hard_Link non-existent source file fails"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Hard_Link non-existent source file sets global error"); + + Folder_Delete(folder, foo_bar); + Folder_Delete(folder, foo_boffo); + Folder_Delete(folder, foo); + DECREF(folder); + tear_down(); +} + +static void +test_Close(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) { + Folder *folder = set_up(); + Folder_Close(folder); + PASS(runner, "Close() concludes without incident"); + Folder_Close(folder); + Folder_Close(folder); + PASS(runner, "Calling Close() multiple times is safe"); + DECREF(folder); + tear_down(); +} + +uint32_t +TestFolderCommon_num_tests() { + return 99; +} + +void +TestFolderCommon_run_tests(TestBatchRunner *runner, set_up_t set_up, + tear_down_t tear_down) { + S_init_strings(); + test_Local_Exists(runner, set_up, tear_down); + test_Local_Is_Directory(runner, set_up, tear_down); + test_Local_Find_Folder(runner, set_up, tear_down); + test_Local_MkDir(runner, set_up, tear_down); + test_Local_Open_Dir(runner, set_up, tear_down); + test_Local_Open_FileHandle(runner, set_up, tear_down); + test_Local_Delete(runner, set_up, tear_down); + test_Rename(runner, set_up, tear_down); + test_Hard_Link(runner, set_up, tear_down); + test_Close(runner, set_up, tear_down); + S_destroy_strings(); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestFolderCommon.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestFolderCommon.cfh b/test/Lucy/Test/Store/TestFolderCommon.cfh new file mode 100644 index 0000000..75042f0 --- /dev/null +++ b/test/Lucy/Test/Store/TestFolderCommon.cfh @@ -0,0 +1,40 @@ +/* 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. + */ + +parcel TestLucy; + +__C__ +typedef lucy_Folder* +LUCY_TestFolderCommon_Set_Up_t(void); +typedef void +LUCY_TestFolderCommon_Tear_Down_t(void); +#ifdef LUCY_USE_SHORT_NAMES + #define TestFolderCommon_Set_Up_t LUCY_TestFolderCommon_Set_Up_t + #define TestFolderCommon_Tear_Down_t LUCY_TestFolderCommon_Tear_Down_t +#endif +__END_C__ + +inert class Lucy::Test::Store::TestFolderCommon { + inert uint32_t + num_tests(); + + inert void + run_tests(TestBatchRunner *runner, + LUCY_TestFolderCommon_Set_Up_t set_up, + LUCY_TestFolderCommon_Tear_Down_t tear_down); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestIOChunks.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestIOChunks.c b/test/Lucy/Test/Store/TestIOChunks.c new file mode 100644 index 0000000..bf35d0b --- /dev/null +++ b/test/Lucy/Test/Store/TestIOChunks.c @@ -0,0 +1,126 @@ +/* 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_TESTLUCY_TESTINSTREAM +#define C_LUCY_INSTREAM +#define C_LUCY_FILEWINDOW +#include <stdlib.h> +#include <time.h> + +#include "charmony.h" + +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Clownfish/TestHarness/TestUtils.h" +#include "Lucy/Test.h" +#include "Lucy/Test/TestUtils.h" +#include "Lucy/Test/Store/TestIOChunks.h" +#include "Lucy/Store/InStream.h" +#include "Lucy/Store/OutStream.h" +#include "Lucy/Store/RAMFile.h" +#include "Lucy/Store/RAMFileHandle.h" + +TestIOChunks* +TestIOChunks_new() { + return (TestIOChunks*)Class_Make_Obj(TESTIOCHUNKS); +} + +static void +test_Align(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + + for (int32_t i = 1; i < 32; i++) { + int64_t random_bytes = TestUtils_random_u64() % 32; + while (random_bytes--) { OutStream_Write_U8(outstream, 0); } + TEST_TRUE(runner, (OutStream_Align(outstream, i) % i) == 0, + "Align to %ld", (long)i); + } + DECREF(file); + DECREF(outstream); +} + +static void +test_Read_Write_Bytes(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + char buf[4]; + + OutStream_Write_Bytes(outstream, "foo", 4); + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + InStream_Read_Bytes(instream, buf, 4); + TEST_TRUE(runner, strcmp(buf, "foo") == 0, "Read_Bytes Write_Bytes"); + + DECREF(instream); + DECREF(outstream); + DECREF(file); +} + +static void +test_Buf(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + size_t size = IO_STREAM_BUF_SIZE * 2 + 5; + InStream *instream; + const char *buf; + + for (uint32_t i = 0; i < size; i++) { + OutStream_Write_U8(outstream, 'a'); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + InStreamIVARS *const ivars = InStream_IVARS(instream); + buf = InStream_Buf(instream, 5); + TEST_INT_EQ(runner, ivars->limit - buf, IO_STREAM_BUF_SIZE, + "Small request bumped up"); + + buf += IO_STREAM_BUF_SIZE - 10; // 10 bytes left in buffer. + InStream_Advance_Buf(instream, buf); + + buf = InStream_Buf(instream, 10); + TEST_INT_EQ(runner, ivars->limit - buf, 10, + "Exact request doesn't trigger refill"); + + buf = InStream_Buf(instream, 11); + TEST_INT_EQ(runner, ivars->limit - buf, IO_STREAM_BUF_SIZE, + "Requesting over limit triggers refill"); + + int64_t expected = InStream_Length(instream) - InStream_Tell(instream); + const char *buff = InStream_Buf(instream, 100000); + int64_t got = CHY_PTR_TO_I64(ivars->limit) - CHY_PTR_TO_I64(buff); + TEST_TRUE(runner, got == expected, + "Requests greater than file size get pared down"); + + DECREF(instream); + DECREF(outstream); + DECREF(file); +} + +void +TestIOChunks_Run_IMP(TestIOChunks *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 36); + srand((unsigned int)time((time_t*)NULL)); + test_Align(runner); + test_Read_Write_Bytes(runner); + test_Buf(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestIOChunks.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestIOChunks.cfh b/test/Lucy/Test/Store/TestIOChunks.cfh new file mode 100644 index 0000000..68c459a --- /dev/null +++ b/test/Lucy/Test/Store/TestIOChunks.cfh @@ -0,0 +1,31 @@ +/* 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. + */ + +parcel TestLucy; + +/** Tests reading and writing of composite types using InStream/OutStream. + */ +class Lucy::Test::Store::TestIOChunks + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestIOChunks* + new(); + + void + Run(TestIOChunks *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestIOPrimitives.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestIOPrimitives.c b/test/Lucy/Test/Store/TestIOPrimitives.c new file mode 100644 index 0000000..e7d32f2 --- /dev/null +++ b/test/Lucy/Test/Store/TestIOPrimitives.c @@ -0,0 +1,518 @@ +/* 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_TESTLUCY_TESTINSTREAM +#define C_LUCY_INSTREAM +#define C_LUCY_FILEWINDOW +#include <stdlib.h> +#include <time.h> + +#include "charmony.h" + +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Clownfish/TestHarness/TestUtils.h" +#include "Lucy/Test.h" +#include "Lucy/Test/TestUtils.h" +#include "Lucy/Test/Store/TestIOPrimitives.h" +#include "Lucy/Store/InStream.h" +#include "Lucy/Store/OutStream.h" +#include "Lucy/Store/RAMFile.h" +#include "Lucy/Store/RAMFileHandle.h" +#include "Lucy/Util/NumberUtils.h" + +TestIOPrimitives* +TestIOPrimitives_new() { + return (TestIOPrimitives*)Class_Make_Obj(TESTIOPRIMITIVES); +} + +static void +test_i8(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + int i; + + for (i = -128; i < 128; i++) { + OutStream_Write_I8(outstream, (int8_t)i); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = -128; i < 128; i++) { + if (InStream_Read_I8(instream) != i) { break; } + } + TEST_INT_EQ(runner, i, 128, "round trip i8 successful for %d out of 256", + i + 128); + + DECREF(instream); + DECREF(outstream); + DECREF(file); +} + +static void +test_u8(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + int i; + + for (i = 0; i < 256; i++) { + OutStream_Write_U8(outstream, (uint8_t)i); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 256; i++) { + if (InStream_Read_U8(instream) != i) { break; } + } + TEST_INT_EQ(runner, i, 256, + "round trip u8 successful for %d out of 256", i); + + DECREF(instream); + DECREF(outstream); + DECREF(file); +} + +static void +test_i32(TestBatchRunner *runner) { + int64_t *ints = TestUtils_random_i64s(NULL, 1000, INT32_MIN, INT32_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + ints[0] = INT32_MIN; + ints[1] = INT32_MIN + 1; + ints[2] = INT32_MAX; + ints[3] = INT32_MAX - 1; + + for (i = 0; i < 1000; i++) { + OutStream_Write_I32(outstream, (int32_t)ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + int32_t got = InStream_Read_I32(instream); + if (got != ints[i]) { + FAIL(runner, "i32 round trip failed: %ld, %ld", (long)got, + (long)ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "i32 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + +static void +test_u32(TestBatchRunner *runner) { + uint64_t *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT32_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + ints[0] = 0; + ints[1] = 1; + ints[2] = UINT32_MAX; + ints[3] = UINT32_MAX - 1; + + for (i = 0; i < 1000; i++) { + OutStream_Write_U32(outstream, (uint32_t)ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + uint32_t got = InStream_Read_U32(instream); + if (got != ints[i]) { + FAIL(runner, "u32 round trip failed: %lu, %lu", (unsigned long)got, + (unsigned long)ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "u32 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + +static void +test_i64(TestBatchRunner *runner) { + int64_t *ints = TestUtils_random_i64s(NULL, 1000, INT64_MIN, INT64_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + ints[0] = INT64_MIN; + ints[1] = INT64_MIN + 1; + ints[2] = INT64_MAX; + ints[3] = INT64_MAX - 1; + + for (i = 0; i < 1000; i++) { + OutStream_Write_I64(outstream, ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + int64_t got = InStream_Read_I64(instream); + if (got != ints[i]) { + FAIL(runner, "i64 round trip failed: %" PRId64 ", %" PRId64, + got, ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "i64 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + + +static void +test_u64(TestBatchRunner *runner) { + uint64_t *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT64_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + ints[0] = 0; + ints[1] = 1; + ints[2] = UINT64_MAX; + ints[3] = UINT64_MAX - 1; + + for (i = 0; i < 1000; i++) { + OutStream_Write_U64(outstream, ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + uint64_t got = InStream_Read_U64(instream); + if (got != ints[i]) { + FAIL(runner, "u64 round trip failed: %" PRIu64 ", %" PRIu64, + got, ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "u64 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + +static void +test_ci32(TestBatchRunner *runner) { + int64_t *ints = TestUtils_random_i64s(NULL, 1000, INT32_MIN, INT32_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + size_t i; + + // Test boundaries. + ints[0] = 0; + ints[1] = 1; + ints[2] = -1; + ints[3] = INT32_MAX; + ints[4] = INT32_MIN; + + for (i = 0; i < 1000; i++) { + OutStream_Write_CI32(outstream, (int32_t)ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + int32_t got = InStream_Read_CI32(instream); + if ((int64_t)got != ints[i]) { + FAIL(runner, "ci32 round trip failed: %" PRId64 ", %" PRId64, + (int64_t)got, ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "ci32 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + +static void +test_cu32(TestBatchRunner *runner) { + uint64_t *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT32_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + ints[0] = 0; + ints[1] = 1; + ints[2] = UINT32_MAX; + ints[3] = UINT32_MAX - 1; + + for (i = 0; i < 1000; i++) { + OutStream_Write_CU32(outstream, (uint32_t)ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + uint32_t got = InStream_Read_CU32(instream); + if (got != ints[i]) { + FAIL(runner, "cu32 round trip failed: %lu, %lu", (unsigned long)got, + (unsigned long)ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "cu32 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + +static void +test_ci64(TestBatchRunner *runner) { + int64_t *ints = TestUtils_random_i64s(NULL, 1000, INT64_MIN, INT64_MAX); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + ints[0] = 0; + ints[1] = 1; + ints[2] = -1; + ints[3] = INT64_MAX; + ints[4] = INT64_MIN; + + for (i = 0; i < 1000; i++) { + OutStream_Write_CI64(outstream, ints[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + int64_t got = InStream_Read_CI64(instream); + if (got != ints[i]) { + FAIL(runner, "ci64 round trip failed: %" PRId64 ", %" PRId64, + got, ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "ci64 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(ints); +} + +static void +test_cu64(TestBatchRunner *runner) { + uint64_t *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT64_MAX); + RAMFile *file = RAMFile_new(NULL, false); + RAMFile *raw_file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + OutStream *raw_outstream = OutStream_open((Obj*)raw_file); + InStream *instream; + InStream *raw_instream; + uint32_t i; + + // Test boundaries. + ints[0] = 0; + ints[1] = 1; + ints[2] = UINT64_MAX; + ints[3] = UINT64_MAX - 1; + + for (i = 0; i < 1000; i++) { + OutStream_Write_CU64(outstream, ints[i]); + OutStream_Write_CU64(raw_outstream, ints[i]); + } + OutStream_Close(outstream); + OutStream_Close(raw_outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + uint64_t got = InStream_Read_CU64(instream); + if (got != ints[i]) { + FAIL(runner, "cu64 round trip failed: %" PRIu64 ", %" PRIu64, + got, ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "cu64 round trip"); + } + + raw_instream = InStream_open((Obj*)raw_file); + for (i = 0; i < 1000; i++) { + char buffer[10]; + const char *buf = buffer; + int size = InStream_Read_Raw_C64(raw_instream, buffer); + uint64_t got = NumUtil_decode_cu64(&buf); + UNUSED_VAR(size); + if (got != ints[i]) { + FAIL(runner, "Read_Raw_C64 failed: %" PRIu64 ", %" PRIu64, + got, ints[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "Read_Raw_C64"); + } + + DECREF(raw_instream); + DECREF(instream); + DECREF(raw_outstream); + DECREF(outstream); + DECREF(raw_file); + DECREF(file); + FREEMEM(ints); +} + +static void +test_f32(TestBatchRunner *runner) { + double *f64s = TestUtils_random_f64s(NULL, 1000); + float *values = (float*)MALLOCATE(1000 * sizeof(float)); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Truncate. + for (i = 0; i < 1000; i++) { + values[i] = (float)f64s[i]; + } + + // Test boundaries. + values[0] = 0.0f; + values[1] = 1.0f; + + for (i = 0; i < 1000; i++) { + OutStream_Write_F32(outstream, values[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + float got = InStream_Read_F32(instream); + if (got != values[i]) { + FAIL(runner, "f32 round trip failed: %f, %f", got, values[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "f32 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(values); + FREEMEM(f64s); +} + +static void +test_f64(TestBatchRunner *runner) { + double *values = TestUtils_random_f64s(NULL, 1000); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + uint32_t i; + + // Test boundaries. + values[0] = 0.0; + values[1] = 1.0; + + for (i = 0; i < 1000; i++) { + OutStream_Write_F64(outstream, values[i]); + } + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + for (i = 0; i < 1000; i++) { + double got = InStream_Read_F64(instream); + if (got != values[i]) { + FAIL(runner, "f64 round trip failed: %f, %f", got, values[i]); + break; + } + } + if (i == 1000) { + PASS(runner, "f64 round trip"); + } + + DECREF(instream); + DECREF(outstream); + DECREF(file); + FREEMEM(values); +} + +void +TestIOPrimitives_Run_IMP(TestIOPrimitives *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 13); + srand((unsigned int)time((time_t*)NULL)); + test_i8(runner); + test_u8(runner); + test_i32(runner); + test_u32(runner); + test_i64(runner); + test_u64(runner); + test_ci32(runner); + test_cu32(runner); + test_ci64(runner); + test_cu64(runner); + test_f32(runner); + test_f64(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestIOPrimitives.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestIOPrimitives.cfh b/test/Lucy/Test/Store/TestIOPrimitives.cfh new file mode 100644 index 0000000..c75419a --- /dev/null +++ b/test/Lucy/Test/Store/TestIOPrimitives.cfh @@ -0,0 +1,31 @@ +/* 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. + */ + +parcel TestLucy; + +/** Tests reading and writing of primitive types using InStream/OutStream. + */ +class Lucy::Test::Store::TestIOPrimitives + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestIOPrimitives* + new(); + + void + Run(TestIOPrimitives *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestInStream.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestInStream.c b/test/Lucy/Test/Store/TestInStream.c new file mode 100644 index 0000000..c32f985 --- /dev/null +++ b/test/Lucy/Test/Store/TestInStream.c @@ -0,0 +1,225 @@ +/* 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_TESTLUCY_TESTINSTREAM +#define C_LUCY_INSTREAM +#define C_LUCY_FILEWINDOW + +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/TestUtils.h" +#include "Lucy/Test/Store/TestInStream.h" +#include "Lucy/Test/Store/MockFileHandle.h" +#include "Lucy/Store/FileWindow.h" +#include "Lucy/Store/InStream.h" +#include "Lucy/Store/OutStream.h" +#include "Lucy/Store/RAMFile.h" +#include "Lucy/Store/RAMFileHandle.h" + +TestInStream* +TestInStream_new() { + return (TestInStream*)Class_Make_Obj(TESTINSTREAM); +} + +static void +test_refill(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + InStream *instream; + char scratch[5]; + InStreamIVARS *ivars; + + for (int32_t i = 0; i < 1023; i++) { + OutStream_Write_U8(outstream, 'x'); + } + OutStream_Write_U8(outstream, 'y'); + OutStream_Write_U8(outstream, 'z'); + OutStream_Close(outstream); + + instream = InStream_open((Obj*)file); + ivars = InStream_IVARS(instream); + InStream_Refill(instream); + TEST_INT_EQ(runner, ivars->limit - ivars->buf, IO_STREAM_BUF_SIZE, + "Refill"); + TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0, + "Correct file pos after standing-start Refill()"); + DECREF(instream); + + instream = InStream_open((Obj*)file); + ivars = InStream_IVARS(instream); + InStream_Fill(instream, 30); + TEST_INT_EQ(runner, ivars->limit - ivars->buf, 30, "Fill()"); + TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0, + "Correct file pos after standing-start Fill()"); + DECREF(instream); + + instream = InStream_open((Obj*)file); + ivars = InStream_IVARS(instream); + InStream_Read_Bytes(instream, scratch, 5); + TEST_INT_EQ(runner, ivars->limit - ivars->buf, + IO_STREAM_BUF_SIZE - 5, "small read triggers refill"); + DECREF(instream); + + instream = InStream_open((Obj*)file); + ivars = InStream_IVARS(instream); + TEST_INT_EQ(runner, InStream_Read_U8(instream), 'x', "Read_U8"); + InStream_Seek(instream, 1023); + TEST_INT_EQ(runner, (long)FileWindow_IVARS(ivars->window)->offset, 0, + "no unnecessary refill on Seek"); + TEST_INT_EQ(runner, (long)InStream_Tell(instream), 1023, "Seek/Tell"); + TEST_INT_EQ(runner, InStream_Read_U8(instream), 'y', + "correct data after in-buffer Seek()"); + TEST_INT_EQ(runner, InStream_Read_U8(instream), 'z', "automatic Refill"); + TEST_TRUE(runner, (FileWindow_IVARS(ivars->window)->offset != 0), + "refilled"); + + DECREF(instream); + DECREF(outstream); + DECREF(file); +} + +static void +test_Clone_and_Reopen(TestBatchRunner *runner) { + String *foo = SSTR_WRAP_C("foo"); + String *bar = SSTR_WRAP_C("bar"); + RAMFile *file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)file); + RAMFileHandle *fh; + InStream *instream; + InStream *clone; + InStream *reopened; + + for (uint8_t i = 0; i < 26; i++) { + OutStream_Write_U8(outstream, 'a' + i); + } + OutStream_Close(outstream); + + fh = RAMFH_open(foo, FH_READ_ONLY, file); + instream = InStream_open((Obj*)fh); + InStream_Seek(instream, 1); + TEST_TRUE(runner, Str_Equals(InStream_Get_Filename(instream), (Obj*)foo), + "Get_Filename"); + + clone = InStream_Clone(instream); + TEST_TRUE(runner, Str_Equals(InStream_Get_Filename(clone), (Obj*)foo), + "Clones have same filename"); + TEST_TRUE(runner, InStream_Length(instream) == InStream_Length(clone), + "Clones have same length"); + TEST_TRUE(runner, InStream_Read_U8(instream) == InStream_Read_U8(clone), + "Clones start at same file position"); + + reopened = InStream_Reopen(instream, bar, 25, 1); + TEST_TRUE(runner, Str_Equals(InStream_Get_Filename(reopened), (Obj*)bar), + "Reopened InStreams take new filename"); + TEST_TRUE(runner, InStream_Read_U8(reopened) == 'z', + "Reopened stream starts at supplied offset"); + TEST_TRUE(runner, InStream_Length(reopened) == 1, + "Reopened stream uses supplied length"); + TEST_TRUE(runner, InStream_Tell(reopened) == 1, + "Tell() uses supplied offset for reopened stream"); + InStream_Seek(reopened, 0); + TEST_TRUE(runner, InStream_Read_U8(reopened) == 'z', + "Seek() uses supplied offset for reopened stream"); + + DECREF(reopened); + DECREF(clone); + DECREF(instream); + DECREF(outstream); + DECREF(fh); + DECREF(file); +} + +static void +test_Close(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + InStream *instream = InStream_open((Obj*)file); + InStream_Close(instream); + TEST_TRUE(runner, InStream_IVARS(instream)->file_handle == NULL, + "Close decrements FileHandle's refcount"); + DECREF(instream); + DECREF(file); +} + +static void +test_Seek_and_Tell(TestBatchRunner *runner) { + int64_t gb1 = INT64_C(0x40000000); + int64_t gb3 = gb1 * 3; + int64_t gb6 = gb1 * 6; + int64_t gb12 = gb1 * 12; + FileHandle *fh = (FileHandle*)MockFileHandle_new(NULL, gb12); + InStream *instream = InStream_open((Obj*)fh); + InStreamIVARS *const ivars = InStream_IVARS(instream); + + InStream_Buf(instream, 10000); + TEST_TRUE(runner, ivars->limit == ((char*)NULL) + 10000, + "InStream_Buf sets limit"); + + InStream_Seek(instream, gb6); + TEST_TRUE(runner, InStream_Tell(instream) == gb6, + "Tell after seek forwards outside buffer"); + TEST_TRUE(runner, ivars->buf == NULL, + "Seek forwards outside buffer sets buf to NULL"); + TEST_TRUE(runner, ivars->limit == NULL, + "Seek forwards outside buffer sets limit to NULL"); + TEST_TRUE(runner, FileWindow_IVARS(ivars->window)->offset == gb6, + "Seek forwards outside buffer tracks pos in window offset"); + + InStream_Buf(instream, (size_t)gb1); + TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1, + "InStream_Buf sets limit"); + + InStream_Seek(instream, gb6 + 10); + TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 10, + "Tell after seek forwards within buffer"); + TEST_TRUE(runner, ivars->buf == ((char*)NULL) + 10, + "Seek within buffer sets buf"); + TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1, + "Seek within buffer leaves limit alone"); + + InStream_Seek(instream, gb6 + 1); + TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 1, + "Tell after seek backwards within buffer"); + TEST_TRUE(runner, ivars->buf == ((char*)NULL) + 1, + "Seek backwards within buffer sets buf"); + TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1, + "Seek backwards within buffer leaves limit alone"); + + InStream_Seek(instream, gb3); + TEST_TRUE(runner, InStream_Tell(instream) == gb3, + "Tell after seek backwards outside buffer"); + TEST_TRUE(runner, ivars->buf == NULL, + "Seek backwards outside buffer sets buf to NULL"); + TEST_TRUE(runner, ivars->limit == NULL, + "Seek backwards outside buffer sets limit to NULL"); + TEST_TRUE(runner, FileWindow_IVARS(ivars->window)->offset == gb3, + "Seek backwards outside buffer tracks pos in window offset"); + + DECREF(instream); + DECREF(fh); +} + +void +TestInStream_Run_IMP(TestInStream *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 37); + test_refill(runner); + test_Clone_and_Reopen(runner); + test_Close(runner); + test_Seek_and_Tell(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestInStream.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestInStream.cfh b/test/Lucy/Test/Store/TestInStream.cfh new file mode 100644 index 0000000..b216fcd --- /dev/null +++ b/test/Lucy/Test/Store/TestInStream.cfh @@ -0,0 +1,33 @@ +/* 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. + */ + +parcel TestLucy; + +/** Tests for basic functionality of InStream using both memory-mapped and + * streamed sources. + */ + +class Lucy::Test::Store::TestInStream + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestInStream* + new(); + + void + Run(TestInStream *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestRAMDirHandle.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestRAMDirHandle.c b/test/Lucy/Test/Store/TestRAMDirHandle.c new file mode 100644 index 0000000..fc6292a --- /dev/null +++ b/test/Lucy/Test/Store/TestRAMDirHandle.c @@ -0,0 +1,91 @@ +/* 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/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/Store/TestRAMDirHandle.h" +#include "Lucy/Store/FileHandle.h" +#include "Lucy/Store/RAMFolder.h" +#include "Lucy/Store/RAMDirHandle.h" + +TestRAMDirHandle* +TestRAMDH_new() { + return (TestRAMDirHandle*)Class_Make_Obj(TESTRAMDIRHANDLE); +} + +static void +test_all(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + String *foo = SSTR_WRAP_C("foo"); + String *boffo = SSTR_WRAP_C("boffo"); + String *foo_boffo = SSTR_WRAP_C("foo/boffo"); + bool saw_foo = false; + bool saw_boffo = false; + bool foo_was_dir = false; + bool boffo_was_dir = false; + int count = 0; + + // Set up folder contents. + RAMFolder_MkDir(folder, foo); + FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + fh = RAMFolder_Open_FileHandle(folder, foo_boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + + RAMDirHandle *dh = RAMDH_new(folder); + while (RAMDH_Next(dh)) { + count++; + String *entry = RAMDH_Get_Entry(dh); + if (Str_Equals(entry, (Obj*)foo)) { + saw_foo = true; + foo_was_dir = RAMDH_Entry_Is_Dir(dh); + } + else if (Str_Equals(entry, (Obj*)boffo)) { + saw_boffo = true; + boffo_was_dir = RAMDH_Entry_Is_Dir(dh); + } + DECREF(entry); + } + TEST_INT_EQ(runner, 2, count, "correct number of entries"); + TEST_TRUE(runner, saw_foo, "Directory was iterated over"); + TEST_TRUE(runner, foo_was_dir, + "Dir correctly identified by Entry_Is_Dir"); + TEST_TRUE(runner, saw_boffo, "File was iterated over"); + TEST_FALSE(runner, boffo_was_dir, + "File correctly identified by Entry_Is_Dir"); + + uint32_t refcount = REFCOUNT_NN(folder); + RAMDH_Close(dh); + TEST_INT_EQ(runner, REFCOUNT_NN(folder), refcount - 1, + "Folder reference released by Close()"); + + DECREF(dh); + DECREF(folder); +} + +void +TestRAMDH_Run_IMP(TestRAMDirHandle *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 6); + test_all(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestRAMDirHandle.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestRAMDirHandle.cfh b/test/Lucy/Test/Store/TestRAMDirHandle.cfh new file mode 100644 index 0000000..4adfb31 --- /dev/null +++ b/test/Lucy/Test/Store/TestRAMDirHandle.cfh @@ -0,0 +1,29 @@ +/* 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. + */ + +parcel TestLucy; + +class Lucy::Test::Store::TestRAMDirHandle nickname TestRAMDH + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestRAMDirHandle* + new(); + + void + Run(TestRAMDirHandle *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestRAMFileHandle.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestRAMFileHandle.c b/test/Lucy/Test/Store/TestRAMFileHandle.c new file mode 100644 index 0000000..e208784 --- /dev/null +++ b/test/Lucy/Test/Store/TestRAMFileHandle.c @@ -0,0 +1,177 @@ +/* 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. + */ + +#include <string.h> + +#define C_TESTLUCY_TESTINSTREAM +#define C_LUCY_INSTREAM +#define C_LUCY_FILEWINDOW +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/Store/TestRAMFileHandle.h" +#include "Lucy/Store/RAMFileHandle.h" +#include "Lucy/Store/FileWindow.h" +#include "Lucy/Store/RAMFile.h" + +TestRAMFileHandle* +TestRAMFH_new() { + return (TestRAMFileHandle*)Class_Make_Obj(TESTRAMFILEHANDLE); +} + +static void +test_open(TestBatchRunner *runner) { + RAMFileHandle *fh; + + Err_set_error(NULL); + fh = RAMFH_open(NULL, FH_WRITE_ONLY, NULL); + TEST_TRUE(runner, fh == NULL, + "open() without a RAMFile or FH_CREATE returns NULL"); + TEST_TRUE(runner, Err_get_error() != NULL, + "open() without a RAMFile or FH_CREATE sets error"); +} + +static void +test_Read_Write(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY, file); + const char *foo = "foo"; + const char *bar = "bar"; + char buffer[12]; + char *buf = buffer; + + TEST_TRUE(runner, Str_Equals_Utf8(RAMFH_Get_Path(fh), "", 0), + "NULL arg as filepath yields empty string"); + + TEST_TRUE(runner, RAMFH_Write(fh, foo, 3), "Write returns success"); + TEST_TRUE(runner, RAMFH_Length(fh) == 3, "Length after one Write"); + TEST_TRUE(runner, RAMFH_Write(fh, bar, 3), "Write returns success"); + TEST_TRUE(runner, RAMFH_Length(fh) == 6, "Length after two Writes"); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFH_Read(fh, buf, 0, 2), + "Reading from a write-only handle returns false"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Reading from a write-only handle sets error"); + + // Reopen for reading. + DECREF(fh); + fh = RAMFH_open(NULL, FH_READ_ONLY, file); + TEST_TRUE(runner, RAMFile_Read_Only(file), + "FH_READ_ONLY propagates to RAMFile's read_only property"); + + TEST_TRUE(runner, RAMFH_Read(fh, buf, 0, 6), "Read returns success"); + TEST_TRUE(runner, strncmp(buf, "foobar", 6) == 0, "Read/Write"); + TEST_TRUE(runner, RAMFH_Read(fh, buf, 2, 3), "Read returns success"); + TEST_TRUE(runner, strncmp(buf, "oba", 3) == 0, "Read with offset"); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFH_Read(fh, buf, -1, 4), + "Read() with a negative offset returns false"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Read() with a negative offset sets error"); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFH_Read(fh, buf, 6, 1), + "Read() past EOF returns false"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Read() past EOF sets error"); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFH_Write(fh, foo, 3), + "Writing to a read-only handle returns false"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Writing to a read-only handle sets error"); + + DECREF(fh); + DECREF(file); +} + +static void +test_Grow_and_Get_File(TestBatchRunner *runner) { + RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY | FH_CREATE, NULL); + RAMFile *ram_file = RAMFH_Get_File(fh); + ByteBuf *contents = RAMFile_Get_Contents(ram_file); + + RAMFH_Grow(fh, 100); + TEST_TRUE(runner, BB_Get_Capacity(contents) >= 100, "Grow"); + + DECREF(fh); +} + +static void +test_Close(TestBatchRunner *runner) { + RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY | FH_CREATE, NULL); + TEST_TRUE(runner, RAMFH_Close(fh), "Close returns true"); + DECREF(fh); +} + +static void +test_Window(TestBatchRunner *runner) { + RAMFile *file = RAMFile_new(NULL, false); + RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY, file); + FileWindow *window = FileWindow_new(); + FileWindowIVARS *const window_ivars = FileWindow_IVARS(window); + + for (uint32_t i = 0; i < 1024; i++) { + RAMFH_Write(fh, "foo ", 4); + } + RAMFH_Close(fh); + + // Reopen for reading. + DECREF(fh); + fh = RAMFH_open(NULL, FH_READ_ONLY, file); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFH_Window(fh, window, -1, 4), + "Window() with a negative offset returns false"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Window() with a negative offset sets error"); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFH_Window(fh, window, 4000, 1000), + "Window() past EOF returns false"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Window() past EOF sets error"); + + TEST_TRUE(runner, RAMFH_Window(fh, window, 1021, 2), + "Window() returns true"); + TEST_TRUE(runner, strncmp(window_ivars->buf, "oo", 2) == 0, "Window()"); + + TEST_TRUE(runner, RAMFH_Release_Window(fh, window), + "Release_Window() returns true"); + TEST_TRUE(runner, window_ivars->buf == NULL, "Release_Window() resets buf"); + TEST_TRUE(runner, window_ivars->offset == 0, "Release_Window() resets offset"); + TEST_TRUE(runner, window_ivars->len == 0, "Release_Window() resets len"); + + DECREF(window); + DECREF(fh); + DECREF(file); +} + +void +TestRAMFH_Run_IMP(TestRAMFileHandle *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 32); + test_open(runner); + test_Read_Write(runner); + test_Grow_and_Get_File(runner); + test_Close(runner); + test_Window(runner); +} + +
