diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9fab07eb..d633d732 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -175,6 +175,18 @@ target_sources( ${ADVSS_SOURCE_DIR}/lib/variables/variable-spinbox.cpp ${ADVSS_SOURCE_DIR}/lib/variables/variable-string.cpp) +# --- macro-condition-file --- # + +target_include_directories(${PROJECT_NAME} + PRIVATE ${ADVSS_SOURCE_DIR}/plugins/base) + +target_sources( + ${PROJECT_NAME} + PRIVATE test-macro-condition-file.cpp + ${ADVSS_SOURCE_DIR}/plugins/base/macro-condition-file.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/file-selection.cpp + ${ADVSS_SOURCE_DIR}/lib/variables/variable-text-edit.cpp) + # --- Testing --- # enable_testing() diff --git a/tests/test-macro-condition-file.cpp b/tests/test-macro-condition-file.cpp new file mode 100644 index 00000000..495af16e --- /dev/null +++ b/tests/test-macro-condition-file.cpp @@ -0,0 +1,325 @@ +#include "catch.hpp" +#include "macro-condition-file.hpp" + +#include +#include +#include +#include +#include + +using advss::MacroConditionFile; + +// Write (or overwrite) a file with the given content. +static void writeFile(const QString &path, const QString &content) +{ + QFile f(path); + f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate); + QTextStream(&f) << content; +} + +// --------------------------------------------------------------------------- +// CONTENT_CHANGE +// --------------------------------------------------------------------------- + +TEST_CASE("CONTENT_CHANGE: first check does not trigger for non-empty file", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "hello world"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::CONTENT_CHANGE); + cond._file = path.toStdString(); + + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("CONTENT_CHANGE: first check does not trigger for empty file", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, ""); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::CONTENT_CHANGE); + cond._file = path.toStdString(); + + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("CONTENT_CHANGE: no trigger when content stays the same", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "same content"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::CONTENT_CHANGE); + cond._file = path.toStdString(); + + cond.CheckCondition(); // baseline + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("CONTENT_CHANGE: triggers when content changes", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "initial"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::CONTENT_CHANGE); + cond._file = path.toStdString(); + + cond.CheckCondition(); // baseline + writeFile(path, "changed"); + REQUIRE(cond.CheckCondition()); +} + +TEST_CASE("CONTENT_CHANGE: no trigger after content stabilizes", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "initial"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::CONTENT_CHANGE); + cond._file = path.toStdString(); + + cond.CheckCondition(); // baseline + writeFile(path, "changed"); + cond.CheckCondition(); // change detected + REQUIRE_FALSE(cond.CheckCondition()); // same content again +} + +TEST_CASE("CONTENT_CHANGE: returns false when file cannot be opened", + "[macro-condition-file]") +{ + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::CONTENT_CHANGE); + cond._file = "/nonexistent/path/to/file.txt"; + + REQUIRE_FALSE(cond.CheckCondition()); +} + +// --------------------------------------------------------------------------- +// DATE_CHANGE +// --------------------------------------------------------------------------- + +TEST_CASE("DATE_CHANGE: first check does not trigger", "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "content"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::DATE_CHANGE); + cond._file = path.toStdString(); + + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("DATE_CHANGE: no trigger when modification date stays the same", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "content"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::DATE_CHANGE); + cond._file = path.toStdString(); + + cond.CheckCondition(); // baseline + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("DATE_CHANGE: triggers when modification date changes", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "content"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::DATE_CHANGE); + cond._file = path.toStdString(); + + cond.CheckCondition(); // baseline + + // Explicitly set the modification time to a known future value so the + // test is not sensitive to filesystem mtime resolution. + QFile f(path); + f.open(QIODevice::ReadWrite); + f.setFileTime(QDateTime::currentDateTime().addSecs(10), + QFileDevice::FileModificationTime); + f.close(); + + REQUIRE(cond.CheckCondition()); +} + +// --------------------------------------------------------------------------- +// MATCH +// --------------------------------------------------------------------------- + +TEST_CASE("MATCH: returns true when file content matches text", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "hello"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::MATCH); + cond._file = path.toStdString(); + cond._text = "hello"; + + REQUIRE(cond.CheckCondition()); +} + +TEST_CASE("MATCH: returns false when file content does not match text", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "hello"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::MATCH); + cond._file = path.toStdString(); + cond._text = "world"; + + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("MATCH: returns false when file cannot be opened", + "[macro-condition-file]") +{ + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::MATCH); + cond._file = "/nonexistent/path/to/file.txt"; + cond._text = "anything"; + + REQUIRE_FALSE(cond.CheckCondition()); +} + +TEST_CASE("MATCH: regex enabled matches file content against pattern", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "hello world"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::MATCH); + cond._file = path.toStdString(); + cond._text = "h.*d"; // matches "hello world" as a regex + cond._regex.SetEnabled(true); + + REQUIRE(cond.CheckCondition()); +} + +TEST_CASE("MATCH: regex disabled treats pattern as literal text", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, "hello world"); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::MATCH); + cond._file = path.toStdString(); + cond._text = "h.*d"; // does not literally appear in "hello world" + cond._regex.SetEnabled(false); + + REQUIRE_FALSE(cond.CheckCondition()); +} + +// --------------------------------------------------------------------------- +// EXISTS +// --------------------------------------------------------------------------- + +TEST_CASE("EXISTS: returns true for an existing file", "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, ""); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::EXISTS); + cond._file = path.toStdString(); + + REQUIRE(cond.CheckCondition()); +} + +TEST_CASE("EXISTS: returns false for a non-existing path", + "[macro-condition-file]") +{ + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::EXISTS); + cond._file = "/nonexistent/path/to/file.txt"; + + REQUIRE_FALSE(cond.CheckCondition()); +} + +// --------------------------------------------------------------------------- +// IS_FILE +// --------------------------------------------------------------------------- + +TEST_CASE("IS_FILE: returns true for a regular file", "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, ""); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::IS_FILE); + cond._file = path.toStdString(); + + REQUIRE(cond.CheckCondition()); +} + +TEST_CASE("IS_FILE: returns false for a directory", "[macro-condition-file]") +{ + QTemporaryDir dir; + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::IS_FILE); + cond._file = dir.path().toStdString(); + + REQUIRE_FALSE(cond.CheckCondition()); +} + +// --------------------------------------------------------------------------- +// IS_FOLDER +// --------------------------------------------------------------------------- + +TEST_CASE("IS_FOLDER: returns true for a directory", "[macro-condition-file]") +{ + QTemporaryDir dir; + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::IS_FOLDER); + cond._file = dir.path().toStdString(); + + REQUIRE(cond.CheckCondition()); +} + +TEST_CASE("IS_FOLDER: returns false for a regular file", + "[macro-condition-file]") +{ + QTemporaryDir dir; + QString path = dir.filePath("test.txt"); + writeFile(path, ""); + + MacroConditionFile cond(nullptr); + cond.SetCondition(MacroConditionFile::Condition::IS_FOLDER); + cond._file = path.toStdString(); + + REQUIRE_FALSE(cond.CheckCondition()); +}