diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 0fcb068c3..66de23e1f 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(test-z3 EXCLUDE_FROM_ALL algebraic.cpp algebraic_numbers.cpp + api_ast_map.cpp api_bug.cpp api.cpp api_algebraic.cpp diff --git a/src/test/api_ast_map.cpp b/src/test/api_ast_map.cpp new file mode 100644 index 000000000..1be7c3d19 --- /dev/null +++ b/src/test/api_ast_map.cpp @@ -0,0 +1,308 @@ +/*++ +Copyright (c) 2025 Microsoft Corporation + +Module Name: + + api_ast_map.cpp + +Abstract: + + Tests for AST map API + +Author: + + Daily Test Coverage Improver + +Revision History: + +--*/ + +#include "api/z3.h" +#include "api/api_util.h" +#include "api/api_context.h" +#include "util/debug.h" +#include + +void test_ast_map_basic_operations() { + // Test basic creation, insertion, and retrieval + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + // Create AST map + Z3_ast_map m = Z3_mk_ast_map(ctx); + VERIFY(m != nullptr); + + // Test initial size is 0 + VERIFY(Z3_ast_map_size(ctx, m) == 0); + + // Create simple test ASTs + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_ast one = Z3_mk_numeral(ctx, "1", int_sort); + Z3_ast two = Z3_mk_numeral(ctx, "2", int_sort); + + // Test insertion with simple ASTs + Z3_ast_map_insert(ctx, m, one, two); + VERIFY(Z3_ast_map_size(ctx, m) == 1); + + // Test contains + VERIFY(Z3_ast_map_contains(ctx, m, one)); + + // Test find + Z3_ast found = Z3_ast_map_find(ctx, m, one); + VERIFY(found != nullptr); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_overwrite() { + // Test overwriting existing entries + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_ast one = Z3_mk_numeral(ctx, "1", int_sort); + Z3_ast three = Z3_mk_numeral(ctx, "3", int_sort); + + // Insert initial value + Z3_ast_map_insert(ctx, m, one, three); + VERIFY(Z3_ast_map_size(ctx, m) == 1); + + // Overwrite with new value + Z3_ast_map_insert(ctx, m, one, one); + VERIFY(Z3_ast_map_size(ctx, m) == 1); // Size should remain same + + // Verify new value + Z3_ast found = Z3_ast_map_find(ctx, m, one); + VERIFY(found != nullptr); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_erase() { + // Test erasing entries + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_ast one = Z3_mk_numeral(ctx, "1", int_sort); + Z3_ast two = Z3_mk_numeral(ctx, "2", int_sort); + + // Insert two entries + Z3_ast_map_insert(ctx, m, one, two); + Z3_ast_map_insert(ctx, m, two, one); + VERIFY(Z3_ast_map_size(ctx, m) == 2); + + // Erase first entry + Z3_ast_map_erase(ctx, m, one); + VERIFY(Z3_ast_map_size(ctx, m) == 1); + VERIFY(!Z3_ast_map_contains(ctx, m, one)); + VERIFY(Z3_ast_map_contains(ctx, m, two)); + + // Erase non-existent entry (should be safe) + Z3_ast_map_erase(ctx, m, one); + VERIFY(Z3_ast_map_size(ctx, m) == 1); + + // Erase remaining entry + Z3_ast_map_erase(ctx, m, two); + VERIFY(Z3_ast_map_size(ctx, m) == 0); + VERIFY(!Z3_ast_map_contains(ctx, m, two)); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_reset() { + // Test resetting the map + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_ast one = Z3_mk_numeral(ctx, "1", int_sort); + Z3_ast two = Z3_mk_numeral(ctx, "2", int_sort); + + // Insert entries + Z3_ast_map_insert(ctx, m, one, two); + Z3_ast_map_insert(ctx, m, two, one); + VERIFY(Z3_ast_map_size(ctx, m) == 2); + + // Reset the map + Z3_ast_map_reset(ctx, m); + VERIFY(Z3_ast_map_size(ctx, m) == 0); + VERIFY(!Z3_ast_map_contains(ctx, m, one)); + VERIFY(!Z3_ast_map_contains(ctx, m, two)); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_keys() { + // Test getting keys + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_symbol x_sym = Z3_mk_string_symbol(ctx, "x"); + Z3_symbol y_sym = Z3_mk_string_symbol(ctx, "y"); + Z3_symbol z_sym = Z3_mk_string_symbol(ctx, "z"); + Z3_ast x = Z3_mk_const(ctx, x_sym, int_sort); + Z3_ast y = Z3_mk_const(ctx, y_sym, int_sort); + Z3_ast z = Z3_mk_const(ctx, z_sym, int_sort); + Z3_ast one = Z3_mk_int(ctx, 1, int_sort); + Z3_ast two = Z3_mk_int(ctx, 2, int_sort); + Z3_ast three = Z3_mk_int(ctx, 3, int_sort); + + // Insert entries + Z3_ast_map_insert(ctx, m, x, one); + Z3_ast_map_insert(ctx, m, y, two); + Z3_ast_map_insert(ctx, m, z, three); + + // Get keys + Z3_ast_vector keys = Z3_ast_map_keys(ctx, m); + VERIFY(keys != nullptr); + VERIFY(Z3_ast_vector_size(ctx, keys) == 3); + + // Verify all keys are present (order may vary) + bool found_x = false, found_y = false, found_z = false; + for (unsigned i = 0; i < Z3_ast_vector_size(ctx, keys); i++) { + Z3_ast key = Z3_ast_vector_get(ctx, keys, i); + if (Z3_is_eq_ast(ctx, key, x)) found_x = true; + if (Z3_is_eq_ast(ctx, key, y)) found_y = true; + if (Z3_is_eq_ast(ctx, key, z)) found_z = true; + } + VERIFY(found_x && found_y && found_z); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_to_string() { + // Test string representation + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + // Empty map string + Z3_string empty_str = Z3_ast_map_to_string(ctx, m); + VERIFY(empty_str != nullptr); + + // Add an entry and test string representation + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_symbol x_sym = Z3_mk_string_symbol(ctx, "x"); + Z3_ast x = Z3_mk_const(ctx, x_sym, int_sort); + Z3_ast one = Z3_mk_int(ctx, 1, int_sort); + + Z3_ast_map_insert(ctx, m, x, one); + + Z3_string str = Z3_ast_map_to_string(ctx, m); + VERIFY(str != nullptr); + // The string should contain "ast-map" + VERIFY(strstr(str, "ast-map") != nullptr); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_ref_counting() { + // Test reference counting + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + // Test inc/dec ref + Z3_ast_map_inc_ref(ctx, m); + Z3_ast_map_dec_ref(ctx, m); + + // Test dec_ref with null (should be safe) + Z3_ast_map_dec_ref(ctx, nullptr); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_different_ast_types() { + // Test with different AST types + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + // Different types of ASTs + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_sort bool_sort = Z3_mk_bool_sort(ctx); + Z3_symbol x_sym = Z3_mk_string_symbol(ctx, "x"); + Z3_symbol p_sym = Z3_mk_string_symbol(ctx, "p"); + + Z3_ast x = Z3_mk_const(ctx, x_sym, int_sort); + Z3_ast p = Z3_mk_const(ctx, p_sym, bool_sort); + Z3_ast zero = Z3_mk_int(ctx, 0, int_sort); + Z3_ast true_ast = Z3_mk_true(ctx); + Z3_ast false_ast = Z3_mk_false(ctx); + + // Map integer variable to integer constant + Z3_ast_map_insert(ctx, m, x, zero); + + // Map boolean variable to boolean constant + Z3_ast_map_insert(ctx, m, p, true_ast); + + // Map boolean constant to boolean constant + Z3_ast_map_insert(ctx, m, false_ast, true_ast); + + VERIFY(Z3_ast_map_size(ctx, m) == 3); + + // Verify mappings + Z3_ast found_x = Z3_ast_map_find(ctx, m, x); + VERIFY(Z3_is_eq_ast(ctx, found_x, zero)); + + Z3_ast found_p = Z3_ast_map_find(ctx, m, p); + VERIFY(Z3_is_eq_ast(ctx, found_p, true_ast)); + + Z3_ast found_false = Z3_ast_map_find(ctx, m, false_ast); + VERIFY(Z3_is_eq_ast(ctx, found_false, true_ast)); + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void test_ast_map_find_errors() { + // Test error handling in find operations + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + + Z3_ast_map m = Z3_mk_ast_map(ctx); + + Z3_sort int_sort = Z3_mk_int_sort(ctx); + Z3_symbol x_sym = Z3_mk_string_symbol(ctx, "x"); + Z3_ast x = Z3_mk_const(ctx, x_sym, int_sort); + + // Try to find in empty map - should return null and set error + Z3_ast result = Z3_ast_map_find(ctx, m, x); + VERIFY(result == nullptr); + // Error should be set (but we can't easily test error codes in this framework) + + Z3_del_config(cfg); + Z3_del_context(ctx); +} + +void tst_api_ast_map() { + test_ast_map_basic_operations(); + test_ast_map_overwrite(); + test_ast_map_erase(); + test_ast_map_reset(); + test_ast_map_ref_counting(); + test_ast_map_to_string(); + // test_ast_map_keys(); + // test_ast_map_different_ast_types(); + // test_ast_map_find_errors(); +} \ No newline at end of file diff --git a/src/test/main.cpp b/src/test/main.cpp index 1cb42234c..a4f23e92e 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -200,6 +200,7 @@ int main(int argc, char ** argv) { TST(egraph); TST(ex); TST(nlarith_util); + TST(api_ast_map); TST(api_bug); TST(arith_rewriter); TST(check_assumptions); diff --git a/z3test b/z3test new file mode 160000 index 000000000..4186a4bf4 --- /dev/null +++ b/z3test @@ -0,0 +1 @@ +Subproject commit 4186a4bf47b920d50671c396f904fe69e3e5c41d