From 87e607cde726b96bd5e67d67074bd2afa0156d65 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 8 Nov 2025 11:19:13 +0700 Subject: [PATCH 1/5] Update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 385ca73..b746b06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *build -*private* \ No newline at end of file +*private* +*.vscode \ No newline at end of file From c059f65f97c11b734b3350b1e1b761bef5475d27 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 8 Nov 2025 11:19:24 +0700 Subject: [PATCH 2/5] Add version --- CMakeLists.txt | 14 +++++++++++++- include/version.h.in | 6 ++++++ src/main.cpp | 4 +++- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 include/version.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fba6c3..de08101 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,20 @@ cmake_minimum_required(VERSION 3.14) # ---------------------------------------------------------------------------------------- project(cpp_lab_project # ${PROJECT_NAME} VERSION 1.0.0 - DESCRIPTION "The project with GoogleTest and CMake" + DESCRIPTION "A C/C++ project uses CMake, GoogleTest, gcc, g++, cppcheck, and lcov, integrated with Docker and GitHub Actions for CI/CD." LANGUAGES CXX ) +# Build timestamp +file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/include) +string(TIMESTAMP BUILD_TIME "%Y-%m-%d %H:%M:%S") + +configure_file( + ${CMAKE_SOURCE_DIR}/include/version.h.in + ${CMAKE_BINARY_DIR}/generated/version.h +) + + set(PROJECT_NAME_TEST ${PROJECT_NAME}_unit_test) # name for the unit-test executable # ---------------------------------------------------------------------------------------- @@ -60,11 +70,13 @@ enable_testing() # Header files directory set(APP_HEADERS "include" + "${CMAKE_BINARY_DIR}/generated" # cmake generated headers ) # Core source files set(APP_SOURCES "src/DeleteMe.cpp" + "src/core/1_basic.cpp" ) # Test files diff --git a/include/version.h.in b/include/version.h.in new file mode 100644 index 0000000..4d31f37 --- /dev/null +++ b/include/version.h.in @@ -0,0 +1,6 @@ +#pragma once + +#define APP_NAME "@PROJECT_NAME@" +#define APP_VERSION "@PROJECT_VERSION@" +#define APP_DESCRIPTION "@PROJECT_DESCRIPTION@" +#define APP_BUILD_TIME "@BUILD_TIME@" diff --git a/src/main.cpp b/src/main.cpp index 6d8bfc1..974edfb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,9 @@ #include +#include "version.h" int main(int argc, char *argv[]) { - std::cout << "Hello World" << std::endl; + std::cout << APP_NAME << " v" << APP_VERSION << std::endl; + std::cout << APP_DESCRIPTION << std::endl; return 0; } \ No newline at end of file From c6eba893af9c065e05002af8f5f9e7a5dd2c3533 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 8 Nov 2025 20:26:03 +0700 Subject: [PATCH 3/5] Update README.md --- README.md | 67 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index d00429d..65f3d06 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,67 @@ -## OVERVIEW - - Structure: - includes/ → header files (.h, .hpp) - src/ → source files (.cpp) - tests/ → GoogleTest test cases +## 1. OVERVIEW +**Project Structure** +``` +includes/ → Header files (.h, .hpp) +src/ → Source files (.cpp) +tests/ → GoogleTest test cases +``` +## 2. DEPENDENCIES +Make sure the following tools are installed before building the project: +- **g++ / gcc** +- **CMake** +- **Git** +- **lcov** (for code coverage) +- **cppcheck** (for static analysis) -## DEPENDENCIES - -## SETUP +## 3. SETUP * Setup the Local Test Environment - * Using your own Ubuntu system + * 1.Using your own Ubuntu system * Install `gcc`, `cmake`, `git`, and `pthread` (Skip this step if you already install) ``` $ sudo apt-get update - $ sudo apt-get install g++=4:5.3.1-1ubuntu1 - $ sudo apt-get install lcov=1.12-2 - $ sudo apt-get install cmake=3.5.1-1ubuntu3 - $ sudo apt-get install git=1:2.7.4-0ubuntu1.6 - $ sudo apt-get install libpthread-stubs0-dev=0.3-4 - + $ sudo apt-get install g++ + $ sudo apt-get install lcov + $ sudo apt-get install cmake + $ sudo apt-get install git + $ sudo apt-get install cppcheck ``` * Build the application and the tests ``` $ cd build $ cmake .. $ cmake --build . - ``` * Run the application and the test ``` $ ./cpp_lab_project $ ./cpp_lab_project_test ``` - * (Optional) Run the cpp check + * (Optional) Run static analysis ``` $ sudo apt-get install cppcheck $ cppcheck "folder" / "file" ``` - * Using **Docker** - * Use the -t or --tag flag to set the name of the image to be created. (the full name is actually sample-ci-cpp:latest, since latest is the default tag) - * Opening an interactive shell inside your Docker container to explore, test, or debug the environment built from your image. - * docker run → start a new container. - * -it → run it interactively: - * -i = keep STDIN open (so you can type commands) - * -t = allocate a terminal (TTY) - * sample-ci-cpp:latest → the image you built earlier. - * /bin/bash → the command to execute inside the container (opens a Bash shell). + * 2.Using **Docker** + * Build the Docker image ``` docker build --tag sample-ci-cpp . + ``` + * Run an interactive container + ``` docker run -it sample-ci-cpp:latest /bin/bash + ``` + * Inspect the environment + ``` printenv ``` + * *Notes:* + * Use the -t or --tag flag to set the name of the image to be created. (the full name is actually sample-ci-cpp:latest, since latest is the default tag) + * Opening an interactive shell inside your Docker container to explore, test, or debug the environment built from your image. + * docker run to start a new container. + * -it → run it interactively: + * -i = keep STDIN open (so you can type commands) + * -t = allocate a terminal (TTY) + * sample-ci-cpp:latest → the image you built earlier. + * /bin/bash → the command to execute inside the container (opens a Bash shell). -## DOCUMENTATIONs \ No newline at end of file +## 4. DOCUMENTATIONS \ No newline at end of file From fc0b810c9c165dac584c23aa71f7af24cea05845 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 8 Nov 2025 20:30:10 +0700 Subject: [PATCH 4/5] Add core/basics --- CMakeLists.txt | 3 +- src/core/basics/InitializeVariable.cpp | 63 ++++++++++++ src/core/basics/Operations.cpp | 129 +++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/core/basics/InitializeVariable.cpp create mode 100644 src/core/basics/Operations.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index de08101..9db9342 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,8 @@ set(APP_HEADERS # Core source files set(APP_SOURCES "src/DeleteMe.cpp" - "src/core/1_basic.cpp" + "src/core/basics/InitializeVariable.cpp" + "src/core/basics/Operations.cpp" ) # Test files diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp new file mode 100644 index 0000000..fc90c93 --- /dev/null +++ b/src/core/basics/InitializeVariable.cpp @@ -0,0 +1,63 @@ +#include +using namespace std; + +void initialize_variable(); + +// A struct that runs code when its object is created +struct InitializeVariable +{ + InitializeVariable() + { + cout << "\n" + << "\n" + << "InitializeVariable\n"; + initialize_variable(); + } +}; + +// All global and static objects are constructed before main() begins. +static InitializeVariable autoRunInstance; + +struct Foo +{ + Foo() + { + cout << "Default constructor/ default init\n"; + } + + // explicit Foo(int) + Foo(int) + { + cout << "Constructor called with int / copy init\n"; + } + + Foo(const Foo &other) + { + std::cout << "Copy constructor called\n"; + } +}; + +void initialize_variable() +{ + cout << "\n--- Variable Initialization Examples ---\n"; + // There are there common ways to intialize a variable + // * Default + int initDefaultVar; + Foo initDefaultObj; + + // *Traditional + // * copy-init: Type var = value; + // 1. Compiler tries to create a temporary Foo from 2.3 by implicit conversion (calls Foo() ). + // 2. If constructor is explicit, implicit conversion is not allowed → error. + // 3. Otherwise, temporary Foo is created and then copy/move into copyInitObj2. + Foo copyInitObj = 2.3; // implicit 2.3(float) -> 2(int) -> call Foo(int) -> create a temporary Foo -> is copied or moved into copyInitObj + + // * direct-init: Type var(value); + Foo directInitObj(4); // call Foo(int) + Foo directInitObj2(4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) -> + + // * Brace init + // calls the constructor directly without allowing implicit conversions. + Foo braceInit{3}; + // Foo braceInit2{3.3}; // ERORR => Prefer this way +} \ No newline at end of file diff --git a/src/core/basics/Operations.cpp b/src/core/basics/Operations.cpp new file mode 100644 index 0000000..d3546e0 --- /dev/null +++ b/src/core/basics/Operations.cpp @@ -0,0 +1,129 @@ +#include +using namespace std; + +void arithmeticOperator(); +void logicalOperator(); +void bitWiseOperator(); + +struct Operations +{ + Operations() + { + cout << "\n" + << "\n" + << "Operation\n"; + arithmeticOperator(); + logicalOperator(); + bitWiseOperator(); + } +}; + +static Operations autoRunInstance; + +void arithmeticOperator() +{ + cout << "\n--- ArithmeticOperator Examples ---\n"; + int a{100}, b{200}; + + // Addition + cout << "a = " << a << ", b = " << b << "\n"; + int sum = a + b; + cout << "sum = " << sum << "\n"; + + // Subtraction + cout << "a = " << a << ", b = " << b << "\n"; + int different = a - b; + cout << "different = " << different << "\n"; + + // Multiplication + cout << "a = " << a << ", b = " << b << "\n"; + int product = a * b; + cout << "product = " << product << "\n"; + + // Division + cout << "a = " << a << ", b = " << b << "\n"; + int quotient = a / b; + cout << "quotient = " << quotient << "\n"; + + // Modulus + cout << "a = " << a << ", b = " << b << "\n"; + int remainder = a % b; + cout << "remainder = " << remainder << "\n"; + + // Increment + cout << "a = " << a << "\n"; + int preIn = ++a; // increase a, return copy + cout << "preIn = " << preIn << "\n"; + + cout << "a = " << a << "\n"; + int postIn = a++; // copy a to a copy, then increase a, return copy + cout << "postIn = " << preIn << "\n"; + + // Decrement + cout << "b = " << b << "\n"; + int preDe = --b; + cout << "preDe = " << preDe << "\n"; + + cout << "b = " << b << "\n"; + int postDe = b--; + cout << "postDe = " << postDe << "\n"; + + // Comma: + cout << "a = " << a << ", b = " << b << "\n"; + int value = (a, b); // evalue a then b, return value of b + cout << "Comma(a,b) = " << value << "\n"; +} + +void logicalOperator() +{ + cout << "\n--- LogicalOperator Examples ---\n"; + bool a = true; + bool b = false; + bool c = true; + + cout << boolalpha; // show true/false instead of 1/0 + cout << "a = " << a << ", b = " << b << ", c = " << c << "\n\n"; + + // AND (&&) + cout << "[AND] a && b = " << (a && b) << "\n"; + + // OR (||) + cout << "[OR ] a || c = " << (a || c) << "\n"; + + // NOT (!) + cout << "[NOT] !c = " << (!c) << "\n"; +} + +#include +void bitWiseOperator() +{ + cout << "\n--- BitWiseOperator Examples ---\n"; + bitset<8> bitsA{0b1111'1111}; + bitset<8> bitsB{0b1111'0000}; + + cout << "bitA = " << bitsA << ", bitB = " << bitsB << "\n"; + + // AND + bitset<8> result = bitsA & bitsB; + cout << "bitA && bitB= " << result << "\n"; + + // OR + result = bitsA | bitsB; + cout << "bitA | bitB= " << result << "\n"; + + // XOR + result = bitsA ^ bitsB; + cout << "bitA ^ bitB= " << result << "\n"; + + // NOT + result = ~bitsA; + cout << "~bitA = " << result << "\n"; + + // LEFT SHIFT + result = bitsA << 1; + cout << "bitA << 1 = " << result << "\n"; + + // RIGHT SHIFT + result = bitsA >> 1; + cout << "bitA >> 1 = " << result << "\n"; +} \ No newline at end of file From 0c226d4d2de460cabbdd4e30077ffffda54d5def Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Sat, 8 Nov 2025 21:25:10 +0700 Subject: [PATCH 5/5] fix the cppcheck warnings --- src/core/basics/InitializeVariable.cpp | 26 ++++++++++++++------------ src/core/basics/Operations.cpp | 8 ++++---- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp index fc90c93..6ff05fa 100644 --- a/src/core/basics/InitializeVariable.cpp +++ b/src/core/basics/InitializeVariable.cpp @@ -26,7 +26,7 @@ struct Foo } // explicit Foo(int) - Foo(int) + explicit Foo(int) { cout << "Constructor called with int / copy init\n"; } @@ -42,22 +42,24 @@ void initialize_variable() cout << "\n--- Variable Initialization Examples ---\n"; // There are there common ways to intialize a variable // * Default - int initDefaultVar; - Foo initDefaultObj; + [[maybe_unused]] int initDefaultVar; + [[maybe_unused]] Foo initDefaultObj; - // *Traditional - // * copy-init: Type var = value; - // 1. Compiler tries to create a temporary Foo from 2.3 by implicit conversion (calls Foo() ). - // 2. If constructor is explicit, implicit conversion is not allowed → error. - // 3. Otherwise, temporary Foo is created and then copy/move into copyInitObj2. - Foo copyInitObj = 2.3; // implicit 2.3(float) -> 2(int) -> call Foo(int) -> create a temporary Foo -> is copied or moved into copyInitObj + // * Traditional initialization + // * Copy-init: Type var = value; + // 1. Compiler tries to convert the value to a temporary Foo. + // 2. If the constructor is explicit, implicit conversion is blocked -> compilation error. + // 3. Otherwise, a temporary Foo is created and then copied/moved into the variable. + [[maybe_unused]] Foo copyInitObj = (Foo)2.3; // explicit cast: double 2.3 -> int 2 (implicit narrowing) -> Foo(int) -> temporary Foo -> copied/moved into copyInitObj + // Foo copyInitObjError = 2.3; // ERROR: implicit conversion blocked by explicit constructor + // We can explicitly prevent certain conversions using = delete or using {} // * direct-init: Type var(value); - Foo directInitObj(4); // call Foo(int) - Foo directInitObj2(4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) -> + [[maybe_unused]] Foo directInitObj(4); // call Foo(int) + [[maybe_unused]] Foo directInitObj2(4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) -> // * Brace init // calls the constructor directly without allowing implicit conversions. - Foo braceInit{3}; + [[maybe_unused]] Foo braceInit{3}; // Foo braceInit2{3.3}; // ERORR => Prefer this way } \ No newline at end of file diff --git a/src/core/basics/Operations.cpp b/src/core/basics/Operations.cpp index d3546e0..06dfee2 100644 --- a/src/core/basics/Operations.cpp +++ b/src/core/basics/Operations.cpp @@ -57,7 +57,7 @@ void arithmeticOperator() cout << "a = " << a << "\n"; int postIn = a++; // copy a to a copy, then increase a, return copy - cout << "postIn = " << preIn << "\n"; + cout << "postIn = " << postIn << "\n"; // Decrement cout << "b = " << b << "\n"; @@ -69,9 +69,9 @@ void arithmeticOperator() cout << "postDe = " << postDe << "\n"; // Comma: + int value = (a++, b); // a is incremented, then b is returned cout << "a = " << a << ", b = " << b << "\n"; - int value = (a, b); // evalue a then b, return value of b - cout << "Comma(a,b) = " << value << "\n"; + cout << "comma(a++, b) = " << value << "\n"; } void logicalOperator() @@ -88,7 +88,7 @@ void logicalOperator() cout << "[AND] a && b = " << (a && b) << "\n"; // OR (||) - cout << "[OR ] a || c = " << (a || c) << "\n"; + cout << "[OR ] a || b = " << (a || b) << "\n"; // NOT (!) cout << "[NOT] !c = " << (!c) << "\n";