Skip to content

Commit f7ba800

Browse files
committed
Add libcprover unit test
1 parent 683b7f2 commit f7ba800

File tree

8 files changed

+131
-0
lines changed

8 files changed

+131
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ cprover_default_properties(
240240
json
241241
json-symtab-language
242242
langapi
243+
lib-unit
243244
linking
244245
pointer-analysis
245246
solvers

unit/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ endif()
1212
file(GLOB_RECURSE sources "*.cpp" "*.h")
1313

1414
file(GLOB_RECURSE testing_utils "testing-utils/*.cpp" "testing-utils/*.h")
15+
file(GLOB_RECURSE libcprover_sources "libcprover-cpp/*.cpp" "libcprover-cpp/*.h")
1516

1617
if(NOT WITH_MEMORY_ANALYZER)
1718
file(GLOB_RECURSE memory_analyzer_sources "memory-analyzer/*.cpp")
@@ -62,9 +63,13 @@ list(REMOVE_ITEM sources
6263

6364
# Intended to fail to compile
6465
${CMAKE_CURRENT_SOURCE_DIR}/util/expr_cast/expr_undefined_casts.cpp
66+
67+
# Built into separate binary
68+
${libcprover_sources}
6569
)
6670

6771
add_subdirectory(testing-utils)
72+
add_subdirectory(libcprover-cpp)
6873

6974
add_executable(unit ${sources})
7075
target_include_directories(unit

unit/count_tests.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ def tests_in_file(file_path):
5656
def count_tests_in_directory(directory_path, exclude_files):
5757
test_count = 0
5858
for root, sub_directories, files in os.walk("."):
59+
# Excluded from count as built into separate binary.
60+
if root.endswith("libcprover-cpp"):
61+
continue
5962
for file_name in files:
6063
if any(file_name == excluded_file for excluded_file in exclude_files):
6164
continue

unit/libcprover-cpp/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
file(GLOB_RECURSE sources "*.cpp" "*.h")
3+
4+
add_executable(lib-unit ${sources})
5+
target_include_directories(lib-unit
6+
PUBLIC
7+
${CBMC_SOURCE_DIR}/libcprover-cpp
8+
)
9+
target_link_libraries(lib-unit
10+
cprover-api-cpp
11+
)
12+
13+
add_test(
14+
NAME lib-unit
15+
COMMAND $<TARGET_FILE:lib-unit>
16+
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
17+
)
18+
19+
set_tests_properties(lib-unit PROPERTIES LABELS "CORE;CBMC")

unit/libcprover-cpp/api.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Author: Diffblue Ltd.
2+
3+
// Note that this test should not include any headers which are internal to
4+
// cbmc. API headers (and STL/catch) should be included only. This is in order
5+
// to confirm that the API can be used without reference to cmbc internals.
6+
7+
#include <libcprover-cpp/api.h>
8+
9+
#include <algorithm>
10+
#include <sstream>
11+
#include <string>
12+
#include <vector>
13+
14+
#include "../catch/catch.hpp"
15+
16+
class contains_in_ordert final
17+
: public Catch::MatcherBase<std::vector<std::string>>
18+
{
19+
public:
20+
contains_in_ordert(std::initializer_list<std::string> expected);
21+
bool match(const std::vector<std::string> &actual) const override;
22+
23+
protected:
24+
std::string describe() const override;
25+
26+
private:
27+
std::vector<std::string> expected;
28+
};
29+
30+
contains_in_ordert::contains_in_ordert(
31+
std::initializer_list<std::string> expected)
32+
: expected{
33+
std::make_move_iterator(expected.begin()),
34+
std::make_move_iterator(expected.end())}
35+
{
36+
}
37+
38+
bool contains_in_ordert::match(const std::vector<std::string> &actual) const
39+
{
40+
auto begin_search = actual.begin();
41+
for(const auto &expected_item : expected)
42+
{
43+
auto find_result = std::find(begin_search, actual.end(), expected_item);
44+
if(find_result == actual.end())
45+
return false;
46+
else
47+
begin_search = ++find_result;
48+
}
49+
return true;
50+
}
51+
52+
std::string contains_in_ordert::describe() const
53+
{
54+
std::stringstream description;
55+
description << "contains these strings in order ";
56+
description << '"' << *expected.begin() << '"';
57+
for(auto iterator = std::next(expected.begin()); iterator != expected.end();
58+
++iterator)
59+
{
60+
description << ", \"" << *iterator << '"';
61+
}
62+
return description.str();
63+
}
64+
65+
TEST_CASE("Test loading model from file.", "[core][libcprover-cpp]")
66+
{
67+
api_sessiont api(api_optionst::create());
68+
69+
std::vector<std::string> output;
70+
// This lambda needs to be non-capturing in order for it to be convertible
71+
// to a function pointer, to pass to the API.
72+
const auto write_output =
73+
[](const api_messaget &message, api_call_back_contextt context) {
74+
std::vector<std::string> &output =
75+
*static_cast<std::vector<std::string> *>(context);
76+
output.emplace_back(api_message_get_string(message));
77+
};
78+
79+
api.set_message_callback(write_output, &output);
80+
api.load_model_from_files({"test.c"});
81+
CHECK_THAT(
82+
output,
83+
(contains_in_ordert{
84+
"Parsing test.c",
85+
"Converting",
86+
"Type-checking test",
87+
"Generating GOTO Program"}));
88+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Author: Diffblue Ltd.
2+
3+
#define CATCH_CONFIG_MAIN
4+
#include "../catch/catch.hpp"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
../catch
2+
libcprover-cpp

unit/libcprover-cpp/test.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Input file to test reading through API, not for compiling!
2+
3+
#include <assert.h>
4+
5+
int main(int argc, char *argv[])
6+
{
7+
int a[] = {0, 1, 2, 3, 4};
8+
assert(a[4] != 4);
9+
}

0 commit comments

Comments
 (0)