Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Tests

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Configure CMake
run: cmake -B build -DBUILD_TESTS=ON
- name: Build
run: cmake --build build --config Release
- name: Run tests
run: ctest --test-dir build/shared -C Release --output-on-failure
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(tasktracker_installer)
project(tasktracker_installer VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 17)

add_subdirectory(shared)
Expand Down
33 changes: 22 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Tasktracker
![Tests](https://github.com/masonlet/tasktracker/actions/workflows/test.yml/badge.svg)
[![C++17](https://img.shields.io/badge/C%2B%2B-17-blue.svg)](https://isocpp.org/std/the-standard)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)

Lightweight Windows 10/11 tool to manage folder statuses from the right-click context menu.
Quickly mark folders as Finished, Hidden, Unfinished, or reset to Default.
Expand All @@ -23,6 +26,8 @@ Right-click any folder to see Tasktracker options.
Folder icons reflect their current status.
![Example](./images/example.png)

<br/>

## Prerequisites
- Windows 10 or 11
- Administrator privileges (required for context menu installation)
Expand All @@ -32,27 +37,33 @@ Folder icons reflect their current status.
2. Run the installer
3. To uninstall, simply re-run the installer

<br/>

## Building the Project
To build TaskTracker and Installer from source using CMake:
### Prerequisites
- C++17
- CMake 3.10+

### 1. Clone the Repository
### Build Steps
```bash
# 1. Clone the repository
git clone https://github.com/masonlet/tasktracker.git
cd tasktracker
```

### 2. Create a Build Directory and Generate Build Files
```bash
mkdir build
cd build
cmake ..
# 2. Create a build directory and generate build files
cmake -B build

# 3. Build the project
cmake --build build
```
Or open the generated `.sln` file in Visual Studio and build the solution.

### 3. Build the Project
### Running Tests
```bash
cmake --build .
cmake -B build -DBUILD_TESTS=ON
cmake --build build
ctest --test-dir build/shared
```
Or open the generated `.sln` file in Visual Studio and build the solution.

## License
MIT License — see [LICENSE](./LICENSE) for details.
25 changes: 24 additions & 1 deletion shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,28 @@ source_group(TREE ${SHARED_INC_DIR} PREFIX "Header Files" FILES ${SHARED_INC})
source_group(TREE ${SHARED_SRC_DIR} PREFIX "Source Files" FILES ${SHARED_SRC})

add_library(shared STATIC ${SHARED_INC} ${SHARED_SRC})

target_include_directories(shared PUBLIC ${SHARED_INC_DIR})

option(BUILD_TESTS "Build unit tests" OFF)

if(BUILD_TESTS)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

enable_testing()
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)

# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

set_target_properties(gtest gtest_main gmock gmock_main PROPERTIES
FOLDER "Tests/GoogleTest"
)

add_subdirectory(tests)
endif()
16 changes: 16 additions & 0 deletions shared/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
add_executable(shared_tests
shared_test.cpp
)

target_link_libraries(shared_tests
PRIVATE
shared
GTest::gtest_main
)

set_target_properties(shared_tests PROPERTIES
FOLDER "Tests"
)

include(GoogleTest)
gtest_discover_tests(shared_tests)
67 changes: 67 additions & 0 deletions shared/tests/shared_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <gtest/gtest.h>
#include <filesystem>
#include <fstream>
#include "../inc/file_utils.hpp"
#include "../inc/system_utils.hpp"

using TPath = TaskTracker::Path;
namespace {
TPath makeTempPath(const std::wstring& name) {
return std::filesystem::temp_directory_path() / name;
}
}

namespace TFile = TaskTracker::FileUtils;
TEST(FileUtils, FileExists_ReturnsTrueWhenPresent) {
TPath path = makeTempPath(L"test_exist.txt");
std::ofstream{ path };

EXPECT_TRUE(TFile::fileExists(path, L"test", false));
std::filesystem::remove(path);
}

TEST(FileUtils, DeleteFile_RemovesExistingFile) {
TPath path = makeTempPath(L"test_delete.txt");
std::ofstream{ path };

EXPECT_TRUE(TFile::deleteFile(path, L"test"));
EXPECT_FALSE(std::filesystem::exists(path));
}

TEST(FileUtils, CreateDirectory_CreatesNewDirectory) {
TPath path = makeTempPath(L"test_create_dir");
EXPECT_TRUE(TFile::createDirectory(path, L"test"));
EXPECT_TRUE(std::filesystem::is_directory(path));
std::filesystem::remove(path);
}

TEST(FileUtils, DeleteDirectory_RemovesExistingDirectory) {
TPath path = makeTempPath(L"test_delete_dir");
std::filesystem::create_directory(path);
EXPECT_TRUE(TFile::deleteDirectory(path, L"test"));
EXPECT_FALSE(std::filesystem::exists(path));
}

namespace TSystem = TaskTracker::SystemUtils;
TEST(SystemUtils, GetProgramFilesPath_ReturnsValidPath) {
TPath path = TSystem::getProgramFilesPath();
EXPECT_FALSE(path.empty());
EXPECT_TRUE(std::filesystem::exists(path));
}

TEST(SystemUtils, IsValidPath_RejectsNonexistent) {
TPath fakePath = makeTempPath(L"nonexistent_dir");
EXPECT_FALSE(TSystem::isValidPath(fakePath, L"test"));
}

TEST(SystemUtils, IsValidPath_RejectsExistingFile) {
TPath filePath = makeTempPath(L"not_a_dir.txt");
std::ofstream{ filePath };
EXPECT_FALSE(TSystem::isValidPath(filePath, L"test"));
std::filesystem::remove(filePath);
}

TEST(SystemUtils, DeleteDesktopIni_HandlesNonexistentFile) {
TPath path = makeTempPath(L"desktop.ini");
EXPECT_TRUE(TSystem::deleteDesktopIni(path, L"test"));
}