.PHONY: all cprover.dir test testing-utils-clean

# Source files for test utilities
SRC = unit_tests.cpp \
      # Empty last line

# Test source files
SRC += analyses/ai/ai.cpp \
       analyses/ai/ai_simplify_lhs.cpp \
       analyses/call_graph.cpp \
       analyses/constant_propagator.cpp \
       analyses/dependence_graph.cpp \
       analyses/disconnect_unreachable_nodes_in_graph.cpp \
       analyses/does_remove_const/does_expr_lose_const.cpp \
       analyses/does_remove_const/does_type_preserve_const_correctness.cpp \
       analyses/does_remove_const/is_type_at_least_as_const_as.cpp \
       big-int/big-int.cpp \
       compound_block_locations.cpp \
       goto-checker/report_util/is_property_less_than.cpp \
       goto-instrument/cover_instrument.cpp \
       goto-instrument/cover/cover_only.cpp \
       goto-programs/goto_model_function_type_consistency.cpp \
       goto-programs/goto_program_assume.cpp \
       goto-programs/goto_program_dead.cpp \
       goto-programs/goto_program_declaration.cpp \
       goto-programs/goto_program_function_call.cpp \
       goto-programs/goto_program_goto_target.cpp \
       goto-programs/goto_program_symbol_type_table_consistency.cpp \
       goto-programs/goto_program_table_consistency.cpp \
       goto-programs/goto_program_validate.cpp \
       goto-programs/goto_trace_output.cpp \
       goto-programs/is_goto_binary.cpp \
       goto-programs/osx_fat_reader.cpp \
       goto-programs/remove_returns.cpp \
       goto-programs/xml_expr.cpp \
       goto-symex/apply_condition.cpp \
       goto-symex/expr_skeleton.cpp \
       goto-symex/goto_symex_state.cpp \
       goto-symex/ssa_equation.cpp \
       goto-symex/is_constant.cpp \
       goto-symex/symex_assign.cpp \
       goto-symex/symex_level0.cpp \
       goto-symex/symex_level1.cpp \
       goto-symex/try_evaluate_pointer_comparisons.cpp \
       interpreter/interpreter.cpp \
       json/json_parser.cpp \
       json_symbol_table.cpp \
       path_strategies.cpp \
       pointer-analysis/value_set.cpp \
       solvers/bdd/miniBDD/miniBDD.cpp \
       solvers/floatbv/float_utils.cpp \
       solvers/lowering/byte_operators.cpp \
       solvers/prop/bdd_expr.cpp \
       solvers/sat/satcheck_minisat2.cpp \
       solvers/strings/array_pool/array_pool.cpp \
       solvers/strings/string_constraint_generator_valueof/calculate_max_string_length.cpp \
       solvers/strings/string_constraint_generator_valueof/get_numeric_value_from_character.cpp \
       solvers/strings/string_constraint_generator_valueof/is_digit_with_radix.cpp \
       solvers/strings/string_format_builtin_function/length_for_format_specifier.cpp \
       solvers/strings/string_format_builtin_function/length_of_decimal_int.cpp \
       solvers/strings/string_refinement/concretize_array.cpp \
       solvers/strings/string_refinement/sparse_array.cpp \
       solvers/strings/string_refinement/string_refinement.cpp \
       solvers/strings/string_refinement/substitute_array_list.cpp \
       solvers/strings/string_refinement/union_find_replace.cpp \
       util/allocate_objects.cpp \
       util/cmdline.cpp \
       util/dense_integer_map.cpp \
       util/expr_cast/expr_cast.cpp \
       util/expr.cpp \
       util/expr_iterator.cpp \
       util/file_util.cpp \
       util/format_number_range.cpp \
       util/get_base_name.cpp \
       util/graph.cpp \
       util/interval_constraint.cpp \
       util/interval_union.cpp \
       util/irep.cpp \
       util/irep_sharing.cpp \
       util/json_array.cpp \
       util/json_object.cpp \
       util/lazy.cpp \
       util/memory_info.cpp \
       util/message.cpp \
       util/optional.cpp \
       util/optional_utils.cpp \
       util/parse_options.cpp \
       util/pointer_offset_size.cpp \
       util/prefix_filter.cpp \
       util/range.cpp \
       util/replace_symbol.cpp \
       util/sharing_map.cpp \
       util/sharing_node.cpp \
       util/simplify_expr.cpp \
       util/small_map.cpp \
       util/small_shared_n_way_ptr.cpp \
       util/ssa_expr.cpp \
       util/std_expr.cpp \
       util/string2int.cpp \
       util/string_utils/join_string.cpp \
       util/string_utils/split_string.cpp \
       util/string_utils/strip_string.cpp \
       util/symbol_table.cpp \
       util/symbol.cpp \
       util/unicode.cpp \
       # Empty last line

ifeq ($(OS),Windows_NT)
    detected_OS := Windows
else
    detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown')
endif

ifeq ($(detected_OS),Linux)
  ifneq ($(WITH_MEMORY_ANALYZER),0)
    # only set if it wasn't explicitly unset
    WITH_MEMORY_ANALYZER=1
  endif
endif

ifeq ($(WITH_MEMORY_ANALYZER),1)
  SRC += memory-analyzer/gdb_api.cpp
endif

INCLUDES= -I ../src/ -I.

CPROVER_DIR = .
include ../src/config.inc
include ../src/common

cprover.dir:
	$(MAKE) $(MAKEARGS) -C ../src

testing-utils/testing-utils$(LIBEXT): cprover.dir
	$(MAKE) $(MAKEARGS) -C testing-utils

testing-utils-clean:
	$(MAKE) $(MAKEARGS) -C testing-utils clean

# We need to link bmc.o to the unit test, so here's everything it depends on...
BMC_DEPS =../src/cbmc/c_test_input_generator$(OBJEXT) \
          ../src/cbmc/cbmc_languages$(OBJEXT) \
          ../src/cbmc/cbmc_parse_options$(OBJEXT) \
          ../src/goto-instrument/source_lines$(OBJEXT) \
          ../src/goto-instrument/cover$(OBJEXT) \
          ../src/goto-instrument/cover_basic_blocks$(OBJEXT) \
          ../src/goto-instrument/cover_filter$(OBJEXT) \
          ../src/goto-instrument/cover_instrument_branch$(OBJEXT) \
          ../src/goto-instrument/cover_instrument_condition$(OBJEXT) \
          ../src/goto-instrument/cover_instrument_decision$(OBJEXT) \
          ../src/goto-instrument/cover_instrument_location$(OBJEXT) \
          ../src/goto-instrument/cover_instrument_mcdc$(OBJEXT) \
          ../src/goto-instrument/cover_instrument_other$(OBJEXT) \
          ../src/goto-instrument/cover_util$(OBJEXT) \
          ../src/goto-instrument/goto_program2code$(OBJEXT) \
          ../src/goto-instrument/reachability_slicer$(OBJEXT) \
          ../src/goto-instrument/nondet_static$(OBJEXT) \
          ../src/goto-instrument/full_slicer$(OBJEXT) \
          ../src/goto-instrument/unwindset$(OBJEXT) \
          ../src/xmllang/xmllang$(LIBEXT) \
          ../src/goto-symex/goto-symex$(LIBEXT) \
          ../src/jsil/jsil$(LIBEXT) \
          # Empty last line
#
CPROVER_LIBS =../src/ansi-c/ansi-c$(LIBEXT) \
              ../src/cpp/cpp$(LIBEXT) \
              ../src/json/json$(LIBEXT) \
              ../src/json-symtab-language/json-symtab-language$(LIBEXT) \
              ../src/linking/linking$(LIBEXT) \
              ../src/util/util$(LIBEXT) \
              ../src/big-int/big-int$(LIBEXT) \
              ../src/goto-checker/goto-checker$(LIBEXT) \
              ../src/goto-programs/goto-programs$(LIBEXT) \
              ../src/pointer-analysis/pointer-analysis$(LIBEXT) \
              ../src/langapi/langapi$(LIBEXT) \
              ../src/assembler/assembler$(LIBEXT) \
              ../src/analyses/analyses$(LIBEXT) \
              ../src/solvers/solvers$(LIBEXT) \
              ../src/statement-list/statement-list$(LIBEXT) \
              $(BMC_DEPS)
              # Empty last line

OBJ += $(CPROVER_LIBS) testing-utils/testing-utils$(LIBEXT)

CATCH_TEST = unit_tests$(EXEEXT)
EXCLUDED_TESTS=expr_undefined_casts.cpp
ifneq ($(WITH_MEMORY_ANALYZER),1)
EXCLUDED_TESTS += gdb_api.cpp
endif

N_CATCH_TESTS = $(shell \
                  cat $$(find . -name "*.cpp" \
                $$(printf ' -not -name %s ' $(EXCLUDED_TESTS))) | \
                  grep -E "(SCENARIO|TEST_CASE)" | grep -c -v '\[\.\]')

CLEANFILES = $(CATCH_TEST) testing-utils/testing-utils$(LIBEXT)

# only add a dependency for libraries to avoid triggering implicit rules, which
# would cause unnecessary rebuilds
$(filter %$(LIBEXT), $(CPROVER_LIBS)): cprover.dir

all: $(CATCH_TEST)

clean: testing-utils-clean

test: $(CATCH_TEST)
	if ! ./$(CATCH_TEST) -l | grep -q "^$(N_CATCH_TESTS) test cases" ; then \
		./$(CATCH_TEST) -l ; fi
	./$(CATCH_TEST)


###############################################################################

unit_tests$(EXEEXT): $(OBJ)
	$(LINKBIN)
