# Tutorial 1.2: Introduction to Unit Testing

**Objective:** To introduce unit testing to the C++ project from Tutorial 1.1. This tutorial will cover adding a testing framework (`googletest`), creating a simple class, writing tests for that class, and integrating the tests into the CMake build system for easy execution within VSCode.

---

## 1. Prerequisites

*   A completed and working project from "Tutorial 1.1: Your First Modern C++ Project".
*   `vcpkg` installed and configured as per Tutorial 1.1.

---

## 2. Installing the Testing Framework

We will use `googletest`, a popular and powerful testing framework for C++.

Just like with `spdlog`, we use `vcpkg` to install it.

```bash
# Use the vcpkg executable to install the library
# Replace /path/to/vcpkg with your actual vcpkg path
/home/YOUR_USERNAME/dev/tools/vcpkg/vcpkg install gtest
```
*Note: The package name is `gtest` for `googletest`.*

---

## 3. Refactoring the Project Structure

To keep our project organized, we'll separate our main application code from the test code. The new structure inside `tutorial-1` will look like this:
```
tutorial-1/
├── CMakeLists.txt
├── src/
│   ├── calculator.h
│   ├── calculator.cpp
│   └── main.cpp
└── test/
    └── test_calculator.cpp
```
The previous steps in this session have already created this structure for you.

---

## 4. Creating a Class to Test

We need some logic to test. We've created a simple `Calculator` class.

**File:** `tutorial-1/src/calculator.h`
```cpp
#ifndef CALCULATOR_H
#define CALCULATOR_H

class Calculator {
public:
    int add(int a, int b);
};

#endif // CALCULATOR_H
```

**File:** `tutorial-1/src/calculator.cpp`
```cpp
#include "calculator.h"

int Calculator::add(int a, int b) {
    return a + b;
}
```

We also updated `main.cpp` to use this new class.

**File:** `tutorial-1/src/main.cpp` (Updated)
```cpp
#include <iostream>
#include "spdlog/spdlog.h"
#include "calculator.h"

int main() {
    spdlog::info("Hello, Modern C++! Initializing trading strategy...");

    Calculator calc;
    int result = calc.add(40, 2);

    spdlog::info("The result of 40 + 2 is: {}", result);

    std::cout << "Check your terminal for spdlog output!" << std::endl;

    return 0;
}
```

---

## 5. Writing the Unit Tests

Now, we'll write our first test in the `test` directory.

**File:** `tutorial-1/test/test_calculator.cpp`
```cpp
#include <gtest/gtest.h>
#include "../src/calculator.h" // Include the header for the class we are testing

// Test fixture for Calculator class
class CalculatorTest : public ::testing::Test {
protected:
    Calculator calc;
};

// Test case for the add method
TEST_F(CalculatorTest, Add) {
    EXPECT_EQ(calc.add(2, 2), 4);
    EXPECT_EQ(calc.add(-1, 1), 0);
    EXPECT_EQ(calc.add(-5, -5), -10);
}

// Another test case for the add method for good measure
TEST_F(CalculatorTest, AddWithZero) {
    EXPECT_EQ(calc.add(0, 5), 5);
    EXPECT_EQ(calc.add(5, 0), 5);
    EXPECT_EQ(calc.add(0, 0), 0);
}
```

---

## 6. Updating the Build System (CMake)

This is the most critical part. We have updated our `CMakeLists.txt` to build both our main application and our tests as separate executables.

**File:** `tutorial-1/CMakeLists.txt` (Updated)
```cmake
cmake_minimum_required(VERSION 3.15)
project(Tutorial1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find dependencies
find_package(spdlog CONFIG REQUIRED)
find_package(GTest CONFIG REQUIRED)

# Create a library for our application code
# This allows us to share the code between the main app and the tests
add_library(MyLib src/calculator.cpp src/calculator.h)
target_include_directories(MyLib PUBLIC src)

# Define our main executable
add_executable(App src/main.cpp)

# Link our App against spdlog and our library
target_link_libraries(App PRIVATE spdlog::spdlog MyLib)

# Enable testing with CTest (CMake's testing framework)
enable_testing()

# Define the test executable
add_executable(RunTests test/test_calculator.cpp)

# Link our test executable against GTest and our library
target_link_libraries(RunTests PRIVATE GTest::GTest GTest::Main MyLib)

# Add the test to CTest
include(GoogleTest)
gtest_add_tests(TARGET RunTests)
```

---

## 7. Building and Running Tests in VSCode

1.  **Install `gtest`:** Make sure you have installed `gtest` using `vcpkg` as described in step 2.
2.  **Configure CMake:** Run `CMake: Configure` from the command palette (Ctrl+Shift+P). It should detect the changes and find `gtest`.
3.  **Build:** Click the **Build** button in the status bar. This will now build `App` and `RunTests`.
4.  **Run Tests:** The "CMake Tools" extension provides a "Test Explorer" view in VSCode.
    *   Open the Test Explorer from the side bar (the icon looks like a beaker).
    *   You should see your test suite (`CalculatorTest`) and the individual tests.
    *   Click the "play" button at the top of the Test Explorer to run all tests.
    *   You can also run individual tests. The results will be shown directly in the UI.

---

**Congratulations!** You have now added unit testing to your project. This is a crucial skill for writing robust and maintainable C++ applications. You've learned how to:
*   Add a testing library (`googletest`) with `vcpkg`.
*   Structure your project to separate app code from test code.
*   Create a shared library and multiple executables with CMake.
*   Write and run unit tests using the VSCode Test Explorer.


## Feedback and Questions

1.  The line ```target_link_libraries(RunTests PRIVATE GTest::GTest GTest::Main MyLib)``` caused cmake compilation error, I changed to
```target_link_libraries(RunTests PRIVATE GTest::gtest_main MyLib)```
I looked up documentation for this.

2. Are there alternative ways to install dependencies other the through vcpkg? For example would FetchContent work (https://cmake.org/cmake/help/latest/module/FetchContent.html)? 

3.Interestingly, in vscode,  the line ```#include <gtest/gtest.h>``` i was curious where the files as located - as i had not specified where it is other the download gtest in a separate process via vcpkg. when in vscode i hovered and clicked on go to definition it went to the location. curious how vscode knows this information.

4.I was interested to debug unit tests individually and managed to do this by following https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/debug-launch.md#debugging-tests
