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