diff --git a/.clang-tidy b/.clang-tidy index 67f6ac7..da93ae8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,46 +1,148 @@ -# Apply to ALL headers (empty = no restriction) -HeaderFilterRegex: '.*' - -# Treat warnings as errors (optional but recommended for CI) -# WarningsAsErrors: '*' -WarningsAsErrors: '' +--- +# Configure clang-tidy for this project. +# Here is an explanation for why some of the checks are disabled: +# +# -google-readability-namespace-comments: the *_CLIENT_NS is a macro, and +# clang-tidy fails to match it against the initial value. +# +# -modernize-use-trailing-return-type: clang-tidy recommends using +# `auto Foo() -> std::string { return ...; }`, we think the code is less +# readable in this form. +# +# --modernize-concat-nested-namespaces: clang-tidy recommends +# `namespace google::cloud {}` over `namespace google { namespace cloud { } }` +# We need to support C++14, which does not supported nested namespaces. +# +# --modernize-use-nodiscard: clang-tidy recommends adding a nodiscard annotation +# to functions where the return value should not be ignored. +# We need to support C++14, which does not supported the annotation. +# +# -modernize-return-braced-init-list: We think removing typenames and using +# only braced-init can hurt readability. +# +# -modernize-avoid-c-arrays: We only use C arrays when they seem to be the +# right tool for the job, such as `char foo[] = "hello"`. In these cases, +# avoiding C arrays often makes the code less readable, and std::array is +# not a drop-in replacement because it doesn't deduce the size. +# +# -modernize-type-traits: clang-tidy recommands using c++17 style variable +# templates. We will enable this check after we moved to c++17. +# +# -modernize-unary-static-assert: clang-tidy asks removing empty string in +# static_assert(), the check is only applicable for c++17 and later code. +# We will enable this check after we moved to c++17. +# +# -performance-move-const-arg: This warning requires the developer to +# know/care more about the implementation details of types/functions than +# should be necessary. For example, `A a; F(std::move(a));` will trigger a +# warning IFF `A` is a trivial type (and therefore the move is +# meaningless). It would also warn if `F` accepts by `const&`, which is +# another detail that the caller need not care about. +# +# -performance-avoid-endl: we would like to turn this on, but there are too +# many legitimate uses in our samples. +# +# -performance-enum-size: Smaller enums may or not may be faster, it depends on +# the architechture. If data size was a consideration, we might decide to +# enable the warnings. +# +# -readability-redundant-declaration: A friend declaration inside a class +# counts as a declaration, so if we also declare that friend outside the +# class in order to document it as part of the public API, that will +# trigger a redundant declaration warning from this check. +# +# -readability-avoid-return-with-void-value: We believe this is idiomatic +# and saves typing, and the intent is obvious. +# +# -readability-function-cognitive-complexity: too many false positives with +# clang-tidy-12. We need to disable this check in macros, and that setting +# only appears in clang-tidy-13. +# +# -bugprone-narrowing-conversions: too many false positives around +# `std::size_t` vs. `*::difference_type`. +# +# -bugprone-easily-swappable-parameters: too many false positives. +# +# -bugprone-implicit-widening-of-multiplication-result: too many false positives. +# Almost any expression of the form `2 * variable` or `long x = a_int * b_int;` +# generates an error. +# +# -bugprone-unchecked-optional-access: too many false positives in tests. +# Despite what the documentation says, this warning appears after +# `ASSERT_TRUE(variable)` or `ASSERT_TRUE(variable.has_value())`. +# +# TODO(#14162): Enable clang-tidy checks. We initially omitted these checks +# because they require large cleanup efforts or were blocking the clang-tidy +# X update. Checks: > -*, - clang-diagnostic-*, - modernize-*, - -modernize-use-trailing-return-type, - -modernize-use-auto, - cppcoreguidelines-*, - -cppcoreguidelines-owning-memory, - -cppcoreguidelines-pro-type-vararg, - -cppcoreguidelines-avoid-magic-numbers, + abseil-*, bugprone-*, + google-*, + misc-*, + modernize-*, performance-*, + portability-*, readability-*, - -readability-magic-numbers, + -bugprone-exception-escape, + -google-readability-braces-around-statements, + -google-readability-namespace-comments, + -google-runtime-references, + -misc-non-private-member-variables-in-classes, + -misc-const-correctness, + -misc-include-cleaner, + -modernize-return-braced-init-list, + -modernize-use-trailing-return-type, + -modernize-concat-nested-namespaces, + -modernize-use-nodiscard, + -modernize-avoid-c-arrays, + -modernize-type-traits, + -modernize-unary-static-assert, + -performance-move-const-arg, + -performance-avoid-endl, + -performance-enum-size, + -readability-braces-around-statements, -readability-identifier-length, - misc-*, - -misc-unused-parameters - -CheckOptions: - - key: readability-identifier-naming.NamespaceCase - value: lower_case - - - key: readability-identifier-naming.ClassCase - value: CamelCase - - - key: readability-identifier-naming.StructCase - value: CamelCase - - - key: readability-identifier-naming.FunctionCase - value: lower_case + -readability-magic-numbers, + -readability-named-parameter, + -readability-redundant-declaration, + -readability-avoid-return-with-void-value, + -readability-function-cognitive-complexity, + -bugprone-narrowing-conversions, + -bugprone-easily-swappable-parameters, + -bugprone-inc-dec-in-conditions, + -bugprone-implicit-widening-of-multiplication-result, + -bugprone-unchecked-optional-access, + -bugprone-unused-local-non-trivial-variable, + -bugprone-unused-return-value - - key: readability-identifier-naming.VariableCase - value: lower_case +# Turn all the warnings from the checks above into errors. +WarningsAsErrors: "*" - - key: readability-identifier-naming.MemberCase - value: lower_case +HeaderFilterRegex: "(google/cloud/|generator/).*\\.h$" - - key: modernize-use-nullptr.NullMacros - value: 'NULL' \ No newline at end of file +CheckOptions: + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } + - { key: readability-identifier-naming.FunctionCase, value: aNy_CasE } + - { key: readability-identifier-naming.VariableCase, value: lower_case } + - { key: readability-identifier-naming.ClassMemberCase, value: lower_case } + - { key: readability-identifier-naming.ClassMemberSuffix, value: _ } + - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } + - { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantPrefix, value: k } + - { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase } + - { key: readability-identifier-naming.ConstexprVariablePrefix, value: k } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantPrefix, value: k } + - { key: readability-identifier-naming.MemberConstantCase, value: CamelCase } + - { key: readability-identifier-naming.MemberConstantPrefix, value: k } + - { key: readability-identifier-naming.StaticConstantCase, value: CamelCase } + - { key: readability-identifier-naming.StaticConstantPrefix, value: k } + - { key: readability-implicit-bool-conversion.AllowIntegerConditions, value: 1 } + - { key: readability-implicit-bool-conversion.AllowPointerConditions, value: 1 } + - { key: readability-function-cognitive-complexity.IgnoreMacros, value: 1 } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d90d64..b03e79d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,33 +1,13 @@ -# ROOT CMAKE -# │ -# ┌─────────────────┴─────────────────┐ -# │ │ -# src module tests module -# │ │ -# ┌────┴────┐ │ -# │ │ │ -# core socket │ -# │ │ │ -# └──────┬──┘ │ -# │ │ -# ▼ ▼ -# cpp_lab_project cpp_lab_project_unit_test -# (main executable) (GoogleTest executable) - cmake_minimum_required(VERSION 3.14) -# ---------------------------------------------------------------------------------------- # Project metadata -# ---------------------------------------------------------------------------------------- project(cpp_lab_project # ${PROJECT_NAME} VERSION 1.0.0 DESCRIPTION "A C/C++ project uses CMake, GoogleTest, gcc, g++, cppcheck, and lcov, integrated with Docker and GitHub Actions for CI/CD." LANGUAGES CXX ) -# ---------------------------------------------------------------------------------------- # Output directories to build/bin -# ---------------------------------------------------------------------------------------- # Executables set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Shared libraries @@ -35,9 +15,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # Static libraries set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -# ---------------------------------------------------------------------------------------- # Compiler and language configuration -# ---------------------------------------------------------------------------------------- # Require at least C++17 for GoogleTest and modern C++ features set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -45,9 +23,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Export compile_commands.json (useful for clang-tidy, clangd, IDEs) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# ---------------------------------------------------------------------------------------- # Build metadata -# ---------------------------------------------------------------------------------------- # Ensure directory exists for generated headers file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/generated) @@ -60,14 +36,10 @@ configure_file( ${CMAKE_BINARY_DIR}/generated/version.h ) -# ---------------------------------------------------------------------------------------- # External dependencies (GoogleTest,...) -# ---------------------------------------------------------------------------------------- include(cmake/Dependencies.cmake) -# ---------------------------------------------------------------------------------------- # Compiler warnings (useful for learning/debugging) -# ---------------------------------------------------------------------------------------- add_compile_options(-Wall -Wextra -Wpedantic) message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") @@ -75,9 +47,7 @@ message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}") message(STATUS "C++ Compiler ID: ${CMAKE_CXX_COMPILER_ID}") message(STATUS "C++ Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") -# ---------------------------------------------------------------------------------------- # Code coverage configuration -# ---------------------------------------------------------------------------------------- option(ENABLE_COVERAGE "Enable coverage reporting" OFF) if(ENABLE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") @@ -86,13 +56,9 @@ if(ENABLE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_link_options(--coverage) endif() -# ---------------------------------------------------------------------------------------- # Enable CTest framework (used by GoogleTest) -# ---------------------------------------------------------------------------------------- enable_testing() -# ---------------------------------------------------------------------------------------- # Add project modules -# ---------------------------------------------------------------------------------------- add_subdirectory(src) add_subdirectory(tests) \ No newline at end of file diff --git a/README.md b/README.md index 2a05e73..b5fc39d 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ Get-ChildItem -Recurse -Include *.cpp, *.h, *.hpp | ForEach-Object { clang-forma $ sudo apt-get install cppcheck $ sudo apt-get install -y clang-tidy $ sudo apt install python3-gcovr + $ sudo apt-get install -y libgtkmm-4.0-dev ``` * Build the application and the tests ```bash diff --git a/include/Logger.h b/include/Logger.h new file mode 100644 index 0000000..2168a9f --- /dev/null +++ b/include/Logger.h @@ -0,0 +1,61 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include + +#ifndef NDEBUG +#include +#include +#include + +class Logger { + public: + static Logger& instance() { + static Logger logger; // guaranteed single instance, thread-safe in C++11+ + return logger; + } + + void log(std::string_view msg, std::string_view level = "INFO", + std::source_location loc = std::source_location::current()) { + std::lock_guard lock(mutex_); + + // Extract filename only (no full path) + std::string_view file = loc.file_name(); + auto pos = file.find_last_of("/\\"); + if (pos != std::string_view::npos) { + file = file.substr(pos + 1); + } + + // Get current time + auto now = std::chrono::system_clock::now(); + auto t = std::chrono::system_clock::to_time_t(now); + std::tm tm{}; + localtime_r(&t, &tm); + + char time_buf[9]; + std::strftime(time_buf, sizeof(time_buf), "%H:%M:%S", &tm); + + std::cout << "[" << time_buf << "]" << "[" << level << "]" << "[" << file + << ":" << loc.line() << "]" << "[" << loc.function_name() << "] " + << msg << '\n'; + } + + // Prevent copies + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; + + private: + Logger() = default; + std::mutex mutex_; +}; + +#define LOG(msg) Logger::instance().log(msg) + +#else + +inline void LOG(const std::string& msg) { + std::cout << msg << '\n'; +} + +#endif +#endif \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh index 3f264b6..a15e535 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -1,7 +1,3 @@ -## NOTE: -## This file was initially generated with the assistance of AI. -## The code has been reviewed and may have been modified by the developer -## to ensure correctness, readability, and compliance with project requirements. #!/usr/bin/env bash set -e # Exit immediately if a command fails diff --git a/src/main.cpp b/src/main.cpp index ff9783b..1752b42 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include #include "ExampleRegistry.h" +#include "Logger.h" #include "version.h" int readChoice() { @@ -103,6 +104,7 @@ void runMenu() { } int main(int argc, char* argv[]) { + LOG("Logger has been integrated"); std::cout << std::endl; if (__cplusplus == 202302L) std::cout << "C++23";