/* * 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 "context/DocumentContextReader.hpp" #include "TestUtils.hpp" #include #include #include using namespace QodeAssist::Context; using namespace QodeAssist::LLMCore; using namespace QodeAssist::Settings; class DocumentContextReaderTest : public QObject, public testing::Test { Q_OBJECT protected: QTextDocument *createTestDocument(const QString &text) { auto *doc = new QTextDocument(this); doc->setPlainText(text); return doc; } DocumentContextReader createTestReader(const QString &text) { return DocumentContextReader(createTestDocument(text), "text/python", "/path/to/file"); } QSharedPointer createSettingsForWholeFile() { // CodeCompletionSettings is noncopyable auto settings = QSharedPointer::create(); settings->readFullFile.setValue(true); return settings; } QSharedPointer createSettingsForLines(int linesBefore, int linesAfter) { // CodeCompletionSettings is noncopyable auto settings = QSharedPointer::create(); settings->readFullFile.setValue(false); settings->readStringsBeforeCursor.setValue(linesBefore); settings->readStringsAfterCursor.setValue(linesAfter); return settings; } }; TEST_F(DocumentContextReaderTest, testGetLineText) { auto reader = createTestReader("Line 0\nLine 1\nLine 2"); EXPECT_EQ(reader.getLineText(0), "Line 0"); EXPECT_EQ(reader.getLineText(1), "Line 1"); EXPECT_EQ(reader.getLineText(2), "Line 2"); EXPECT_EQ(reader.getLineText(0, 4), "Line"); } TEST_F(DocumentContextReaderTest, testGetContext) { auto reader = createTestReader("Line 0\nLine 1\nLine 2\nLine 3\nLine 4"); // Unknown cursor position EXPECT_EQ(reader.getContextBefore(0, -1, 2), "Line 0"); EXPECT_EQ(reader.getContextAfter(0, -1, 2), "Line 0\nLine 1"); EXPECT_EQ(reader.getContextBefore(1, -1, 2), "Line 0\nLine 1"); EXPECT_EQ(reader.getContextAfter(1, -1, 2), "Line 1\nLine 2"); EXPECT_EQ(reader.getContextBefore(2, -1, 2), "Line 1\nLine 2"); EXPECT_EQ(reader.getContextAfter(2, -1, 2), "Line 2\nLine 3"); EXPECT_EQ(reader.getContextBefore(3, -1, 2), "Line 2\nLine 3"); EXPECT_EQ(reader.getContextAfter(3, -1, 2), "Line 3\nLine 4"); // Known cursor position EXPECT_EQ(reader.getContextBefore(0, 1, 2), "L"); EXPECT_EQ(reader.getContextAfter(0, 1, 2), "ine 0\nLine 1"); EXPECT_EQ(reader.getContextBefore(1, 1, 2), "Line 0\nL"); EXPECT_EQ(reader.getContextAfter(1, 1, 2), "ine 1\nLine 2"); EXPECT_EQ(reader.getContextBefore(2, 1, 2), "Line 1\nL"); EXPECT_EQ(reader.getContextAfter(2, 1, 2), "ine 2\nLine 3"); EXPECT_EQ(reader.getContextBefore(3, 1, 2), "Line 2\nL"); EXPECT_EQ(reader.getContextAfter(3, 1, 2), "ine 3\nLine 4"); } TEST_F(DocumentContextReaderTest, testGetContextWithCopyright) { auto reader = createTestReader("/* Copyright (C) 2024 */\nLine 0\nLine 1\nLine 2\nLine 3"); // Unknown cursor position EXPECT_EQ(reader.getContextBefore(0, -1, 2), ""); EXPECT_EQ(reader.getContextAfter(0, -1, 2), "Line 0"); EXPECT_EQ(reader.getContextBefore(1, -1, 2), "Line 0"); EXPECT_EQ(reader.getContextAfter(1, -1, 2), "Line 0\nLine 1"); EXPECT_EQ(reader.getContextBefore(2, -1, 2), "Line 0\nLine 1"); EXPECT_EQ(reader.getContextAfter(2, -1, 2), "Line 1\nLine 2"); EXPECT_EQ(reader.getContextBefore(3, -1, 2), "Line 1\nLine 2"); EXPECT_EQ(reader.getContextAfter(3, -1, 2), "Line 2\nLine 3"); // Known cursor position EXPECT_EQ(reader.getContextBefore(0, 1, 2), ""); EXPECT_EQ(reader.getContextAfter(0, 1, 2), "Line 0"); EXPECT_EQ(reader.getContextBefore(1, 1, 2), "L"); EXPECT_EQ(reader.getContextAfter(1, 1, 2), "ine 0\nLine 1"); EXPECT_EQ(reader.getContextBefore(2, 1, 2), "Line 0\nL"); EXPECT_EQ(reader.getContextAfter(2, 1, 2), "ine 1\nLine 2"); EXPECT_EQ(reader.getContextBefore(3, 1, 2), "Line 1\nL"); EXPECT_EQ(reader.getContextAfter(3, 1, 2), "ine 2\nLine 3"); } TEST_F(DocumentContextReaderTest, testReadWholeFile) { auto reader = createTestReader("Line 0\nLine 1\nLine 2\nLine 3\nLine 4"); // Unknown cursor position EXPECT_EQ(reader.readWholeFileBefore(0, -1), "Line 0"); EXPECT_EQ(reader.readWholeFileAfter(0, -1), "Line 0\nLine 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(1, -1), "Line 0\nLine 1"); EXPECT_EQ(reader.readWholeFileAfter(1, -1), "Line 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(2, -1), "Line 0\nLine 1\nLine 2"); EXPECT_EQ(reader.readWholeFileAfter(2, -1), "Line 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(3, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileAfter(3, -1), "Line 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(4, -1), "Line 0\nLine 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileAfter(4, -1), "Line 4"); // Known cursor position EXPECT_EQ(reader.readWholeFileBefore(0, 1), "L"); EXPECT_EQ(reader.readWholeFileAfter(0, 1), "ine 0\nLine 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(1, 1), "Line 0\nL"); EXPECT_EQ(reader.readWholeFileAfter(1, 1), "ine 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(2, 1), "Line 0\nLine 1\nL"); EXPECT_EQ(reader.readWholeFileAfter(2, 1), "ine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(3, 1), "Line 0\nLine 1\nLine 2\nL"); EXPECT_EQ(reader.readWholeFileAfter(3, 1), "ine 3\nLine 4"); EXPECT_EQ(reader.readWholeFileBefore(4, 1), "Line 0\nLine 1\nLine 2\nLine 3\nL"); EXPECT_EQ(reader.readWholeFileAfter(4, 1), "ine 4"); } TEST_F(DocumentContextReaderTest, testReadWholeFileWithCopyright) { auto reader = createTestReader("/* Copyright (C) 2024 */\nLine 0\nLine 1\nLine 2\nLine 3"); // Unknown cursor position EXPECT_EQ(reader.readWholeFileBefore(0, -1), ""); EXPECT_EQ(reader.readWholeFileAfter(0, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(1, -1), "Line 0"); EXPECT_EQ(reader.readWholeFileAfter(1, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(2, -1), "Line 0\nLine 1"); EXPECT_EQ(reader.readWholeFileAfter(2, -1), "Line 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(3, -1), "Line 0\nLine 1\nLine 2"); EXPECT_EQ(reader.readWholeFileAfter(3, -1), "Line 2\nLine 3"); // Known cursor position EXPECT_EQ(reader.readWholeFileBefore(0, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(0, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(1, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(1, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(2, 0), "Line 0\n"); EXPECT_EQ(reader.readWholeFileAfter(2, 0), "Line 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(3, 0), "Line 0\nLine 1\n"); EXPECT_EQ(reader.readWholeFileAfter(3, 0), "Line 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(0, 1), ""); EXPECT_EQ(reader.readWholeFileAfter(0, 1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(1, 1), "L"); EXPECT_EQ(reader.readWholeFileAfter(1, 1), "ine 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(2, 1), "Line 0\nL"); EXPECT_EQ(reader.readWholeFileAfter(2, 1), "ine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(3, 1), "Line 0\nLine 1\nL"); EXPECT_EQ(reader.readWholeFileAfter(3, 1), "ine 2\nLine 3"); } TEST_F(DocumentContextReaderTest, testReadWholeFileWithMultilineCopyright) { auto reader = createTestReader( "/*\n * Copyright (C) 2024\n * \n * This file is part of QodeAssist.\n */\n" "Line 0\nLine 1\nLine 2\nLine 3"); // Unknown cursor position EXPECT_EQ(reader.readWholeFileBefore(0, -1), ""); EXPECT_EQ(reader.readWholeFileAfter(0, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(1, -1), ""); EXPECT_EQ(reader.readWholeFileAfter(1, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(2, -1), ""); EXPECT_EQ(reader.readWholeFileAfter(2, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(3, -1), ""); EXPECT_EQ(reader.readWholeFileAfter(3, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(4, -1), ""); EXPECT_EQ(reader.readWholeFileAfter(4, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(5, -1), "Line 0"); EXPECT_EQ(reader.readWholeFileAfter(5, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(6, -1), "Line 0\nLine 1"); EXPECT_EQ(reader.readWholeFileAfter(6, -1), "Line 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(7, -1), "Line 0\nLine 1\nLine 2"); EXPECT_EQ(reader.readWholeFileAfter(7, -1), "Line 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(8, -1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileAfter(8, -1), "Line 3"); // Known cursor position EXPECT_EQ(reader.readWholeFileBefore(0, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(0, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(1, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(1, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(2, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(2, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(3, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(3, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(4, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(4, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(5, 0), ""); EXPECT_EQ(reader.readWholeFileAfter(5, 0), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(6, 0), "Line 0\n"); EXPECT_EQ(reader.readWholeFileAfter(6, 0), "Line 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(7, 0), "Line 0\nLine 1\n"); EXPECT_EQ(reader.readWholeFileAfter(7, 0), "Line 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(8, 0), "Line 0\nLine 1\nLine 2\n"); EXPECT_EQ(reader.readWholeFileAfter(8, 0), "Line 3"); EXPECT_EQ(reader.readWholeFileBefore(0, 1), ""); EXPECT_EQ(reader.readWholeFileAfter(0, 1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(1, 1), ""); EXPECT_EQ(reader.readWholeFileAfter(1, 1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(2, 1), ""); EXPECT_EQ(reader.readWholeFileAfter(2, 1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(3, 1), ""); EXPECT_EQ(reader.readWholeFileAfter(3, 1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(4, 1), ""); EXPECT_EQ(reader.readWholeFileAfter(4, 1), "Line 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(5, 1), "L"); EXPECT_EQ(reader.readWholeFileAfter(5, 1), "ine 0\nLine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(6, 1), "Line 0\nL"); EXPECT_EQ(reader.readWholeFileAfter(6, 1), "ine 1\nLine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(7, 1), "Line 0\nLine 1\nL"); EXPECT_EQ(reader.readWholeFileAfter(7, 1), "ine 2\nLine 3"); EXPECT_EQ(reader.readWholeFileBefore(8, 1), "Line 0\nLine 1\nLine 2\nL"); EXPECT_EQ(reader.readWholeFileAfter(8, 1), "ine 3"); } TEST_F(DocumentContextReaderTest, testFindCopyrightSingleLine) { auto reader = createTestReader("/* Copyright (C) 2024 */\nCode line 0\nCode line 1"); auto info = reader.findCopyright(); ASSERT_TRUE(info.found); EXPECT_EQ(info.startLine, 0); EXPECT_EQ(info.endLine, 0); } TEST_F(DocumentContextReaderTest, testFindCopyrightMultiLine) { auto reader = createTestReader( "/*\n * Copyright (C) 2024\n * \n * This file is part of QodeAssist.\n */\nCode line 0"); auto info = reader.findCopyright(); ASSERT_TRUE(info.found); EXPECT_EQ(info.startLine, 0); EXPECT_EQ(info.endLine, 4); } TEST_F(DocumentContextReaderTest, testFindCopyrightMultipleBlocks) { auto reader = createTestReader("/* Copyright 2023 */\n\n/* Copyright 2024 */\nCode"); auto info = reader.findCopyright(); ASSERT_TRUE(info.found); EXPECT_EQ(info.startLine, 0); EXPECT_EQ(info.endLine, 0); } TEST_F(DocumentContextReaderTest, testFindCopyrightNoCopyright) { auto reader = createTestReader("/* Just a comment */\nCode line 0"); auto info = reader.findCopyright(); ASSERT_TRUE(!info.found); EXPECT_EQ(info.startLine, -1); EXPECT_EQ(info.endLine, -1); } TEST_F(DocumentContextReaderTest, testGetContextBetween) { auto reader = createTestReader("Line 0\nLine 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ(reader.getContextBetween(2, -1, 0, -1), ""); EXPECT_EQ(reader.getContextBetween(0, -1, 0, -1), "Line 0"); EXPECT_EQ(reader.getContextBetween(1, -1, 1, -1), "Line 1"); EXPECT_EQ(reader.getContextBetween(1, 3, 1, 1), ""); EXPECT_EQ(reader.getContextBetween(1, 3, 1, 3), ""); EXPECT_EQ(reader.getContextBetween(1, 3, 1, 4), "e"); EXPECT_EQ(reader.getContextBetween(1, -1, 3, -1), "Line 1\nLine 2\nLine 3"); EXPECT_EQ(reader.getContextBetween(1, 2, 3, -1), "ne 1\nLine 2\nLine 3"); EXPECT_EQ(reader.getContextBetween(1, -1, 3, 2), "Line 1\nLine 2\nLi"); EXPECT_EQ(reader.getContextBetween(1, 2, 3, 2), "ne 1\nLine 2\nLi"); } TEST_F(DocumentContextReaderTest, testPrepareContext) { auto reader = createTestReader("Line 0\nLine 1\nLine 2\nLine 3\nLine 4"); EXPECT_EQ( reader.prepareContext(2, 3, *createSettingsForWholeFile()), (ContextData{ .prefix = "Line 0\nLine 1\nLin", .suffix = "e 2\nLine 3\nLine 4", .fileContext = "\n Language: (MIME: text/python) filepath: /path/to/file()\n\n" "Recent Project Changes Context:\n "})); EXPECT_EQ( reader.prepareContext(2, 3, *createSettingsForLines(1, 1)), (ContextData{ .prefix = "Line 1\nLin", .suffix = "e 2\nLine 3", .fileContext = "\n Language: (MIME: text/python) filepath: /path/to/file()\n\n" "Recent Project Changes Context:\n "})); EXPECT_EQ( reader.prepareContext(2, 3, *createSettingsForLines(2, 2)), (ContextData{ .prefix = "Line 0\nLine 1\nLin", .suffix = "e 2\nLine 3\nLine 4", .fileContext = "\n Language: (MIME: text/python) filepath: /path/to/file()\n\n" "Recent Project Changes Context:\n "})); } #include "DocumentContextReaderTest.moc"