--- /dev/null
+#
+# Copyright (C) 2025 Michael Zucchi
+#
+# This is the copyright for java.make
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# ######################################################################
+# junit(5) makefile fragment
+
+# This runs tests names *Test.java or *IT.java in the src/*/tests
+# directories.
+
+# Couldn't work out how netbeans does it, might only do junit4.
+
+# This integrates with java.make and maven.make:
+
+# include java.make
+# include junit5.make
+# include maven.make
+
+maven_central_JARS += org.junit.platform:junit-platform-console-standalone:1.13.4
+
+junit5_module = org.junit.platform.console.standalone
+junit5_launcher = org.junit.platform.console.ConsoleLauncher
+
+# ######################################################################
+
+define java_tests=
+ifndef $$($1_TEST_JAVA)
+$1_TEST_JAVA := $(shell find src/$1/tests -type f -name '*.java')
+$1_TEST_PACKAGE = $$(subst /,.,$$(patsubst src/$1/tests/%/,%,$$(sort $$(dir $$($1_TEST_JAVA)))))
+endif
+
+ifdef $1_TEST_JAVA
+test: $1-test
+test-it: $1-it
+check: $1-test $1-it
+bin/status/$1.tests: bin/status/$1.classes $$($1_TEST_JAVA)
+.PHONY: $1-test $1-it
+
+bin/status/$1.tests:
+ @install -d $$(@D)
+ $$(JAVAC) \
+ --module-path bin/modules:.lib \
+ --patch-module $1=src/$1/tests \
+ --add-modules $(junit5_module) \
+ --add-reads $1=$(junit5_module),ALL-UNNAMED \
+ --module-source-path 'src/*/tests' \
+ -d bin/tests \
+ $$($1_TEST_JAVA)
+ touch $$@
+
+$1-test: bin/status/$1.tests
+ $$(JAVA) \
+ --module-path bin/modules:.lib \
+ --patch-module $1=bin/tests/$1 \
+ --add-modules $1 \
+ --add-reads $1=$(junit5_module),ALL-UNNAMED \
+ $$(patsubst %,--add-opens $1/%=$(junit5_module),$$($1_TEST_PACKAGE)) \
+ $$(patsubst %,--add-exports $1/%=$(junit5_module),$$($1_TEST_PACKAGE)) \
+ -m $(junit5_module)/$(junit5_launcher) \
+ --scan-modules --include-classname='.*Test'
+
+$1-it: bin/status/$1.tests
+ $$(JAVA) \
+ --module-path bin/modules:.lib \
+ --patch-module $1=bin/tests/$1 \
+ --add-modules $1 \
+ --add-reads $1=$(junit5_module),ALL-UNNAMED \
+ $$(patsubst %,--add-opens $1/%=$(junit5_module),$$($1_TEST_PACKAGE)) \
+ $$(patsubst %,--add-exports $1/%=$(junit5_module),$$($1_TEST_PACKAGE)) \
+ -m $(junit5_module)/$(junit5_launcher) \
+ --scan-modules --include-classname='.*IT'
+endif
+
+endef
+
+.PHONY: test check
+
+$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/tests),$(eval $(call java_tests,$(module)))))
+#$(foreach module,$(java_MODULES),$(if $(wildcard src/$(module)/tests),$(info $(call java_tests,$(module)))))
+
+# ######################################################################