core_sources = \ src/xmpp/contact.c src/xmpp/contact.h \ src/log.c src/common.c \ src/chatlog.c src/chatlog.h \ src/database.h src/database.c \ src/database_flatfile.c src/database_flatfile.h \ src/database_flatfile_parser.c \ src/database_flatfile_verify.c \ src/database_export.c \ src/log.h src/profanity.c src/common.h \ src/profanity.h src/xmpp/chat_session.c \ src/xmpp/chat_session.h src/xmpp/muc.c src/xmpp/muc.h src/xmpp/jid.h src/xmpp/jid.c \ src/xmpp/chat_state.h src/xmpp/chat_state.c \ src/xmpp/resource.c src/xmpp/resource.h \ src/xmpp/roster_list.c src/xmpp/roster_list.h \ src/xmpp/xmpp.h src/xmpp/capabilities.c src/xmpp/session.c \ src/xmpp/connection.h src/xmpp/connection.c \ src/xmpp/iq.c src/xmpp/message.c src/xmpp/presence.c src/xmpp/stanza.c \ src/xmpp/stanza.h src/xmpp/message.h src/xmpp/iq.h src/xmpp/presence.h \ src/xmpp/capabilities.h src/xmpp/session.h \ src/xmpp/roster.c src/xmpp/roster.h \ src/xmpp/bookmark.c src/xmpp/bookmark.h \ src/xmpp/blocking.c src/xmpp/blocking.h \ src/xmpp/form.c src/xmpp/form.h \ src/xmpp/avatar.c src/xmpp/avatar.h \ src/xmpp/ox.c src/xmpp/ox.h \ src/xmpp/vcard.c src/xmpp/vcard.h src/xmpp/vcard_funcs.h \ src/event/common.c src/event/common.h \ src/event/server_events.c src/event/server_events.h \ src/event/client_events.c src/event/client_events.h \ src/ui/ui.h src/ui/window.c src/ui/window.h src/ui/core.c \ src/ui/titlebar.c src/ui/statusbar.c src/ui/inputwin.c \ src/ui/titlebar.h src/ui/statusbar.h src/ui/inputwin.h \ src/ui/screen.h src/ui/screen.c \ src/ui/console.c src/ui/notifier.c \ src/ui/win_types.h \ src/ui/window_list.c src/ui/window_list.h \ src/ui/rosterwin.c src/ui/occupantswin.c \ src/ui/buffer.c src/ui/buffer.h \ src/ui/aiwin.c \ src/ui/chatwin.c \ src/ui/mucwin.c \ src/ui/privwin.c \ src/ui/confwin.c \ src/ui/xmlwin.c \ src/ui/vcardwin.c \ src/command/cmd_defs.h src/command/cmd_defs.c \ src/command/cmd_funcs.h src/command/cmd_funcs.c \ src/command/cmd_ac.h src/command/cmd_ac.c \ src/tools/parser.c \ src/tools/parser.h \ src/tools/http_common.c \ src/tools/http_common.h \ src/tools/http_upload.c \ src/tools/http_upload.h \ src/tools/http_download.c \ src/tools/http_download.h \ src/tools/plugin_download.c \ src/tools/plugin_download.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ src/tools/autocomplete.c src/tools/autocomplete.h \ src/tools/clipboard.c src/tools/clipboard.h \ src/tools/editor.c src/tools/editor.h \ src/config/files.c src/config/files.h \ src/config/conflists.c src/config/conflists.h \ src/config/accounts.c src/config/accounts.h \ src/config/tlscerts.c src/config/tlscerts.h \ src/config/account.c src/config/account.h \ src/config/preferences.c src/config/preferences.h \ src/config/theme.c src/config/theme.h \ src/config/color.c src/config/color.h \ src/config/scripts.c src/config/scripts.h \ src/config/cafile.c src/config/cafile.h \ src/plugins/plugins.h src/plugins/plugins.c \ src/plugins/api.h src/plugins/api.c \ src/plugins/callbacks.h src/plugins/callbacks.c \ src/plugins/autocompleters.c src/plugins/autocompleters.h \ src/plugins/themes.c src/plugins/themes.h \ src/plugins/settings.c src/plugins/settings.h \ src/plugins/disco.c src/plugins/disco.h \ src/ui/tray.h src/ui/tray.c \ src/ai/ai_client.h src/ai/ai_client.c unittest_sources = \ src/xmpp/contact.c src/xmpp/contact.h src/common.c \ src/log.h src/profanity.c src/common.h \ src/profanity.h src/xmpp/chat_session.c \ src/xmpp/chat_session.h src/xmpp/muc.c src/xmpp/muc.h src/xmpp/jid.h src/xmpp/jid.c \ src/xmpp/resource.c src/xmpp/resource.h \ src/xmpp/chat_state.h src/xmpp/chat_state.c \ src/xmpp/roster_list.c src/xmpp/roster_list.h \ src/xmpp/xmpp.h src/xmpp/form.c \ src/ai/ai_client.h src/ai/ai_client.c \ src/ui/ui.h \ src/otr/otr.h \ src/pgp/gpg.h \ src/pgp/ox.h \ src/omemo/omemo.h \ src/omemo/crypto.h \ src/omemo/store.h \ src/xmpp/vcard.h src/xmpp/vcard_funcs.h \ src/database_flatfile.h \ src/database_flatfile_parser.c \ src/command/cmd_defs.h src/command/cmd_defs.c \ src/command/cmd_funcs.h src/command/cmd_funcs.c \ src/command/cmd_ac.h src/command/cmd_ac.c \ src/tools/parser.c \ src/tools/parser.h \ src/tools/autocomplete.c src/tools/autocomplete.h \ src/tools/clipboard.c src/tools/clipboard.h \ src/tools/editor.c src/tools/editor.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ src/config/accounts.h \ src/config/account.c src/config/account.h \ src/config/files.c src/config/files.h \ src/config/tlscerts.c src/config/tlscerts.h \ src/config/preferences.c src/config/preferences.h \ src/config/theme.c src/config/theme.h \ src/config/color.c src/config/color.h \ src/config/scripts.c src/config/scripts.h \ src/config/conflists.c src/config/conflists.h \ src/plugins/plugins.h src/plugins/plugins.c \ src/plugins/api.h src/plugins/api.c \ src/plugins/callbacks.h src/plugins/callbacks.c \ src/plugins/autocompleters.c src/plugins/autocompleters.h \ src/plugins/themes.c src/plugins/themes.h \ src/plugins/settings.c src/plugins/settings.h \ src/plugins/disco.c src/plugins/disco.h \ src/ui/window_list.c src/ui/window_list.h \ src/event/common.c src/event/common.h \ src/event/server_events.c src/event/server_events.h \ src/event/client_events.c src/event/client_events.h \ src/ui/tray.h src/ui/tray.c \ tests/prof_cmocka.h \ tests/unittests/xmpp/stub_vcard.c \ tests/unittests/xmpp/stub_avatar.c \ tests/unittests/xmpp/stub_ox.c \ tests/unittests/xmpp/stub_xmpp.c \ tests/unittests/xmpp/stub_message.c \ tests/unittests/ui/stub_ui.c tests/unittests/ui/stub_ui.h \ tests/unittests/ui/stub_vcardwin.c \ tests/unittests/ui/stub_ai.c \ tests/unittests/log/stub_log.c \ tests/unittests/chatlog/stub_chatlog.c \ tests/unittests/database/stub_database.c \ tests/unittests/config/stub_accounts.c \ tests/unittests/config/stub_cafile.c \ tests/unittests/tools/stub_http_upload.c \ tests/unittests/tools/stub_http_download.c \ tests/unittests/tools/stub_aesgcm_download.c \ tests/unittests/tools/stub_plugin_download.c \ tests/unittests/helpers.c tests/unittests/helpers.h \ tests/unittests/xmpp/test_form.c tests/unittests/xmpp/test_form.h \ tests/unittests/test_common.c tests/unittests/test_common.h \ tests/unittests/tools/test_autocomplete.c tests/unittests/tools/test_autocomplete.h \ tests/unittests/xmpp/test_jid.c tests/unittests/xmpp/test_jid.h \ tests/unittests/tools/test_parser.c tests/unittests/tools/test_parser.h \ tests/unittests/xmpp/test_roster_list.c tests/unittests/xmpp/test_roster_list.h \ tests/unittests/xmpp/test_chat_session.c tests/unittests/xmpp/test_chat_session.h \ tests/unittests/xmpp/test_contact.c tests/unittests/xmpp/test_contact.h \ tests/unittests/config/test_preferences.c tests/unittests/config/test_preferences.h \ tests/unittests/event/test_server_events.c tests/unittests/event/test_server_events.h \ tests/unittests/xmpp/test_muc.c tests/unittests/xmpp/test_muc.h \ tests/unittests/command/test_cmd_presence.c tests/unittests/command/test_cmd_presence.h \ tests/unittests/command/test_cmd_alias.c tests/unittests/command/test_cmd_alias.h \ tests/unittests/command/test_cmd_connect.c tests/unittests/command/test_cmd_connect.h \ tests/unittests/command/test_cmd_rooms.c tests/unittests/command/test_cmd_rooms.h \ tests/unittests/command/test_cmd_account.c tests/unittests/command/test_cmd_account.h \ tests/unittests/command/test_cmd_sub.c tests/unittests/command/test_cmd_sub.h \ tests/unittests/command/test_cmd_bookmark.c tests/unittests/command/test_cmd_bookmark.h \ tests/unittests/command/test_cmd_otr.c tests/unittests/command/test_cmd_otr.h \ tests/unittests/command/test_cmd_pgp.c tests/unittests/command/test_cmd_pgp.h \ tests/unittests/command/test_cmd_join.c tests/unittests/command/test_cmd_join.h \ tests/unittests/command/test_cmd_roster.c tests/unittests/command/test_cmd_roster.h \ tests/unittests/command/test_cmd_disconnect.c tests/unittests/command/test_cmd_disconnect.h \ tests/unittests/command/test_cmd_ac.c tests/unittests/command/test_cmd_ac.h \ tests/unittests/plugins/test_callbacks.c tests/unittests/plugins/test_callbacks.h \ tests/unittests/plugins/test_plugins_disco.c tests/unittests/plugins/test_plugins_disco.h \ tests/unittests/test_forced_encryption.c tests/unittests/test_forced_encryption.h \ tests/unittests/test_ai_client.c tests/unittests/test_ai_client.h \ tests/unittests/test_database_export.c tests/unittests/test_database_export.h \ tests/unittests/test_database_stress.c tests/unittests/test_database_stress.h \ tests/unittests/unittests.c functionaltest_sources = \ tests/prof_cmocka.h \ tests/functionaltests/proftest.c tests/functionaltests/proftest.h \ tests/functionaltests/test_connect.c tests/functionaltests/test_connect.h \ tests/functionaltests/test_ping.c tests/functionaltests/test_ping.h \ tests/functionaltests/test_rooms.c tests/functionaltests/test_rooms.h \ tests/functionaltests/test_presence.c tests/functionaltests/test_presence.h \ tests/functionaltests/test_message.c tests/functionaltests/test_message.h \ tests/functionaltests/test_chat_session.c tests/functionaltests/test_chat_session.h \ tests/functionaltests/test_carbons.c tests/functionaltests/test_carbons.h \ tests/functionaltests/test_receipts.c tests/functionaltests/test_receipts.h \ tests/functionaltests/test_roster.c tests/functionaltests/test_roster.h \ tests/functionaltests/test_software.c tests/functionaltests/test_software.h \ tests/functionaltests/test_muc.c tests/functionaltests/test_muc.h \ tests/functionaltests/test_disconnect.c tests/functionaltests/test_disconnect.h \ tests/functionaltests/test_history.c tests/functionaltests/test_history.h \ tests/functionaltests/test_lastactivity.c tests/functionaltests/test_lastactivity.h \ tests/functionaltests/test_autoping.c tests/functionaltests/test_autoping.h \ tests/functionaltests/test_disco.c tests/functionaltests/test_disco.h \ tests/functionaltests/test_export_import.c tests/functionaltests/test_export_import.h \ tests/functionaltests/test_ai.c tests/functionaltests/test_ai.h \ tests/functionaltests/functionaltests.c main_source = src/main.c python_sources = \ src/plugins/python_plugins.h src/plugins/python_plugins.c \ src/plugins/python_api.h src/plugins/python_api.c c_sources = \ src/plugins/c_plugins.h src/plugins/c_plugins.c \ src/plugins/c_api.h src/plugins/c_api.c git_include = src/gitversion.h pgp_sources = \ src/pgp/gpg.h src/pgp/gpg.c \ src/pgp/ox.h src/pgp/ox.c pgp_unittest_sources = \ tests/unittests/pgp/stub_gpg.c \ tests/unittests/pgp/stub_ox.c otr4_sources = \ src/otr/otrlib.h src/otr/otrlibv4.c src/otr/otr.h src/otr/otr.c omemo_sources = \ src/omemo/omemo.h src/omemo/omemo.c src/omemo/crypto.h src/omemo/crypto.c \ src/omemo/store.h src/omemo/store.c src/xmpp/omemo.h src/xmpp/omemo.c \ src/tools/aesgcm_download.h src/tools/aesgcm_download.c omemo_unittest_sources = \ tests/unittests/omemo/stub_omemo.c if BUILD_PYTHON_API core_sources += $(python_sources) unittest_sources += $(python_sources) endif if BUILD_C_API core_sources += $(c_sources) unittest_sources += $(c_sources) endif otr_unittest_sources = \ tests/unittests/otr/stub_otr.c themes_sources = $(top_srcdir)/themes/* icons_sources = $(top_srcdir)/icons/* script_sources = bootstrap.sh man1_sources = $(wildcard $(top_srcdir)/docs/profanity*.1) if BUILD_PGP core_sources += $(pgp_sources) unittest_sources += $(pgp_unittest_sources) endif if BUILD_OTR unittest_sources += $(otr_unittest_sources) core_sources += $(otr4_sources) endif if BUILD_OMEMO core_sources += $(omemo_sources) unittest_sources += $(omemo_unittest_sources) endif sqlite_sources = src/database_sqlite.c if BUILD_SQLITE core_sources += $(sqlite_sources) endif all_c_sources = $(core_sources) $(unittest_sources) \ $(pgp_sources) $(pgp_unittest_sources) \ $(otr4_sources) $(otr_unittest_sources) \ $(omemo_sources) $(omemo_unittest_sources) \ $(c_sources) $(python_sources) \ $(main_source) AM_CFLAGS = @AM_CFLAGS@ -I$(srcdir)/src bin_PROGRAMS = profanity profanity_SOURCES = $(core_sources) $(main_source) if THEMES_INSTALL profanity_themesdir = @THEMES_PATH@ profanity_themes_DATA = $(themes_sources) endif if INCLUDE_GIT_VERSION BUILT_SOURCES = $(git_include) endif profanity_iconsdir = @ICONS_PATH@ profanity_icons_DATA = $(icons_sources) if BUILD_C_API lib_LTLIBRARIES = libprofanity.la libprofanity_la_LDFLAGS = -version-info 0:0:0 -shared -no-undefined libprofanity_la_SOURCES = src/plugins/profapi.c library_includedir=$(includedir) library_include_HEADERS = src/plugins/profapi.h endif TESTS = tests/unittests/unittests check_PROGRAMS = tests/unittests/unittests tests_unittests_unittests_CPPFLAGS = -I$(srcdir)/tests -I$(srcdir)/tests/unittests tests_unittests_unittests_SOURCES = $(unittest_sources) tests_unittests_unittests_LDADD = -lcmocka # Functional tests require libstabber. # They are only built when libstabber is available. # See: https://github.com/profanity-im/profanity/pull/1010 # https://github.com/profanity-im/stabber/issues/5 # # Note: We use forkpty() instead of libexpect for PTY handling. if HAVE_STABBER if HAVE_FORKPTY TESTS += tests/functionaltests/functionaltests check_PROGRAMS += tests/functionaltests/functionaltests tests_functionaltests_functionaltests_SOURCES = $(functionaltest_sources) tests_functionaltests_functionaltests_CPPFLAGS = -I$(srcdir)/tests tests_functionaltests_functionaltests_CFLAGS = $(AM_CFLAGS) tests_functionaltests_functionaltests_LDADD = -lcmocka -lstabber @FORKPTY_LIB@ # Parallel functional tests target (~3x faster than sequential) # Usage: make check-functional-parallel # To add more groups: increase FUNC_TEST_GROUPS and add group in functionaltests.c FUNC_TEST_GROUPS = 1 2 3 4 check-functional-parallel: tests/functionaltests/functionaltests @echo "Running functional tests in parallel ($(words $(FUNC_TEST_GROUPS)) groups)..." @mkdir -p $(builddir)/test-logs $(builddir)/test-files @pids=""; \ for g in $(FUNC_TEST_GROUPS); do \ ./tests/functionaltests/functionaltests $$g > $(builddir)/test-logs/group$$g.log 2>&1 & \ pids="$$pids $$!"; \ done; \ failed=0; i=1; \ for pid in $$pids; do \ wait $$pid || { echo "Group $$i FAILED"; cat $(builddir)/test-logs/group$$i.log; failed=1; }; \ i=$$((i + 1)); \ done; \ echo "=== Test Results Summary ==="; \ grep -E 'PASSED|FAILED|Running' $(builddir)/test-logs/group*.log || true; \ if [ $$failed -ne 0 ]; then echo "FUNCTIONAL TESTS FAILED"; exit 1; fi; \ echo "All functional test groups passed!" # Run functional tests with the flat-file database backend # Usage: make check-functional-flatfile check-functional-flatfile: tests/functionaltests/functionaltests @echo "Running functional tests with flat-file backend ($(words $(FUNC_TEST_GROUPS)) groups)..." @mkdir -p $(builddir)/test-logs $(builddir)/test-files @pids=""; \ for g in $(FUNC_TEST_GROUPS); do \ PROF_FLATFILE=1 ./tests/functionaltests/functionaltests $$g > $(builddir)/test-logs/group$$g-flatfile.log 2>&1 & \ pids="$$pids $$!"; \ done; \ failed=0; i=1; \ for pid in $$pids; do \ wait $$pid || { echo "Group $$i FAILED (flatfile)"; cat $(builddir)/test-logs/group$$i-flatfile.log; failed=1; }; \ i=$$((i + 1)); \ done; \ echo "=== Flat-file Test Results Summary ==="; \ grep -E 'PASSED|FAILED|Running' $(builddir)/test-logs/group*-flatfile.log || true; \ if [ $$failed -ne 0 ]; then echo "FLAT-FILE FUNCTIONAL TESTS FAILED"; exit 1; fi; \ echo "All flat-file functional test groups passed!" endif endif man1_MANS = $(man1_sources) # --------------------------------------------------------------------------- # Bench harness — synthetic database load tests. Not part of `make check`. # Build only when invoked via `make bench` / `make bench-quick`. # Sources live in tests/bench/. See tests/bench/README.md. bench_common_sources = \ tests/bench/bench_stubs.c \ tests/bench/bench_common.c tests/bench/bench_common.h \ tests/bench/bench_csv.c tests/bench/bench_csv.h \ src/database_flatfile.c src/database_flatfile.h \ src/database_flatfile_parser.c \ src/database_flatfile_verify.c \ src/common.c src/common.h # Sources needed only by the export/import bench (S7/S8). Pulls in the SQLite # backend, the cross-backend export/import code, and the dispatcher. bench_export_sources = \ src/database.c src/database.h \ src/database_sqlite.c \ src/database_export.c EXTRA_PROGRAMS = \ tests/bench/gen_history \ tests/bench/bench_runner \ tests/bench/bench_long_messages \ tests/bench/bench_failure_modes \ tests/bench/bench_export_import tests_bench_gen_history_SOURCES = tests/bench/gen_history.c $(bench_common_sources) tests_bench_gen_history_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/tests/bench tests_bench_gen_history_CFLAGS = $(AM_CFLAGS) tests_bench_gen_history_LDADD = tests_bench_bench_runner_SOURCES = tests/bench/bench_runner.c $(bench_common_sources) tests_bench_bench_runner_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/tests/bench tests_bench_bench_runner_CFLAGS = $(AM_CFLAGS) tests_bench_bench_runner_LDADD = tests_bench_bench_long_messages_SOURCES = tests/bench/bench_long_messages.c $(bench_common_sources) tests_bench_bench_long_messages_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/tests/bench tests_bench_bench_long_messages_CFLAGS = $(AM_CFLAGS) tests_bench_bench_long_messages_LDADD = tests_bench_bench_failure_modes_SOURCES = tests/bench/bench_failure_modes.c $(bench_common_sources) tests_bench_bench_failure_modes_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/tests/bench tests_bench_bench_failure_modes_CFLAGS = $(AM_CFLAGS) tests_bench_bench_failure_modes_LDADD = tests_bench_bench_export_import_SOURCES = tests/bench/bench_export_import.c \ $(bench_common_sources) $(bench_export_sources) tests_bench_bench_export_import_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/tests/bench tests_bench_bench_export_import_CFLAGS = $(AM_CFLAGS) tests_bench_bench_export_import_LDADD = # Volume control: BENCH_VOLUME={small|medium|max}. Default `small` is safe # even on tight disks (~5 MB). `max` is heavyweight — see README. BENCH_VOLUME ?= small BENCH_DATA_DIR ?= /tmp/cproof-bench-corpus BENCH_CSV ?= tests/bench/current.csv bench-build: tests/bench/gen_history tests/bench/bench_runner tests/bench/bench_long_messages tests/bench/bench_failure_modes tests/bench/bench_export_import # Resolve --lines / --years for the configured volume. bench-gen: bench-build @mkdir -p $(BENCH_DATA_DIR) @case "$(BENCH_VOLUME)" in \ small) L=10000; Y=1; P=mixed ;; \ medium) L=500000; Y=5; P=mixed ;; \ max) L=5000000; Y=10; P=long ;; \ *) echo "BENCH_VOLUME must be small|medium|max"; exit 2 ;; \ esac; \ echo "==> generating volume=$(BENCH_VOLUME) lines=$$L years=$$Y profile=$$P"; \ ./tests/bench/gen_history --lines=$$L --years=$$Y --msg-len-profile=$$P \ --lmc-rate=3 --mam-ooo-rate=0 --resources-per-contact=3 \ --output=$(BENCH_DATA_DIR) --seed=42 bench-run: bench-build @echo "==> running scenarios (csv=$(BENCH_CSV))" @BENCH_VOLUME=$(BENCH_VOLUME) BENCH_DATA_DIR=$(BENCH_DATA_DIR) \ ./tests/bench/bench_runner --data=$(BENCH_DATA_DIR) --csv=$(BENCH_CSV) @echo "==> CSV: $(BENCH_CSV)" @cat $(BENCH_CSV) bench: bench-gen bench-run bench-quick: @$(MAKE) bench BENCH_VOLUME=small # Long-message tests (L1–L14). Independent of corpus volume, uses its own tmp dir. bench-longmsg: bench-build @echo "==> long-message tests (csv=$(BENCH_CSV))" @./tests/bench/bench_long_messages \ --tmp=$(BENCH_DATA_DIR)-longmsg --csv=$(BENCH_CSV) @rm -rf $(BENCH_DATA_DIR)-longmsg # Failure-injection (F1–F15). Independent corpus, asserts behaviour on bad data. bench-failure: bench-build @echo "==> failure-injection tests (csv=$(BENCH_CSV))" @./tests/bench/bench_failure_modes \ --tmp=$(BENCH_DATA_DIR)-fail --csv=$(BENCH_CSV) @rm -rf $(BENCH_DATA_DIR)-fail # Export/import (S7/S8) pipeline. Independent corpus under BENCH_DATA_DIR-export. # Default scale: 100k rows (~5–30 s). Override with BENCH_PIPE_ROWS=N. BENCH_PIPE_ROWS ?= 100000 BENCH_PIPE_VOLUME ?= pipe$(BENCH_PIPE_ROWS) bench-export: bench-build @echo "==> S7 export pipeline ($(BENCH_PIPE_ROWS) rows, csv=$(BENCH_CSV))" @rm -rf $(BENCH_DATA_DIR)-export @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import seed --rows=$(BENCH_PIPE_ROWS) --account=bench@bench.example @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import export --account=bench@bench.example \ --csv=$(BENCH_CSV) --label=S7a_export_cold --volume=$(BENCH_PIPE_VOLUME) @echo " -- second pass (dedup hot path)" @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import export --account=bench@bench.example \ --csv=$(BENCH_CSV) --label=S7b_export_dedup --volume=$(BENCH_PIPE_VOLUME) @rm -rf $(BENCH_DATA_DIR)-export bench-import: bench-build @echo "==> S8 import pipeline ($(BENCH_PIPE_ROWS) rows, csv=$(BENCH_CSV))" @rm -rf $(BENCH_DATA_DIR)-export @# Seed account A, export it, then wipe its DB but keep flatlog. Import @# back into the same account — that way the to: header in flatfile @# matches the importing account so dedup works correctly. @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import seed --rows=$(BENCH_PIPE_ROWS) --account=bench@bench.example @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import export --account=bench@bench.example \ --csv=$(BENCH_CSV) --label=S7_seed_export --volume=$(BENCH_PIPE_VOLUME) @rm -f $(BENCH_DATA_DIR)-export/database/bench_at_bench.example/chatlog.db* @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import import --account=bench@bench.example \ --csv=$(BENCH_CSV) --label=S8a_import_cold --volume=$(BENCH_PIPE_VOLUME) @echo " -- second import (idempotency)" @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import import --account=bench@bench.example \ --csv=$(BENCH_CSV) --label=S8b_import_idempotent --volume=$(BENCH_PIPE_VOLUME) @rm -rf $(BENCH_DATA_DIR)-export # Full roundtrip with content diff at default volume. PASSes only if # every row in the rebuilt DB matches the source byte-for-byte. bench-roundtrip: bench-build @echo "==> S8e roundtrip+full diff ($(BENCH_PIPE_ROWS) rows, csv=$(BENCH_CSV))" @rm -rf $(BENCH_DATA_DIR)-export @BENCH_DATA_DIR=$(BENCH_DATA_DIR)-export \ ./tests/bench/bench_export_import roundtrip --rows=$(BENCH_PIPE_ROWS) \ --csv=$(BENCH_CSV) --label=S8e_roundtrip --volume=$(BENCH_PIPE_VOLUME) --full-diff @rm -rf $(BENCH_DATA_DIR)-export # Pipeline at medium volume (default BENCH_PIPE_ROWS=100k). bench-pipeline: bench-export bench-import bench-roundtrip # Pipeline at MAX volume — 1M rows. Heavy: ~5–10 min, ~500MB SQLite + ~500MB # flatfile + ~500MB second SQLite. Run only when you can afford the time # and the disk. Set BENCH_PIPE_ROWS_MAX to override (default 1_000_000). BENCH_PIPE_ROWS_MAX ?= 1000000 bench-pipeline-max: bench-build @echo "==> bench-pipeline-max: $(BENCH_PIPE_ROWS_MAX) rows (heavy!)" @$(MAKE) bench-export BENCH_PIPE_ROWS=$(BENCH_PIPE_ROWS_MAX) @$(MAKE) bench-import BENCH_PIPE_ROWS=$(BENCH_PIPE_ROWS_MAX) @$(MAKE) bench-roundtrip BENCH_PIPE_ROWS=$(BENCH_PIPE_ROWS_MAX) # S9: 200 contacts × 50k lines per contact = 10M lines distributed. bench-multicontact: bench-build @mkdir -p $(BENCH_DATA_DIR)-multi @echo "==> S9: 200 contacts x 5000 lines" @./tests/bench/gen_history --lines=1000000 --contacts=200 --years=3 \ --msg-len-profile=mixed --output=$(BENCH_DATA_DIR)-multi --seed=42 @BENCH_VOLUME=multicontact BENCH_DATA_DIR=$(BENCH_DATA_DIR)-multi \ ./tests/bench/bench_runner --data=$(BENCH_DATA_DIR)-multi --csv=$(BENCH_CSV) \ --scenarios=S4,S6 @rm -rf $(BENCH_DATA_DIR)-multi # S10: 30% LMC corrections. bench-lmc: bench-build @mkdir -p $(BENCH_DATA_DIR)-lmc @echo "==> S10: LMC-heavy corpus (30%% corrections)" @./tests/bench/gen_history --lines=100000 --years=2 --lmc-rate=30 \ --msg-len-profile=mixed --output=$(BENCH_DATA_DIR)-lmc --seed=42 @BENCH_VOLUME=lmc BENCH_DATA_DIR=$(BENCH_DATA_DIR)-lmc \ ./tests/bench/bench_runner --data=$(BENCH_DATA_DIR)-lmc --csv=$(BENCH_CSV) @rm -rf $(BENCH_DATA_DIR)-lmc # S11: 20% MAM out-of-order timestamps. bench-ooo: bench-build @mkdir -p $(BENCH_DATA_DIR)-ooo @echo "==> S11: MAM-OOO corpus (20%% out-of-order)" @./tests/bench/gen_history --lines=100000 --years=2 --mam-ooo-rate=20 \ --msg-len-profile=mixed --output=$(BENCH_DATA_DIR)-ooo --seed=42 @BENCH_VOLUME=ooo BENCH_DATA_DIR=$(BENCH_DATA_DIR)-ooo \ ./tests/bench/bench_runner --data=$(BENCH_DATA_DIR)-ooo --csv=$(BENCH_CSV) \ --scenarios=S6 @rm -rf $(BENCH_DATA_DIR)-ooo # Run everything: P1 scenarios + long messages + failure injection + multicontact + LMC + OOO. bench-full: bench bench-longmsg bench-failure bench-multicontact bench-lmc bench-ooo # Compare current.csv against baseline.csv and exit non-zero on regressions. BENCH_BASELINE ?= tests/bench/baseline.csv BENCH_THRESHOLD ?= 25 bench-compare: @python3 tests/bench/compare_baseline.py \ --baseline=$(BENCH_BASELINE) --current=$(BENCH_CSV) \ --threshold=$(BENCH_THRESHOLD) # Snapshot current.csv as the new baseline. Run this only after manually # reviewing that the numbers look healthy. bench-update-baseline: @cp $(BENCH_CSV) $(BENCH_BASELINE) @echo "baseline updated: $(BENCH_BASELINE)" bench-clean: rm -rf $(BENCH_DATA_DIR) $(BENCH_DATA_DIR)-longmsg $(BENCH_DATA_DIR)-fail \ $(BENCH_DATA_DIR)-multi $(BENCH_DATA_DIR)-lmc $(BENCH_DATA_DIR)-ooo \ $(BENCH_DATA_DIR)-export $(BENCH_CSV) .PHONY: bench bench-quick bench-build bench-gen bench-run bench-clean \ bench-longmsg bench-failure bench-multicontact bench-lmc bench-ooo \ bench-full bench-compare bench-update-baseline \ bench-export bench-import bench-roundtrip bench-pipeline bench-pipeline-max EXTRA_DIST = $(man1_sources) $(icons_sources) $(themes_sources) $(script_sources) profrc.example theme_template LICENSE.txt README.md CHANGELOG # Ship API documentation with `make dist` EXTRA_DIST += \ apidocs/c/c-prof.conf \ apidocs/c/gen.sh \ apidocs/c/profapi.h \ apidocs/c/profhooks.h \ apidocs/python/conf.py \ apidocs/python/gen.sh \ apidocs/python/index.rst \ apidocs/python/Makefile \ apidocs/python/src/plugin.py \ apidocs/python/src/prof.py # Bench harness sources (not built by default; see EXTRA_PROGRAMS above) EXTRA_DIST += \ tests/bench/README.md \ tests/bench/compare_baseline.py \ tests/bench/gen_history.c \ tests/bench/bench_runner.c \ tests/bench/bench_long_messages.c \ tests/bench/bench_failure_modes.c \ tests/bench/bench_export_import.c \ tests/bench/bench_stubs.c \ tests/bench/bench_common.c tests/bench/bench_common.h \ tests/bench/bench_csv.c tests/bench/bench_csv.h \ tests/bench/baseline.csv if INCLUDE_GIT_VERSION EXTRA_DIST += .git/HEAD .git/index $(git_include).in: .git/HEAD .git/index rm -f $@ echo "#ifndef PROF_GIT_BRANCH" >> $@ echo "#define PROF_GIT_BRANCH \"$(shell git rev-parse --symbolic-full-name --abbrev-ref HEAD)\"" >> $@ echo "#endif" >> $@ echo "#ifndef PROF_GIT_REVISION" >> $@ echo "#define PROF_GIT_REVISION \"$(shell git log --pretty=format:'%h' -n 1)\"" >> $@ echo "#endif" >> $@ # # Create $(git_include) atomically to catch possible race. The race can occur # when $(git_include) is generated in parallel with building of src/profanity.c. # So this hack allows to find and fix the problem earlier. # $(git_include): $(git_include).in cp $< $@ clean-local: rm -f $(git_include) $(git_include).in endif clean-functional-tests: rm -rf $(builddir)/test-files $(builddir)/test-logs .PHONY: my-prof.supp clean-functional-tests my-prof.supp: @sed '/^# AUTO-GENERATED START/q' prof.supp > $@ @printf "\n\n# glib\n" >> $@ @cat /usr/share/glib-2.0/valgrind/glib.supp >> $@ @printf "\n\n# Python\n" >> $@ @wget -O- https://raw.githubusercontent.com/python/cpython/refs/tags/v`python3 --version | cut -d' ' -f2`/Misc/valgrind-python.supp >> $@ @printf "\n\n# gtk\n" >> $@ @test -z "@GTK_VERSION@" || wget -O- https://raw.githubusercontent.com/GNOME/gtk/refs/tags/@GTK_VERSION@/gtk.supp >> $@ @printf "\n\n# more gtk\n" >> $@ @test -z "@GTK_VERSION@" || cat /usr/share/gtk-3.0/valgrind/gtk.supp >> $@ check-unit: tests/unittests/unittests tests/unittests/unittests @VALGRIND_CHECK_RULES@ VALGRIND_SUPPRESSIONS_FILES=$(srcdir)/prof.supp # Code coverage targets (requires --enable-coverage) coverage-clean: find . -name '*.gcda' -delete find . -name '*.gcno' -delete rm -rf coverage-html coverage.info coverage-report: check lcov --capture --directory . --output-file coverage.info --ignore-errors inconsistent lcov --remove coverage.info '/usr/*' '*/tests/*' --output-file coverage.info --ignore-errors inconsistent genhtml coverage.info --output-directory coverage-html @echo "Coverage report generated in coverage-html/index.html" .PHONY: coverage-clean coverage-report format: $(all_c_sources) clang-format -i $(all_c_sources) format-sources: $(core_sources) $(main_source) clang-format -i $^ spell: codespell doublecheck: format check spell