diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index a5013df09..0557b79cc 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -24,7 +24,7 @@ jobs: - name: Bootstrap project run: ./bootstrap.sh - name: Configure project - run: ./configure --enable-debug + run: ./configure --enable-debug=yes --with-csv-module=yes --with-psql-module=yes - name: Compile project run: make - name: Run acceptance tests diff --git a/.github/workflows/c.yml b/.github/workflows/c.yml index 50ceec553..7019fe75c 100644 --- a/.github/workflows/c.yml +++ b/.github/workflows/c.yml @@ -20,7 +20,7 @@ jobs: - name: Bootstrap project run: ./bootstrap.sh - name: Configure project with gcc compiler - run: ./configure CC=gcc --enable-debug + run: ./configure CC=gcc --enable-debug=yes --with-csv-module=yes --with-psql-module=yes - name: Compile project run: make - name: Run tests diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml index 0eaf584d6..9177f90fc 100644 --- a/.github/workflows/cpp.yml +++ b/.github/workflows/cpp.yml @@ -20,7 +20,7 @@ jobs: - name: Bootstrap project run: ./bootstrap.sh - name: Configure project with g++ compiler - run: ./configure CC=g++ --enable-debug + run: ./configure CC=g++ --enable-debug=yes --with-psql-module=yes --with-csv-module=yes - name: Compile project run: make - name: Run tests diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 9bd430d7f..8e3425d5f 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -24,7 +24,7 @@ jobs: - name: Bootstrap project run: ./bootstrap.sh - name: Configure project - run: ./configure --enable-debug + run: ./configure --enable-debug=yes --with-csv-module=yes --with-psql-module=yes - name: Compile project run: make - name: Run pytest diff --git a/bin/main.c b/bin/main.c index e21c90335..6db34f7a3 100644 --- a/bin/main.c +++ b/bin/main.c @@ -11,10 +11,13 @@ #include "common.h" #include "diff.h" #include "history.h" -#include "libpq-fe.h" #include "patch.h" #include "rebase.h" +#ifdef HAVE_LIBPQ +#include "libpq-fe.h" +#endif // HAVE_LIBPQ + enum OPTION_VALUE { OPTION_WORKDIR = 1, OPTION_INFORM, @@ -95,7 +98,9 @@ int main(int argc, char *argv[]) { * doesn't find any references to it. Adding a reference to one of the symbols * here, seems to fix the issue. */ +#ifdef HAVE_LIBPQ PQlibVersion(); +#endif // HAVE_LIBPQ int opt; while ((opt = getopt_long(argc, argv, "+", OPTIONS, NULL)) != -1) { diff --git a/configure.ac b/configure.ac index 922eb3ac0..0ab3c6019 100644 --- a/configure.ac +++ b/configure.ac @@ -35,9 +35,13 @@ AC_CHECK_FUNCS([memmove memset strchr strspn strdup strerror strndup mkdir rmdir # Configure arguments. AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable debugging]), [debug=$enableval], [debug=no]) +AC_ARG_WITH([psql-module], AS_HELP_STRING([--with-psql-module], [build PostgreSQL module])) +AC_ARG_WITH([csv-module], AS_HELP_STRING([--with-csv-module], [build CSV module])) # Automake conditionals. AM_CONDITIONAL([NDEBUG], [test x"$debug" = x"no"]) +AM_CONDITIONAL([PSQL_MODULE], [test x"$psql-module" = x"yes"]) +AM_CONDITIONAL([CSV_MODULE], [test x"$csv-module" = x"yes"]) # Config constants. AC_DEFINE([LCH_DEFAULT_MAX_CHAIN_LENGTH], 2048, [Default max chain length used in block garbage collector]) @@ -49,7 +53,13 @@ AC_DEFINE([LCH_LIST_CAPACITY], 256, [Initial list capacity allocated by leech]) # pkg-check modules. PKG_CHECK_MODULES([CHECK], [check]) -PKG_CHECK_MODULES([PSQL], [libpq]) +AS_IF([test "x$with_psql_module" = "xyes"], [ + PKG_CHECK_MODULES([PSQL], [libpq], + [AC_DEFINE([HAVE_LIBPQ], [1], + [Define to 1 if you have the header file.] + ) + ]) +]) AC_CONFIG_FILES([Makefile lib/Makefile bin/Makefile tests/Makefile]) AC_OUTPUT diff --git a/lib/Makefile.am b/lib/Makefile.am index e7dc01e39..6a1c4731f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -3,15 +3,20 @@ AM_CPPFLAGS = -include config.h include_HEADERS = $(top_builddir)/lib/leech.h lib_LTLIBRARIES = libleech.la -pkglib_LTLIBRARIES = leech_csv.la leech_psql.la - -leech_csv_la_SOURCES = leech_csv.c -leech_csv_la_LDFLAGS = -avoid-version -module -shared -export-dynamic - -leech_psql_la_SOURCES = leech_psql.c -leech_psql_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -leech_psql_la_CFLAGS = @PSQL_CFLAGS@ +pkglib_LTLIBRARIES = +if CSV_MODULE + pkglib_LTLIBRARIES += leech_csv.la + leech_csv_la_SOURCES = leech_csv.c + leech_csv_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +endif +if PSQL_MODULE + pkglib_LTLIBRARIES += leech_psql.la + leech_psql_la_SOURCES = leech_psql.c + leech_psql_la_LDFLAGS = -avoid-version -module -shared -export-dynamic + leech_psql_la_CFLAGS = @PSQL_CFLAGS@ +endif + libleech_la_SOURCES = leech.c \ block.h block.c \ buffer.h buffer.c \ diff --git a/lib/block.c b/lib/block.c index 25ca48f3b..3a7832b49 100644 --- a/lib/block.c +++ b/lib/block.c @@ -4,6 +4,7 @@ #include #include +#include "definitions.h" #include "files.h" #include "head.h" #include "logger.h" diff --git a/lib/buffer.h b/lib/buffer.h index 3e0c322b0..47b4e3afa 100644 --- a/lib/buffer.h +++ b/lib/buffer.h @@ -4,53 +4,11 @@ #include #include -typedef struct LCH_Buffer LCH_Buffer; +#include "leech.h" /** - * @brief create a byte buffer. - * @note buffer is always null terminated and must be freed with - * LCH_BufferDestroy. - * @return byte buffer. + * Put private LCH_Buffer functions here: */ -LCH_Buffer *LCH_BufferCreate(void); - -/** - * @brief append a byte to the buffer. - * @param[in] buffer buffer. - * @param[in] byte byte to append. - * @return false in case of error. - */ -bool LCH_BufferAppend(LCH_Buffer *buffer, char byte); - -/** - * @brief format- and print string to byte buffer. - * @note buffer capacity is expanded if need be. - * @param[in] buffer buffer. - * @param[in] format format string. - * @return false in case of failure. - */ -bool LCH_BufferPrintFormat(LCH_Buffer *buffer, const char *format, ...); - -/** - * @brief get length of buffer. - * @param[in] buffer buffer. - * @return length of buffer excluding the terminating null byte. - */ -size_t LCH_BufferLength(const LCH_Buffer *buffer); - -/** - * @brief destroy buffer. - * @note noop if buffer is NULL. - * @param[in] buffer buffer. - */ -void LCH_BufferDestroy(void *buffer); - -/** - * @brief get buffer. - * @param [in] buffer buffer. - * @return pointer to internal buffer. - */ -const char *LCH_BufferData(const LCH_Buffer *buffer); /** * @brief allocate memory in buffer. @@ -93,40 +51,10 @@ bool LCH_BufferHexToBytes(LCH_Buffer *bytes, const LCH_Buffer *hex); */ bool LCH_BufferUnicodeToUTF8(LCH_Buffer *const buffer, const char *in); -void LCH_BufferChop(LCH_Buffer *const buffer, size_t offset); - -/** - * @brief Get pointer to internal buffer and destroy surrounding data structure. - * @param buffer Buffer. - * @return Pointer to internal char buffer. - * @note Returned buffer must be freed with free(3). If you don't want to - * destroy the surrounding data structure, you can use LCH_BufferData() - * instead. - */ -char *LCH_BufferToString(LCH_Buffer *buffer); - -/** - * @brief Create a buffer containing string. - * @param str String content of created buffer. - * @return Buffer containing string. - * @note String must be terminated by the NULL-byte. - */ -LCH_Buffer *LCH_BufferFromString(const char *str); - const LCH_Buffer *LCH_BufferStaticFromString(const char *str); -bool LCH_BufferReadFile(LCH_Buffer *buffer, const char *filename); - -bool LCH_BufferWriteFile(const LCH_Buffer *buffer, const char *filename); - void LCH_BufferTrim(LCH_Buffer *buffer, char ch); bool LCH_BufferAppendBuffer(LCH_Buffer *buffer, const LCH_Buffer *append); -bool LCH_BufferEqual(const LCH_Buffer *self, const LCH_Buffer *other); - -int LCH_BufferCompare(const LCH_Buffer *self, const LCH_Buffer *other); - -LCH_Buffer *LCH_BufferDuplicate(const LCH_Buffer *buffer); - #endif // _LEECH_BUFFER_H diff --git a/lib/definitions.h b/lib/definitions.h index 42b02f592..72b3124ba 100644 --- a/lib/definitions.h +++ b/lib/definitions.h @@ -19,7 +19,4 @@ #define LCH_PATH_SEP '/' #endif // _WIN32 -typedef int (*LCH_CompareFn)(const void *, const void *); -typedef void *(*LCH_DuplicateFn)(const void *); - #endif // _LEECH_DEFINITIONS_H diff --git a/lib/leech.c b/lib/leech.c index 79b6eb11a..df28d8e48 100644 --- a/lib/leech.c +++ b/lib/leech.c @@ -589,8 +589,7 @@ LCH_Buffer *LCH_Rebase(const char *const work_dir) { return buffer; } -static bool HistoryAppendRecord( - const LCH_Instance *const instance, +static bool HistoryAppendRecord(const LCH_Instance *const instance, const char *const table_id, const LCH_Json *const history, const char *const block_id, @@ -650,8 +649,10 @@ static bool HistoryAppendRecord( return false; } - const LCH_TableInfo *const table_info = LCH_InstanceGetTable(instance, table_id); - const LCH_List *const subsidiary_names = LCH_TableInfoGetSubsidiaryFields(table_info); + const LCH_TableInfo *const table_info = + LCH_InstanceGetTable(instance, table_id); + const LCH_List *const subsidiary_names = + LCH_TableInfoGetSubsidiaryFields(table_info); const size_t num_fields = LCH_ListLength(subsidiary_fields); assert(num_fields == LCH_ListLength(subsidiary_names)); @@ -744,8 +745,8 @@ static bool HistoryFindRecord(const LCH_Instance *const instance, if (timestamp >= to) { // Continue without recording history (yet) - if (!HistoryFindRecord(instance, history, table_id, primary_key, parent_id, from, - to)) { + if (!HistoryFindRecord(instance, history, table_id, primary_key, parent_id, + from, to)) { LCH_JsonDestroy(block); return false; } @@ -768,7 +769,7 @@ static bool HistoryFindRecord(const LCH_Instance *const instance, return false; } - { // Skip tables that does not match table identifier + { // Skip tables that does not match table identifier const LCH_Buffer *const key = LCH_BufferStaticFromString("id"); const LCH_Buffer *const tid = LCH_JsonObjectGetString(delta, key); if (tid == NULL) { @@ -807,8 +808,8 @@ static bool HistoryFindRecord(const LCH_Instance *const instance, return false; } - if (!HistoryAppendRecord(instance, table_id, history, block_id, timestamp, "insert", - subsidiary_value)) { + if (!HistoryAppendRecord(instance, table_id, history, block_id, timestamp, + "insert", subsidiary_value)) { LCH_JsonDestroy(block); return false; } @@ -820,8 +821,8 @@ static bool HistoryFindRecord(const LCH_Instance *const instance, return false; } - if (!HistoryAppendRecord(instance, table_id, history, block_id, timestamp, "delete", - subsidiary_value)) { + if (!HistoryAppendRecord(instance, table_id, history, block_id, timestamp, + "delete", subsidiary_value)) { LCH_JsonDestroy(block); return false; } @@ -833,15 +834,16 @@ static bool HistoryFindRecord(const LCH_Instance *const instance, return false; } - if (!HistoryAppendRecord(instance, table_id, history, block_id, timestamp, "update", - subsidiary_value)) { + if (!HistoryAppendRecord(instance, table_id, history, block_id, timestamp, + "update", subsidiary_value)) { LCH_JsonDestroy(block); return false; } } } - if (!HistoryFindRecord(instance, history, table_id, primary_key, parent_id, from, to)) { + if (!HistoryFindRecord(instance, history, table_id, primary_key, parent_id, + from, to)) { LCH_JsonDestroy(block); return false; } @@ -884,7 +886,8 @@ LCH_Buffer *LCH_History(const char *const work_dir, const char *const table_id, { const LCH_TableInfo *const table_info = LCH_InstanceGetTable(instance, table_id); - const LCH_List *const primary_names = LCH_TableInfoGetPrimaryFields(table_info); + const LCH_List *const primary_names = + LCH_TableInfoGetPrimaryFields(table_info); LCH_Json *const primary = LCH_JsonObjectCreate(); if (primary == NULL) { @@ -968,7 +971,8 @@ LCH_Buffer *LCH_History(const char *const work_dir, const char *const table_id, return NULL; } - if (!HistoryFindRecord(instance, history, table_id, primary, block_id, from, to)) { + if (!HistoryFindRecord(instance, history, table_id, primary, block_id, from, + to)) { LCH_BufferDestroy(primary); free(block_id); LCH_BufferDestroy(response); diff --git a/lib/leech.h b/lib/leech.h index 74340496b..44171858e 100644 --- a/lib/leech.h +++ b/lib/leech.h @@ -4,8 +4,170 @@ #include #include -#include "buffer.h" -#include "list.h" +/****************************************************************************/ +/* Misc */ +/****************************************************************************/ + +typedef int (*LCH_CompareFn)(const void *, const void *); +typedef void *(*LCH_DuplicateFn)(const void *); + +/****************************************************************************/ +/* Buffer */ +/****************************************************************************/ + +typedef struct LCH_Buffer LCH_Buffer; + +/** + * @brief create a byte buffer. + * @note buffer is always null terminated and must be freed with + * LCH_BufferDestroy. + * @return byte buffer. + */ +LCH_Buffer *LCH_BufferCreate(void); + +/** + * @brief append a byte to the buffer. + * @param[in] buffer buffer. + * @param[in] byte byte to append. + * @return false in case of error. + */ +bool LCH_BufferAppend(LCH_Buffer *buffer, char byte); + +/** + * @brief format- and print string to byte buffer. + * @note buffer capacity is expanded if need be. + * @param[in] buffer buffer. + * @param[in] format format string. + * @return false in case of failure. + */ +bool LCH_BufferPrintFormat(LCH_Buffer *buffer, const char *format, ...); + +/** + * @brief get length of buffer. + * @param[in] buffer buffer. + * @return length of buffer excluding the terminating null byte. + */ +size_t LCH_BufferLength(const LCH_Buffer *buffer); + +/** + * @brief get buffer. + * @param [in] buffer buffer. + * @return pointer to internal buffer. + */ +const char *LCH_BufferData(const LCH_Buffer *buffer); + +void LCH_BufferChop(LCH_Buffer *const buffer, size_t offset); + +/** + * @brief Get pointer to internal buffer and destroy surrounding data structure. + * @param buffer Buffer. + * @return Pointer to internal char buffer. + * @note Returned buffer must be freed with free(3). If you don't want to + * destroy the surrounding data structure, you can use LCH_BufferData() + * instead. + */ +char *LCH_BufferToString(LCH_Buffer *buffer); + +/** + * @brief Create a buffer containing string. + * @param str String content of created buffer. + * @return Buffer containing string. + * @note String must be terminated by the NULL-byte. + */ +LCH_Buffer *LCH_BufferFromString(const char *str); + +/** + * @brief destroy buffer. + * @note noop if buffer is NULL. + * @param[in] buffer buffer. + */ +void LCH_BufferDestroy(void *buffer); + +bool LCH_BufferEqual(const LCH_Buffer *self, const LCH_Buffer *other); + +int LCH_BufferCompare(const LCH_Buffer *self, const LCH_Buffer *other); + +LCH_Buffer *LCH_BufferDuplicate(const LCH_Buffer *buffer); + +bool LCH_BufferReadFile(LCH_Buffer *buffer, const char *filename); + +bool LCH_BufferWriteFile(const LCH_Buffer *buffer, const char *filename); + +/****************************************************************************/ +/* List */ +/****************************************************************************/ + +typedef struct LCH_List LCH_List; + +/** + * Create a list. + * The list is allocated on the heap and must be freed with `LCH_ListDestroy`. + * @return pointer to list. + */ +LCH_List *LCH_ListCreate(void); + +/** + * Get number of items in a list. + * @param[in] list pointer to list. + * @return length of list. + */ +size_t LCH_ListLength(const LCH_List *list); + +/** + * Get list item. + * @param[in] list pointer to list. + * @param[in] index index of item. + * @return data pointer. + */ +void *LCH_ListGet(const LCH_List *list, size_t index); + +/** + * Append value to a list. + * @param[in] list pointer to dict. + * @param[in] value data pointer. + * @param[in] destroy data destroy function. + * @return true if success. + */ +bool LCH_ListAppend(LCH_List *list, void *value, void (*destroy)(void *)); + +/** + * Destroy list and contents. + * @param[in] list pointer to list. + */ +void LCH_ListDestroy(void *list); + +/** + * Assing value to list item at index. + * @param[in] list pointer to list. + * @param[in] index index of item. + * @param[in] value value to assign. + */ +void LCH_ListSet(LCH_List *list, size_t index, void *value, + void (*destroy)(void *)); + +/** + * Get index of first occurance of value in list. + * @param[in] list pointer to list. + * @param[in] value value to find. + * @param[in] compare comparison function. + */ +size_t LCH_ListIndex(const LCH_List *list, const void *value, + LCH_CompareFn compare); + +/** + * Sort list. + * @param[in] list pointer to list. + * @param[in] compare comparison function. + */ +void LCH_ListSort(LCH_List *const list, LCH_CompareFn compare); + +void *LCH_ListRemove(LCH_List *list, size_t index); + +LCH_List *LCH_ListCopy(const LCH_List *list, LCH_DuplicateFn duplicate_fn, + void (*destroy)(void *)); + +bool LCH_ListInsert(LCH_List *list, size_t index, void *value, + void (*destroy)(void *)); /****************************************************************************/ /* Debug Messenger */ @@ -23,6 +185,10 @@ void LCH_LoggerSeveritySet(unsigned char severity); void LCH_LoggerCallbackSet(LCH_LoggerCallbackFn callback); +/****************************************************************************/ +/* Main Interface */ +/****************************************************************************/ + bool LCH_Commit(const char *work_dir); LCH_Buffer *LCH_Diff(const char *work_dir, const char *block_id); diff --git a/lib/list.h b/lib/list.h index 02bdb32d8..fb407c10a 100644 --- a/lib/list.h +++ b/lib/list.h @@ -4,78 +4,10 @@ #include #include -#include "definitions.h" - -typedef struct LCH_List LCH_List; - -/** - * Create a list. - * The list is allocated on the heap and must be freed with `LCH_ListDestroy`. - * @return pointer to list. - */ -LCH_List *LCH_ListCreate(void); - -/** - * Get number of items in a list. - * @param[in] list pointer to list. - * @return length of list. - */ -size_t LCH_ListLength(const LCH_List *list); - -/** - * Get list item. - * @param[in] list pointer to list. - * @param[in] index index of item. - * @return data pointer. - */ -void *LCH_ListGet(const LCH_List *list, size_t index); - -/** - * Append value to a list. - * @param[in] list pointer to dict. - * @param[in] value data pointer. - * @param[in] destroy data destroy function. - * @return true if success. - */ -bool LCH_ListAppend(LCH_List *list, void *value, void (*destroy)(void *)); +#include "leech.h" /** - * Destroy list and contents. - * @param[in] list pointer to list. + * Put private LCH_List functions here: */ -void LCH_ListDestroy(void *list); - -/** - * Assing value to list item at index. - * @param[in] list pointer to list. - * @param[in] index index of item. - * @param[in] value value to assign. - */ -void LCH_ListSet(LCH_List *list, size_t index, void *value, - void (*destroy)(void *)); - -/** - * Get index of first occurance of value in list. - * @param[in] list pointer to list. - * @param[in] value value to find. - * @param[in] compare comparison function. - */ -size_t LCH_ListIndex(const LCH_List *list, const void *value, - LCH_CompareFn compare); - -/** - * Sort list. - * @param[in] list pointer to list. - * @param[in] compare comparison function. - */ -void LCH_ListSort(LCH_List *const list, LCH_CompareFn compare); - -void *LCH_ListRemove(LCH_List *list, size_t index); - -LCH_List *LCH_ListCopy(const LCH_List *list, LCH_DuplicateFn duplicate_fn, - void (*destroy)(void *)); - -bool LCH_ListInsert(LCH_List *list, size_t index, void *value, - void (*destroy)(void *)); #endif // _LEECH_LIST_H diff --git a/lib/string_lib.c b/lib/string_lib.c index 914231c92..66b3c6cdc 100644 --- a/lib/string_lib.c +++ b/lib/string_lib.c @@ -7,6 +7,7 @@ #include #include "buffer.h" +#include "definitions.h" #include "logger.h" /******************************************************************************/ diff --git a/lib/table.c b/lib/table.c index 106a8786a..17eba46c7 100644 --- a/lib/table.c +++ b/lib/table.c @@ -114,6 +114,8 @@ LCH_TableInfo *LCH_TableInfoLoad(const char *const identifer, return NULL; } + memset(info, 0, sizeof(LCH_TableInfo)); + info->identifier = LCH_StringDuplicate(identifer); if (info->identifier == NULL) { LCH_TableInfoDestroy(info); diff --git a/tests/Makefile.am b/tests/Makefile.am index f13e935cd..cd04662d4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,5 +18,5 @@ unit_test_SOURCES = unit_test.c \ check_table.c \ check_utils.c \ check_instance.c -unit_test_CFLAGS = @CHECK_CFLAGS@ @PSQL_CFLAGS@ -unit_test_LDADD = @CHECK_LIBS@ @PSQL_LIBS@ $(top_builddir)/lib/libleech.la +unit_test_CFLAGS = @CHECK_CFLAGS@ +unit_test_LDADD = @CHECK_LIBS@ $(top_builddir)/lib/libleech.la diff --git a/tests/check_dict.c b/tests/check_dict.c index e6fea4108..420bdc337 100644 --- a/tests/check_dict.c +++ b/tests/check_dict.c @@ -1,6 +1,7 @@ #include #include +#include "../lib/definitions.h" #include "../lib/dict.h" START_TEST(test_LCH_Dict) { diff --git a/tests/check_list.c b/tests/check_list.c index 784d3ed95..ae5add5cb 100644 --- a/tests/check_list.c +++ b/tests/check_list.c @@ -1,6 +1,7 @@ #include #include +#include "../lib/definitions.h" #include "../lib/list.h" START_TEST(test_LCH_List) { diff --git a/tests/test_leech.py b/tests/test_leech.py index b7ca9fc0c..2d0d9ba1b 100644 --- a/tests/test_leech.py +++ b/tests/test_leech.py @@ -1054,6 +1054,7 @@ def test_leech_churn(tmp_path): ] assert execute(command, True) == 0 + def test_leech_history(tmp_path): ########################################################################## # Create config @@ -1138,7 +1139,15 @@ def test_leech_history(tmp_path): time.sleep(1) history_path = os.path.join(tmp_path, "history.json") - command = [bin_path, "--debug", f"--workdir={tmp_path}", "history", "--table=BTL", "--primary=Paul,McCartney", f"--file={history_path}"] + command = [ + bin_path, + "--debug", + f"--workdir={tmp_path}", + "history", + "--table=BTL", + "--primary=Paul,McCartney", + f"--file={history_path}", + ] assert execute(command, True) == 0 with open(history_path, "r") as f: @@ -1150,7 +1159,17 @@ def test_leech_history(tmp_path): ts_from = history["history"][3]["timestamp"] ts_to = history["history"][0]["timestamp"] - command = [bin_path, "--debug", f"--workdir={tmp_path}", "history", "--table=BTL", "--primary=Paul,McCartney", f"--file={history_path}", f"--from={ts_from}", f"--to={ts_to}"] + command = [ + bin_path, + "--debug", + f"--workdir={tmp_path}", + "history", + "--table=BTL", + "--primary=Paul,McCartney", + f"--file={history_path}", + f"--from={ts_from}", + f"--to={ts_to}", + ] assert execute(command, True) == 0 with open(history_path, "r") as f: