diff --git a/CodeHandler.hpp b/CodeHandler.hpp
index 9b704b4..dfc86b9 100644
--- a/CodeHandler.hpp
+++ b/CodeHandler.hpp
@@ -30,9 +30,10 @@ class CodeHandler
public:
static QString processText(QString text);
+ static QString detectLanguage(const QString &line);
+
private:
static QString getCommentPrefix(const QString &language);
- static QString detectLanguage(const QString &line);
static const QRegularExpression &getFullCodeBlockRegex();
static const QRegularExpression &getPartialStartBlockRegex();
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6702761..e6291d8 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,4 +1,6 @@
add_executable(QodeAssistTest
+ ../CodeHandler.cpp
+ CodeHandlerTest.cpp
DocumentContextReaderTest.cpp
unittest_main.cpp
)
diff --git a/test/CodeHandlerTest.cpp b/test/CodeHandlerTest.cpp
new file mode 100644
index 0000000..570fc92
--- /dev/null
+++ b/test/CodeHandlerTest.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2025 Povilas Kanapickas
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#include "CodeHandler.hpp"
+#include "TestUtils.hpp"
+
+#include
+#include
+#include
+
+using namespace QodeAssist;
+
+class CodeHandlerTest : public QObject, public testing::Test
+{
+ // Tests are written in the fixture format with the expectation that CodeHandler will
+ // be expanded.
+ Q_OBJECT
+};
+
+TEST_F(CodeHandlerTest, testProcessTextWithCodeBlock)
+{
+ QString input = "This is a comment\n"
+ "```python\nprint('Hello, world!')\n```\n"
+ "Another comment";
+
+ EXPECT_EQ(
+ CodeHandler::processText(input),
+ "# This is a comment\n\nprint('Hello, world!')\n# Another comment\n\n");
+}
+
+TEST_F(CodeHandlerTest, testProcessTextWithMultipleCodeBlocks)
+{
+ QString input = "First comment\n```python\nprint('Block 1')\n"
+ "```\nMiddle comment\n"
+ "```cpp\ncout << \"Block 2\";\n```\n"
+ "Last comment";
+
+ EXPECT_EQ(
+ CodeHandler::processText(input),
+ "# First comment\n\n"
+ "print('Block 1')\n"
+ "// Middle comment\n\n"
+ "cout << \"Block 2\";\n"
+ "// Last comment\n\n");
+}
+
+TEST_F(CodeHandlerTest, testProcessTextWithEmptyLines)
+{
+ QString input = "Comment with empty line\n\n```python\nprint('Hello')\n```\n\nAnother comment";
+
+ EXPECT_EQ(
+ CodeHandler::processText(input),
+ "# Comment with empty line\n\n\nprint('Hello')\n\n# Another comment\n\n");
+}
+
+TEST_F(CodeHandlerTest, testProcessTextWithoutCodeBlock)
+{
+ QString input = "This is just a comment\nwith multiple lines";
+
+ EXPECT_EQ(
+ CodeHandler::processText(input), "// This is just a comment\n// with multiple lines\n\n");
+}
+
+TEST_F(CodeHandlerTest, testProcessTextWithDifferentLanguages)
+{
+ QString input = "Python code:\n"
+ "```python\nprint('Hello')\n```\n"
+ "JavaScript code:\n"
+ "```javascript\nconsole.log('Hello');\n```";
+
+ EXPECT_EQ(
+ CodeHandler::processText(input),
+ "# Python code:\n\nprint('Hello')\n"
+ "// JavaScript code:\n\nconsole.log('Hello');\n");
+}
+
+TEST_F(CodeHandlerTest, testDetectLanguage)
+{
+ EXPECT_EQ(CodeHandler::detectLanguage("```python"), "python");
+ EXPECT_EQ(CodeHandler::detectLanguage("```javascript"), "javascript");
+ EXPECT_EQ(CodeHandler::detectLanguage("```cpp"), "cpp");
+ EXPECT_EQ(CodeHandler::detectLanguage("``` ruby "), "ruby");
+ EXPECT_EQ(CodeHandler::detectLanguage("```"), "");
+ EXPECT_EQ(CodeHandler::detectLanguage("``` "), "");
+}
+TEST_F(CodeHandlerTest, testCommentPrefixForDifferentLanguages)
+{
+ struct TestCase
+ {
+ std::string language;
+ QString input;
+ QString expected;
+ };
+
+ std::vector testCases
+ = {{"python", "Comment\n```python\ncode\n```", "# Comment\n\ncode\n"},
+ {"cpp", "Comment\n```cpp\ncode\n```", "// Comment\n\ncode\n"},
+ {"ruby", "Comment\n```ruby\ncode\n```", "# Comment\n\ncode\n"},
+ {"lua", "Comment\n```lua\ncode\n```", "-- Comment\n\ncode\n"}};
+
+ for (const auto &testCase : testCases) {
+ EXPECT_EQ(CodeHandler::processText(testCase.input), testCase.expected)
+ << "Failed for language: " << testCase.language;
+ }
+}
+
+TEST_F(CodeHandlerTest, testEmptyInput)
+{
+ EXPECT_EQ(CodeHandler::processText(""), "\n\n");
+}
+
+TEST_F(CodeHandlerTest, testCodeBlockWithoutLanguage)
+{
+ QString input = "Comment\n```\ncode\n```";
+
+ EXPECT_EQ(CodeHandler::processText(input), "// Comment\n\ncode\n");
+}
+
+#include "CodeHandlerTest.moc"
diff --git a/test/DocumentContextReaderTest.cpp b/test/DocumentContextReaderTest.cpp
index 9e85e00..103560d 100644
--- a/test/DocumentContextReaderTest.cpp
+++ b/test/DocumentContextReaderTest.cpp
@@ -18,6 +18,7 @@
*/
#include "context/DocumentContextReader.hpp"
+#include "TestUtils.hpp"
#include
#include
@@ -27,62 +28,6 @@ using namespace QodeAssist::Context;
using namespace QodeAssist::LLMCore;
using namespace QodeAssist::Settings;
-QT_BEGIN_NAMESPACE
-
-// gtest can't pick pretty printer when comparing QString
-inline void PrintTo(const QString &value, ::std::ostream *out)
-{
- *out << '"' << value.toStdString() << '"';
-}
-
-QT_END_NAMESPACE
-
-std::ostream &operator<<(std::ostream &out, const QString &value)
-{
- out << '"' << value.toStdString() << '"';
- return out;
-}
-
-template
-std::ostream &operator<<(std::ostream &out, const QVector &value)
-{
- out << "[";
- for (const auto &el : value) {
- out << value << ", ";
- }
- out << "]";
- return out;
-}
-
-template
-std::ostream &operator<<(std::ostream &out, const std::optional &value)
-{
- if (value.has_value()) {
- out << value.value();
- } else {
- out << "(no value)";
- }
- return out;
-}
-
-namespace QodeAssist::LLMCore {
-std::ostream &operator<<(std::ostream &out, const Message &value)
-{
- out << "Message{"
- << "role=" << value.role << "content=" << value.content << "}";
- return out;
-}
-
-std::ostream &operator<<(std::ostream &out, const ContextData &value)
-{
- out << "ContextData{"
- << "\n systemPrompt=" << value.systemPrompt << "\n prefix=" << value.prefix
- << "\n suffix=" << value.suffix << "\n fileContext=" << value.fileContext
- << "\n history=" << value.history << "\n}";
- return out;
-}
-} // namespace QodeAssist::LLMCore
-
class DocumentContextReaderTest : public QObject, public testing::Test
{
Q_OBJECT
diff --git a/test/TestUtils.hpp b/test/TestUtils.hpp
new file mode 100644
index 0000000..533bb8f
--- /dev/null
+++ b/test/TestUtils.hpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2025 Povilas Kanapickas
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#include
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+
+// gtest can't pick pretty printer when comparing QString
+inline void PrintTo(const QString &value, ::std::ostream *out)
+{
+ *out << '"' << value.toStdString() << '"';
+}
+
+QT_END_NAMESPACE
+
+inline std::ostream &operator<<(std::ostream &out, const QString &value)
+{
+ out << '"' << value.toStdString() << '"';
+ return out;
+}
+
+template
+std::ostream &operator<<(std::ostream &out, const QVector &value)
+{
+ out << "[";
+ for (const auto &el : value) {
+ out << value << ", ";
+ }
+ out << "]";
+ return out;
+}
+
+template
+std::ostream &operator<<(std::ostream &out, const std::optional &value)
+{
+ if (value.has_value()) {
+ out << value.value();
+ } else {
+ out << "(no value)";
+ }
+ return out;
+}
+
+namespace QodeAssist::LLMCore {
+
+inline std::ostream &operator<<(std::ostream &out, const Message &value)
+{
+ out << "Message{"
+ << "role=" << value.role << "content=" << value.content << "}";
+ return out;
+}
+
+inline std::ostream &operator<<(std::ostream &out, const ContextData &value)
+{
+ out << "ContextData{"
+ << "\n systemPrompt=" << value.systemPrompt << "\n prefix=" << value.prefix
+ << "\n suffix=" << value.suffix << "\n fileContext=" << value.fileContext
+ << "\n history=" << value.history << "\n}";
+ return out;
+}
+
+} // namespace QodeAssist::LLMCore