diffblue-cbmc/unit/util/irep.cpp

305 lines
8.4 KiB
C++

// Copyright 2018 Michael Tautschnig
/// \file Tests that irept memory consumption is fixed
#include <testing-utils/use_catch.h>
#include <util/irep.h>
SCENARIO("irept_memory", "[core][utils][irept]")
{
GIVEN("Always")
{
THEN("An irept is just a pointer")
{
REQUIRE(sizeof(irept) == sizeof(void *));
}
THEN("The storage size of an irept is fixed")
{
#ifdef SHARING
const std::size_t ref_count_size = sizeof(unsigned);
#else
const std::size_t ref_count_size = 0;
#endif
#ifndef USE_STRING
const std::size_t data_size = sizeof(dstringt);
REQUIRE(sizeof(dstringt) == sizeof(unsigned));
#else
const std::size_t data_size = sizeof(std::string);
REQUIRE(sizeof(std::string) == sizeof(void *));
#endif
const std::size_t sub_size = sizeof(std::vector<int>);
#ifndef _GLIBCXX_DEBUG
REQUIRE(sizeof(std::vector<int>) == 3 * sizeof(void *));
#endif
#ifndef NAMED_SUB_IS_FORWARD_LIST
const std::size_t named_size = sizeof(std::map<int, int>);
# ifndef _GLIBCXX_DEBUG
# ifdef __APPLE__
REQUIRE(sizeof(std::map<int, int>) == 3 * sizeof(void *));
# elif defined(_WIN32)
REQUIRE(sizeof(std::map<int, int>) == 2 * sizeof(void *));
# else
REQUIRE(sizeof(std::map<int, int>) == 6 * sizeof(void *));
# endif
# endif
#else
const std::size_t named_size = sizeof(std::forward_list<int>);
# ifndef _GLIBCXX_DEBUG
REQUIRE(sizeof(std::forward_list<int>) == sizeof(void *));
# endif
#endif
#if HASH_CODE
const std::size_t hash_code_size = sizeof(std::size_t);
#else
const std::size_t hash_code_size = 0;
#endif
REQUIRE(
sizeof(irept::dt) ==
ref_count_size + data_size + sub_size + named_size + hash_code_size);
}
THEN("get_nil_irep yields ID_nil")
{
REQUIRE(get_nil_irep().id() == ID_nil);
REQUIRE(get_nil_irep().is_nil());
REQUIRE(!get_nil_irep().is_not_nil());
}
}
GIVEN("Parts of an irep")
{
irept irep("some_id", {{"some_member", irept("other")}}, {irept("op")});
THEN("It is properly initialized")
{
REQUIRE(irep.id() == "some_id");
REQUIRE(irep.find("some_member") == irept("other"));
REQUIRE(irep.get_sub().size() == 1);
REQUIRE(irep.get_sub().front() == irept("op"));
}
}
GIVEN("An initialized irep")
{
irept irep("some_id");
irept irep_copy(irep);
irept irep_assign = irep;
irept irep_other("some_other_id");
THEN("Its id is some_id")
{
REQUIRE(irep.id() == "some_id");
REQUIRE(irep_copy.id() == "some_id");
REQUIRE(irep_assign.id() == "some_id");
REQUIRE(irep_other.id() == "some_other_id");
// TODO(tautschnig): id_string() should be deprecated in favour of
// id2string(...)
REQUIRE(irep.id_string().size() == 7);
}
THEN("Swapping works")
{
irep.swap(irep_other);
REQUIRE(irep.id() == "some_other_id");
REQUIRE(irep_copy.id() == "some_id");
REQUIRE(irep_assign.id() == "some_id");
REQUIRE(irep_other.id() == "some_id");
}
}
GIVEN("An irep")
{
irept irep;
THEN("Its id is empty")
{
REQUIRE(irep.is_not_nil());
REQUIRE(irep.id().empty());
}
THEN("Its id can be set")
{
irep.id("new_id");
REQUIRE(irep.id() == "new_id");
}
THEN("find of a non-existent element yields nil")
{
REQUIRE(irep.find("no-such-element").is_nil());
}
THEN("Adding/removing elements is possible")
{
REQUIRE(irep.get_sub().empty());
REQUIRE(irep.get_named_sub().empty());
irept &e = irep.add("a_new_element");
REQUIRE(e.id().empty());
e.id("some_id");
REQUIRE(irep.find("a_new_element").id() == "some_id");
irept irep2("second_irep");
irep.add("a_new_element", irep2);
REQUIRE(!irept::is_comment("a_new_element"));
REQUIRE(irep.find("a_new_element").id() == "second_irep");
std::size_t named_sub_size =
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
REQUIRE(named_sub_size == 1);
irep.add("#a_comment", irep2);
REQUIRE(irept::is_comment("#a_comment"));
REQUIRE(irep.find("#a_comment").id() == "second_irep");
named_sub_size =
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
REQUIRE(named_sub_size == 2);
REQUIRE(irept::number_of_non_comments(irep.get_named_sub()) == 1);
irept bak(irep);
irep.remove("no_such_id");
REQUIRE(bak == irep);
irep.remove("a_new_element");
REQUIRE(bak != irep);
REQUIRE(irep.find("a_new_element").is_nil());
irep.move_to_sub(bak);
REQUIRE(irep.get_sub().size() == 1);
irep.move_to_named_sub("another_entry", irep2);
REQUIRE(irep.get_sub().size() == 1);
named_sub_size =
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
REQUIRE(named_sub_size == 2);
irept irep3;
irep.move_to_named_sub("#a_comment", irep3);
REQUIRE(irep.find("#a_comment").id().empty());
REQUIRE(irep.get_sub().size() == 1);
named_sub_size =
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
REQUIRE(named_sub_size == 2);
irept irep4;
irep.move_to_named_sub("#another_comment", irep4);
named_sub_size =
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
REQUIRE(named_sub_size == 3);
irept irep5("moved_irep");
irep.add("a_moved_element", std::move(irep5));
REQUIRE(irep.find("a_moved_element").id() == "moved_irep");
named_sub_size =
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
REQUIRE(named_sub_size == 4);
}
THEN("Setting and getting works")
{
// TODO(tautschnig): get_string() should be deprecated in favour of
// id2string(...)
REQUIRE(irep.get_string("no_such_id").empty());
REQUIRE(irep.get("no_such_id").empty());
// TODO(tautschnig): it's not clear whether we need all of the below
// variants in the API
REQUIRE(!irep.get_bool("no_such_id"));
REQUIRE(irep.get_int("no_such_id") == 0);
REQUIRE(irep.get_size_t("no_such_id") == 0u);
REQUIRE(irep.get_long_long("no_such_id") == 0);
irep.set("some_id", "some string");
REQUIRE(irep.get("some_id") == "some string");
irept irep2("second_irep");
irep.set("a_new_element", irep2);
REQUIRE(irep.find("a_new_element").id() == "second_irep");
irep.set("numeric_id", 1);
REQUIRE(irep.get_bool("numeric_id"));
irep.set("numeric_id", 42);
REQUIRE(!irep.get_bool("numeric_id"));
REQUIRE(irep.get_int("numeric_id") == 42);
REQUIRE(irep.get_size_t("numeric_id") == 42u);
REQUIRE(irep.get_long_long("numeric_id") == 42);
irept irep3("move me");
irep.set("another_moved_element", std::move(irep3));
REQUIRE(irep.find("another_moved_element").id() == "move me");
irep.clear();
REQUIRE(irep.id().empty());
REQUIRE(irep.get_sub().empty());
REQUIRE(irep.get_named_sub().empty());
irep.make_nil();
REQUIRE(irep.id() == ID_nil);
REQUIRE(irep.get_sub().empty());
REQUIRE(irep.get_named_sub().empty());
}
THEN("Pretty printing works")
{
irept sub("sub_id");
irep.id("our_id");
irep.add("some_op", sub);
irep.add("#comment", sub);
irep.move_to_sub(sub);
std::string pretty = irep.pretty();
REQUIRE(
pretty ==
"our_id\n"
" * some_op: sub_id\n"
" * #comment: sub_id\n"
" 0: sub_id");
}
THEN("Hashing works")
{
irep.id("some_id");
irep.set("#a_comment", 42);
REQUIRE(irep.hash() != 0);
REQUIRE(irep.full_hash() != 0);
REQUIRE(irep.hash() != irep.full_hash());
}
}
GIVEN("Multiple ireps")
{
irept irep1, irep2;
THEN("Comparison works")
{
REQUIRE(irep1 == irep2);
REQUIRE(irep1.full_eq(irep2));
irep1.id("id1");
irep2.id("id2");
REQUIRE(irep1 != irep2);
const bool one_lt_two = irep1 < irep2;
const bool two_lt_one = irep2 < irep1;
REQUIRE(one_lt_two != two_lt_one);
REQUIRE(irep1.ordering(irep2) != irep2.ordering(irep1));
REQUIRE(irep1.compare(irep2) != 0);
irep2.id("id1");
REQUIRE(irep1 == irep2);
REQUIRE(irep1.full_eq(irep2));
irep2.set("#a_comment", 42);
REQUIRE(irep1 == irep2);
REQUIRE(!irep1.full_eq(irep2));
}
}
}