# dm/host unit tests in one command: make -C dm/host/tests GAME= run (takes seconds; build output goes to build/ and is not committed)
B = build
PYTHON ?= python3
# game profile header (dm.h needs game_profile.h, generated by the host Makefile into ../gen//)
# tests that use the game profile need GAME= (there is no default game); GINC only expands when used, so tests without the profile build as before
GINC = $(if $(strip $(GAME)),-I../gen/$(GAME) -I../../games/$(GAME),$(error GAME is not set: make GAME=: $(shell python3 ../../games/game.py list | awk -F'\t' '{printf "%s (%s) ", $$1, $$3}')))
GAME_H = ../gen/$(GAME)/game_profile.h
run: $(B)/t_heap_size $(B)/t_touch $(B)/t_gesture $(B)/t_oe $(B)/t_fs $(B)/t_fs_commit_list $(B)/t_thread_leak $(B)/t_fs_case $(B)/t_audio $(B)/t_audio_spsc $(B)/t_swkbd $(B)/t_altstack $(B)/t_condvar $(B)/t_condvar_old $(B)/t_pctl $(B)/t_time $(B)/t_shared_font $(B)/t_vorbis $(B)/t_vorbis_divides $(B)/t_hid $(B)/t_haptics $(B)/t_haptics_apple
$(B)/t_heap_size
$(B)/t_touch
$(B)/t_gesture
$(B)/t_oe 2>/dev/null
$(B)/t_fs 2>/dev/null
TMPDIR="$(abspath $(B))" $(B)/t_fs_commit_list
$(B)/t_thread_leak
TMPDIR="$(abspath $(B))" $(B)/t_fs_case 2>/dev/null
$(B)/t_audio
$(B)/t_audio_spsc
$(B)/t_fpslock
$(B)/t_audren_work
$(B)/t_swkbd
$(B)/t_altstack
$(B)/t_condvar
$(B)/t_condvar_old
$(B)/t_preempt
$(B)/t_preempt --all-peers
$(B)/t_pctl
$(B)/t_time
$(B)/t_shared_font
$(B)/t_system_event
$(B)/t_vorbis
$(B)/t_vorbis_divides
$(B)/t_movie_vpx
$(B)/t_hid
$(B)/t_haptics
$(B)/t_haptics_apple
$(B)/t_nro
$(B)/t_symbols
run: $(B)/t_nro
run: $(B)/t_symbols
$(B)/t_symbols: t_symbols.c ../hle.c ../loader.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Werror -Wno-unused-function -Wno-deprecated-declarations -I.. $(GINC) -o $@ t_symbols.c
.PHONY: symbols
symbols: $(B)/t_symbols
$(B)/t_symbols
run: $(B)/t_system_event
run: $(B)/t_audren_work
$(B)/t_audren_work: t_audren_work.c ../hle_audren.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_audren_work.c
.PHONY: audren-work
audren-work: $(B)/t_audren_work
$(B)/t_audren_work
$(B)/t_system_event: t_system_event.c ../hle_thread.c ../hle_sdk16.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Werror -Wno-unused-function -Wno-frame-address -I.. $(GINC) -o $@ t_system_event.c
.PHONY: system-event
system-event: $(B)/t_system_event
$(B)/t_system_event
$(B)/t_nro: t_nro.c ../loader.c ../hle_ro.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Wno-unused-function -Wno-deprecated-declarations -I.. $(GINC) -o $@ t_nro.c
.PHONY: nro
nro: $(B)/t_nro
$(B)/t_nro
$(GAME_H):
$(MAKE) -C .. game_profile GAME=$(GAME)
$(B)/t_heap_size: t_heap_size.c ../hle_svc.c ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Werror -Wno-unused-function -fsanitize=undefined -I.. $(GINC) -o $@ t_heap_size.c
.PHONY: heap_size
heap_size: $(B)/t_heap_size
$(B)/t_heap_size
$(B)/t_touch: t_touch.c ../hle_touch.c ../front.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_touch.c ../hle_touch.c
$(B)/t_gesture: t_gesture.c ../hle_touch.c ../front.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_gesture.c ../hle_touch.c
$(B)/t_thread_leak: t_thread_leak.c ../thread.c ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_thread_leak.c
$(B)/t_fs: t_fs.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_fs.c t_fs_stub.c ../hle_bigstack.c
$(B)/t_fs_commit_list: t_fs_commit_list.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_fs_commit_list.c t_fs_stub.c ../hle_bigstack.c
$(B)/t_fs_commit_list_tsan: t_fs_commit_list.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -fsanitize=thread -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_fs_commit_list.c t_fs_stub.c ../hle_bigstack.c
.PHONY: fs-tsan
fs-tsan: $(B)/t_fs_commit_list_tsan
TMPDIR="$(abspath $(B))" $(B)/t_fs_commit_list_tsan
$(B)/t_fs_case: t_fs_case.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_fs_case.c ../hle_bigstack.c
$(B)/t_audio: t_audio.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_audio.c -framework AudioToolbox
$(B)/t_audio_spsc: t_audio_spsc.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_audio_spsc.c -framework AudioToolbox
$(B)/t_audio_device: t_audio_device.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_audio_device.c -framework AudioToolbox
.PHONY: audio-device
audio-device: $(B)/t_audio_device
$(B)/t_audio_device
run: audio-device
$(B)/t_audio_spsc_tsan: t_audio_spsc.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -O1 -fsanitize=thread -Wno-unused-function -I.. $(GINC) -o $@ t_audio_spsc.c -framework AudioToolbox
run: $(B)/t_fpslock
$(B)/t_fpslock: t_fpslock.c ../hle_fpslock.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wno-unused-function $(GINC) -o $@ t_fpslock.c
$(B)/t_swkbd: t_swkbd.c ../hle_swkbd.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_swkbd.c ../hle_swkbd.c
$(B)/t_altstack: t_altstack.c t_altstack_stub.c ../crash.c ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_altstack.c t_altstack_stub.c ../crash.c
$(B)/t_pctl: t_pctl.c ../hle_misc.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_pctl.c
$(B)/t_shared_font: t_shared_font.c ../hle_sdk16.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Werror -Wno-unused-function -Wno-frame-address -I.. $(GINC) -o $@ t_shared_font.c
$(B)/t_hid: t_hid.c ../hle_hid.c ../hle_haptics.c ../hle_haptics.h ../pad_slots.h ../dm_input.h ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_hid.c ../hle_haptics.c
$(B)/t_hid_tsan: t_hid.c ../hle_hid.c ../hle_haptics.c ../hle_haptics.h ../pad_slots.h ../dm_input.h ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -fsanitize=thread -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_hid.c ../hle_haptics.c
$(B)/t_haptics: t_haptics.c ../hle_haptics.c ../hle_haptics.h ../dm_input.h | $(B)
clang -O1 -g -Wall -Werror -I.. -o $@ t_haptics.c ../hle_haptics.c
$(B)/t_haptics_apple: t_haptics_apple.m ../haptics_apple.m ../haptics_apple.h ../hle_haptics.c ../hle_haptics.h | $(B)
clang -O1 -g -fobjc-arc -Wall -Werror -I.. -o $@ t_haptics_apple.m ../hle_haptics.c -framework Cocoa -framework GameController -framework CoreHaptics
$(B)/t_time: t_time.c ../hle_time.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_time.c
$(B)/t_oe: t_oe.c ../hle_oe.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_oe.c
$(B)/t_condvar: t_condvar.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -DDM_TEST_HOOKS -I.. $(GINC) -o $@ t_condvar.c t_condvar_stub.c ../hle_thread.c
$(B)/t_condvar_old: t_condvar.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
clang -O1 -Wno-unused-function -DDM_TEST_HOOKS -DDM_TEST_CV_OLD_ORDER -I.. $(GINC) -o $@ t_condvar.c t_condvar_stub.c ../hle_thread.c
$(B)/t_preempt: t_preempt.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_preempt.c t_condvar_stub.c
.PHONY: preempt
preempt: $(B)/t_preempt
$(B)/t_preempt
$(B)/t_preempt --all-peers
run: $(B)/t_preempt
# the Vorbis tests build their own packets and need no game profile (they build without GAME)
$(B)/t_vorbis: t_vorbis.c ../../third_party/stb_vorbis/stb_vorbis.c | $(B)
clang -O1 -g -Wno-unused-function -Wno-tautological-compare -o $@ t_vorbis.c
$(B)/t_vorbis_divides: t_vorbis.c ../../third_party/stb_vorbis/stb_vorbis.c | $(B)
clang -O1 -g -DSTB_VORBIS_DIVIDES_IN_RESIDUE -Wno-unused-function -Wno-tautological-compare -o $@ t_vorbis.c
run: $(B)/t_movie_vpx
$(B)/t_movie_vpx: t_movie_vpx.c ../hle_movie.c $(GAME_H) ../gen/vpx/libvpx.a | $(B)
clang -O1 -g -Wno-unused-function -Wno-tautological-compare $(GINC) -I../../third_party/libvpx -I../../third_party/libvpx/config -I../../third_party/stb_vorbis -Wl,-dead_strip -o $@ t_movie_vpx.c ../gen/vpx/libvpx.a -framework AudioToolbox
../gen/vpx/libvpx.a: FORCE_VPX
$(MAKE) -C .. GAME=$(GAME) gen/vpx/libvpx.a
.PHONY: FORCE_VPX
$(B):
mkdir -p $@
.PHONY: run tsan
tsan: $(B)/t_audio_spsc_tsan $(B)/t_hid_tsan
$(B)/t_audio_spsc_tsan
$(B)/t_hid_tsan
MEM_FLAGS = -O1 -Wall -Werror -Wno-unused-function -Imemory_profile -I..
MEM_DEPS = t_svc_memory.c memory_profile/game_profile.h ../hle_svc.c ../hle_guestthread.c ../hle.h ../dm.h
$(B)/t_svc_memory: $(MEM_DEPS) | $(B)
clang $(MEM_FLAGS) -fsanitize=undefined -o $@ t_svc_memory.c
$(B)/t_svc_memory_unlimited: $(MEM_DEPS) | $(B)
clang $(MEM_FLAGS) -fsanitize=undefined -DDM_GAME_MEM_MAP_LIMIT=0 -o $@ t_svc_memory.c
$(B)/t_svc_memory_16k: $(MEM_DEPS) | $(B)
clang $(MEM_FLAGS) -fsanitize=address,undefined -DTEST_PAGE_16K -o $@ t_svc_memory.c
$(B)/t_svc_memory_tsan: $(MEM_DEPS) | $(B)
clang $(MEM_FLAGS) -fsanitize=thread -o $@ t_svc_memory.c
$(B)/t_svc_memory_dirty: $(MEM_DEPS) ../../gfx/nvn/nvn_dirty.c ../../gfx/nvn/nvn_dirty.h | $(B)
clang $(MEM_FLAGS) -DTEST_REAL_DIRTY -o $@ t_svc_memory.c ../../gfx/nvn/nvn_dirty.c
.PHONY: memory memory-tsan memory-dirty memory-profile
memory: $(B)/t_svc_memory $(B)/t_svc_memory_unlimited $(B)/t_svc_memory_16k
$(B)/t_svc_memory
$(B)/t_svc_memory_unlimited
$(B)/t_svc_memory_16k
memory-tsan: $(B)/t_svc_memory_tsan
$(B)/t_svc_memory_tsan
memory-dirty: $(B)/t_svc_memory_dirty
$(B)/t_svc_memory_dirty
memory-profile: $(B)/t_svc_memory
$(PYTHON) test_memory_profile.py
run: memory memory-dirty memory-profile
# A native blocking notification wait must release the thread's guest core.
$(B)/t_notify_sched: t_notify_sched.c t_condvar_stub.c ../hle_thread.c ../hle_oe.c ../hle.h ../dm.h $(GAME_H) | $(B)
clang -O1 -g -Wall -Werror -Wno-unused-function -DDM_TEST_THREAD_ENTER -I.. $(GINC) -o $@ t_notify_sched.c t_condvar_stub.c
.PHONY: notify-scheduler
notify-scheduler: $(B)/t_notify_sched
$(B)/t_notify_sched
$(B)/t_notify_sched --all-peers
run: notify-scheduler