#######################################################################
# Makefile for python test-suite
#######################################################################

PYTHON = python3

LANGUAGE     = python
PYFLAGS      = -Werror
SCRIPTSUFFIX = _runme.py
PY_VER_3_DIGIT    = 312
PYCODESTYLE       = 
PYCODESTYLE_FLAGS = --ignore=E252,E30,E402,E501,E731,E741,W291,W391
PYREFLY           = 
PYREFLY_FLAGS     = --summary=none --python-interpreter-path=$(PYTHON) --search-path=. --ignore=missing-import

HAVE_CXX11   = 1
HAVE_CXX14   = 1
HAVE_CXX17   = 1
HAVE_CXX20   = 1
srcdir       = .
top_srcdir   = ../../..
top_builddir = ../../..

FAILING_CPP_TESTS = \
	cpp17_map_no_default_ctor \

CPP_TEST_CASES += \
	callback \
	complextest \
	director_guard \
	director_stl \
	director_wstring \
	file_test \
	iadd \
	implicittest \
	inplaceadd \
	input \
	li_cstring \
	li_cwstring \
	li_factory \
	li_implicit \
	li_std_containers_int \
	li_std_list \
	li_std_map_member \
	li_std_multimap \
	li_std_pair_extra \
	li_std_set \
	li_std_stream \
	li_std_string_extra \
	li_std_vectora \
	li_std_vector_extra \
	li_std_wstream \
	li_std_wstring_inherit \
	primitive_types \
	python_abstractbase \
	python_annotations_c \
	python_annotations_typing \
	python_annotations_variable_c \
	python_annotations_variable_typing \
	python_append \
	python_builtin \
	python_destructor_exception \
	python_director \
	python_director_pyobject \
	python_docstring \
	python_extranative \
	python_flatstaticmethod \
	python_moduleimport \
	python_nokwargs_feature \
	python_nokwargs_keyword \
	python_overload_simple_cast \
	python_pickle \
	python_pyi \
	python_pythoncode \
	python_richcompare \
	python_strict_unicode \
	python_threads \
	python_typehints \
	python_typemap_macro \
	python_various \
	simutry \
	std_containers \
	swigobject \
	template_matrix \

#	director_profile

ifeq (,$(PY_ABI_VER))
PY_ABI_311:=1
else
PY_ABI_VER_INTEGER:=$(shell printf "%d%02d" $(subst ., ,$(PY_ABI_VER)))
PY_ABI_311:=$(shell test $(PY_ABI_VER_INTEGER) -ge 311 && echo "1")
endif

# Test requiring python-3.11 minimum if using Py_LIMITED_API
ifeq (1,$(PY_ABI_311))
CPP_TEST_CASES += pyabi311_bufferinterface
endif

# Test requiring python-3.11 minimum if using Py_LIMITED_API if and only if python>=3.13
ifeq (1,$(PY_ABI_311))
CPP_TEST_CASES += python_pybuffer
else
PY_313:=$(shell test $(PY_VER_3_DIGIT) -ge 313 && echo "1")
ifeq (,$(PY_313))
CPP_TEST_CASES += python_pybuffer
endif
endif

CPP11_TEST_CASES = \
	cpp11_hash_tables \
	cpp11_std_unordered_map \
	cpp11_std_unordered_multimap \
	cpp11_std_unordered_multiset \
	cpp11_std_unordered_set \

CPP17_TEST_CASES = \
	cpp17_std_filesystem

C_TEST_CASES += \
	ccomplextest \
	file_test \
	li_cstring \
	li_cwstring \
	python_nondynamic \
	python_varargs_typemap \
	python_weakref \

MULTI_CPP_TEST_CASES += \
	import_callback \
	python_annotations_import \
	python_crossmod \
	python_pyiterator_rename \
	python_runtime_data \

include $(srcdir)/../common.mk

# Overridden variables here
LIBS         = -L.
VALGRIND_OPT += --suppressions=pythonswig.supp

# Ensure testsuite remains free from SWIG warnings.
SWIGOPT += -Werror

# Custom tests - tests with additional commandline options
python_flatstaticmethod.cpptest: SWIGOPT += -flatstaticmethod
python_nokwargs_keyword.cpptest: SWIGOPT += -keyword
python_typehints.cpptest: SWIGOPT += -typehints
python_pyi.cpptest: SWIGOPT += -pyi

# C/C++ annotations are not PEP 484 type hints, so -typehints and Pyrefly do not apply to these tests.
python_annotations_c.cpptest: override SWIG_FEATURES := $(filter-out -typehints,$(SWIG_FEATURES))
python_annotations_variable_c.cpptest: override SWIG_FEATURES := $(filter-out -typehints,$(SWIG_FEATURES))

# Make sure just python_runtime_data_builtin.i uses the -builtin option. Note: does not use python_runtime_data.list for all steps.
# PY_ABI_VER is unset for python_runtime_data_builtin because stable ABI is not supported by builtin
python_runtime_data.multicpptest: override SWIG_FEATURES := $(filter-out -builtin,$(SWIG_FEATURES))
python_runtime_data.multicpptest: override SWIGOPT := $(filter-out -builtin,$(SWIGOPT))
python_runtime_data.multicpptest: swig_and_compile_multi_cpp = \
	$(call swig_and_compile_cpp_helper,python_runtime_data_builtin,'$(SWIGOPT) -builtin' PY_ABI_VER=) && \
	$(call swig_and_compile_cpp_helper,python_runtime_data_nobuiltin,'$(SWIGOPT)')

# Rules for the different types of tests
%.cpptest:
	$(setup)
	+$(swig_and_compile_cpp)
	$(check_pep8)
	$(check_typehints)
	$(run_testcase)

%.ctest:
	$(setup)
	+$(swig_and_compile_c)
	$(check_pep8)
	$(check_typehints)
	$(run_testcase)

%.multicpptest:
	$(setup)
	+$(swig_and_compile_multi_cpp)
	$(check_pep8_multi_cpp)
	$(check_typehints_multi_cpp)
	$(run_testcase)


# Python code style checking
ifneq (,$(PYCODESTYLE))
check_pep8 = $(COMPILETOOL) $(PYCODESTYLE) $(PYCODESTYLE_FLAGS) $(SCRIPTPREFIX)$*.py

check_pep8_multi_cpp = \
	for f in `cat $(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list` ; do \
	  $(COMPILETOOL) $(PYCODESTYLE) $(PYCODESTYLE_FLAGS) $$f.py; \
	done
endif

# Type checking of the PEP 484 type hints in the generated wrapper when -typehints is used. Also tests .pyi file if generated.
# Enable it for every test case with:
#   env SWIG_FEATURES=-typehints make check-python-test-suite
ifneq (,$(PYREFLY))
check_typehints = $(if $(filter -typehints,$(SWIG_FEATURES)), \
	$(COMPILETOOL) $(PYREFLY) check $(PYREFLY_FLAGS) $(PYREFLY_EXTRA_FLAGS) $(SCRIPTPREFIX)$*.py $(if $(filter -pyi,$(SWIG_FEATURES)),$(SCRIPTPREFIX)$*.pyi))

check_typehints_multi_cpp = \
	$(if $(filter -typehints,$(SWIG_FEATURES)), \
	  for f in `cat $(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list` ; do \
	    $(COMPILETOOL) $(PYREFLY) check $(PYREFLY_FLAGS) $(PYREFLY_EXTRA_FLAGS) $$f.py $(if $(filter -pyi,$(SWIG_FEATURES)),$$f.pyi) || exit 1; \
	  done)
endif

# Runs the testcase. A testcase is only run if
# a file is found which has _runme.py appended after the testcase name.
run_testcase = \
	if [ -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then \
	  env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PYTHONPATH=.:$(srcdir):$$PYTHONPATH $(RUNTOOL) $(PYTHON) $(PYFLAGS) $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX); \
	fi

# Clean: remove the generated Python files
%.clean:
	@rm -f $*.py*

clean:
	$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR='$(SRCDIR)' python_clean
	rm -f ../hugemod.h ../hugemod_a.i ../hugemod_b.i hugemod_a.py* hugemod_b.py* $(hugemod_runme)
	rm -f clientdata_prop_a.py* clientdata_prop_b.py*
	rm -f import_callback_x.py* import_callback_y.py*
	rm -f python_crossmod_a.py* python_crossmod_b.py*
	rm -f python_annotations_import_a.py* python_annotations_import_b.py*
	rm -f import_share_a.py* import_share_b.py* import_share_c.py*
	rm -f import_stl_a.py* import_stl_b.py*
	rm -f imports_a.py* imports_b.py* mod_a.py* mod_b.py*
	rm -f multi_import_a.py* multi_import_b.py* multi_import_d.py*
	rm -f packageoption_a.py* packageoption_b.py* packageoption_c.py*
	rm -f python_pyiterator_rename_a.py* python_pyiterator_rename_b.py*
	rm -f python_runtime_data_builtin.py* python_runtime_data_nobuiltin.py*
	rm -f template_typedef_cplx2.py*

hugemod_runme = $(SCRIPTPREFIX)hugemod$(SCRIPTSUFFIX)

# Note: hugemod not run by default
hugemod:
	perl hugemod.pl $(hugemod_runme)
	$(MAKE) hugemod_a.cpptest
	$(MAKE) hugemod_b.cpptest
	time $(PYTHON) $(PYFLAGS) $(hugemod_runme)
	time $(PYTHON) $(PYFLAGS) $(hugemod_runme)
