From d18bf63bfc550abe38f3b1f4b1731d8b25bda6db Mon Sep 17 00:00:00 2001 From: Charliechen114514 <725610365@qq.com> Date: Sun, 5 Jul 2026 21:52:26 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=B7=A5=E7=A8=8B=E6=B7=B1?= =?UTF-8?q?=E5=8C=96=20=E2=80=94=20CI=20=E5=AE=88=E9=97=A8=20+=20FileCopie?= =?UTF-8?q?r=20=E6=B5=8B=E8=AF=95=20+=20ASan/UBSan=20+=20clang-tidy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rename 同步(本仓已 GitHub rename 为 engineering_cpp): - README 标题 + clone 命令改 engineering_cpp 工程深化(hub 教工程,自己该名副其实): - FileCopier 提成共享库 filecopier_lib + 补 Catch2 测试 (正常拷贝 / 大文件分块 / 空文件 / 源不存在) - HUB_SANITIZE option(ASan+UBSan),本地验证无 leak/UB - CI(.github/workflows/ci.yml):gcc-13/gcc-14 双版本 × Release/ASan 矩阵 + clang-tidy job(report only,不阻塞) - .clang-tidy 基础配置(bugprone/modernize/performance/readability, 排除教学仓噪音大的检查) 验证: - 默认 build + ctest:3/3(argparser/dirscanner/filecopier)全绿 - HUB_SANITIZE=ON build + ctest:3/3 全绿(ASan/UBSan 干净) --- .clang-tidy | 24 +++++++ .github/workflows/ci.yml | 53 +++++++++++++++ CMakeLists.txt | 20 +++++- README.md | 6 +- src/FileCopier/test/filecopier_test.cpp | 86 +++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 .clang-tidy create mode 100644 .github/workflows/ci.yml create mode 100644 src/FileCopier/test/filecopier_test.cpp diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..0677c74 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,24 @@ +# clang-tidy 基础配置(engineering-cpp hub) +# 检查:bugprone / modernize / performance / readability 四大类 +# 排除教学仓里噪音较大的检查(magic-numbers / identifier-length 等) +# WarningsAsErrors 留空:CI 里 clang-tidy 仅报告,不阻塞(初次跑会有历史 warning) + +Checks: > + -*, + bugprone-*, + modernize-*, + performance-*, + readability-*, + -bugprone-easily-swappable-parameters, + -bugprone-narrowing-conversions, + -modernize-use-trailing-return-type, + -modernize-use-nodiscard, + -performance-unnecessary-value-param, + -readability-identifier-length, + -readability-magic-numbers, + -readability-function-cognitive-complexity, + -readability-named-parameter + +WarningsAsErrors: '' + +HeaderFilterRegex: 'src/.*\.h$' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3775c9d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + build-test: + name: ${{ matrix.name }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - { name: "gcc-14 Release", gcc: 14, sanitize: OFF } + - { name: "gcc-13 Release", gcc: 13, sanitize: OFF } + - { name: "gcc-14 ASan+UBSan", gcc: 14, sanitize: ON } + steps: + - uses: actions/checkout@v4 + - name: Install g++-${{ matrix.gcc }} + run: | + sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + sudo apt-get update + sudo apt-get install -y g++-${{ matrix.gcc }} + - name: Configure + run: | + cmake -B build \ + -DCMAKE_C_COMPILER=gcc-${{ matrix.gcc }} \ + -DCMAKE_CXX_COMPILER=g++-${{ matrix.gcc }} \ + -DCMAKE_BUILD_TYPE=Release \ + -DHUB_SANITIZE=${{ matrix.sanitize }} + - name: Build + run: cmake --build build -j$(nproc) + - name: Test + run: ctest --test-dir build --output-on-failure + + clang-tidy: + name: clang-tidy (report) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install + run: | + sudo apt-get update + sudo apt-get install -y clang-tidy cmake g++ + - name: Configure (compile_commands.json,不拉测试依赖) + run: cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DHUB_BUILD_TESTS=OFF + - name: Run clang-tidy + run: | + FILES=$(find src -name '*.cpp' -not -path '*/test/*') + echo "Checking:" $FILES + clang-tidy -p build $FILES diff --git a/CMakeLists.txt b/CMakeLists.txt index 365ca9c..b708e1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,12 +17,18 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(HUB_SANITIZE) + add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer) + add_link_options(-fsanitize=address,undefined) +endif() + include(CTest) # 自动 enable_testing() + BUILD_TESTING 默认 ON option(HUB_BUILD_ARGPARSER "Build ArgParser demo" ON) option(HUB_BUILD_FILECOPIER "Build FileCopier demo" ON) option(HUB_BUILD_DIRSCANNER "Build DirScanner demo" ON) option(HUB_BUILD_TESTS "Build unit tests (Catch2)" ON) +option(HUB_SANITIZE "Enable AddressSanitizer + UBSan" OFF) # ── 共享库:argparser(消双源后的唯一源头)───────────────────────── add_library(argparser STATIC src/ArgParser/ArgParser.cpp) @@ -45,9 +51,12 @@ if(HUB_BUILD_ARGPARSER) endif() # ── FileCopier demo ───────────────────────────────────────────── +add_library(filecopier_lib STATIC src/FileCopier/FileCopier.cpp) +target_include_directories(filecopier_lib PUBLIC src/FileCopier) + if(HUB_BUILD_FILECOPIER) - add_executable(fcopy src/FileCopier/FileCopier.cpp src/FileCopier/demo.cpp) - target_include_directories(fcopy PRIVATE src/FileCopier) + add_executable(fcopy src/FileCopier/demo.cpp) + target_link_libraries(fcopy PRIVATE filecopier_lib) endif() # ── DirScanner(lib + demo + test)──────────────────────────────── @@ -72,3 +81,10 @@ if(BUILD_TESTING AND HUB_BUILD_TESTS) target_link_libraries(argparser_test PRIVATE argparser Catch2::Catch2WithMain) add_test(NAME argparser_test COMMAND argparser_test) endif() + +# ── FileCopier tests ──────────────────────────────────────────── +if(BUILD_TESTING AND HUB_BUILD_TESTS) + add_executable(filecopier_test src/FileCopier/test/filecopier_test.cpp) + target_link_libraries(filecopier_test PRIVATE filecopier_lib Catch2::Catch2WithMain) + add_test(NAME filecopier_test COMMAND filecopier_test) +endif() diff --git a/README.md b/README.md index e03ad58..65e6b29 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 🎬 Project_CXXBaseComponents +# 🎬 engineering-cpp **C++23 | CMake 3.25+ | MIT License** @@ -46,8 +46,8 @@ ```bash # 克隆主仓库 -git clone https://github.com/Awesome-Embedded-Learning-Studio/Project_CXXBaseComponents -cd Project_CXXBaseComponents +git clone https://github.com/Awesome-Embedded-Learning-Studio/engineering_cpp +cd engineering_cpp # 初始化子模块(spoke 专栏仓:IniParser / MemoryPool) git submodule update --init diff --git a/src/FileCopier/test/filecopier_test.cpp b/src/FileCopier/test/filecopier_test.cpp new file mode 100644 index 0000000..4fcf39d --- /dev/null +++ b/src/FileCopier/test/filecopier_test.cpp @@ -0,0 +1,86 @@ +// ============================================================================= +// FileCopier 单元测试(Catch2) +// 覆盖:正常拷贝(内容/大小一致)/ 大文件分块 / 空文件 / 源不存在 +// ============================================================================= +#include "fcopy.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +namespace { +const fs::path fixture_root() { + return fs::temp_directory_path() / "engineering_cpp_filecopier_test"; +} + +std::string make_src(const std::string &name, const std::string &content) { + fs::create_directories(fixture_root()); + const auto path = fixture_root() / name; + std::ofstream f(path); + f << content; + return path.string(); +} + +std::string dst(const std::string &name) { + fs::create_directories(fixture_root()); + return (fixture_root() / name).string(); +} + +std::string read_all(const std::string &path) { + std::ifstream f(path); + return std::string((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); +} +} // namespace + +TEST_CASE("FileCopier 正常拷贝内容一致", "[filecopier]") { + fs::remove_all(fixture_root()); + const auto src = make_src("src_normal.txt", "hello filecopier\n"); + const auto d = dst("dst_normal.txt"); + + FileCopier fc; + REQUIRE(fc.copy(src, d)); + REQUIRE(fs::exists(d)); + REQUIRE(fs::file_size(d) == fs::file_size(src)); + REQUIRE(read_all(d) == "hello filecopier\n"); + + fs::remove_all(fixture_root()); +} + +TEST_CASE("FileCopier 大文件分块(1KB chunk,触发多轮)", "[filecopier]") { + fs::remove_all(fixture_root()); + const std::string big(100000, 'X'); + const auto src = make_src("src_big.bin", big); + const auto d = dst("dst_big.bin"); + + FileCopier fc(1024); // 1KB chunk,默认 8KB,触发多次分块 + REQUIRE(fc.copy(src, d)); + REQUIRE(fs::file_size(d) == big.size()); + REQUIRE(read_all(d) == big); + + fs::remove_all(fixture_root()); +} + +TEST_CASE("FileCopier 空文件", "[filecopier]") { + fs::remove_all(fixture_root()); + const auto src = make_src("src_empty.txt", ""); + const auto d = dst("dst_empty.txt"); + + FileCopier fc; + REQUIRE(fc.copy(src, d)); + REQUIRE(fs::exists(d)); + REQUIRE(fs::file_size(d) == 0); + + fs::remove_all(fixture_root()); +} + +TEST_CASE("FileCopier 源不存在返回 false", "[filecopier]") { + fs::remove_all(fixture_root()); + FileCopier fc; + REQUIRE_FALSE(fc.copy("/no/such/__engineering_cpp_test__.txt", dst("dst_nope.txt"))); + fs::remove_all(fixture_root()); +} From 7e8098b519796558dc3764076dbed03b5659c6f7 Mon Sep 17 00:00:00 2001 From: Charliechen114514 <725610365@qq.com> Date: Sun, 5 Jul 2026 22:22:00 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(ci):=20=E5=8E=BB=20gcc-13(demo=20?= =?UTF-8?q?=E7=94=A8=20=20=E9=9C=80=20gcc-14)+=20README=20=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E8=AF=9A=E5=AE=9E=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI 矩阵去掉 gcc-13( 需 gcc-14+),留 gcc-14 Release + ASan/UBSan。 README 环境诚实化:GCC 13+→14+ / Clang 16+→18+ / MSVC 193+→19.34+ (demo.cpp 用 std::println 教 C++23 ,保留现代写法)。 --- .github/workflows/ci.yml | 1 - README.md | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3775c9d..1c18406 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,6 @@ jobs: matrix: include: - { name: "gcc-14 Release", gcc: 14, sanitize: OFF } - - { name: "gcc-13 Release", gcc: 13, sanitize: OFF } - { name: "gcc-14 ASan+UBSan", gcc: 14, sanitize: ON } steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index 65e6b29..1f23b45 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,13 @@ | 项目 | 最低版本 | 推荐版本 | |------|----------|----------| | C++ 标准 | C++23 | C++23 | -| GCC | 11+ | 13+ | -| Clang | 13+ | 16+ | -| MSVC | 193+ | 最新 | +| GCC | 14+ | 14+ | +| Clang | 18+ | 19+ | +| MSVC | 19.34+ | 最新 | | CMake | 3.25+ | 3.28+ | +> demo.cpp 用 `std::println`(C++23 ``)演示现代写法,因此 GCC 14+ / Clang 18+ / MSVC 19.34+ 才能编译。 + ### 克隆仓库 ```bash