diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 8464cedf9..658647ea6 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -106,6 +106,7 @@ add_executable(test-z3 sat_lookahead.cpp sat_user_scope.cpp scoped_timer.cpp + scoped_vector.cpp simple_parser.cpp simplex.cpp simplifier.cpp diff --git a/src/test/dlist.cpp b/src/test/dlist.cpp index 1bf3f17ef..14991c9ac 100644 --- a/src/test/dlist.cpp +++ b/src/test/dlist.cpp @@ -15,7 +15,6 @@ Author: --*/ -#include #include #include "util/dlist.h" @@ -30,28 +29,28 @@ public: // Test the prev() method void test_prev() { TestNode node(1); - assert(node.prev() == &node); + SASSERT(node.prev() == &node); std::cout << "test_prev passed." << std::endl; } // Test the next() method void test_next() { TestNode node(1); - assert(node.next() == &node); + SASSERT(node.next() == &node); std::cout << "test_next passed." << std::endl; } // Test the const prev() method void test_const_prev() { const TestNode node(1); - assert(node.prev() == &node); + SASSERT(node.prev() == &node); std::cout << "test_const_prev passed." << std::endl; } // Test the const next() method void test_const_next() { const TestNode node(1); - assert(node.next() == &node); + SASSERT(node.next() == &node); std::cout << "test_const_next passed." << std::endl; } @@ -59,9 +58,9 @@ void test_const_next() { void test_init() { TestNode node(1); node.init(&node); - assert(node.next() == &node); - assert(node.prev() == &node); - assert(node.invariant()); + SASSERT(node.next() == &node); + SASSERT(node.prev() == &node); + SASSERT(node.invariant()); std::cout << "test_init passed." << std::endl; } @@ -71,10 +70,10 @@ void test_pop() { TestNode node1(1); TestNode::push_to_front(list, &node1); TestNode* popped = TestNode::pop(list); - assert(popped == &node1); - assert(list == nullptr); - assert(popped->next() == popped); - assert(popped->prev() == popped); + SASSERT(popped == &node1); + SASSERT(list == nullptr); + SASSERT(popped->next() == popped); + SASSERT(popped->prev() == popped); std::cout << "test_pop passed." << std::endl; } @@ -83,12 +82,12 @@ void test_insert_after() { TestNode node1(1); TestNode node2(2); node1.insert_after(&node2); - assert(node1.next() == &node2); - assert(node2.prev() == &node1); - assert(node1.prev() == &node2); - assert(node2.next() == &node1); - assert(node1.invariant()); - assert(node2.invariant()); + SASSERT(node1.next() == &node2); + SASSERT(node2.prev() == &node1); + SASSERT(node1.prev() == &node2); + SASSERT(node2.next() == &node1); + SASSERT(node1.invariant()); + SASSERT(node2.invariant()); std::cout << "test_insert_after passed." << std::endl; } @@ -97,12 +96,12 @@ void test_insert_before() { TestNode node1(1); TestNode node2(2); node1.insert_before(&node2); - assert(node1.prev() == &node2); - assert(node2.next() == &node1); - assert(node1.next() == &node2); - assert(node2.prev() == &node1); - assert(node1.invariant()); - assert(node2.invariant()); + SASSERT(node1.prev() == &node2); + SASSERT(node2.next() == &node1); + SASSERT(node1.next() == &node2); + SASSERT(node2.prev() == &node1); + SASSERT(node1.invariant()); + SASSERT(node2.invariant()); std::cout << "test_insert_before passed." << std::endl; } @@ -114,11 +113,9 @@ void test_remove_from() { TestNode::push_to_front(list, &node1); TestNode::push_to_front(list, &node2); TestNode::remove_from(list, &node1); - assert(list == &node2); - assert(node2.next() == &node2); - assert(node2.prev() == &node2); - assert(node1.next() == &node1); - assert(node1.prev() == &node1); + SASSERT(list == &node2); + SASSERT(node2.next() == &node2); + SASSERT(node2.prev() == &node2); std::cout << "test_remove_from passed." << std::endl; } @@ -127,9 +124,9 @@ void test_push_to_front() { TestNode* list = nullptr; TestNode node1(1); TestNode::push_to_front(list, &node1); - assert(list == &node1); - assert(node1.next() == &node1); - assert(node1.prev() == &node1); + SASSERT(list == &node1); + SASSERT(node1.next() == &node1); + SASSERT(node1.prev() == &node1); std::cout << "test_push_to_front passed." << std::endl; } @@ -137,20 +134,20 @@ void test_push_to_front() { void test_detach() { TestNode node(1); TestNode::detach(&node); - assert(node.next() == &node); - assert(node.prev() == &node); - assert(node.invariant()); + SASSERT(node.next() == &node); + SASSERT(node.prev() == &node); + SASSERT(node.invariant()); std::cout << "test_detach passed." << std::endl; } // Test the invariant() method void test_invariant() { TestNode node1(1); - assert(node1.invariant()); + SASSERT(node1.invariant()); TestNode node2(2); node1.insert_after(&node2); - assert(node1.invariant()); - assert(node2.invariant()); + SASSERT(node1.invariant()); + SASSERT(node2.invariant()); std::cout << "test_invariant passed." << std::endl; } @@ -161,10 +158,10 @@ void test_contains() { TestNode node2(2); TestNode::push_to_front(list, &node1); TestNode::push_to_front(list, &node2); - assert(TestNode::contains(list, &node1)); - assert(TestNode::contains(list, &node2)); + SASSERT(TestNode::contains(list, &node1)); + SASSERT(TestNode::contains(list, &node2)); TestNode node3(3); - assert(!TestNode::contains(list, &node3)); + SASSERT(!TestNode::contains(list, &node3)); std::cout << "test_contains passed." << std::endl; } diff --git a/src/test/main.cpp b/src/test/main.cpp index 0d3679529..f028d6ceb 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -269,4 +269,5 @@ int main(int argc, char ** argv) { TST(euf_bv_plugin); TST(euf_arith_plugin); TST(sls_test); + TST(scoped_vector); } diff --git a/src/test/scoped_vector.cpp b/src/test/scoped_vector.cpp new file mode 100644 index 000000000..05d98fcf1 --- /dev/null +++ b/src/test/scoped_vector.cpp @@ -0,0 +1,99 @@ +#include +#include "util/scoped_vector.h" + +void test_push_back_and_access() { + scoped_vector sv; + sv.push_back(10); + + sv.push_back(20); + + SASSERT(sv.size() == 2); + SASSERT(sv[0] == 10); + SASSERT(sv[1] == 20); + + std::cout << "test_push_back_and_access passed." << std::endl; +} + +void test_scopes() { + scoped_vector sv; + sv.push_back(10); + sv.push_back(20); + + sv.push_scope(); + sv.push_back(30); + sv.push_back(40); + + SASSERT(sv.size() == 4); + SASSERT(sv[2] == 30); + SASSERT(sv[3] == 40); + + sv.pop_scope(1); + + std::cout << "test_scopes passed." << std::endl; + SASSERT(sv.size() == 2); + SASSERT(sv[0] == 10); + SASSERT(sv[1] == 20); + + std::cout << "test_scopes passed." << std::endl; +} + +void test_set() { + scoped_vector sv; + sv.push_back(10); + sv.push_back(20); + + sv.set(0, 30); + sv.set(1, 40); + + SASSERT(sv.size() == 2); + SASSERT(sv[0] == 30); + SASSERT(sv[1] == 40); + + sv.push_scope(); + sv.set(0, 50); + SASSERT(sv[0] == 50); + sv.pop_scope(1); + SASSERT(sv[0] == 30); + + std::cout << "test_set passed." << std::endl; +} + +void test_pop_back() { + scoped_vector sv; + sv.push_back(10); + sv.push_back(20); + + SASSERT(sv.size() == 2); + sv.pop_back(); + SASSERT(sv.size() == 1); + SASSERT(sv[0] == 10); + sv.pop_back(); + SASSERT(sv.size() == 0); + + std::cout << "test_pop_back passed." << std::endl; +} + +void test_erase_and_swap() { + scoped_vector sv; + sv.push_back(10); + sv.push_back(20); + sv.push_back(30); + + sv.erase_and_swap(1); + + SASSERT(sv.size() == 2); + SASSERT(sv[0] == 10); + SASSERT(sv[1] == 30); + + std::cout << "test_erase_and_swap passed." << std::endl; +} + +void tst_scoped_vector() { + test_push_back_and_access(); + test_scopes(); + test_set(); + test_pop_back(); + test_erase_and_swap(); + + std::cout << "All tests passed." << std::endl; +} diff --git a/src/util/scoped_vector.h b/src/util/scoped_vector.h index 2c6cfaa21..b5945fb44 100644 --- a/src/util/scoped_vector.h +++ b/src/util/scoped_vector.h @@ -176,8 +176,46 @@ private: } bool invariant() const { - return - m_size <= m_elems.size() && - m_elems_start <= m_elems.size(); + + + if (!(m_size <= m_elems.size() && m_elems_start <= m_elems.size())) + return false; + + // Check that source and destination trails have the same length. + if (m_src.size() != m_dst.size()) + return false; + // The size of m_src, m_dst, and m_src_lim should be consistent with the scope stack. + if (m_src_lim.size() != m_sizes.size() || m_src.size() != m_dst.size()) + return false; + + // m_elems_lim stores the past sizes of m_elems for each scope. Each element in m_elems_lim should be + // within bounds and in non-decreasing order. + for (unsigned i = 1; i < m_elems_lim.size(); ++i) { + if (m_elems_lim[i - 1] > m_elems_lim[i]) return false; + } + + + // m_sizes tracks the size of the vector at each scope level. + // Each element in m_sizes should be non-decreasing and within the size of m_elems. + for (unsigned i = 1; i < m_sizes.size(); ++i) { + if (m_sizes[i - 1] > m_sizes[i]) + return false; + } + + // The m_src and m_dst vectors should have the same size and should contain valid indices. + if (m_src.size() != m_dst.size()) return false; + for (unsigned i = 0; i < m_src.size(); ++i) { + if (m_src[i] >= m_index.size() || m_dst[i] >= m_elems.size()) return false; + } + + + // The size of m_src_lim should be less than or equal to the size of m_sizes and store valid indices. + if (m_src_lim.size() > m_sizes.size()) return false; + for (unsigned elem : m_src_lim) { + if (elem > m_src.size()) return false; + } + + return true; + } };