/* Tests basic behavior of the copy constructor and assignment operator. */ void BasicCopyTest() try { #if BasicCopyTestEnabled PrintBanner("Basic Copy Test"); /* For simplicity, we'll use one-dimensional KDTrees in this step. */ KDTree<1, size_t> one; for (size_t i = 0; i < 10; ++i) one[MakePoint(2 * i)] = i; // Load with 0, 2, 4, ..., 18 { /* Create a clone of one and confirm that everything copied correctly. * This uses the copy constructor. */ KDTree<1, size_t> clone = one; /* Basic checks. */ CheckCondition(one.size() == clone.size(), "Copy has the same number of elements as the original."); CheckCondition(one.empty() == clone.empty(), "Copy and original agree on emptiness."); CheckCondition(one.dimension() == clone.dimension(), "Copy and original agree on dimension."); /* Check that everything in one is there. */ for (size_t i = 0; i < 10; ++i) CheckCondition(clone.at(MakePoint(2 * i)) == i, "Element from original present in copy."); /* Check that nothing else is. */ for (size_t i = 0; i < 10; ++i) CheckCondition(!clone.contains(MakePoint(2 * i + 1)), "Other elements not present in copy."); } { /* Create a clone of one and confirm that everything copied correctly. * This uses the assignment operator. */ KDTree<1, size_t> clone; clone = one; /* Basic checks. */ CheckCondition(one.size() == clone.size(), "Copy has the same number of elements as the original."); CheckCondition(one.empty() == clone.empty(), "Copy and original agree on emptiness."); CheckCondition(one.dimension() == clone.dimension(), "Copy and original agree on dimension."); /* Check that everything in one is there. */ for (size_t i = 0; i < 10; ++i) CheckCondition(clone.at(MakePoint(2 * i)) == i, "Element from original present in copy."); /* Check that nothing else is. */ for (size_t i = 0; i < 10; ++i) CheckCondition(!clone.contains(MakePoint(2 * i + 1)), "Other elements not present in copy."); } EndTest(); #else TestDisabled("BasicCopyTest"); #endif } catch (const exception& e) { FailTest(e); }
/* This test still uses just the basic functionality, but it hammers it a bit more * by checking for strange edge cases like duplicated elements. */ void HarderKDTreeTest() try { #if HarderKDTreeTestEnabled PrintBanner("Harder KDTree Test"); /* Build the data set. */ const double dataPoints[][4] = { {0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0}, // Duplicate! {0, 1, 0, 1}, // Duplicate! {0, 1, 1, 0}, {1, 0, 1, 0}, }; KDTree<4, size_t> kd; for (size_t i = 0; i < 6; ++i) kd.insert(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4), i); /* Check basic properties. */ CheckCondition(kd.dimension() == 4, "Dimension is four."); CheckCondition(kd.size() == 4, "New KD tree has the right number of elements (no duplicates)."); CheckCondition(!kd.empty(), "New KD tree is nonempty."); /* Make sure that elements are still there, without checking values. */ for (size_t i = 0; i < 6; ++i) CheckCondition(kd.contains(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)), "New KD tree has original elems."); /* Check that the elements have the correct keys. Elements [2, 6) should have the * correct keys, but elements 0 and 1 will have the keys of elements 2 and 3 because * they were overwritten. */ for (size_t i = 2; i < 6; ++i) CheckCondition(kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i, "KD tree has correct labels."); for (size_t i = 0; i < 2; ++i) CheckCondition(kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i + 2, "Insert overwrites old labels."); EndTest(); #else TestDisabled("HarderKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* This test checks that the at() operators correctly throw * exceptions when elements are not found. This is not an * exhaustive test, and you should be sure to confirm on your * own that everything works correctly. */ void ThrowingKDTreeTest() try { #if MutatingKDTreeTestEnabled PrintBanner("Throwing KDTree Test"); { /* Create a non-const, empty KDTree and look things up. */ KDTree<3, size_t> empty; bool didThrow = false; try { empty.at(MakePoint(0, 0, 0)); } catch (const out_of_range&) { didThrow = true; } CheckCondition(didThrow, "Exception generated during non-const lookup."); } { /* Create a const, empty KDTree and look things up. */ KDTree<3, size_t> empty; bool didThrow = false; try { empty.at(MakePoint(0, 0, 0)); } catch (const out_of_range&) { didThrow = true; } CheckCondition(didThrow, "Exception generated during const lookup."); } EndTest(); #else TestDisabled("ThrowingKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* A basic test that creates a const KDTree and a non-const KDTree to ensure * the class still compiles properly. It also tests the the const version of * at is working correctly on the basic KDTree tests. */ void ConstKDTreeTest() try { #if ConstKDTreeTestEnabled PrintBanner("Const KDTree Test"); /* Build the data set. */ const double dataPoints[][4] = { {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1} }; KDTree<4, size_t> kd; for (size_t i = 0; i < 4; ++i) kd.insert(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4), i); /* Check that the code compiles for the non-const version. */ kd.dimension(); kd.size(); kd.empty(); kd.at(PointFromRange<4>(dataPoints[0], dataPoints[0] + 4)) = 100; const KDTree<4, size_t>& const_kd = kd; /* Check that the code compiles for the const version. */ const_kd.dimension(); const_kd.size(); const_kd.empty(); const_kd.at(PointFromRange<4>(dataPoints[0], dataPoints[0] + 4)); CheckCondition(true, "Const code compiles."); /* Run the basic KD Tree tests using a const KD Tree. */ CheckCondition(const_kd.contains(PointFromRange<4>(dataPoints[0], dataPoints[0] + 4)), "Const KD tree has element zero."); CheckCondition(const_kd.contains(PointFromRange<4>(dataPoints[1], dataPoints[1] + 4)), "Const KD tree has element one."); CheckCondition(const_kd.contains(PointFromRange<4>(dataPoints[2], dataPoints[2] + 4)), "Const KD tree has element two."); CheckCondition(const_kd.contains(PointFromRange<4>(dataPoints[3], dataPoints[3] + 4)), "Const KD tree has element three."); /* Make sure that the values of these points are correct. */ CheckCondition(const_kd.at(PointFromRange<4>(dataPoints[0], dataPoints[0] + 4)) == 100, "Const KD tree has correct values."); for (size_t i = 1; i < 4; ++i) CheckCondition(const_kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i, "Const KD tree has correct values."); EndTest(); #else TestDisabled("ConstKDTreeTest"); #endif } catch (const exception& e) { cout << "Note: KD tree lookup failed, but const code compiles." << endl; FailTest(e); }
/* A trickier test that involves looking up nonexistent elements and working with a * larger data set. */ void ModerateKDTreeTest() try { #if ModerateKDTreeTestEnabled PrintBanner("Moderate KDTree Test"); /* Build the data set. */ const double dataPoints[][4] = { {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1}, {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 0, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 1}, }; KDTree<4, size_t> kd; for (size_t i = 0; i < 16; ++i) kd.insert(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4), i); /* Check that basic properties hold. */ CheckCondition(kd.dimension() == 4, "Dimension is four."); CheckCondition(kd.size() == 16, "New KD tree has the right number of elements."); CheckCondition(!kd.empty(), "New KD tree is nonempty."); /* Make sure that the values of these points are correct. */ for (size_t i = 0; i < 16; ++i) CheckCondition(kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i, "New KD tree has correct values."); /* Try looking up some nonexistent elements and see what happens. */ CheckCondition(!kd.contains(MakePoint(1.0, 1.0, 1.0, 0.5)), "Nonexistent elements aren't in the tree."); CheckCondition(!kd.contains(MakePoint(0.0, 0.0, 0.0, -0.5)), "Nonexistent elements aren't in the tree."); EndTest(); #else TestDisabled("ModerateKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* Basic test: Can we build a small tree and look up the elements it contains? */ void BasicKDTreeTest() try { #if BasicKDTreeTestEnabled PrintBanner("Basic KDTree Test"); /* Construct the KDTree. */ KDTree<3, size_t> kd; CheckCondition(true, "KDTree construction completed."); /* Check basic properties of the KDTree. */ CheckCondition(kd.dimension() == 3, "Dimension is three."); CheckCondition(kd.size() == 0, "New KD tree has no elements."); CheckCondition(kd.empty(), "New KD tree is empty."); /* Add some elements. */ const double dataPoints[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }; for (size_t i = 0; i < 3; ++i) kd.insert(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3), i); /* Check basic properties again. */ CheckCondition(kd.size() == 3, "After adding three elements, KDTree has size 3."); CheckCondition(!kd.empty(), "After adding three elements, KDTree is not empty."); /* Make sure that the elements we built the tree out of are still there. */ CheckCondition(kd.contains(PointFromRange<3>(dataPoints[0], dataPoints[0] + 3)), "New KD tree has element zero."); CheckCondition(kd.contains(PointFromRange<3>(dataPoints[1], dataPoints[1] + 3)), "New KD tree has element one."); CheckCondition(kd.contains(PointFromRange<3>(dataPoints[2], dataPoints[2] + 3)), "New KD tree has element two."); /* Make sure that the values of these points are correct. */ for (size_t i = 0; i < 3; ++i) CheckCondition(kd.at(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)) == i, "New KD tree has correct values."); EndTest(); #else TestDisabled("BasicKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }