From d151fe4f0e1d0ddb5d264d4e59b11160e1115add Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 9 Mar 2025 15:13:18 -0700 Subject: [PATCH 01/21] [Refactor] Update include file path to fix testing errors --- src/CodeEditor.cpp | 6 +++--- src/MainWindow.cpp | 2 +- src/main.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CodeEditor.cpp b/src/CodeEditor.cpp index 4259f81..947dc59 100644 --- a/src/CodeEditor.cpp +++ b/src/CodeEditor.cpp @@ -1,6 +1,6 @@ -#include "CodeEditor.h" -#include "MainWindow.h" -#include "LineNumberArea.h" +#include "../include/CodeEditor.h" +#include "../include/MainWindow.h" +#include "../include/LineNumberArea.h" #include #include diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ae44543..a687ac3 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1,4 +1,4 @@ -#include "MainWindow.h" +#include "../include/MainWindow.h" #include #include diff --git a/src/main.cpp b/src/main.cpp index b7aa619..313b85a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "MainWindow.h" +#include "../include/MainWindow.h" #include #include From bcca0dbaec35a51f4ada195d2de8d06d9f83298e Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 9 Mar 2025 15:13:46 -0700 Subject: [PATCH 02/21] Added testing to the build --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49c46d0..aa40a27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ endif() set(CMAKE_PREFIX_PATH ${Qt_DIR}) # Find Qt Widgets -find_package(Qt${QT_MAJOR_VERSION} COMPONENTS Widgets REQUIRED) +find_package(Qt${QT_MAJOR_VERSION} COMPONENTS Widgets Test REQUIRED) # Add executable and source files add_executable(${TARGET_NAME} @@ -58,6 +58,8 @@ add_executable(${TARGET_NAME} include/CodeEditor.h ) +add_subdirectory(tests) + qt_add_resources(APP_RESOURCES resources.qrc) target_sources(${TARGET_NAME} PRIVATE ${APP_RESOURCES}) From e068893f2c23b0f1250a6f3c70f715dc7c48acfa Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 9 Mar 2025 15:14:05 -0700 Subject: [PATCH 03/21] [Make] Added automating testing from Make file --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile b/Makefile index f990940..b0973ed 100644 --- a/Makefile +++ b/Makefile @@ -75,3 +75,11 @@ install: fi \ fi @echo "$(PROJECT) installed." + +test: + @for test in ./build/tests/test_*; do \ + if [ -f $$test ]; then \ + echo "Running $$test..."; \ + $$test; \ + fi; \ + done From f165366cea8efb64ed703f5d3f853be95f72eb47 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 9 Mar 2025 15:14:26 -0700 Subject: [PATCH 04/21] [Test] CMakeLists file for testing directory --- tests/CMakeLists.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/CMakeLists.txt diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..7bf9e34 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +# Enable testing +enable_testing() + +# Add individual test executables +add_executable(test_mainwindow + test_mainwindow.cpp + ../src/MainWindow.cpp + ../src/CodeEditor.cpp + ../include/MainWindow.h + ../include/CodeEditor.h +) + +# Link each test with necessary libraries +target_link_libraries(test_mainwindow PRIVATE Qt6::Widgets Qt6::Test) + +# Register each test with CTest +add_test(NAME test_mainwindow COMMAND test_mainwindow) + +# Set the runtime output directory for the test executables +set_target_properties(test_mainwindow PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/tests +) \ No newline at end of file From d07ddc3db7cb876e9837c6121cf5a521fc285962 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 9 Mar 2025 15:14:51 -0700 Subject: [PATCH 05/21] [Test] Added init :test: mainwindow --- tests/test_mainwindow.cpp | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test_mainwindow.cpp diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp new file mode 100644 index 0000000..67797be --- /dev/null +++ b/tests/test_mainwindow.cpp @@ -0,0 +1,51 @@ +#include "../include/MainWindow.h" + +#include +#include +#include + +class TestMainWindow : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); // Runs before all tests + void cleanupTestCase(); // Runs after all tests + void testWindowTitle(); + void testMenuBar(); + void testNewFileAction(); +}; + +void TestMainWindow::initTestCase() +{ + qDebug() << "Initializing MainWindow tests..."; +} + +void TestMainWindow::cleanupTestCase() +{ + qDebug() << "Cleaning up MainWindow tests..."; +} + +void TestMainWindow::testWindowTitle() +{ + MainWindow window; + QCOMPARE(window.windowTitle(), QString("CodeAstra ~ Code Editor")); +} + +void TestMainWindow::testMenuBar() +{ + MainWindow window; + QMenuBar *menuBar = window.menuBar(); + QVERIFY(menuBar != nullptr); + QCOMPARE(menuBar->actions().size(), 3); // File, Help, CodeAstra +} + +void TestMainWindow::testNewFileAction() +{ + MainWindow window; + QAction *newAction = window.findChild("New File"); + QVERIFY(newAction != nullptr); +} + +QTEST_MAIN(TestMainWindow) +#include "test_mainwindow.moc" From ef882ff4834adcf2a1171cc7ca08c8a90eb5f9cf Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 9 Mar 2025 18:13:36 -0700 Subject: [PATCH 06/21] [Update] Added Syntax to the test build --- src/Syntax.cpp | 2 +- tests/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Syntax.cpp b/src/Syntax.cpp index 553c927..80d1043 100644 --- a/src/Syntax.cpp +++ b/src/Syntax.cpp @@ -1,4 +1,4 @@ -#include "Syntax.h" +#include "../include/Syntax.h" Syntax::Syntax(QTextDocument *parent) : QSyntaxHighlighter(parent) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7bf9e34..a291c85 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,8 +6,10 @@ add_executable(test_mainwindow test_mainwindow.cpp ../src/MainWindow.cpp ../src/CodeEditor.cpp + ../src/Syntax.cpp ../include/MainWindow.h ../include/CodeEditor.h + ../include/Syntax.h ) # Link each test with necessary libraries From 036bfe3b30e518ad74551555332c9d451d8435d9 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 20:59:16 -0700 Subject: [PATCH 07/21] [Refactor] Update include directives to use relative paths for unit test --- src/FileManager.cpp | 6 +++--- src/Syntax.cpp | 3 ++- src/Tree.cpp | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/FileManager.cpp b/src/FileManager.cpp index ab3c6a3..a9728db 100644 --- a/src/FileManager.cpp +++ b/src/FileManager.cpp @@ -1,11 +1,11 @@ -#include "FileManager.h" +#include "../include/FileManager.h" +#include "../include/CodeEditor.h" +#include "../include/MainWindow.h" #include #include #include #include -#include "CodeEditor.h" -#include "MainWindow.h" FileManager::FileManager(CodeEditor *editor, MainWindow *mainWindow) : m_editor(editor), m_mainWindow(mainWindow) diff --git a/src/Syntax.cpp b/src/Syntax.cpp index e516db1..18f2266 100644 --- a/src/Syntax.cpp +++ b/src/Syntax.cpp @@ -1,6 +1,7 @@ +#include "../include/Syntax.h" + #include #include -#include "../include/Syntax.h" Syntax::Syntax(QTextDocument *parent) : QSyntaxHighlighter(parent) { diff --git a/src/Tree.cpp b/src/Tree.cpp index f8fab29..d60076e 100644 --- a/src/Tree.cpp +++ b/src/Tree.cpp @@ -1,6 +1,6 @@ -#include "Tree.h" -#include "CodeEditor.h" -#include "FileManager.h" +#include "../include/Tree.h" +#include "../include/CodeEditor.h" +#include "../include/FileManager.h" #include #include From 04ed7f4318cf2944624dc3838b59da0b7b449a61 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 20:59:31 -0700 Subject: [PATCH 08/21] [Refactor] Add object names to menu items in createMenuBar for improved accessibility (required for UnitTests) --- src/MainWindow.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index de4b2c2..8203ee8 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -62,8 +62,13 @@ void MainWindow::createMenuBar() QMenuBar *menuBar = new QMenuBar(this); QMenu *fileMenu = menuBar->addMenu("File"); + fileMenu->setObjectName("File"); + QMenu *helpMenu = menuBar->addMenu("Help"); - QMenu *appMenu = menuBar->addMenu("CodeAstra"); + helpMenu->setObjectName("Help"); + + QMenu *appMenu = menuBar->addMenu("CodeAstra"); + appMenu->setObjectName("CodeAstra"); createFileActions(fileMenu); createHelpActions(helpMenu); From c44394a5fb92475a179e01ed2493048e7e76a14e Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 21:33:32 -0700 Subject: [PATCH 09/21] [Refactor] Rename target variables and restructure CMakeLists.txt for clarity and organization (to work with Unit Tests) --- CMakeLists.txt | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c293c7..06a1427 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.16) # Project name -set(TARGET_NAME CodeAstra) +set(TARGET_NAME CodeAstraApp) +set(EXECUTABLE_NAME CodeAstra) set(QT_MAJOR_VERSION 6) @@ -49,9 +50,8 @@ set(CMAKE_PREFIX_PATH ${Qt_DIR}) # Find Qt Widgets find_package(Qt${QT_MAJOR_VERSION} COMPONENTS Widgets Test REQUIRED) -# Add executable and source files -add_executable(${TARGET_NAME} - src/main.cpp +# Create the CodeAstra library +add_library(${TARGET_NAME} src/MainWindow.cpp src/CodeEditor.cpp src/Syntax.cpp @@ -65,31 +65,42 @@ add_executable(${TARGET_NAME} include/FileManager.h ) +# Create the executable for the application +add_executable(${EXECUTABLE_NAME} + src/main.cpp +) + +# Link the main executable with the CodeAstra library and Qt libraries +target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${TARGET_NAME} Qt${QT_MAJOR_VERSION}::Widgets) + +# Add the tests subdirectory add_subdirectory(tests) +# Qt resource files (if any) qt_add_resources(APP_RESOURCES resources.qrc) -target_sources(${TARGET_NAME} PRIVATE ${APP_RESOURCES}) +target_sources(${EXECUTABLE_NAME} PRIVATE ${APP_RESOURCES}) # Compiler flags per OS if(MSVC) - target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX) + target_compile_options(${EXECUTABLE_NAME} PRIVATE /W4 /WX) elseif(APPLE) - target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) - set_target_properties(${TARGET_NAME} PROPERTIES MACOSX_BUNDLE TRUE) + target_compile_options(${EXECUTABLE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) + set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE TRUE) else() - target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) + target_compile_options(${EXECUTABLE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror) endif() # Include directories -target_include_directories(${TARGET_NAME} PRIVATE ${Qt${QT_MAJOR_VERSION}_INCLUDE_DIRS}) +target_include_directories(${EXECUTABLE_NAME} PRIVATE ${Qt${QT_MAJOR_VERSION}_INCLUDE_DIRS}) +target_include_directories(${EXECUTABLE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) # Set output names properly for Debug and Release -set_target_properties(${TARGET_NAME} PROPERTIES +set_target_properties(${EXECUTABLE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}" - DEBUG_OUTPUT_NAME "${TARGET_NAME}d" - RELEASE_OUTPUT_NAME ${TARGET_NAME} + DEBUG_OUTPUT_NAME "${EXECUTABLE_NAME}d" + RELEASE_OUTPUT_NAME ${EXECUTABLE_NAME} ) -# Link necessary Qt libraries +# Link necessary Qt libraries to CodeAstra library target_link_libraries(${TARGET_NAME} PRIVATE Qt${QT_MAJOR_VERSION}::Widgets) \ No newline at end of file From 14c2589dea064515f29c573a10e1a52d3d5d435c Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 21:33:56 -0700 Subject: [PATCH 10/21] [Refactor] Update test_mainwindow CMake configuration to link with CodeAstra library and improve organization --- tests/CMakeLists.txt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a291c85..7023a6e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,16 +4,10 @@ enable_testing() # Add individual test executables add_executable(test_mainwindow test_mainwindow.cpp - ../src/MainWindow.cpp - ../src/CodeEditor.cpp - ../src/Syntax.cpp - ../include/MainWindow.h - ../include/CodeEditor.h - ../include/Syntax.h ) -# Link each test with necessary libraries -target_link_libraries(test_mainwindow PRIVATE Qt6::Widgets Qt6::Test) +# Link the test with the CodeAstra library and necessary Qt libraries +target_link_libraries(test_mainwindow PRIVATE ${TARGET_NAME} Qt6::Widgets Qt6::Test) # Register each test with CTest add_test(NAME test_mainwindow COMMAND test_mainwindow) @@ -21,4 +15,8 @@ add_test(NAME test_mainwindow COMMAND test_mainwindow) # Set the runtime output directory for the test executables set_target_properties(test_mainwindow PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/tests -) \ No newline at end of file +) + +set_property(SOURCE test_mainwindow.cpp PROPERTY SKIP_AUTOMOC OFF) + +target_include_directories(test_mainwindow PRIVATE ${CMAKE_SOURCE_DIR}/include) \ No newline at end of file From c0b69c62682f16d26716da2170236b024ee96fe2 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 21:34:53 -0700 Subject: [PATCH 11/21] [Refactor] Update include directives to use local paths instead of relative path --- src/CodeEditor.cpp | 8 ++++---- src/FileManager.cpp | 6 +++--- src/MainWindow.cpp | 10 +++++----- src/Syntax.cpp | 2 +- src/Tree.cpp | 6 +++--- src/main.cpp | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/CodeEditor.cpp b/src/CodeEditor.cpp index 4dec245..0d23421 100644 --- a/src/CodeEditor.cpp +++ b/src/CodeEditor.cpp @@ -1,7 +1,7 @@ -#include "../include/CodeEditor.h" -#include "../include/MainWindow.h" -#include "../include/LineNumberArea.h" -#include "../include/FileManager.h" +#include "CodeEditor.h" +#include "MainWindow.h" +#include "LineNumberArea.h" +#include "FileManager.h" #include #include diff --git a/src/FileManager.cpp b/src/FileManager.cpp index a9728db..454321c 100644 --- a/src/FileManager.cpp +++ b/src/FileManager.cpp @@ -1,6 +1,6 @@ -#include "../include/FileManager.h" -#include "../include/CodeEditor.h" -#include "../include/MainWindow.h" +#include "FileManager.h" +#include "CodeEditor.h" +#include "MainWindow.h" #include #include diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 8203ee8..68ce95b 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1,8 +1,8 @@ -#include "../include/MainWindow.h" -#include "../include/Syntax.h" -#include "../include/Tree.h" -#include "../include/CodeEditor.h" -#include "../include/FileManager.h" +#include "MainWindow.h" +#include "Syntax.h" +#include "Tree.h" +#include "CodeEditor.h" +#include "FileManager.h" #include #include diff --git a/src/Syntax.cpp b/src/Syntax.cpp index 18f2266..5896a88 100644 --- a/src/Syntax.cpp +++ b/src/Syntax.cpp @@ -1,4 +1,4 @@ -#include "../include/Syntax.h" +#include "Syntax.h" #include #include diff --git a/src/Tree.cpp b/src/Tree.cpp index d60076e..f8fab29 100644 --- a/src/Tree.cpp +++ b/src/Tree.cpp @@ -1,6 +1,6 @@ -#include "../include/Tree.h" -#include "../include/CodeEditor.h" -#include "../include/FileManager.h" +#include "Tree.h" +#include "CodeEditor.h" +#include "FileManager.h" #include #include diff --git a/src/main.cpp b/src/main.cpp index cfe70f2..93247d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "../include/MainWindow.h" +#include "MainWindow.h" #include #include From fa6e3425130d68c79c717f936655a4573d82555c Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 21:36:19 -0700 Subject: [PATCH 12/21] [Refactor] Improve test structure and initialization in TestMainWindow --- tests/test_mainwindow.cpp | 52 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp index 67797be..b25a1cb 100644 --- a/tests/test_mainwindow.cpp +++ b/tests/test_mainwindow.cpp @@ -1,51 +1,67 @@ -#include "../include/MainWindow.h" - #include #include -#include + +#include "MainWindow.h" +#include "CodeEditor.h" +#include "FileManager.h" class TestMainWindow : public QObject { Q_OBJECT private slots: - void initTestCase(); // Runs before all tests - void cleanupTestCase(); // Runs after all tests + void initTestCase(); + void cleanupTestCase(); void testWindowTitle(); + void testEditorInitialization(); void testMenuBar(); - void testNewFileAction(); + +private: + std::unique_ptr mainWindow; }; void TestMainWindow::initTestCase() { qDebug() << "Initializing MainWindow tests..."; + mainWindow = std::make_unique(); + mainWindow->show(); } void TestMainWindow::cleanupTestCase() { qDebug() << "Cleaning up MainWindow tests..."; + mainWindow.reset(); } void TestMainWindow::testWindowTitle() { - MainWindow window; - QCOMPARE(window.windowTitle(), QString("CodeAstra ~ Code Editor")); + QCOMPARE(mainWindow->windowTitle(), "CodeAstra ~ Code Editor"); } -void TestMainWindow::testMenuBar() +void TestMainWindow::testEditorInitialization() { - MainWindow window; - QMenuBar *menuBar = window.menuBar(); - QVERIFY(menuBar != nullptr); - QCOMPARE(menuBar->actions().size(), 3); // File, Help, CodeAstra + QVERIFY2(mainWindow->findChild() != nullptr, + "MainWindow must contain a CodeEditor."); } -void TestMainWindow::testNewFileAction() +void TestMainWindow::testMenuBar() { - MainWindow window; - QAction *newAction = window.findChild("New File"); - QVERIFY(newAction != nullptr); + QMenuBar *menuBar = mainWindow->menuBar(); + QVERIFY2(menuBar != nullptr, "MainWindow must have a QMenuBar."); + QCOMPARE(menuBar->actions().size(), 3); // File, Help, CodeAstra + + QMenu *fileMenu = menuBar->findChild("File"); + QVERIFY2(fileMenu != nullptr, "QMenuBar must contain a 'File' menu."); + QCOMPARE(fileMenu->title(), "File"); + + QMenu *helpMenu = menuBar->findChild("Help"); + QVERIFY2(helpMenu != nullptr, "QMenuBar must contain a 'Help' menu."); + QCOMPARE(helpMenu->title(), "Help"); + + QMenu *appMenu = menuBar->findChild("CodeAstra"); + QVERIFY2(appMenu != nullptr, "QMenuBar must contain a 'CodeAstra' menu."); + QCOMPARE(appMenu->title(), "CodeAstra"); } QTEST_MAIN(TestMainWindow) -#include "test_mainwindow.moc" +#include "test_mainwindow.moc" \ No newline at end of file From 3d54fb9d69ab9d851f0efd263feba7bfd79ce342 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 22 Mar 2025 21:54:34 -0700 Subject: [PATCH 13/21] [Refactor] Update comment --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06a1427..e7d76fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${TARGET_NAME} Qt${QT_MAJOR_VER # Add the tests subdirectory add_subdirectory(tests) -# Qt resource files (if any) +# Qt resource files qt_add_resources(APP_RESOURCES resources.qrc) target_sources(${EXECUTABLE_NAME} PRIVATE ${APP_RESOURCES}) From 6f1c6490cdf8005459bf38176d577c8261fbddf5 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:21:24 -0700 Subject: [PATCH 14/21] [added] Add test_tree executable and update CMake configuration --- tests/CMakeLists.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7023a6e..48b3ff8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,17 +6,30 @@ add_executable(test_mainwindow test_mainwindow.cpp ) +# Add test_tree executable +add_executable(test_tree + test_tree.cpp +) + # Link the test with the CodeAstra library and necessary Qt libraries target_link_libraries(test_mainwindow PRIVATE ${TARGET_NAME} Qt6::Widgets Qt6::Test) +target_link_libraries(test_tree PRIVATE ${TARGET_NAME} Qt6::Widgets Qt6::Test) # Register each test with CTest add_test(NAME test_mainwindow COMMAND test_mainwindow) +add_test(NAME test_tree COMMAND test_tree) # Set the runtime output directory for the test executables set_target_properties(test_mainwindow PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/tests ) +set_target_properties(test_tree PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/tests +) set_property(SOURCE test_mainwindow.cpp PROPERTY SKIP_AUTOMOC OFF) +set_property(SOURCE test_tree.cpp PROPERTY SKIP_AUTOMOC OFF) -target_include_directories(test_mainwindow PRIVATE ${CMAKE_SOURCE_DIR}/include) \ No newline at end of file +# Include directories for tests +target_include_directories(test_mainwindow PRIVATE ${CMAKE_SOURCE_DIR}/include) +target_include_directories(test_tree PRIVATE ${CMAKE_SOURCE_DIR}/include) From 4aeafd55a0d9505df55aebb8550068c46356fde0 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:22:25 -0700 Subject: [PATCH 15/21] [Refactor] Moved getDirectoryPath method from FileManager and createAction method from MainWindow from private to public --- include/FileManager.h | 2 ++ include/MainWindow.h | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/FileManager.h b/include/FileManager.h index 160026f..bccf188 100644 --- a/include/FileManager.h +++ b/include/FileManager.h @@ -43,6 +43,8 @@ public slots: void openFile(); void loadFileInEditor(const QString &filePath); + QString getDirectoryPath() const; + private: FileManager(CodeEditor *editor, MainWindow *mainWindow); ~FileManager(); diff --git a/include/MainWindow.h b/include/MainWindow.h index 7cd1ce8..591a273 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -31,6 +31,10 @@ class MainWindow : public QMainWindow // of the main window, alongside the code editor void initTree(); + QAction *createAction(const QIcon &icon, const QString &text, + const QKeySequence &shortcut, const QString &statusTip, + const std::function &slot); + private slots: void showAbout(); @@ -40,10 +44,6 @@ private slots: void createHelpActions(QMenu *helpMenu); void createAppActions(QMenu *appMenu); - QAction *createAction(const QIcon &icon, const QString &text, - const QKeySequence &shortcut, const QString &statusTip, - const std::function &slot); - std::unique_ptr m_editor; std::unique_ptr m_syntax; std::unique_ptr m_tree; From 45fc75395acaa128aa438f6db0f0fb734f9d3324 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:22:34 -0700 Subject: [PATCH 16/21] [Refactor] Simplify Tree constructor by removing FileManager dependency and reorganizing method visibility --- include/Tree.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/Tree.h b/include/Tree.h index 2fc65a1..210c733 100644 --- a/include/Tree.h +++ b/include/Tree.h @@ -22,20 +22,18 @@ class Tree : public QObject Q_OBJECT public: - explicit Tree(QSplitter *splitter, FileManager *FileManager); + explicit Tree(QSplitter *splitter); ~Tree(); -private: - void showContextMenu(const QPoint &pos); - void setupModel(); + void initialize(const QString &directory); + void setupModel(const QString &directory); void setupTree(); void openFile(const QModelIndex &index); - QString getDirectoryPath() const; +private: + void showContextMenu(const QPoint &pos); std::unique_ptr m_iconProvider; std::unique_ptr m_model; std::unique_ptr m_tree; - - FileManager * m_FileManager; }; \ No newline at end of file From 0f41a6b92bbbe9794757c10352421060182d80c2 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:22:49 -0700 Subject: [PATCH 17/21] [added] Implement getDirectoryPath method to allow directory selection --- src/FileManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/FileManager.cpp b/src/FileManager.cpp index 454321c..6f6c89e 100644 --- a/src/FileManager.cpp +++ b/src/FileManager.cpp @@ -144,3 +144,10 @@ QString FileManager::getFileExtension() const return QFileInfo(m_currentFileName).suffix().toLower(); } + +QString FileManager::getDirectoryPath() const +{ + return QFileDialog::getExistingDirectory( + nullptr, QObject::tr("Open Directory"), QDir::homePath(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); +} From a10d9244b841b65094bd129aaf3e08866832072f Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:23:00 -0700 Subject: [PATCH 18/21] [added] Implement Open Project action in file menu to initialize tree with selected directory --- src/MainWindow.cpp | 333 +++++++++++++++++++++++---------------------- 1 file changed, 171 insertions(+), 162 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 68ce95b..1e1b2a6 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1,162 +1,171 @@ -#include "MainWindow.h" -#include "Syntax.h" -#include "Tree.h" -#include "CodeEditor.h" -#include "FileManager.h" - -#include -#include -#include -#include -#include -#include - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), - m_editor(std::make_unique(this)), - m_syntax(std::make_unique(m_editor->document())), - m_tree(nullptr), - m_fileManager(&FileManager::getInstance()) -{ - m_fileManager->initialize(m_editor.get(), this); - setWindowTitle("CodeAstra ~ Code Editor"); - - connect(m_editor.get(), &CodeEditor::statusMessageChanged, this, [this](const QString &message) - { - QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); - statusBar()->showMessage("[" + timestamp + "] " + message, 4000); - }); - - // Set tab width to 4 spaces - QFontMetrics metrics(m_editor->font()); - int spaceWidth = metrics.horizontalAdvance(" "); - m_editor->setTabStopDistance(spaceWidth * 4); - m_editor->setLineWrapMode(QPlainTextEdit::NoWrap); - - initTree(); - createMenuBar(); - showMaximized(); -} - -MainWindow::~MainWindow() {} - -void MainWindow::initTree() -{ - QSplitter *splitter = new QSplitter(Qt::Horizontal, this); - setCentralWidget(splitter); - - m_tree = std::make_unique(splitter, m_fileManager); - - splitter->addWidget(m_editor.get()); - splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - splitter->setHandleWidth(5); - splitter->setSizes(QList() << 150 << 800); - splitter->setStretchFactor(0, 1); - splitter->setStretchFactor(1, 3); - splitter->setChildrenCollapsible(false); - splitter->setOpaqueResize(true); -} - -void MainWindow::createMenuBar() -{ - QMenuBar *menuBar = new QMenuBar(this); - - QMenu *fileMenu = menuBar->addMenu("File"); - fileMenu->setObjectName("File"); - - QMenu *helpMenu = menuBar->addMenu("Help"); - helpMenu->setObjectName("Help"); - - QMenu *appMenu = menuBar->addMenu("CodeAstra"); - appMenu->setObjectName("CodeAstra"); - - createFileActions(fileMenu); - createHelpActions(helpMenu); - createAppActions(appMenu); - - setMenuBar(menuBar); -} - -void MainWindow::createFileActions(QMenu *fileMenu) -{ - fileMenu->addAction(createAction(QIcon(), tr("&New"), QKeySequence::New, tr("Create a new file"), [this]() { m_fileManager->newFile(); })); - fileMenu->addAction(createAction(QIcon(), tr("&Open"), QKeySequence::Open, tr("Open an existing file"), [this]() { m_fileManager->openFile(); })); - fileMenu->addSeparator(); - fileMenu->addAction(createAction(QIcon(), tr("&Save"), QKeySequence::Save, tr("Save the current file"), [this]() { m_fileManager->saveFile(); })); - fileMenu->addAction(createAction(QIcon(), tr("Save &As"), QKeySequence::SaveAs, tr("Save the file with a new name"), [this]() { m_fileManager->saveFileAs(); })); -} - -void MainWindow::createHelpActions(QMenu *helpMenu) -{ - QAction *helpDoc = new QAction(tr("Documentation"), this); - connect(helpDoc, &QAction::triggered, this, []() - { - QDesktopServices::openUrl(QUrl("https://github.com/sandbox-science/CodeAstra/wiki")); - }); - - helpDoc->setStatusTip(tr("Open Wiki")); - helpMenu->addAction(helpDoc); -} - -void MainWindow::createAppActions(QMenu *appMenu) -{ - QAction *aboutAction = new QAction("About CodeAstra", this); - connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout); - appMenu->addAction(aboutAction); -} - -QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, const std::function &slot) -{ - QAction *action = new QAction(icon, text, this); - - action->setShortcuts(QList{shortcut}); - action->setStatusTip(statusTip); - connect(action, &QAction::triggered, this, slot); - - return action; -} - -void MainWindow::showAbout() -{ - // Extract the C++ version from the __cplusplus macro - QString cppVersion; - if (__cplusplus == 201103L) - { - cppVersion = "C++11"; - } - else if (__cplusplus == 201402L) - { - cppVersion = "C++14"; - } - else if (__cplusplus == 201703L) - { - cppVersion = "C++17"; - } - else if (__cplusplus == 202002L) - { - cppVersion = "C++20"; - } - else - { - cppVersion = "C++"; - } - - // Construct the about text - QString aboutText = QString( - "

" - "%1
" - "Version: %2

" - "Developed by %3.
" - "Built with %4 and Qt %5.

" - "© 2025 %3. All rights reserved." - "

") - .arg(QApplication::applicationName().toHtmlEscaped(), - QApplication::applicationVersion().toHtmlEscaped(), - QApplication::organizationName().toHtmlEscaped(), - cppVersion, - QString::number(QT_VERSION >> 16) + "." + // Major version - QString::number((QT_VERSION >> 8) & 0xFF) + "." + // Minor version - QString::number(QT_VERSION & 0xFF)); // Patch version - - QMessageBox::about(this, tr("About"), aboutText); -} +#include "MainWindow.h" +#include "Syntax.h" +#include "Tree.h" +#include "CodeEditor.h" +#include "FileManager.h" + +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), + m_editor(std::make_unique(this)), + m_syntax(std::make_unique(m_editor->document())), + m_tree(nullptr), + m_fileManager(&FileManager::getInstance()) +{ + m_fileManager->initialize(m_editor.get(), this); + setWindowTitle("CodeAstra ~ Code Editor"); + + connect(m_editor.get(), &CodeEditor::statusMessageChanged, this, [this](const QString &message) + { + QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); + statusBar()->showMessage("[" + timestamp + "] " + message, 4000); + }); + + // Set tab width to 4 spaces + QFontMetrics metrics(m_editor->font()); + int spaceWidth = metrics.horizontalAdvance(" "); + m_editor->setTabStopDistance(spaceWidth * 4); + m_editor->setLineWrapMode(QPlainTextEdit::NoWrap); + + initTree(); + createMenuBar(); + showMaximized(); +} + +MainWindow::~MainWindow() {} + +void MainWindow::initTree() +{ + QSplitter *splitter = new QSplitter(Qt::Horizontal, this); + setCentralWidget(splitter); + + m_tree = std::make_unique(splitter); + + splitter->addWidget(m_editor.get()); + splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + splitter->setHandleWidth(5); + splitter->setSizes(QList() << 150 << 800); + splitter->setStretchFactor(0, 1); + splitter->setStretchFactor(1, 3); + splitter->setChildrenCollapsible(false); + splitter->setOpaqueResize(true); +} + +void MainWindow::createMenuBar() +{ + QMenuBar *menuBar = new QMenuBar(this); + + QMenu *fileMenu = menuBar->addMenu("File"); + fileMenu->setObjectName("File"); + + QMenu *helpMenu = menuBar->addMenu("Help"); + helpMenu->setObjectName("Help"); + + QMenu *appMenu = menuBar->addMenu("CodeAstra"); + appMenu->setObjectName("CodeAstra"); + + createFileActions(fileMenu); + createHelpActions(helpMenu); + createAppActions(appMenu); + + setMenuBar(menuBar); +} + +void MainWindow::createFileActions(QMenu *fileMenu) +{ + fileMenu->addAction(createAction(QIcon(), tr("&New"), QKeySequence::New, tr("Create a new file"), [this]() { m_fileManager->newFile(); })); + fileMenu->addSeparator(); + fileMenu->addAction(createAction(QIcon(), tr("&Open &Project"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_O), tr("Open a project"), [this]() + { + QString projectPath = m_fileManager->getDirectoryPath(); + if (!projectPath.isEmpty()) + { + m_tree->initialize(projectPath); + } + })); + fileMenu->addAction(createAction(QIcon(), tr("&Open"), QKeySequence::Open, tr("Open an existing file"), [this]() { m_fileManager->openFile(); })); + fileMenu->addSeparator(); + fileMenu->addAction(createAction(QIcon(), tr("&Save"), QKeySequence::Save, tr("Save the current file"), [this]() { m_fileManager->saveFile(); })); + fileMenu->addAction(createAction(QIcon(), tr("Save &As"), QKeySequence::SaveAs, tr("Save the file with a new name"), [this]() { m_fileManager->saveFileAs(); })); +} + +void MainWindow::createHelpActions(QMenu *helpMenu) +{ + QAction *helpDoc = new QAction(tr("Documentation"), this); + connect(helpDoc, &QAction::triggered, this, []() + { + QDesktopServices::openUrl(QUrl("https://github.com/sandbox-science/CodeAstra/wiki")); + }); + + helpDoc->setStatusTip(tr("Open Wiki")); + helpMenu->addAction(helpDoc); +} + +void MainWindow::createAppActions(QMenu *appMenu) +{ + QAction *aboutAction = new QAction("About CodeAstra", this); + connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout); + appMenu->addAction(aboutAction); +} + +QAction *MainWindow::createAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, const QString &statusTip, const std::function &slot) +{ + QAction *action = new QAction(icon, text, this); + + action->setShortcuts(QList{shortcut}); + action->setStatusTip(statusTip); + connect(action, &QAction::triggered, this, slot); + + return action; +} + +void MainWindow::showAbout() +{ + // Extract the C++ version from the __cplusplus macro + QString cppVersion; + if (__cplusplus == 201103L) + { + cppVersion = "C++11"; + } + else if (__cplusplus == 201402L) + { + cppVersion = "C++14"; + } + else if (__cplusplus == 201703L) + { + cppVersion = "C++17"; + } + else if (__cplusplus == 202002L) + { + cppVersion = "C++20"; + } + else + { + cppVersion = "C++"; + } + + // Construct the about text + QString aboutText = QString( + "

" + "%1
" + "Version: %2

" + "Developed by %3.
" + "Built with %4 and Qt %5.

" + "© 2025 %3. All rights reserved." + "

") + .arg(QApplication::applicationName().toHtmlEscaped(), + QApplication::applicationVersion().toHtmlEscaped(), + QApplication::organizationName().toHtmlEscaped(), + cppVersion, + QString::number(QT_VERSION >> 16) + "." + // Major version + QString::number((QT_VERSION >> 8) & 0xFF) + "." + // Minor version + QString::number(QT_VERSION & 0xFF)); // Patch version + + QMessageBox::about(this, tr("About"), aboutText); +} From ef2f1dd2cbbc48d0cf07b784cc60139e52922322 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:23:11 -0700 Subject: [PATCH 19/21] Refactor Tree class to remove FileManager dependency and streamline initialization process --- src/Tree.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Tree.cpp b/src/Tree.cpp index f8fab29..185d0ab 100644 --- a/src/Tree.cpp +++ b/src/Tree.cpp @@ -9,24 +9,26 @@ #include #include -Tree::Tree(QSplitter *splitter, FileManager *FileManager) +Tree::Tree(QSplitter *splitter) : QObject(splitter), m_iconProvider(std::make_unique()), m_model(std::make_unique()), - m_tree(std::make_unique(splitter)), - m_FileManager(FileManager) + m_tree(std::make_unique(splitter)) { - setupModel(); - setupTree(); - connect(m_tree.get(), &QTreeView::doubleClicked, this, &Tree::openFile); } Tree::~Tree() {} -void Tree::setupModel() +void Tree::initialize(const QString &directory) { - m_model->setRootPath(getDirectoryPath()); + setupModel(directory); + setupTree(); +} + +void Tree::setupModel(const QString &directory) +{ + m_model->setRootPath(directory); m_model->setIconProvider(m_iconProvider.get()); m_model->setFilter(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot); } @@ -51,13 +53,6 @@ void Tree::setupTree() connect(m_tree.get(), &QTreeView::customContextMenuRequested, this, &Tree::showContextMenu); } -QString Tree::getDirectoryPath() const -{ - return QFileDialog::getExistingDirectory( - nullptr, QObject::tr("Open Directory"), QDir::homePath(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); -} - void Tree::openFile(const QModelIndex &index) { QString filePath = m_model->filePath(index); From d463bdd7bb1d97071bd500368bad8e023af384b4 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:23:24 -0700 Subject: [PATCH 20/21] [added] Implement tests for QSplitter initialization and action creation in TestMainWindow --- tests/test_mainwindow.cpp | 47 +++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp index b25a1cb..14567c0 100644 --- a/tests/test_mainwindow.cpp +++ b/tests/test_mainwindow.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "MainWindow.h" #include "CodeEditor.h" @@ -15,6 +16,8 @@ private slots: void testWindowTitle(); void testEditorInitialization(); void testMenuBar(); + void testInitTree(); + void testCreateAction(); private: std::unique_ptr mainWindow; @@ -48,19 +51,55 @@ void TestMainWindow::testMenuBar() { QMenuBar *menuBar = mainWindow->menuBar(); QVERIFY2(menuBar != nullptr, "MainWindow must have a QMenuBar."); - QCOMPARE(menuBar->actions().size(), 3); // File, Help, CodeAstra + QCOMPARE_EQ(menuBar->actions().size(), 3); // File, Help, CodeAstra QMenu *fileMenu = menuBar->findChild("File"); QVERIFY2(fileMenu != nullptr, "QMenuBar must contain a 'File' menu."); - QCOMPARE(fileMenu->title(), "File"); + QCOMPARE_EQ(fileMenu->title(), "File"); QMenu *helpMenu = menuBar->findChild("Help"); QVERIFY2(helpMenu != nullptr, "QMenuBar must contain a 'Help' menu."); - QCOMPARE(helpMenu->title(), "Help"); + QCOMPARE_EQ(helpMenu->title(), "Help"); QMenu *appMenu = menuBar->findChild("CodeAstra"); QVERIFY2(appMenu != nullptr, "QMenuBar must contain a 'CodeAstra' menu."); - QCOMPARE(appMenu->title(), "CodeAstra"); + QCOMPARE_EQ(appMenu->title(), "CodeAstra"); +} + +void TestMainWindow::testInitTree() +{ + QSplitter *splitter = dynamic_cast(mainWindow->centralWidget()); + QVERIFY2(splitter != nullptr, "Central widget should be a QSplitter."); + + QCOMPARE_EQ(splitter->handleWidth(), 5); + QCOMPARE_EQ(splitter->childrenCollapsible(), false); + QCOMPARE_EQ(splitter->opaqueResize(), true); + + QList sizes = splitter->sizes(); + QCOMPARE_EQ(sizes.size(), 2); +} + +void TestMainWindow::testCreateAction() +{ + // Mock parameters for createAction + QIcon icon; + QString text = "Test Action"; + QKeySequence shortcut = QKeySequence(Qt::CTRL | Qt::Key_T); + QString statusTip = "This is a test action"; + bool slotCalled = false; + + auto slot = [&slotCalled]() { slotCalled = true; }; + + QAction *action = mainWindow->createAction(icon, text, shortcut, statusTip, slot); + + QVERIFY2(action != nullptr, "Action should be successfully created."); + QCOMPARE_EQ(action->text(), text); + QCOMPARE_EQ(action->shortcuts().first(), shortcut); + QCOMPARE_EQ(action->statusTip(), statusTip); + + // Simulate triggering the action + action->trigger(); + QCOMPARE_EQ(slotCalled, true); } QTEST_MAIN(TestMainWindow) From 03ff07606c8167cea2bf7fe382139bf4470ccdb8 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Mar 2025 00:23:34 -0700 Subject: [PATCH 21/21] [added] Implement unit tests for Tree class to validate openFile method with invalid input --- tests/test_tree.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/test_tree.cpp diff --git a/tests/test_tree.cpp b/tests/test_tree.cpp new file mode 100644 index 0000000..f00465c --- /dev/null +++ b/tests/test_tree.cpp @@ -0,0 +1,44 @@ +#include +#include +#include "Tree.h" +#include "FileManager.h" +#include "CodeEditor.h" + +#include +#include +#include + +class TestTree : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + void testOpenFile_invalid(); +}; + +void TestTree::initTestCase() +{ + qDebug() << "Initializing TestTree tests..."; +} + +void TestTree::cleanupTestCase() +{ + qDebug() << "Cleaning up TestTree tests..."; +} + +void TestTree::testOpenFile_invalid() +{ + QSplitter *splitter = new QSplitter; + Tree tree(splitter); + + QModelIndex index; + + tree.openFile(index); + + QVERIFY2(FileManager::getInstance().getCurrentFileName().isEmpty(), "FileManager should not process an invalid file."); +} + +QTEST_MAIN(TestTree) +#include "test_tree.moc"