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
24 changes: 24 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -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$'
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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-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
20 changes: 18 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)────────────────────────────────
Expand All @@ -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()
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 🎬 Project_CXXBaseComponents
# 🎬 engineering-cpp

**C++23 | CMake 3.25+ | MIT License**

Expand Down Expand Up @@ -37,17 +37,19 @@
| 项目 | 最低版本 | 推荐版本 |
|------|----------|----------|
| 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 `<print>`)演示现代写法,因此 GCC 14+ / Clang 18+ / MSVC 19.34+ 才能编译。

### 克隆仓库

```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
Expand Down
86 changes: 86 additions & 0 deletions src/FileCopier/test/filecopier_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// =============================================================================
// FileCopier 单元测试(Catch2)
// 覆盖:正常拷贝(内容/大小一致)/ 大文件分块 / 空文件 / 源不存在
// =============================================================================
#include "fcopy.h"

#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <string>

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<char>(f)),
std::istreambuf_iterator<char>());
}
} // 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());
}
Loading