# The MIT License (MIT)
#
# Copyright (C) 2026 Scott Duensing
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

# Terminal suite -- the file transfer library, the connection library
# and the Terminal program (a DVX BASIC program), all on the host.
#
#   testXfer       XMODEM/YMODEM/ZMODEM engines against each other through
#                  fault-injecting pipes, and against scripted peers
#   testLrzsz      the engines against lrz / lsz (toolchains/lrzsz, built
#                  by installLrzsz.sh); reports "skipped" when absent
#   testConn       serial, modem and secure-link connections over the
#                  serial suite's loopback shim, with transfers on top, and
#                  the BASIC functions of the transfer and connection
#                  libraries
#   testConnProxy  the secure link through the real host proxy
#                  (proxy.c, main renamed) to a fake telnet BBS, over the
#                  proxy's serial socket shim and directly over TCP
#   testTelnet     the Telnet filter byte for byte, and Telnet sessions
#                  against a host played by the test on a loopback socket
#   testTermApp    the Terminal program (compiled from its project, run by
#                  the BASIC stub) in the host shell, end to end, and its
#                  phone book module on its own (bookTest/bookTest.dbp)
#
# `make` builds and runs everything (SAN/COV per common.mk).

include ../dvxtest/dvxtest.mk

.DEFAULT_GOAL := all

ROOT      = $(DVXTEST_ROOT)
LIBS      = $(ROOT)/src/libs/kpunch
XFERDIR   = $(LIBS)/xfer
CONNDIR   = $(LIBS)/conn
SERIAL    = $(LIBS)/serial
SHELLDIR  = $(LIBS)/dvxshell
PROXYDIR  = $(ROOT)/src/tools/proxy
SERTEST   = $(ROOT)/src/test/serial
SHELLTEST = $(ROOT)/src/test/shell
FILEOPS   = $(LIBS)/fileops
LRZSZ_BIN = $(ROOT)/toolchains/lrzsz/bin
OBJDIR    = $(DVXTEST_BINDIR)/terminal
APPS_SO   = $(DVXTEST_OBJDIR)/apps

# Plain library tests need only the library headers; the app test uses
# the dvxtest and shell includes as well.
CFLAGS     = $(HOST_CFLAGS) -I$(LIBS) -I$(XFERDIR) -I$(CONNDIR) -I$(LIBS)/libdvx -I$(LIBS)/libdvx/platform -I$(LIBS)/libdvx/thirdparty -I$(ROOT)/src/widgets/kpunch
APP_CFLAGS = $(DVXTEST_CFLAGS) -I$(LIBS) -I$(SHELLDIR) -I$(DVXTEST_BASICDIR) -DDVXTEST_APPS_DIR='"$(APPS_SO)"' -DDVXTEST_FIXTURES_DIR='"$(OBJDIR)"' -DSHELLTEST_BASSTUB_SO='"$(DVXTEST_BASSTUB_SO)"' -DSHELLTEST_BASCOMP='"$(DVXTEST_BASCOMP)"'
SHIM       = -include $(SERTEST)/loopShim.h

XFER_OBJS  = $(OBJDIR)/xfer.o $(OBJDIR)/xferZmodem.o
# The connection library (Telnet and TCP use the host's own sockets), and
# the BASIC faces of both libraries (these need libdvx)
CONN_OBJS  = $(OBJDIR)/conn.o $(OBJDIR)/connTelnet.o
BAS_OBJS   = $(OBJDIR)/connBas.o $(OBJDIR)/xferBas.o
# The file operations library (the Terminal makes its download folder)
FILEOPS_OBJS = $(patsubst $(FILEOPS)/%.c,$(OBJDIR)/fileops/%.o,$(wildcard $(FILEOPS)/*.c))
# The serial stack over the loopback shim (clock() redirected), and over
# the proxy's socket shim.
LOOP_OBJS  = $(OBJDIR)/loopShim.o $(OBJDIR)/loopPacket.o $(OBJDIR)/loopSecLink.o $(OBJDIR)/secHash.o $(OBJDIR)/security.o
SOCK_OBJS  = $(OBJDIR)/sockShim.o $(OBJDIR)/sockPacket.o $(OBJDIR)/sockSecLink.o $(OBJDIR)/secHash.o $(OBJDIR)/security.o $(OBJDIR)/proxyMain.o
# Every shell source (the app test runs the real shell).
SHELL_OBJS = $(patsubst $(SHELLDIR)/%.c,$(OBJDIR)/shell/%.o,$(wildcard $(SHELLDIR)/*.c)) $(OBJDIR)/shell/shellFixture.o

BINS = $(OBJDIR)/testXfer $(OBJDIR)/testLrzsz $(OBJDIR)/testConn $(OBJDIR)/testConnProxy $(OBJDIR)/testTelnet $(OBJDIR)/testTermApp

.PHONY: all build run clean

all: run

build: $(BINS)

# Each binary runs in the object directory (it makes its temp folders
# there).  The app test needs the widget shared objects, the BASIC stub
# and the BASIC compiler.
run: build
	cd $(OBJDIR) && ASAN_OPTIONS=detect_leaks=1 ./testXfer
	cd $(OBJDIR) && ASAN_OPTIONS=detect_leaks=1 ./testLrzsz
	cd $(OBJDIR) && ASAN_OPTIONS=detect_leaks=1 ./testConn
	cd $(OBJDIR) && ASAN_OPTIONS=detect_leaks=1 ./testConnProxy
	cd $(OBJDIR) && ASAN_OPTIONS=detect_leaks=1 ./testTelnet
	cd $(OBJDIR) && ASAN_OPTIONS=detect_leaks=1:detect_odr_violation=0 ./testTermApp

$(OBJDIR)/testXfer: testXfer.c $(XFER_OBJS) $(DVXTEST_LIBDVX_A) $(DVX_MAKEFILES) | dvxtest-libs
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -o $@ testXfer.c $(XFER_OBJS) $(HOST_LDFLAGS) $(DVXTEST_LIBDVX_A) -ldl -lm

$(OBJDIR)/testLrzsz: testLrzsz.c $(XFER_OBJS) $(DVXTEST_LIBDVX_A) $(DVX_MAKEFILES) | dvxtest-libs
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -DLRZSZ_BIN='"$(LRZSZ_BIN)"' -o $@ testLrzsz.c $(XFER_OBJS) $(HOST_LDFLAGS) $(DVXTEST_LIBDVX_A) -ldl -lm

$(OBJDIR)/testConn: testConn.c $(CONN_OBJS) $(BAS_OBJS) $(LOOP_OBJS) $(XFER_OBJS) $(DVXTEST_LIBDVX_A) $(DVX_MAKEFILES) | dvxtest-libs
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -I$(SERIAL) -o $@ testConn.c $(CONN_OBJS) $(BAS_OBJS) $(LOOP_OBJS) $(XFER_OBJS) $(HOST_LDFLAGS) -rdynamic $(DVXTEST_LIBDVX_A) -ldl -lm

$(OBJDIR)/testConnProxy: testConnProxy.c $(CONN_OBJS) $(SOCK_OBJS) $(XFER_OBJS) $(DVXTEST_LIBDVX_A) $(DVX_MAKEFILES) | dvxtest-libs
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -I$(SERIAL) -I$(PROXYDIR) -o $@ testConnProxy.c $(CONN_OBJS) $(SOCK_OBJS) $(XFER_OBJS) $(HOST_LDFLAGS) $(DVXTEST_LIBDVX_A) -ldl -lm

$(OBJDIR)/testTelnet: testTelnet.c $(CONN_OBJS) $(LOOP_OBJS) $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -o $@ testTelnet.c $(CONN_OBJS) $(LOOP_OBJS) $(HOST_LDFLAGS)

# The BASIC stub resolves the runtime and the libraries from the
# executable (-rdynamic).
$(OBJDIR)/testTermApp: testTermApp.c $(SHELL_OBJS) $(CONN_OBJS) $(BAS_OBJS) $(FILEOPS_OBJS) $(LOOP_OBJS) $(XFER_OBJS) $(DVXTEST_ARCHIVES) $(DVXTEST_TASKS_A) $(DVXTEST_BASRT_A) $(DVXTEST_BASSTUB_SO) $(DVX_MAKEFILES) | dvxtest-libs dvxtest-apps dvxtest-bascomp
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(APP_CFLAGS) -I$(SHELLTEST) -o $@ testTermApp.c $(SHELL_OBJS) $(CONN_OBJS) $(BAS_OBJS) $(FILEOPS_OBJS) $(LOOP_OBJS) $(XFER_OBJS) $(DVXTEST_LDFLAGS) -Wl,--whole-archive $(DVXTEST_BASRT_A) $(DVXTEST_LIBDVX_A) $(DVXTEST_TASKS_A) $(DVXTEST_LIB) -Wl,--no-whole-archive -ldl -lm

$(OBJDIR)/xfer.o: $(XFERDIR)/xfer.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/xferBas.o: $(XFERDIR)/xferBas.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/xferZmodem.o: $(XFERDIR)/xferZmodem.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/conn.o: $(CONNDIR)/conn.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/connBas.o: $(CONNDIR)/connBas.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/connTelnet.o: $(CONNDIR)/connTelnet.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/fileops/%.o: $(FILEOPS)/%.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)/fileops
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/loopShim.o: $(SERTEST)/loopShim.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/loopPacket.o: $(SERIAL)/packet/packet.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) $(SHIM) -c -o $@ $<

$(OBJDIR)/loopSecLink.o: $(SERIAL)/seclink/secLink.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) $(SHIM) -c -o $@ $<

$(OBJDIR)/secHash.o: $(SERIAL)/security/secHash.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/security.o: $(SERIAL)/security/security.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/sockShim.o: $(PROXYDIR)/sockShim.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/sockPacket.o: $(SERIAL)/packet/packet.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -include $(PROXYDIR)/sockShim.h -c -o $@ $<

$(OBJDIR)/sockSecLink.o: $(SERIAL)/seclink/secLink.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -include $(PROXYDIR)/sockShim.h -c -o $@ $<

$(OBJDIR)/proxyMain.o: $(PROXYDIR)/proxy.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)
	$(HOSTCC) $(CFLAGS) -Dmain=proxyMain -c -o $@ $<

$(OBJDIR)/shell/%.o: $(SHELLDIR)/%.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)/shell
	$(HOSTCC) $(APP_CFLAGS) -c -o $@ $<

$(OBJDIR)/shell/shellFixture.o: $(SHELLTEST)/shellFixture.c $(DVX_MAKEFILES)
	@mkdir -p $(OBJDIR)/shell
	$(HOSTCC) $(APP_CFLAGS) -I$(SHELLTEST) -c -o $@ $<

-include $(wildcard $(OBJDIR)/*.d $(OBJDIR)/shell/*.d $(OBJDIR)/fileops/*.d)

clean:
	rm -rf $(OBJDIR)
