http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestRAMFileHandle.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestRAMFileHandle.cfh b/test/Lucy/Test/Store/TestRAMFileHandle.cfh new file mode 100644 index 0000000..d5418cf --- /dev/null +++ b/test/Lucy/Test/Store/TestRAMFileHandle.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::TestRAMFileHandle nickname TestRAMFH + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestRAMFileHandle* + new(); + + void + Run(TestRAMFileHandle *self, TestBatchRunner *runner); +} + +
http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestRAMFolder.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestRAMFolder.c b/test/Lucy/Test/Store/TestRAMFolder.c new file mode 100644 index 0000000..c148fe3 --- /dev/null +++ b/test/Lucy/Test/Store/TestRAMFolder.c @@ -0,0 +1,521 @@ +/* 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/TestRAMFolder.h" +#include "Lucy/Store/RAMFolder.h" +#include "Lucy/Store/DirHandle.h" +#include "Lucy/Store/RAMDirHandle.h" +#include "Lucy/Store/RAMFileHandle.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_boffo = NULL; +static String *foo_boffo = NULL; +static String *foo_foo = NULL; +static String *nope = NULL; +static String *nope_nyet = NULL; + +TestRAMFolder* +TestRAMFolder_new() { + return (TestRAMFolder*)Class_Make_Obj(TESTRAMFOLDER); +} + +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_Initialize_and_Check(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + RAMFolder_Initialize(folder); + PASS(runner, "Initialized concludes without incident"); + TEST_TRUE(runner, RAMFolder_Check(folder), "Check succeeds"); + DECREF(folder); +} + +static void +test_Local_Exists(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + RAMFolder_Local_MkDir(folder, foo); + + TEST_TRUE(runner, RAMFolder_Local_Exists(folder, boffo), + "Local_Exists() returns true for file"); + TEST_TRUE(runner, RAMFolder_Local_Exists(folder, foo), + "Local_Exists() returns true for dir"); + TEST_FALSE(runner, RAMFolder_Local_Exists(folder, bar), + "Local_Exists() returns false for non-existent entry"); + + DECREF(folder); +} + +static void +test_Local_Is_Directory(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + RAMFolder_Local_MkDir(folder, foo); + + TEST_FALSE(runner, RAMFolder_Local_Is_Directory(folder, boffo), + "Local_Is_Directory() returns false for file"); + TEST_TRUE(runner, RAMFolder_Local_Is_Directory(folder, foo), + "Local_Is_Directory() returns true for dir"); + TEST_FALSE(runner, RAMFolder_Local_Is_Directory(folder, bar), + "Local_Is_Directory() returns false for non-existent entry"); + + DECREF(folder); +} + +static void +test_Local_Find_Folder(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + RAMFolder *local; + FileHandle *fh; + + RAMFolder_MkDir(folder, foo); + RAMFolder_MkDir(folder, foo_bar); + 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); + + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, nope); + TEST_TRUE(runner, local == NULL, "Non-existent entry yields NULL"); + + String *empty = SSTR_BLANK(); + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, empty); + TEST_TRUE(runner, local == NULL, "Empty string yields NULL"); + + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, foo_bar); + TEST_TRUE(runner, local == NULL, "nested folder yields NULL"); + + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, foo_boffo); + TEST_TRUE(runner, local == NULL, "nested file yields NULL"); + + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, boffo); + TEST_TRUE(runner, local == NULL, "local file yields NULL"); + + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, bar); + TEST_TRUE(runner, local == NULL, "name of nested folder yields NULL"); + + local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, foo); + TEST_TRUE(runner, + local + && RAMFolder_is_a(local, RAMFOLDER) + && Str_Equals_Utf8(RAMFolder_Get_Path(local), "foo", 3), + "Find local directory"); + + DECREF(folder); +} + +static void +test_Local_MkDir(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + bool result; + + result = RAMFolder_Local_MkDir(folder, foo); + TEST_TRUE(runner, result, "Local_MkDir succeeds and returns true"); + + Err_set_error(NULL); + result = RAMFolder_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, RAMFolder_Exists(folder, foo), + "Existing dir untouched after failed Local_MkDir"); + + FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + Err_set_error(NULL); + result = RAMFolder_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, RAMFolder_Exists(folder, boffo) && + !RAMFolder_Local_Is_Directory(folder, boffo), + "Existing file untouched after failed Local_MkDir"); + + DECREF(folder); +} + +static void +test_Local_Open_Dir(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + DirHandle *dh = RAMFolder_Local_Open_Dir(folder); + TEST_TRUE(runner, dh && DH_is_a(dh, RAMDIRHANDLE), + "Local_Open_Dir returns a RAMDirHandle"); + DECREF(dh); + DECREF(folder); +} + +static void +test_Local_Open_FileHandle(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + FileHandle *fh; + + fh = RAMFolder_Local_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + TEST_TRUE(runner, fh && FH_is_a(fh, RAMFILEHANDLE), + "opened FileHandle"); + DECREF(fh); + + fh = RAMFolder_Local_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY); + TEST_TRUE(runner, fh && FH_is_a(fh, RAMFILEHANDLE), + "opened FileHandle for append"); + DECREF(fh); + + Err_set_error(NULL); + fh = RAMFolder_Local_Open_FileHandle(folder, boffo, + FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE); + TEST_TRUE(runner, fh == NULL, "FH_EXLUSIVE flag prevents open"); + TEST_TRUE(runner, Err_get_error() != NULL, + "failure due to FH_EXLUSIVE flag sets global error"); + + fh = RAMFolder_Local_Open_FileHandle(folder, boffo, FH_READ_ONLY); + TEST_TRUE(runner, fh && FH_is_a(fh, RAMFILEHANDLE), + "opened FileHandle for reading"); + DECREF(fh); + + Err_set_error(NULL); + fh = RAMFolder_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"); + + DECREF(folder); +} + +static void +test_Local_Delete(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + FileHandle *fh; + + fh = RAMFolder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + TEST_TRUE(runner, RAMFolder_Local_Delete(folder, boffo), + "Local_Delete on file succeeds"); + + RAMFolder_Local_MkDir(folder, foo); + fh = RAMFolder_Open_FileHandle(folder, foo_boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + + Err_set_error(NULL); + TEST_FALSE(runner, RAMFolder_Local_Delete(folder, foo), + "Local_Delete on non-empty dir fails"); + + RAMFolder_Delete(folder, foo_boffo); + TEST_TRUE(runner, RAMFolder_Local_Delete(folder, foo), + "Local_Delete on empty dir succeeds"); + + DECREF(folder); +} + +static void +test_Rename(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + FileHandle *fh; + bool result; + + RAMFolder_MkDir(folder, foo); + RAMFolder_MkDir(folder, foo_bar); + fh = RAMFolder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + + // Move files. + + result = RAMFolder_Rename(folder, boffo, banana); + TEST_TRUE(runner, result, "Rename succeeds and returns true"); + TEST_TRUE(runner, RAMFolder_Exists(folder, banana), + "File exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, boffo), + "File no longer exists at old path"); + + result = RAMFolder_Rename(folder, banana, foo_bar_boffo); + TEST_TRUE(runner, result, "Rename to file in nested dir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_boffo), + "File exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, banana), + "File no longer exists at old path"); + + result = RAMFolder_Rename(folder, foo_bar_boffo, boffo); + TEST_TRUE(runner, result, "Rename from file in nested dir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, boffo), + "File exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, foo_bar_boffo), + "File no longer exists at old path"); + + fh = RAMFolder_Open_FileHandle(folder, foo_boffo, + FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + result = RAMFolder_Rename(folder, boffo, foo_boffo); + TEST_TRUE(runner, result, "Clobber"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, boffo), + "File no longer exists at old path"); + + // Move Dirs. + + RAMFolder_MkDir(folder, baz); + result = RAMFolder_Rename(folder, baz, boffo); + TEST_TRUE(runner, result, "Rename dir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, boffo), + "Folder exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, baz), + "Folder no longer exists at old path"); + + result = RAMFolder_Rename(folder, boffo, foo_foo); + TEST_TRUE(runner, result, "Rename dir into nested subdir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_foo), + "Folder exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, boffo), + "Folder no longer exists at old path"); + + result = RAMFolder_Rename(folder, foo_foo, foo_bar_baz); + TEST_TRUE(runner, result, "Rename dir from nested subdir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_baz), + "Folder exists at new path"); + TEST_FALSE(runner, RAMFolder_Exists(folder, foo_foo), + "Folder no longer exists at old path"); + + // Test failed clobbers. + + Err_set_error(NULL); + result = RAMFolder_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, RAMFolder_Exists(folder, foo_boffo), + "File still exists at old path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar), + "Dir still exists after failed clobber"); + + Err_set_error(NULL); + result = RAMFolder_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, RAMFolder_Exists(folder, foo_bar), + "Dir still exists at old path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File still exists after failed clobber"); + + // Test that "renaming" succeeds where to and from are the same. + + result = RAMFolder_Rename(folder, foo_boffo, foo_boffo); + TEST_TRUE(runner, result, "Renaming file to itself succeeds"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File still exists"); + + result = RAMFolder_Rename(folder, foo_bar, foo_bar); + TEST_TRUE(runner, result, "Renaming dir to itself succeeds"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar), + "Dir still exists"); + + // Invalid filepaths. + + Err_set_error(NULL); + result = RAMFolder_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, RAMFolder_Exists(folder, foo_boffo), + "Entry still exists at old path"); + + Err_set_error(NULL); + result = RAMFolder_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"); + + DECREF(folder); +} + +static void +test_Hard_Link(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + FileHandle *fh; + bool result; + + RAMFolder_MkDir(folder, foo); + RAMFolder_MkDir(folder, foo_bar); + fh = RAMFolder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + + // Link files. + + result = RAMFolder_Hard_Link(folder, boffo, banana); + TEST_TRUE(runner, result, "Hard_Link succeeds and returns true"); + TEST_TRUE(runner, RAMFolder_Exists(folder, banana), + "File exists at new path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, boffo), + "File still exists at old path"); + RAMFolder_Delete(folder, boffo); + + result = RAMFolder_Hard_Link(folder, banana, foo_bar_boffo); + TEST_TRUE(runner, result, "Hard_Link to target within nested dir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_boffo), + "File exists at new path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, banana), + "File still exists at old path"); + RAMFolder_Delete(folder, banana); + + result = RAMFolder_Hard_Link(folder, foo_bar_boffo, foo_boffo); + TEST_TRUE(runner, result, "Hard_Link from file in nested dir"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File exists at new path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_boffo), + "File still exists at old path"); + RAMFolder_Delete(folder, foo_bar_boffo); + + // Invalid clobbers. + + fh = RAMFolder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY); + DECREF(fh); + result = RAMFolder_Hard_Link(folder, foo_boffo, boffo); + TEST_FALSE(runner, result, "Clobber of file fails"); + TEST_TRUE(runner, RAMFolder_Exists(folder, boffo), + "File still exists at new path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File still exists at old path"); + RAMFolder_Delete(folder, boffo); + + RAMFolder_MkDir(folder, baz); + result = RAMFolder_Hard_Link(folder, foo_boffo, baz); + TEST_FALSE(runner, result, "Clobber of dir fails"); + TEST_TRUE(runner, RAMFolder_Exists(folder, baz), + "Dir still exists at new path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File still exists at old path"); + RAMFolder_Delete(folder, baz); + + // Invalid Hard_Link of dir. + + RAMFolder_MkDir(folder, baz); + result = RAMFolder_Hard_Link(folder, baz, banana); + TEST_FALSE(runner, result, "Hard_Link dir fails"); + TEST_FALSE(runner, RAMFolder_Exists(folder, banana), + "Nothing at new path"); + TEST_TRUE(runner, RAMFolder_Exists(folder, baz), + "Folder still exists at old path"); + RAMFolder_Delete(folder, baz); + + // Test that linking to yourself fails. + + result = RAMFolder_Hard_Link(folder, foo_boffo, foo_boffo); + TEST_FALSE(runner, result, "Hard_Link file to itself fails"); + TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo), + "File still exists"); + + // Invalid filepaths. + + Err_set_error(NULL); + result = RAMFolder_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, RAMFolder_Exists(folder, foo_boffo), + "Entry still exists at old path"); + + Err_set_error(NULL); + result = RAMFolder_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"); + + DECREF(folder); +} + +static void +test_Close(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + RAMFolder_Close(folder); + PASS(runner, "Close() concludes without incident"); + RAMFolder_Close(folder); + RAMFolder_Close(folder); + PASS(runner, "Calling Close() multiple times is safe"); + DECREF(folder); +} + +void +TestRAMFolder_Run_IMP(TestRAMFolder *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 98); + S_init_strings(); + test_Initialize_and_Check(runner); + test_Local_Exists(runner); + test_Local_Is_Directory(runner); + test_Local_Find_Folder(runner); + test_Local_MkDir(runner); + test_Local_Open_Dir(runner); + test_Local_Open_FileHandle(runner); + test_Local_Delete(runner); + test_Rename(runner); + test_Hard_Link(runner); + test_Close(runner); + S_destroy_strings(); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Store/TestRAMFolder.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Store/TestRAMFolder.cfh b/test/Lucy/Test/Store/TestRAMFolder.cfh new file mode 100644 index 0000000..6fc392c --- /dev/null +++ b/test/Lucy/Test/Store/TestRAMFolder.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::TestRAMFolder + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestRAMFolder* + new(); + + void + Run(TestRAMFolder *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/TestSchema.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/TestSchema.c b/test/Lucy/Test/TestSchema.c new file mode 100644 index 0000000..1e1c3c1 --- /dev/null +++ b/test/Lucy/Test/TestSchema.c @@ -0,0 +1,112 @@ +/* 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_TESTSCHEMA +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/Plan/TestArchitecture.h" +#include "Lucy/Test/TestSchema.h" +#include "Lucy/Analysis/StandardTokenizer.h" +#include "Lucy/Plan/FullTextType.h" +#include "Lucy/Plan/Architecture.h" +#include "Lucy/Util/Freezer.h" + +TestSchema* +TestSchema_new(bool use_alt_arch) { + TestSchema *self = (TestSchema*)Class_Make_Obj(TESTSCHEMA); + return TestSchema_init(self, use_alt_arch); +} + +TestSchema* +TestSchema_init(TestSchema *self, bool use_alt_arch) { + StandardTokenizer *tokenizer = StandardTokenizer_new(); + FullTextType *type = FullTextType_new((Analyzer*)tokenizer); + + TestSchema_IVARS(self)->use_alt_arch = use_alt_arch; + + Schema_init((Schema*)self); + FullTextType_Set_Highlightable(type, true); + String *content = SSTR_WRAP_C("content"); + TestSchema_Spec_Field(self, content, (FieldType*)type); + DECREF(type); + DECREF(tokenizer); + + return self; +} + +Architecture* +TestSchema_Architecture_IMP(TestSchema *self) { + if (TestSchema_IVARS(self)->use_alt_arch) { + return Arch_new(); + } + else { + return (Architecture*)TestArch_new(); + } +} + +TestBatchSchema* +TestBatchSchema_new() { + return (TestBatchSchema*)Class_Make_Obj(TESTBATCHSCHEMA); +} + +static void +test_Equals(TestBatchRunner *runner) { + TestSchema *schema = TestSchema_new(false); + TestSchema *arch_differs = TestSchema_new(true); + TestSchema *spec_differs = TestSchema_new(false); + String *content = SSTR_WRAP_C("content"); + FullTextType *type = (FullTextType*)TestSchema_Fetch_Type(spec_differs, + content); + + TEST_TRUE(runner, TestSchema_Equals(schema, (Obj*)schema), "Equals"); + + FullTextType_Set_Boost(type, 2.0f); + TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)spec_differs), + "Equals spoiled by differing FieldType"); + + TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)arch_differs), + "Equals spoiled by differing Architecture"); + + DECREF(schema); + DECREF(arch_differs); + DECREF(spec_differs); +} + +static void +test_Dump_and_Load(TestBatchRunner *runner) { + TestSchema *schema = TestSchema_new(false); + Obj *dump = (Obj*)TestSchema_Dump(schema); + TestSchema *loaded = (TestSchema*)Freezer_load(dump); + + TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)loaded), + "Dump => Load round trip"); + + DECREF(schema); + DECREF(dump); + DECREF(loaded); +} + +void +TestBatchSchema_Run_IMP(TestBatchSchema *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 4); + test_Equals(runner); + test_Dump_and_Load(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/TestSchema.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/TestSchema.cfh b/test/Lucy/Test/TestSchema.cfh new file mode 100644 index 0000000..5cd897a --- /dev/null +++ b/test/Lucy/Test/TestSchema.cfh @@ -0,0 +1,48 @@ +/* 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; + +/** Schema for use by the test suite. + * + * Exposes problems faced by much larger indexes by using an TestArchitecture, + * which returns absurdly low values for [](cfish:.Index_Interval) and [](cfish:.Skip_Interval). + */ + +class Lucy::Test::TestSchema inherits Lucy::Plan::Schema { + bool use_alt_arch; + + inert incremented TestSchema* + new(bool use_alt_arch = false); + + inert TestSchema* + init(TestSchema *self, bool use_alt_arch = false); + + public incremented Architecture* + Architecture(TestSchema *self); +} + +class Lucy::Test::TestBatchSchema + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestBatchSchema* + new(); + + void + Run(TestBatchSchema *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/TestSimple.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/TestSimple.c b/test/Lucy/Test/TestSimple.c new file mode 100644 index 0000000..93fd747 --- /dev/null +++ b/test/Lucy/Test/TestSimple.c @@ -0,0 +1,112 @@ +/* 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_TESTSIMPLE +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Lucy/Test/TestSimple.h" +#include "Lucy/Simple.h" + +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Document/Doc.h" +#include "Lucy/Document/HitDoc.h" +#include "Lucy/Store/RAMFolder.h" + +TestSimple* +TestSimple_new() { + return (TestSimple*)Class_Make_Obj(TESTSIMPLE); +} + +static void +test_simple(TestBatchRunner *runner) { + RAMFolder *folder = RAMFolder_new(NULL); + String *language = SSTR_WRAP_C("en"); + Simple *lucy = Simple_new((Obj*)folder, language); + + String *food_field = SSTR_WRAP_C("food"); + + { + Doc *doc = Doc_new(NULL, 0); + String *value = SSTR_WRAP_C("creamed corn"); + Doc_Store(doc, food_field, (Obj*)value); + Simple_Add_Doc(lucy, doc); + DECREF(doc); + + String *query = SSTR_WRAP_C("creamed"); + uint32_t num_results = Simple_Search(lucy, query, 0, 10); + TEST_INT_EQ(runner, num_results, 1, "Search works right after add"); + } + + { + Doc *doc = Doc_new(NULL, 0); + String *value = SSTR_WRAP_C("creamed spinach"); + Doc_Store(doc, food_field, (Obj*)value); + Simple_Add_Doc(lucy, doc); + DECREF(doc); + + String *query = SSTR_WRAP_C("creamed"); + uint32_t num_results = Simple_Search(lucy, query, 0, 10); + TEST_INT_EQ(runner, num_results, 2, "Search returns total hits"); + } + + { + Doc *doc = Doc_new(NULL, 0); + String *value = SSTR_WRAP_C("creamed broccoli"); + Doc_Store(doc, food_field, (Obj*)value); + Simple_Add_Doc(lucy, doc); + DECREF(doc); + + DECREF(lucy); + lucy = Simple_new((Obj*)folder, language); + + String *query = SSTR_WRAP_C("cream"); + uint32_t num_results = Simple_Search(lucy, query, 0, 10); + TEST_INT_EQ(runner, num_results, 3, "commit upon destroy"); + + HitDoc *hit; + while ((hit = Simple_Next(lucy)) != NULL) { + String *food = (String*)HitDoc_Extract(hit, food_field); + TEST_TRUE(runner, Str_Starts_With_Utf8(food, "cream", 5), "Next"); + DECREF(food); + DECREF(hit); + } + } + + { + Doc *doc = Doc_new(NULL, 0); + String *band_field = SSTR_WRAP_C("band"); + String *value = SSTR_WRAP_C("Cream"); + Doc_Store(doc, band_field, (Obj*)value); + Simple_Add_Doc(lucy, doc); + DECREF(doc); + + String *query = SSTR_WRAP_C("cream"); + uint32_t num_results = Simple_Search(lucy, query, 0, 10); + TEST_INT_EQ(runner, num_results, 4, + "Search uses correct EasyAnalyzer"); + } + + DECREF(lucy); + DECREF(folder); +} + +void +TestSimple_Run_IMP(TestSimple *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 7); + test_simple(runner); +} + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/TestSimple.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/TestSimple.cfh b/test/Lucy/Test/TestSimple.cfh new file mode 100644 index 0000000..045fe8c --- /dev/null +++ b/test/Lucy/Test/TestSimple.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::TestSimple + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestSimple* + new(); + + void + Run(TestSimple *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/TestUtils.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/TestUtils.c b/test/Lucy/Test/TestUtils.c new file mode 100644 index 0000000..bddfa7b --- /dev/null +++ b/test/Lucy/Test/TestUtils.c @@ -0,0 +1,183 @@ +/* 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_TESTUTILS +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" +#include <string.h> + +#include "Lucy/Test/TestUtils.h" +#include "Lucy/Test.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Clownfish/TestHarness/TestUtils.h" +#include "Lucy/Analysis/Analyzer.h" +#include "Lucy/Analysis/Inversion.h" +#include "Lucy/Analysis/Token.h" +#include "Lucy/Search/TermQuery.h" +#include "Lucy/Search/PhraseQuery.h" +#include "Lucy/Search/LeafQuery.h" +#include "Lucy/Search/ANDQuery.h" +#include "Lucy/Search/NOTQuery.h" +#include "Lucy/Search/ORQuery.h" +#include "Lucy/Search/RangeQuery.h" +#include "Lucy/Store/FSFolder.h" +#include "Lucy/Store/InStream.h" +#include "Lucy/Store/OutStream.h" +#include "Lucy/Store/RAMFile.h" +#include "Lucy/Util/Freezer.h" + +Vector* +TestUtils_doc_set() { + Vector *docs = Vec_new(10); + + Vec_Push(docs, (Obj*)TestUtils_get_str("x")); + Vec_Push(docs, (Obj*)TestUtils_get_str("y")); + Vec_Push(docs, (Obj*)TestUtils_get_str("z")); + Vec_Push(docs, (Obj*)TestUtils_get_str("x a")); + Vec_Push(docs, (Obj*)TestUtils_get_str("x a b")); + Vec_Push(docs, (Obj*)TestUtils_get_str("x a b c")); + Vec_Push(docs, (Obj*)TestUtils_get_str("x foo a b c d")); + + return docs; +} + +PolyQuery* +TestUtils_make_poly_query(uint32_t boolop, ...) { + va_list args; + Query *child; + PolyQuery *retval; + Vector *children = Vec_new(0); + + va_start(args, boolop); + while (NULL != (child = va_arg(args, Query*))) { + Vec_Push(children, (Obj*)child); + } + va_end(args); + + retval = boolop == BOOLOP_OR + ? (PolyQuery*)ORQuery_new(children) + : (PolyQuery*)ANDQuery_new(children); + DECREF(children); + return retval; +} + +TermQuery* +TestUtils_make_term_query(const char *field, const char *term) { + String *field_str = SSTR_WRAP_C(field); + String *term_str = SSTR_WRAP_C(term); + return TermQuery_new((String*)field_str, (Obj*)term_str); +} + +PhraseQuery* +TestUtils_make_phrase_query(const char *field, ...) { + String *field_str = SSTR_WRAP_C(field); + va_list args; + Vector *terms = Vec_new(0); + PhraseQuery *query; + char *term_str; + + va_start(args, field); + while (NULL != (term_str = va_arg(args, char*))) { + Vec_Push(terms, (Obj*)TestUtils_get_str(term_str)); + } + va_end(args); + + query = PhraseQuery_new(field_str, terms); + DECREF(terms); + return query; +} + +LeafQuery* +TestUtils_make_leaf_query(const char *field, const char *term) { + String *term_str = SSTR_WRAP_C(term); + String *field_str = field ? SSTR_WRAP_C(field) : NULL; + return LeafQuery_new(field_str, term_str); +} + +NOTQuery* +TestUtils_make_not_query(Query* negated_query) { + NOTQuery *not_query = NOTQuery_new(negated_query); + DECREF(negated_query); + return not_query; +} + +RangeQuery* +TestUtils_make_range_query(const char *field, const char *lower_term, + const char *upper_term, bool include_lower, + bool include_upper) { + String *f = SSTR_WRAP_C(field); + String *lterm = SSTR_WRAP_C(lower_term); + String *uterm = SSTR_WRAP_C(upper_term); + return RangeQuery_new(f, (Obj*)lterm, (Obj*)uterm, include_lower, + include_upper); +} + +void +TestUtils_test_analyzer(TestBatchRunner *runner, Analyzer *analyzer, + String *source, Vector *expected, + const char *message) { + Token *seed = Token_new(Str_Get_Ptr8(source), Str_Get_Size(source), + 0, 0, 1.0f, 1); + Inversion *starter = Inversion_new(seed); + Inversion *transformed = Analyzer_Transform(analyzer, starter); + Vector *got = Vec_new(1); + Token *token; + while (NULL != (token = Inversion_Next(transformed))) { + String *token_text + = Str_new_from_utf8(Token_Get_Text(token), Token_Get_Len(token)); + Vec_Push(got, (Obj*)token_text); + } + TEST_TRUE(runner, Vec_Equals(expected, (Obj*)got), + "Transform(): %s", message); + DECREF(transformed); + + transformed = Analyzer_Transform_Text(analyzer, source); + Vec_Clear(got); + while (NULL != (token = Inversion_Next(transformed))) { + String *token_text + = Str_new_from_utf8(Token_Get_Text(token), Token_Get_Len(token)); + Vec_Push(got, (Obj*)token_text); + } + TEST_TRUE(runner, Vec_Equals(expected, (Obj*)got), + "Transform_Text(): %s", message); + DECREF(transformed); + + DECREF(got); + got = Analyzer_Split(analyzer, source); + TEST_TRUE(runner, Vec_Equals(expected, (Obj*)got), "Split(): %s", message); + + DECREF(got); + DECREF(starter); + DECREF(seed); +} + +FSFolder* +TestUtils_modules_folder() { + static const char *const paths[] = { "modules", "../modules" }; + + for (size_t i = 0; i < sizeof(paths) / sizeof(char*); i++) { + String *path = Str_newf(paths[i]); + FSFolder *modules_folder = FSFolder_new(path); + DECREF(path); + if (FSFolder_Check(modules_folder)) { + return modules_folder; + } + DECREF(modules_folder); + } + + return NULL; +} + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/TestUtils.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/TestUtils.cfh b/test/Lucy/Test/TestUtils.cfh new file mode 100644 index 0000000..0d3e15c --- /dev/null +++ b/test/Lucy/Test/TestUtils.cfh @@ -0,0 +1,87 @@ +/* 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; + +inert class Lucy::Test::TestUtils { + + /** Return a Vector of Strings, each representing the content for a + * document in the shared collection. + */ + inert incremented Vector* + doc_set(); + + /** Testing-only TermQuery factory. + */ + inert incremented TermQuery* + make_term_query(const char *field, const char *term); + + /** Testing-only PhraseQuery factory. + */ + inert incremented PhraseQuery* + make_phrase_query(const char *field, ...); + + /** Testing-only LeafQuery factory. + */ + inert incremented LeafQuery* + make_leaf_query(const char *field, const char *term); + + /** Return a new NOTQuery, decrementing the refcount for + * `negated_query`. + */ + inert incremented NOTQuery* + make_not_query(Query *negated_query); + + inert incremented RangeQuery* + make_range_query(const char *field, const char *lower_term = NULL, + const char *upper_term = NULL, + bool include_lower = true, + bool include_upper = true); + + /** Return either an ORQuery or an ANDQuery depending on the value of + * `boolop`. Takes a NULL-terminated list of Query objects. + * Decrements the refcounts of all supplied children, under the assumption + * that they were created solely for inclusion within the aggregate query. + */ + inert incremented PolyQuery* + make_poly_query(uint32_t boolop, ...); + + /** Verify an Analyzer's transform, transform_text, and split methods. + */ + inert void + test_analyzer(TestBatchRunner *runner, Analyzer *analyzer, String *source, + Vector *expected, const char *message); + + /** Return the "modules" folder. + * + * If the folder cannot be found, return NULL. + */ + inert incremented nullable FSFolder* + modules_folder(); +} + +__C__ + +#define LUCY_TESTUTILS_BOOLOP_OR 1 +#define LUCY_TESTUTILS_BOOLOP_AND 2 +#ifdef LUCY_USE_SHORT_NAMES + #define BOOLOP_OR LUCY_TESTUTILS_BOOLOP_OR + #define BOOLOP_AND LUCY_TESTUTILS_BOOLOP_AND +#endif + +__END_C__ + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestFreezer.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestFreezer.c b/test/Lucy/Test/Util/TestFreezer.c new file mode 100644 index 0000000..2cfba78 --- /dev/null +++ b/test/Lucy/Test/Util/TestFreezer.c @@ -0,0 +1,178 @@ +/* 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 TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Clownfish/Blob.h" +#include "Clownfish/Boolean.h" +#include "Clownfish/Num.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Clownfish/TestHarness/TestUtils.h" +#include "Lucy/Test/Util/TestFreezer.h" +#include "Lucy/Store/InStream.h" +#include "Lucy/Store/OutStream.h" +#include "Lucy/Store/RAMFile.h" +#include "Lucy/Util/Freezer.h" + +TestFreezer* +TestFreezer_new() { + return (TestFreezer*)Class_Make_Obj(TESTFREEZER); +} + +// Return the result of round-tripping the object through FREEZE and THAW. +static Obj* +S_freeze_thaw(Obj *object) { + if (object) { + RAMFile *ram_file = RAMFile_new(NULL, false); + OutStream *outstream = OutStream_open((Obj*)ram_file); + FREEZE(object, outstream); + OutStream_Close(outstream); + DECREF(outstream); + + InStream *instream = InStream_open((Obj*)ram_file); + Obj *retval = THAW(instream); + DECREF(instream); + DECREF(ram_file); + return retval; + } + else { + return NULL; + } +} + +// Return the result of round-tripping the object through dump() and load(). +static Obj* +S_dump_load(Obj *object) { + if (object) { + Obj *dump = Freezer_dump(object); + Obj *loaded = Freezer_load(dump); + DECREF(dump); + return loaded; + } + else { + return NULL; + } +} + +static void +test_blob(TestBatchRunner *runner) { + Blob *wanted = Blob_new("foobar", 6); + Blob *got = (Blob*)S_freeze_thaw((Obj*)wanted); + TEST_TRUE(runner, got && Blob_Equals(wanted, (Obj*)got), + "Serialization round trip"); + DECREF(wanted); + DECREF(got); +} + +static void +test_string(TestBatchRunner *runner) { + String *wanted = TestUtils_get_str("foo"); + String *got = (String*)S_freeze_thaw((Obj*)wanted); + TEST_TRUE(runner, got && Str_Equals(wanted, (Obj*)got), + "Round trip through FREEZE/THAW"); + DECREF(got); + DECREF(wanted); +} + +static void +test_hash(TestBatchRunner *runner) { + Hash *wanted = Hash_new(0); + + for (uint32_t i = 0; i < 10; i++) { + String *str = TestUtils_random_string(rand() % 1200); + Integer *num = Int_new(i); + Hash_Store(wanted, str, (Obj*)num); + DECREF(str); + } + + { + Hash *got = (Hash*)S_freeze_thaw((Obj*)wanted); + TEST_TRUE(runner, got && Hash_Equals(wanted, (Obj*)got), + "Round trip through serialization."); + DECREF(got); + } + + { + Obj *got = S_dump_load((Obj*)wanted); + TEST_TRUE(runner, Hash_Equals(wanted, got), + "Dump => Load round trip"); + DECREF(got); + } + + DECREF(wanted); +} + +static void +test_num(TestBatchRunner *runner) { + Float *f64 = Float_new(1.33); + Integer *i64 = Int_new(-1); + Float *f64_thaw = (Float*)S_freeze_thaw((Obj*)f64); + Integer *i64_thaw = (Integer*)S_freeze_thaw((Obj*)i64); + + TEST_TRUE(runner, Float_Equals(f64, (Obj*)f64_thaw), + "Float freeze/thaw"); + TEST_TRUE(runner, Int_Equals(i64, (Obj*)i64_thaw), + "Integer freeze/thaw"); + +#ifdef LUCY_VALGRIND + SKIP(runner, 1, "known leaks"); +#else + Boolean *true_thaw = (Boolean*)S_freeze_thaw((Obj*)CFISH_TRUE); + TEST_TRUE(runner, Bool_Equals(CFISH_TRUE, (Obj*)true_thaw), + "Boolean freeze/thaw"); +#endif + + DECREF(i64_thaw); + DECREF(f64_thaw); + DECREF(i64); + DECREF(f64); +} + +static void +test_varray(TestBatchRunner *runner) { + Vector *array = Vec_new(0); + Vec_Store(array, 1, (Obj*)Str_newf("foo")); + Vec_Store(array, 3, (Obj*)Str_newf("bar")); + + { + Obj *got = S_freeze_thaw((Obj*)array); + TEST_TRUE(runner, got && Vec_Equals(array, got), + "Round trip through FREEZE/THAW"); + DECREF(got); + } + + { + Obj *got = S_dump_load((Obj*)array); + TEST_TRUE(runner, got && Vec_Equals(array, got), + "Dump => Load round trip"); + DECREF(got); + } + + DECREF(array); +} + +void +TestFreezer_Run_IMP(TestFreezer *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 9); + test_blob(runner); + test_string(runner); + test_hash(runner); + test_num(runner); + test_varray(runner); +} + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestFreezer.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestFreezer.cfh b/test/Lucy/Test/Util/TestFreezer.cfh new file mode 100644 index 0000000..4e7cd90 --- /dev/null +++ b/test/Lucy/Test/Util/TestFreezer.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::Util::TestFreezer + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestFreezer* + new(); + + void + Run(TestFreezer *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestIndexFileNames.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestIndexFileNames.c b/test/Lucy/Test/Util/TestIndexFileNames.c new file mode 100644 index 0000000..a9d5708 --- /dev/null +++ b/test/Lucy/Test/Util/TestIndexFileNames.c @@ -0,0 +1,73 @@ +/* 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 "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/Util/TestIndexFileNames.h" +#include "Lucy/Util/IndexFileNames.h" + +TestIndexFileNames* +TestIxFileNames_new() { + return (TestIndexFileNames*)Class_Make_Obj(TESTINDEXFILENAMES); +} + +static void +S_test_local_part(TestBatchRunner *runner, const char *source, + const char *wanted, const char *test_name) { + String *source_str = SSTR_WRAP_C(source); + String *got = IxFileNames_local_part(source_str); + TEST_TRUE(runner, Str_Equals_Utf8(got, wanted, strlen(wanted)), test_name); + DECREF(got); +} + +static void +test_local_part(TestBatchRunner *runner) { + S_test_local_part(runner, "", "", "simple name"); + S_test_local_part(runner, "foo.txt", "foo.txt", "name with extension"); + S_test_local_part(runner, "/foo", "foo", "strip leading slash"); + S_test_local_part(runner, "/foo/", "foo", "strip trailing slash"); + S_test_local_part(runner, "foo/bar\\ ", "bar\\ ", + "Include garbage like backslashes and spaces"); + S_test_local_part(runner, "foo/bar/baz.txt", "baz.txt", + "find last component"); +} + +static void +S_test_extract_gen(TestBatchRunner *runner, const char *name, uint64_t gen, + const char *test_name) { + String *source = SSTR_WRAP_C(name); + TEST_TRUE(runner, IxFileNames_extract_gen(source) == gen, test_name); +} + +static void +test_extract_gen(TestBatchRunner *runner) { + S_test_extract_gen(runner, "seg_9", 9, "extract_gen"); + S_test_extract_gen(runner, "seg_9/", 9, "deal with trailing slash"); + S_test_extract_gen(runner, "seg_9_8", 9, "Only go past first underscore"); + S_test_extract_gen(runner, "snapshot_5.json", 5, "Deal with file suffix"); +} + +void +TestIxFileNames_Run_IMP(TestIndexFileNames *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 10); + test_local_part(runner); + test_extract_gen(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestIndexFileNames.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestIndexFileNames.cfh b/test/Lucy/Test/Util/TestIndexFileNames.cfh new file mode 100644 index 0000000..c5ec962 --- /dev/null +++ b/test/Lucy/Test/Util/TestIndexFileNames.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::Util::TestIndexFileNames nickname TestIxFileNames + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestIndexFileNames* + new(); + + void + Run(TestIndexFileNames *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestJson.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestJson.c b/test/Lucy/Test/Util/TestJson.c new file mode 100644 index 0000000..c67e292 --- /dev/null +++ b/test/Lucy/Test/Util/TestJson.c @@ -0,0 +1,365 @@ +/* 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 TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Clownfish/Num.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/Util/TestJson.h" +#include "Lucy/Util/Json.h" +#include "Lucy/Store/FileHandle.h" +#include "Lucy/Store/RAMFolder.h" + +TestJson* +TestJson_new() { + return (TestJson*)Class_Make_Obj(TESTJSON); +} + +// Create a test data structure including at least one each of Hash, Vector, +// and String. +static Obj* +S_make_dump() { + Hash *dump = Hash_new(0); + Hash_Store_Utf8(dump, "foo", 3, (Obj*)Str_newf("foo")); + Hash_Store_Utf8(dump, "stuff", 5, (Obj*)Vec_new(0)); + return (Obj*)dump; +} + +static void +test_tolerance(TestBatchRunner *runner) { + String *foo = Str_newf("foo"); + String *not_json = Json_to_json((Obj*)foo); + TEST_TRUE(runner, not_json == NULL, + "to_json returns NULL when fed invalid data type"); + TEST_TRUE(runner, Err_get_error() != NULL, + "to_json sets global error when fed invalid data type"); + DECREF(foo); +} + +// Test escapes for control characters ASCII 0-31. +static const char* control_escapes[] = { + "\\u0000", + "\\u0001", + "\\u0002", + "\\u0003", + "\\u0004", + "\\u0005", + "\\u0006", + "\\u0007", + "\\b", + "\\t", + "\\n", + "\\u000b", + "\\f", + "\\r", + "\\u000e", + "\\u000f", + "\\u0010", + "\\u0011", + "\\u0012", + "\\u0013", + "\\u0014", + "\\u0015", + "\\u0016", + "\\u0017", + "\\u0018", + "\\u0019", + "\\u001a", + "\\u001b", + "\\u001c", + "\\u001d", + "\\u001e", + "\\u001f", + NULL +}; + +// Test quote and backslash escape in isolation, then in context. +static const char* quote_escapes_source[] = { + "\"", + "\\", + "abc\"", + "abc\\", + "\"xyz", + "\\xyz", + "\\\"", + "\"\\", + NULL +}; +static const char* quote_escapes_json[] = { + "\\\"", + "\\\\", + "abc\\\"", + "abc\\\\", + "\\\"xyz", + "\\\\xyz", + "\\\\\\\"", + "\\\"\\\\", + NULL +}; + +static void +test_escapes(TestBatchRunner *runner) { + for (int i = 0; control_escapes[i] != NULL; i++) { + String *string = Str_new_from_char(i); + const char *escaped = control_escapes[i]; + String *json = Json_to_json((Obj*)string); + String *trimmed = Str_Trim(json); + String *decoded = (String*)Json_from_json(json); + + String *json_wanted = Str_newf("\"%s\"", escaped); + TEST_TRUE(runner, Str_Equals(json_wanted, (Obj*)trimmed), + "encode control escape: %s", escaped); + + TEST_TRUE(runner, decoded != NULL && Str_Equals(string, (Obj*)decoded), + "decode control escape: %s", escaped); + + DECREF(string); + DECREF(json); + DECREF(trimmed); + DECREF(decoded); + DECREF(json_wanted); + } + + for (int i = 0; quote_escapes_source[i] != NULL; i++) { + const char *source = quote_escapes_source[i]; + const char *escaped = quote_escapes_json[i]; + String *string = Str_new_from_utf8(source, strlen(source)); + String *json = Json_to_json((Obj*)string); + String *trimmed = Str_Trim(json); + String *decoded = (String*)Json_from_json(json); + + String *json_wanted = Str_newf("\"%s\"", escaped); + TEST_TRUE(runner, Str_Equals(json_wanted, (Obj*)trimmed), + "encode quote/backslash escapes: %s", source); + + TEST_TRUE(runner, decoded != NULL && Str_Equals(string, (Obj*)decoded), + "decode quote/backslash escapes: %s", source); + + DECREF(string); + DECREF(json); + DECREF(trimmed); + DECREF(decoded); + DECREF(json_wanted); + } +} + +static void +test_numbers(TestBatchRunner *runner) { + Integer *i64 = Int_new(33); + String *json = Json_to_json((Obj*)i64); + String *trimmed = Str_Trim(json); + TEST_TRUE(runner, Str_Equals_Utf8(trimmed, "33", 2), "Integer"); + DECREF(json); + DECREF(trimmed); + + Float *f64 = Float_new(33.33); + json = Json_to_json((Obj*)f64); + if (json) { + double value = Str_To_F64(json); + double diff = 33.33 - value; + if (diff < 0.0) { diff = 0.0 - diff; } + TEST_TRUE(runner, diff < 0.0001, "Float"); + DECREF(json); + } + else { + FAIL(runner, "Float conversion to json failed."); + } + + DECREF(i64); + DECREF(f64); +} + +static void +test_to_and_from(TestBatchRunner *runner) { + Obj *dump = S_make_dump(); + String *json = Json_to_json(dump); + Obj *got = Json_from_json(json); + TEST_TRUE(runner, got != NULL && Obj_Equals(dump, got), + "Round trip through to_json and from_json"); + DECREF(dump); + DECREF(json); + DECREF(got); +} + +static void +test_spew_and_slurp(TestBatchRunner *runner) { + Obj *dump = S_make_dump(); + Folder *folder = (Folder*)RAMFolder_new(NULL); + + String *foo = SSTR_WRAP_C("foo"); + bool result = Json_spew_json(dump, folder, foo); + TEST_TRUE(runner, result, "spew_json returns true on success"); + TEST_TRUE(runner, Folder_Exists(folder, foo), + "spew_json wrote file"); + + Obj *got = Json_slurp_json(folder, foo); + TEST_TRUE(runner, got && Obj_Equals(dump, got), + "Round trip through spew_json and slurp_json"); + DECREF(got); + + Err_set_error(NULL); + result = Json_spew_json(dump, folder, foo); + TEST_FALSE(runner, result, "Can't spew_json when file exists"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Failed spew_json sets global error"); + + Err_set_error(NULL); + String *bar = SSTR_WRAP_C("bar"); + got = Json_slurp_json(folder, bar); + TEST_TRUE(runner, got == NULL, + "slurp_json returns NULL when file doesn't exist"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Failed slurp_json sets global error"); + + String *boffo = SSTR_WRAP_C("boffo"); + + FileHandle *fh + = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY); + FH_Write(fh, "garbage", 7); + DECREF(fh); + + Err_set_error(NULL); + got = Json_slurp_json(folder, boffo); + TEST_TRUE(runner, got == NULL, + "slurp_json returns NULL when file doesn't contain valid JSON"); + TEST_TRUE(runner, Err_get_error() != NULL, + "Failed slurp_json sets global error"); + DECREF(got); + + DECREF(dump); + DECREF(folder); +} + +static void +S_verify_bad_syntax(TestBatchRunner *runner, const char *bad, const char *mess) { + String *has_errors = SSTR_WRAP_C(bad); + Err_set_error(NULL); + Obj *not_json = Json_from_json(has_errors); + TEST_TRUE(runner, not_json == NULL, "from_json returns NULL: %s", mess); + TEST_TRUE(runner, Err_get_error() != NULL, + "from_json sets global error: %s", mess); +} + +static void +test_syntax_errors(TestBatchRunner *runner) { + S_verify_bad_syntax(runner, "[", "unclosed left bracket"); + S_verify_bad_syntax(runner, "]", "unopened right bracket"); + S_verify_bad_syntax(runner, "{", "unclosed left curly"); + S_verify_bad_syntax(runner, "}", "unopened right curly"); + S_verify_bad_syntax(runner, "{}[]", "two top-level objects"); + S_verify_bad_syntax(runner, "[1 \"foo\"]", "missing comma in array"); + S_verify_bad_syntax(runner, "[1, \"foo\",]", "extra comma in array"); + S_verify_bad_syntax(runner, "{\"1\":1 \"2\":2}", "missing comma in hash"); + S_verify_bad_syntax(runner, "{\"1\":1,\"2\":2,}", "extra comma in hash"); + S_verify_bad_syntax(runner, "\"1", "unterminated string"); + // Tolerated by strtod(). + // S_verify_bad_syntax(runner, "1. ", "float missing fraction"); + // S_verify_bad_syntax(runner, "-.3 ", "Number missing integral part"); + S_verify_bad_syntax(runner, "-. ", "Number missing any digits"); + S_verify_bad_syntax(runner, "+1.0 ", "float with prepended plus"); + S_verify_bad_syntax(runner, "\"\\g\"", "invalid char escape"); + S_verify_bad_syntax(runner, "\"\\uAAAZ\"", "invalid \\u escape"); +} + +static void +S_round_trip_integer(TestBatchRunner *runner, int64_t value) { + Integer *num = Int_new(value); + Vector *array = Vec_new(1); + Vec_Store(array, 0, (Obj*)num); + String *json = Json_to_json((Obj*)array); + Obj *dump = Json_from_json(json); + TEST_TRUE(runner, Vec_Equals(array, dump), "Round trip integer %ld", + (long)value); + DECREF(dump); + DECREF(json); + DECREF(array); +} + +static void +test_integers(TestBatchRunner *runner) { + S_round_trip_integer(runner, 0); + S_round_trip_integer(runner, -1); + S_round_trip_integer(runner, -1000000); + S_round_trip_integer(runner, 1000000); +} + +static void +S_round_trip_float(TestBatchRunner *runner, double value, double max_diff) { + Float *num = Float_new(value); + Vector *array = Vec_new(1); + Vec_Store(array, 0, (Obj*)num); + String *json = Json_to_json((Obj*)array); + Obj *dump = CERTIFY(Json_from_json(json), VECTOR); + Float *got = (Float*)CERTIFY(Vec_Fetch((Vector*)dump, 0), FLOAT); + double diff = Float_Get_Value(num) - Float_Get_Value(got); + if (diff < 0) { diff = 0 - diff; } + TEST_TRUE(runner, diff <= max_diff, "Round trip float %f", value); + DECREF(dump); + DECREF(json); + DECREF(array); +} + +static void +test_floats(TestBatchRunner *runner) { + S_round_trip_float(runner, 0.0, 0.0); + S_round_trip_float(runner, 0.1, 0.00001); + S_round_trip_float(runner, -0.1, 0.00001); + S_round_trip_float(runner, 1000000.5, 1.0); + S_round_trip_float(runner, -1000000.5, 1.0); +} + +static void +test_max_depth(TestBatchRunner *runner) { + Hash *circular = Hash_new(0); + Hash_Store_Utf8(circular, "circular", 8, INCREF(circular)); + Err_set_error(NULL); + String *not_json = Json_to_json((Obj*)circular); + TEST_TRUE(runner, not_json == NULL, + "to_json returns NULL when fed recursing data"); + TEST_TRUE(runner, Err_get_error() != NULL, + "to_json sets global error when fed recursing data"); + DECREF(Hash_Delete_Utf8(circular, "circular", 8)); + DECREF(circular); +} + +void +TestJson_Run_IMP(TestJson *self, TestBatchRunner *runner) { + uint32_t num_tests = 105; +#ifndef LUCY_VALGRIND + num_tests += 28; // FIXME: syntax errors leak memory. +#endif + TestBatchRunner_Plan(runner, (TestBatch*)self, num_tests); + + // Test tolerance, then liberalize for testing. + test_tolerance(runner); + Json_set_tolerant(true); + + test_to_and_from(runner); + test_escapes(runner); + test_numbers(runner); + test_spew_and_slurp(runner); + test_integers(runner); + test_floats(runner); + test_max_depth(runner); + +#ifndef LUCY_VALGRIND + test_syntax_errors(runner); +#endif +} + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestJson.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestJson.cfh b/test/Lucy/Test/Util/TestJson.cfh new file mode 100644 index 0000000..ddba309 --- /dev/null +++ b/test/Lucy/Test/Util/TestJson.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::Util::TestJson + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestJson* + new(); + + void + Run(TestJson *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestMemoryPool.c ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestMemoryPool.c b/test/Lucy/Test/Util/TestMemoryPool.c new file mode 100644 index 0000000..7e960ab --- /dev/null +++ b/test/Lucy/Test/Util/TestMemoryPool.c @@ -0,0 +1,61 @@ +/* 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_TESTMEMORYPOOL +#define C_LUCY_MEMORYPOOL +#define TESTLUCY_USE_SHORT_NAMES +#include "Lucy/Util/ToolSet.h" + +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Lucy/Test.h" +#include "Lucy/Test/Util/TestMemoryPool.h" +#include "Lucy/Util/MemoryPool.h" + +TestMemoryPool* +TestMemPool_new() { + return (TestMemoryPool*)Class_Make_Obj(TESTMEMORYPOOL); +} + +void +TestMemPool_Run_IMP(TestMemoryPool *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 5); + + MemoryPool *mem_pool = MemPool_new(0); + MemoryPoolIVARS *const ivars = MemPool_IVARS(mem_pool); + char *ptr_a, *ptr_b; + + ptr_a = (char*)MemPool_Grab(mem_pool, 10); + size_t expected = sizeof(void*) == 8 ? 16 : 12; + TEST_UINT_EQ(runner, MemPool_Get_Consumed(mem_pool), expected, + "Round up allocation to word size"); + ptr_b = (char*)MemPool_Grab(mem_pool, 10); + TEST_UINT_EQ(runner, MemPool_Get_Consumed(mem_pool), expected * 2, + "Accumulate consumed."); + + ptr_a = ivars->buf; + MemPool_Resize(mem_pool, ptr_b, 6); + TEST_TRUE(runner, ivars->buf < ptr_a, "Resize adjusts next allocation"); + TEST_TRUE(runner, MemPool_Get_Consumed(mem_pool) < expected * 2, + "Resize() adjusts `consumed`"); + + MemPool_Release_All(mem_pool); + TEST_UINT_EQ(runner, MemPool_Get_Consumed(mem_pool), 0, + "Release_All() resets `consumed`"); + + DECREF(mem_pool); +} + + http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestMemoryPool.cfh ---------------------------------------------------------------------- diff --git a/test/Lucy/Test/Util/TestMemoryPool.cfh b/test/Lucy/Test/Util/TestMemoryPool.cfh new file mode 100644 index 0000000..f3d2433 --- /dev/null +++ b/test/Lucy/Test/Util/TestMemoryPool.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::Util::TestMemoryPool nickname TestMemPool + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestMemoryPool* + new(); + + void + Run(TestMemoryPool *self, TestBatchRunner *runner); +} + +
