| /* 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_TESTVARRAY |
| #include "Lucy/Util/ToolSet.h" |
| |
| #include "Lucy/Test.h" |
| #include "Lucy/Test/TestUtils.h" |
| #include "Lucy/Test/Object/TestVArray.h" |
| |
| static CharBuf* |
| S_new_cb(const char *text) { |
| return CB_new_from_utf8(text, strlen(text)); |
| } |
| |
| static void |
| test_Equals(TestBatch *batch) { |
| VArray *array = VA_new(0); |
| VArray *other = VA_new(0); |
| ZombieCharBuf *stuff = ZCB_WRAP_STR("stuff", 5); |
| |
| TEST_TRUE(batch, VA_Equals(array, (Obj*)other), |
| "Empty arrays are equal"); |
| |
| VA_Push(array, INCREF(&EMPTY)); |
| TEST_FALSE(batch, VA_Equals(array, (Obj*)other), |
| "Add one elem and Equals returns false"); |
| |
| VA_Push(other, INCREF(&EMPTY)); |
| TEST_TRUE(batch, VA_Equals(array, (Obj*)other), |
| "Add a matching elem and Equals returns true"); |
| |
| VA_Store(array, 2, INCREF(&EMPTY)); |
| TEST_FALSE(batch, VA_Equals(array, (Obj*)other), |
| "Add elem after a NULL and Equals returns false"); |
| |
| VA_Store(other, 2, INCREF(&EMPTY)); |
| TEST_TRUE(batch, VA_Equals(array, (Obj*)other), |
| "Empty elems don't spoil Equals"); |
| |
| VA_Store(other, 2, INCREF(stuff)); |
| TEST_FALSE(batch, VA_Equals(array, (Obj*)other), |
| "Non-matching value spoils Equals"); |
| |
| VA_Excise(array, 1, 2); // removes empty elems |
| VA_Delete(other, 1); // leaves NULL in place of deleted elem |
| VA_Delete(other, 2); |
| TEST_FALSE(batch, VA_Equals(array, (Obj*)other), |
| "Empty trailing elements spoil Equals"); |
| |
| DECREF(array); |
| DECREF(other); |
| } |
| |
| static void |
| test_Store_Fetch(TestBatch *batch) { |
| VArray *array = VA_new(0); |
| CharBuf *elem; |
| |
| TEST_TRUE(batch, VA_Fetch(array, 2) == NULL, "Fetch beyond end"); |
| |
| VA_Store(array, 2, (Obj*)CB_newf("foo")); |
| elem = (CharBuf*)CERTIFY(VA_Fetch(array, 2), CHARBUF); |
| TEST_INT_EQ(batch, 3, VA_Get_Size(array), "Store updates size"); |
| TEST_TRUE(batch, CB_Equals_Str(elem, "foo", 3), "Store"); |
| |
| INCREF(elem); |
| TEST_INT_EQ(batch, 2, CB_Get_RefCount(elem), |
| "start with refcount of 2"); |
| VA_Store(array, 2, (Obj*)CB_newf("bar")); |
| TEST_INT_EQ(batch, 1, CB_Get_RefCount(elem), |
| "Displacing elem via Store updates refcount"); |
| DECREF(elem); |
| elem = (CharBuf*)CERTIFY(VA_Fetch(array, 2), CHARBUF); |
| TEST_TRUE(batch, CB_Equals_Str(elem, "bar", 3), "Store displacement"); |
| |
| DECREF(array); |
| } |
| |
| static void |
| test_Push_Pop_Shift_Unshift(TestBatch *batch) { |
| VArray *array = VA_new(0); |
| CharBuf *elem; |
| |
| TEST_INT_EQ(batch, VA_Get_Size(array), 0, "size starts at 0"); |
| VA_Push(array, (Obj*)CB_newf("a")); |
| VA_Push(array, (Obj*)CB_newf("b")); |
| VA_Push(array, (Obj*)CB_newf("c")); |
| |
| TEST_INT_EQ(batch, VA_Get_Size(array), 3, "size after Push"); |
| TEST_TRUE(batch, NULL != CERTIFY(VA_Fetch(array, 2), CHARBUF), "Push"); |
| |
| elem = (CharBuf*)CERTIFY(VA_Shift(array), CHARBUF); |
| TEST_TRUE(batch, CB_Equals_Str(elem, "a", 1), "Shift"); |
| TEST_INT_EQ(batch, VA_Get_Size(array), 2, "size after Shift"); |
| DECREF(elem); |
| |
| elem = (CharBuf*)CERTIFY(VA_Pop(array), CHARBUF); |
| TEST_TRUE(batch, CB_Equals_Str(elem, "c", 1), "Pop"); |
| TEST_INT_EQ(batch, VA_Get_Size(array), 1, "size after Pop"); |
| DECREF(elem); |
| |
| VA_Unshift(array, (Obj*)CB_newf("foo")); |
| elem = (CharBuf*)CERTIFY(VA_Fetch(array, 0), CHARBUF); |
| TEST_TRUE(batch, CB_Equals_Str(elem, "foo", 3), "Unshift"); |
| TEST_INT_EQ(batch, VA_Get_Size(array), 2, "size after Shift"); |
| |
| DECREF(array); |
| } |
| |
| static void |
| test_Delete(TestBatch *batch) { |
| VArray *wanted = VA_new(5); |
| VArray *got = VA_new(5); |
| uint32_t i; |
| |
| for (i = 0; i < 5; i++) { VA_Push(got, (Obj*)CB_newf("%u32", i)); } |
| VA_Store(wanted, 0, (Obj*)CB_newf("0", i)); |
| VA_Store(wanted, 1, (Obj*)CB_newf("1", i)); |
| VA_Store(wanted, 4, (Obj*)CB_newf("4", i)); |
| DECREF(VA_Delete(got, 2)); |
| DECREF(VA_Delete(got, 3)); |
| TEST_TRUE(batch, VA_Equals(wanted, (Obj*)got), "Delete"); |
| |
| DECREF(wanted); |
| DECREF(got); |
| } |
| |
| static void |
| test_Resize(TestBatch *batch) { |
| VArray *array = VA_new(3); |
| uint32_t i; |
| |
| for (i = 0; i < 2; i++) { VA_Push(array, (Obj*)CB_newf("%u32", i)); } |
| TEST_INT_EQ(batch, VA_Get_Capacity(array), 3, "Start with capacity 3"); |
| |
| VA_Resize(array, 4); |
| TEST_INT_EQ(batch, VA_Get_Size(array), 4, "Resize up"); |
| TEST_INT_EQ(batch, VA_Get_Capacity(array), 4, |
| "Resize changes capacity"); |
| |
| VA_Resize(array, 2); |
| TEST_INT_EQ(batch, VA_Get_Size(array), 2, "Resize down"); |
| TEST_TRUE(batch, VA_Fetch(array, 2) == NULL, "Resize down zaps elem"); |
| |
| DECREF(array); |
| } |
| |
| static void |
| test_Excise(TestBatch *batch) { |
| VArray *wanted = VA_new(5); |
| VArray *got = VA_new(5); |
| |
| for (uint32_t i = 0; i < 5; i++) { |
| VA_Push(wanted, (Obj*)CB_newf("%u32", i)); |
| VA_Push(got, (Obj*)CB_newf("%u32", i)); |
| } |
| |
| VA_Excise(got, 7, 1); |
| TEST_TRUE(batch, VA_Equals(wanted, (Obj*)got), |
| "Excise outside of range is no-op"); |
| |
| VA_Excise(got, 2, 2); |
| DECREF(VA_Delete(wanted, 2)); |
| DECREF(VA_Delete(wanted, 3)); |
| VA_Store(wanted, 2, VA_Delete(wanted, 4)); |
| VA_Resize(wanted, 3); |
| TEST_TRUE(batch, VA_Equals(wanted, (Obj*)got), |
| "Excise multiple elems"); |
| |
| VA_Excise(got, 2, 2); |
| VA_Resize(wanted, 2); |
| TEST_TRUE(batch, VA_Equals(wanted, (Obj*)got), |
| "Splicing too many elems truncates"); |
| |
| VA_Excise(got, 0, 1); |
| VA_Store(wanted, 0, VA_Delete(wanted, 1)); |
| VA_Resize(wanted, 1); |
| TEST_TRUE(batch, VA_Equals(wanted, (Obj*)got), |
| "Excise first elem"); |
| |
| DECREF(got); |
| DECREF(wanted); |
| } |
| |
| static void |
| test_Push_VArray(TestBatch *batch) { |
| VArray *wanted = VA_new(0); |
| VArray *got = VA_new(0); |
| VArray *scratch = VA_new(0); |
| uint32_t i; |
| |
| for (i = 0; i < 4; i++) { VA_Push(wanted, (Obj*)CB_newf("%u32", i)); } |
| for (i = 0; i < 2; i++) { VA_Push(got, (Obj*)CB_newf("%u32", i)); } |
| for (i = 2; i < 4; i++) { VA_Push(scratch, (Obj*)CB_newf("%u32", i)); } |
| |
| VA_Push_VArray(got, scratch); |
| TEST_TRUE(batch, VA_Equals(wanted, (Obj*)got), "Push_VArray"); |
| |
| DECREF(wanted); |
| DECREF(got); |
| DECREF(scratch); |
| } |
| |
| static void |
| test_Clone_and_Shallow_Copy(TestBatch *batch) { |
| VArray *array = VA_new(0); |
| VArray *twin; |
| uint32_t i; |
| |
| for (i = 0; i < 10; i++) { |
| VA_Push(array, (Obj*)CB_newf("%u32", i)); |
| } |
| twin = VA_Shallow_Copy(array); |
| TEST_TRUE(batch, VA_Equals(array, (Obj*)twin), "Shallow_Copy"); |
| TEST_TRUE(batch, VA_Fetch(array, 1) == VA_Fetch(twin, 1), |
| "Shallow_Copy doesn't clone elements"); |
| DECREF(twin); |
| |
| twin = VA_Clone(array); |
| TEST_TRUE(batch, VA_Equals(array, (Obj*)twin), "Clone"); |
| TEST_TRUE(batch, VA_Fetch(array, 1) != VA_Fetch(twin, 1), |
| "Clone performs deep clone"); |
| |
| DECREF(array); |
| DECREF(twin); |
| } |
| |
| static void |
| test_Dump_and_Load(TestBatch *batch) { |
| VArray *array = VA_new(0); |
| Obj *dump; |
| VArray *loaded; |
| |
| VA_Push(array, (Obj*)S_new_cb("foo")); |
| dump = (Obj*)VA_Dump(array); |
| loaded = (VArray*)Obj_Load(dump, dump); |
| TEST_TRUE(batch, VA_Equals(array, (Obj*)loaded), |
| "Dump => Load round trip"); |
| |
| DECREF(array); |
| DECREF(dump); |
| DECREF(loaded); |
| } |
| |
| static void |
| test_serialization(TestBatch *batch) { |
| VArray *array = VA_new(0); |
| VArray *dupe; |
| VA_Store(array, 1, (Obj*)CB_newf("foo")); |
| VA_Store(array, 3, (Obj*)CB_newf("bar")); |
| dupe = (VArray*)TestUtils_freeze_thaw((Obj*)array); |
| TEST_TRUE(batch, dupe && VA_Equals(array, (Obj*)dupe), |
| "Round trip through FREEZE/THAW"); |
| DECREF(dupe); |
| DECREF(array); |
| } |
| |
| void |
| TestVArray_run_tests() { |
| TestBatch *batch = TestBatch_new(39); |
| |
| TestBatch_Plan(batch); |
| |
| test_Equals(batch); |
| test_Store_Fetch(batch); |
| test_Push_Pop_Shift_Unshift(batch); |
| test_Delete(batch); |
| test_Resize(batch); |
| test_Excise(batch); |
| test_Push_VArray(batch); |
| test_Clone_and_Shallow_Copy(batch); |
| test_Dump_and_Load(batch); |
| test_serialization(batch); |
| |
| DECREF(batch); |
| } |
| |
| |