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
27 changes: 26 additions & 1 deletion .github/workflows/debian-forky.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ name: debian 14 forky


jobs:
container-test-job:
container-automake:
name: automake
runs-on: ubuntu-latest
container:
image: debian:forky-slim
Expand Down Expand Up @@ -41,3 +42,27 @@ jobs:
uses: actions/upload-artifact@v4
with:
path: '**/*.log'
name: 'automake logs'

container-cmake:
name: cmake
runs-on: ubuntu-latest
container:
image: debian:forky-slim
steps:
- name: checkout
uses: actions/checkout@v4
- name: install packages
run: apt-get update && apt-get install cmake pkgconf build-essential nettle-dev libcap2-bin --yes
- name: configure
run: cmake -B build -S inofficial_cmake/
- name: build
run: cmake --build build
- name: test
run: ctest --test-dir build --output-on-failure
- name: store cmake logs as artifacts
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
path: '**/*.log'
name: 'cmake logs'
29 changes: 27 additions & 2 deletions .github/workflows/debian-trixie.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ name: debian 13 trixie


jobs:
container-test-job:
container-automake:
name: automake
runs-on: ubuntu-latest
container:
image: debian:trixie-slim
Expand All @@ -36,8 +37,32 @@ jobs:
./configure
make
make check
- name: store the logs as an artifact
- name: store automake logs as artifacts
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
path: '**/*.log'
name: 'automake logs'

container-cmake:
name: cmake
runs-on: ubuntu-latest
container:
image: debian:trixie-slim
steps:
- name: checkout
uses: actions/checkout@v4
- name: install packages
run: apt-get update && apt-get install cmake pkgconf build-essential nettle-dev libcap2-bin --yes
- name: configure
run: cmake -B build -S inofficial_cmake/
- name: build
run: cmake --build build
- name: test
run: ctest --test-dir build --output-on-failure
- name: store cmake logs as artifacts
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
path: '**/*.log'
name: 'cmake logs'
34 changes: 33 additions & 1 deletion .github/workflows/formatting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name: code formatting


jobs:
build:
clang-format:
name: Auto format with clang 18
runs-on: ubuntu-24.04

Expand Down Expand Up @@ -41,3 +41,35 @@ jobs:
name: clang-format.patch
path: clang-format.patch
if-no-files-found: ignore

cmake-format:
name: Auto format with cmake-format
runs-on: ubuntu-24.04

steps:
- name: checkout
uses: actions/checkout@v4
- name: install packages
run: sudo apt install cmake-format
- name: run cmake format
run: |
./do_cmake_format.sh
- name: check for differences
run: |
git diff >cmake-format.patch
if [ $(wc -c <cmake-format.patch) -ne 0 ] ; then
echo "there was a formatting issue."
cat /etc/os-release
echo "you may download the artifact and apply it with git apply"
cat cmake-format.patch
exit 1
else
rm cmake-format.patch
fi
- name: store patch as artifact if there is one
if: failure()
uses: actions/upload-artifact@v4
with:
name: cmake-format.patch
path: cmake-format.patch
if-no-files-found: ignore
40 changes: 39 additions & 1 deletion Checksum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include <array>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <stdexcept>
#include <utility>

// project
#include "Checksum.hh"
Expand Down Expand Up @@ -45,6 +47,43 @@ Checksum::Checksum(checksumtypes type)
}
}

Checksum::Checksum(Checksum&& other)
: m_checksumtype(other.m_checksumtype)
{
#ifdef HAVE_LIBXXHASH
if (m_checksumtype == checksumtypes::XXH128) {
m_state.xxh128 = std::exchange(other.m_state.xxh128, nullptr);
} else
#endif
{
std::memcpy(&m_state, &other.m_state, sizeof(m_state));
}
}

Checksum::Checksum(const Checksum& other)
: m_checksumtype(other.m_checksumtype)
{
#ifdef HAVE_LIBXXHASH
if (m_checksumtype == checksumtypes::XXH128) {
m_state.xxh128 = XXH3_createState();
assert(m_state.xxh128 != NULL && "Out of memory!");
XXH3_copyState(m_state.xxh128, other.m_state.xxh128);
} else
#endif
{
std::memcpy(&m_state, &other.m_state, sizeof(m_state));
}
}

Checksum::~Checksum()
{
#ifdef HAVE_LIBXXHASH
if (m_checksumtype == checksumtypes::XXH128) {
XXH3_freeState(m_state.xxh128);
}
#endif
}

int
Checksum::update(std::size_t length, const unsigned char* buffer)
{
Expand Down Expand Up @@ -208,7 +247,6 @@ Checksum::printToBuffer(void* buffer, std::size_t N)
XXH128_hash_t result = XXH3_128bits_digest(m_state.xxh128);
XXH128_canonicalFromHash(static_cast<XXH128_canonical_t*>(buffer),
result);
XXH3_freeState(m_state.xxh128);
} else {
// bad size.
return -1;
Expand Down
3 changes: 3 additions & 0 deletions Checksum.hh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public:
};

explicit Checksum(checksumtypes type);
Checksum(const Checksum& other);
Checksum(Checksum&& other);
~Checksum();

int update(std::size_t length, const unsigned char* buffer);
int update(std::size_t length, const char* buffer);
Expand Down
7 changes: 7 additions & 0 deletions do_cmake_format.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
#
# cmake autoformat. apt install cmake-format

set -e

cmake-format -i inofficial_cmake/CMakeLists.txt
41 changes: 30 additions & 11 deletions inofficial_cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ endif()

configure_file(config.h.in config.h @ONLY)

add_executable(
rdfind
# the implementation is in this object library, to make it possible to unit test
add_library(
rdfindimpl OBJECT
../Checksum.cc
../Checksum.hh
../CmdlineParser.cc
Expand All @@ -31,23 +32,32 @@ add_executable(
../EasyRandom.hh
../Fileinfo.cc
../Fileinfo.hh
../rdfind.cc
../RdfindDebug.hh
../Rdutil.cc
../Rdutil.hh
../UndoableUnlink.cc
../UndoableUnlink.hh)
target_include_directories(rdfind PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
target_include_directories(rdfind PRIVATE ..)

target_compile_features(rdfind PRIVATE cxx_std_17)
target_link_libraries(rdfind nettle)
target_include_directories(rdfindimpl PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
target_include_directories(rdfindimpl PUBLIC ..)
target_compile_features(rdfindimpl PUBLIC cxx_std_17)
target_compile_options(rdfindimpl PUBLIC -Wall -Wextra -Wpedantic)
target_link_libraries(rdfindimpl nettle)
if(xxhash_FOUND)
target_link_libraries(rdfind PkgConfig::xxhash)
target_link_libraries(rdfindimpl PkgConfig::xxhash)
endif()
target_compile_options(rdfind PRIVATE -Wall -Wextra -Wpedantic)

file(GENERATE OUTPUT .gitignore CONTENT "*")
# the executable mostly contains the main function
add_executable(rdfind ../rdfind.cc)
target_include_directories(rdfind PRIVATE ..)
target_link_libraries(rdfind PUBLIC rdfindimpl)

file(
GENERATE
OUTPUT .gitignore
CONTENT "*")

# apt install libcatch2-dev
find_package(Catch2 3.7)

enable_testing()

Expand Down Expand Up @@ -80,3 +90,12 @@ foreach(testscript ${testscripts})
set_tests_properties(${testname} PROPERTIES ENVIRONMENT
RDFIND=$<TARGET_FILE:rdfind>)
endforeach()

if(Catch2_FOUND)
set(unittests test_checksum)
foreach(unittest ${unittests})
add_executable(${unittest} ../unittests/test_checksum.cc)
target_compile_features(${unittest} PRIVATE cxx_std_20)
target_link_libraries(${unittest} PRIVATE rdfindimpl Catch2::Catch2WithMain)
endforeach()
endif()
96 changes: 96 additions & 0 deletions unittests/test_checksum.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <catch2/catch_test_macros.hpp>

#include "Checksum.hh"
#include <set>

namespace {
using enum Checksum::checksumtypes;
const auto types = { MD5,
SHA1,
SHA256,
SHA512
#ifdef HAVE_LIBXXHASH
,
XXH128
#endif
};

// helper function to store the result in a string
std::string
finalize_checksum(Checksum& ck)
{
std::string ret(static_cast<std::size_t>(ck.getDigestLength()), ' ');
REQUIRE(0 == ck.printToBuffer(ret.data(), ret.size()));
return ret;
}

}

TEST_CASE("different checksums are distinct")
{
std::set<std::string> answers;
for (auto type : types) {
Checksum ck(type);
const auto answer = finalize_checksum(ck);
answers.insert(answer);
}
REQUIRE(types.size() == answers.size());
}

TEST_CASE("update with zero bytes is fine")
{
for (auto type : types) {
const auto s1 = [type]() {
Checksum ck(type);
return finalize_checksum(ck);
}();
const auto s2 = [type]() {
Checksum ck(type);
REQUIRE(0 == ck.update(0, static_cast<const char*>(nullptr)));
return finalize_checksum(ck);
}();
REQUIRE(s1 == s2);
}
}

TEST_CASE("creating and not using it is fine")
{
for (auto type : types) {
Checksum ck(type);
}
}

TEST_CASE("copying a checksum is fine")
{
static const char* content = "abcd";
for (auto type : types) {
const auto expected = [type]() {
Checksum ck(type);
REQUIRE(0 == ck.update(std::strlen(content), content));
return finalize_checksum(ck);
}();
Checksum original(type);
REQUIRE(0 == original.update(std::strlen(content), content));
Checksum copy(original);
REQUIRE(expected == finalize_checksum(copy));
REQUIRE(expected == finalize_checksum(original));
}
}

TEST_CASE("copy from an rval is fine")
{
static const char* content = "abcd";
for (auto type : types) {
const auto expected = [type]() {
Checksum ck(type);
REQUIRE(0 == ck.update(std::strlen(content), content));
return finalize_checksum(ck);
}();
Checksum original(type);
REQUIRE(0 == original.update(std::strlen(content), content));

// move copy should be ok
Checksum movedto(std::move(original));
REQUIRE(expected == finalize_checksum(movedto));
}
}
Loading