Compare commits

..

No commits in common. "37dcda3d962893a1b60488bfa9514abcf7e189d7" and "5b5d53e49b0bdfd8c125a5713a25184545f31a34" have entirely different histories.

21 changed files with 88 additions and 308 deletions

View File

@ -1,22 +0,0 @@
FROM alpine:3.21.3
# Install tools required for building.
RUN apk update && \
apk add --no-cache \
autoconf \
bash \
boost-build \
build-base \
cmake \
gdb \
git \
libstdc++ \
libtool \
linux-headers \
ninja \
m4 \
perl \
python3 \
py3-pip && \
pip install --break-system-packages conan && \
conan profile detect

View File

@ -1,19 +0,0 @@
{
"name": "C++",
"build": {
"dockerfile": "Dockerfile"
},
// Configure tool-specific properties.
"customizations": {
"vscode": {
"settings": {},
"extensions": [
"ms-vscode.cpptools",
"twxs.cmake",
"ms-vscode.cmake-tools",
"konicy.conan-extension"
]
}
}
}

3
.gitignore vendored
View File

@ -1,6 +1,3 @@
/build
# ---> C++ # ---> C++
# Prerequisites # Prerequisites
*.d *.d

25
3rdparty-boost.cmake Normal file
View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.0)
project(3rdparty-boost)
add_library(
${PROJECT_NAME}
STATIC
empty.cpp
)
set_property(
TARGET ${PROJECT_NAME}
PROPERTY CXX_STANDARD 20
)
target_link_libraries(
${PROJECT_NAME}
INTERFACE
/home/bart/Development/3rd-party/boost/boost_1_81_0/lib/libboost_url.a
/home/bart/Development/3rd-party/boost/boost_1_81_0/lib/libboost_json.a
)
target_include_directories(
${PROJECT_NAME}
PUBLIC /home/bart/Development/3rd-party/boost/boost_1_81_0/include/
)

37
3rdparty-googletest.cmake Normal file
View File

@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.0)
project(3rdparty-googletest)
find_package(GTest REQUIRED)
add_library(
${PROJECT_NAME}
STATIC
empty.cpp
)
target_link_libraries(
${PROJECT_NAME}
INTERFACE
GTest::gtest
GTest::gmock
)
project(3rdparty-googletest-main)
add_library(
${PROJECT_NAME}
STATIC
empty.cpp
)
target_link_libraries(
${PROJECT_NAME}
INTERFACE
3rdparty-googletest
GTest::gtest_main
)

View File

@ -1,7 +1,8 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.0)
project(all) project(all)
enable_testing() enable_testing()
include(3rdparty-boost.cmake)
include(3rdparty-googletest.cmake)
add_subdirectory(bmrshared) add_subdirectory(bmrshared)
add_subdirectory(bmrshared-magic)

View File

@ -1,2 +0,0 @@
add_subdirectory(lib)
add_subdirectory(tst)

View File

@ -1,26 +0,0 @@
// GNU Lesser General Public License v3.0
// Copyright (c) 2025 Bart Beumer <bart@4beumer.nl>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License v3.0 as published by
// the Free Software Foundation.
//
#include <filesystem>
#include <magic.h>
namespace bmrshared
{
class magic_file_info final
{
public:
explicit magic_file_info(const std::filesystem::path& path);
~magic_file_info();
std::string get_mime(const std::filesystem::path& path) const;
private:
magic_t m_magic_cookie;
};
} // namespace bmrshared

View File

@ -1,31 +0,0 @@
cmake_minimum_required(VERSION 3.20)
find_package(libmagic 5.45 REQUIRED)
project(bmrshared-magic)
add_library(
${PROJECT_NAME}
magic_file_info.cpp
)
set_property(
TARGET ${PROJECT_NAME}
PROPERTY CXX_STANDARD 20
)
target_include_directories(
${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include
)
target_link_libraries(
${PROJECT_NAME}
PUBLIC
libmagic::libmagic
)
install(
FILES ${CONAN_LIBMAGIC_PACKAGE_FOLDER}/res/magic.mgc
DESTINATION bin
)

View File

@ -1,59 +0,0 @@
// GNU Lesser General Public License v3.0
// Copyright (c) 2025 Bart Beumer <bart@4beumer.nl>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License v3.0 as published by
// the Free Software Foundation.
//
#include <bmrshared/magic_file_info.hpp>
namespace bmrshared
{
magic_file_info::magic_file_info(const std::filesystem::path& path)
: m_magic_cookie(nullptr)
{
bool load_ok = false;
m_magic_cookie = magic_open(MAGIC_MIME_TYPE);
if (m_magic_cookie != nullptr && std::filesystem::is_regular_file(path))
{
load_ok = (magic_load(m_magic_cookie, path.native().c_str()) == 0);
}
if (m_magic_cookie && !load_ok)
{
magic_close(m_magic_cookie);
m_magic_cookie = nullptr;
}
if (!load_ok)
{
throw std::runtime_error("Could not initialize libmagic.");
}
}
magic_file_info::~magic_file_info()
{
magic_close(m_magic_cookie);
}
std::string magic_file_info::get_mime(const std::filesystem::path& path) const
{
std::string mime;
if (std::filesystem::is_regular_file(path))
{
const char* file_name = path.native().c_str();
const char* magic_full = nullptr;
if (file_name != nullptr)
{
magic_full = magic_file(m_magic_cookie, file_name);
}
if (magic_full != nullptr)
{
mime = magic_full;
}
}
return mime;
}
} // namespace bmrshared

View File

@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.20)
find_package(GTest REQUIRED)
include(GoogleTest)
project(bmrshared-magic-test)
add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
add_executable(
${PROJECT_NAME}
test_magic.cpp
)
set_property(
TARGET ${PROJECT_NAME}
PROPERTY CXX_STANDARD 20
)
target_link_libraries(
${PROJECT_NAME}
PUBLIC
bmrshared-magic
GTest::gtest_main
)

View File

@ -1,26 +0,0 @@
// GNU Lesser General Public License v3.0
// Copyright (c) 2025 Bart Beumer <bart@4beumer.nl>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License v3.0 as published by
// the Free Software Foundation.
//
#include <bmrshared/magic_file_info.hpp>
#include <gtest/gtest.h>
namespace
{
constexpr std::string_view magic_file_location = "/usr/local/bin/magic.mgc";
}
TEST(test_magic, no_throw_on_query)
{
bmrshared::magic_file_info mfi(magic_file_location);
EXPECT_NO_THROW(mfi.get_mime(magic_file_location));
}
TEST(test_magic, throw_on_wrong_magic_file)
{
EXPECT_THROW(bmrshared::magic_file_info mfi(""), std::exception);
EXPECT_THROW(bmrshared::magic_file_info mfi("/etc/hostname"), std::exception);
}

View File

@ -28,7 +28,6 @@ class flexible_value final
std::vector<int64_t>, std::vector<int64_t>,
std::vector<uint64_t>, std::vector<uint64_t>,
std::vector<std::string>, std::vector<std::string>,
std::vector<flexible_value>,
keyvalue_type>; keyvalue_type>;
flexible_value(); flexible_value();

View File

@ -23,8 +23,7 @@ struct function_wrapper;
template<typename T, typename... TExtraArguments> template<typename T, typename... TExtraArguments>
requires(std::is_const<T>::value == true) requires(std::is_const<T>::value == true) struct function_wrapper<T, TExtraArguments...>
struct function_wrapper<T, TExtraArguments...>
{ {
using wrapper_type = std::function<flexible_value(const T&, const IDataSource&, TExtraArguments...)>; using wrapper_type = std::function<flexible_value(const T&, const IDataSource&, TExtraArguments...)>;
@ -34,15 +33,14 @@ struct function_wrapper<T, TExtraArguments...>
std::array<std::string, sizeof...(TSourceParams)> names{paramNames...}; std::array<std::string, sizeof...(TSourceParams)> names{paramNames...};
return [callableFn, names](const T& obj, const IDataSource& source, TExtraArguments... args) return [callableFn, names](const T& obj, const IDataSource& source, TExtraArguments... args)
{ {
return invoke<M, T, sizeof...(TSourceParams), TExtraArguments...>(obj, callableFn, names, source, args...); return invoke(obj, callableFn, names, source, args...);
}; };
} }
}; };
template<typename T, typename... TExtraArguments> template<typename T, typename... TExtraArguments>
requires(std::is_const<T>::value == false) requires(std::is_const<T>::value == false) struct function_wrapper<T, TExtraArguments...>
struct function_wrapper<T, TExtraArguments...>
{ {
using wrapper_type = std::function<flexible_value(T&, const IDataSource&, TExtraArguments...)>; using wrapper_type = std::function<flexible_value(T&, const IDataSource&, TExtraArguments...)>;
@ -52,7 +50,7 @@ struct function_wrapper<T, TExtraArguments...>
std::array<std::string, sizeof...(TSourceParams)> names{paramNames...}; std::array<std::string, sizeof...(TSourceParams)> names{paramNames...};
return [callableFn, names](T& obj, const IDataSource& source, TExtraArguments... args) return [callableFn, names](T& obj, const IDataSource& source, TExtraArguments... args)
{ {
return invoke<M, T, sizeof...(TSourceParams), TExtraArguments...>(obj, callableFn, names, source, args...); return invoke(obj, callableFn, names, source, args...);
}; };
} }
}; };

View File

@ -54,11 +54,11 @@ namespace detail
template<typename M, typename T, std::size_t TParameterCount, typename... TExtraArguments> template<typename M, typename T, std::size_t TParameterCount, typename... TExtraArguments>
requires(function_info<M T::*>::is_const_member == false) requires(function_info<M T::*>::is_const_member == false)
flexible_value invoke(T& callableObj, flexible_value invoke(T& callableObj,
M T::*callableFn, M T::*callableFn,
std::array<std::string, TParameterCount> names, std::array<std::string, TParameterCount> names,
const IDataSource& source, const IDataSource& source,
TExtraArguments&&... arguments) TExtraArguments... arguments)
{ {
using CallableInfo = function_info<decltype(callableFn)>; using CallableInfo = function_info<decltype(callableFn)>;
using SourceArgumentsTuple = using SourceArgumentsTuple =
@ -74,11 +74,11 @@ flexible_value invoke(T& callableObj,
template<typename M, typename T, std::size_t TParameterCount, typename... TExtraArguments> template<typename M, typename T, std::size_t TParameterCount, typename... TExtraArguments>
requires(function_info<M T::*>::is_const_member == true) requires(function_info<M T::*>::is_const_member == true)
flexible_value invoke(const T& callableObj, flexible_value invoke(const T& callableObj,
M T::*callableFn, M T::*callableFn,
std::array<std::string, TParameterCount> names, std::array<std::string, TParameterCount> names,
const IDataSource& source, const IDataSource& source,
TExtraArguments&&... arguments) TExtraArguments... arguments)
{ {
using CallableInfo = function_info<decltype(callableFn)>; using CallableInfo = function_info<decltype(callableFn)>;
using SourceArgumentsTuple = using SourceArgumentsTuple =
@ -95,7 +95,7 @@ template<typename TCallable, std::size_t TParameterCount, typename... TExtraArgu
flexible_value invoke(TCallable& fn, flexible_value invoke(TCallable& fn,
std::array<std::string, TParameterCount> names, std::array<std::string, TParameterCount> names,
const IDataSource& source, const IDataSource& source,
TExtraArguments&&... arguments) TExtraArguments... arguments)
{ {
return invoke(fn, &TCallable::operator(), names, source, arguments...); return invoke(fn, &TCallable::operator(), names, source, arguments...);
} }

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.0)
project(bmrshared) project(bmrshared)

View File

@ -6,7 +6,6 @@
// the Free Software Foundation. // the Free Software Foundation.
// //
#include "bmrshared/to_tuple.hpp" #include "bmrshared/to_tuple.hpp"
#include <algorithm>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>

View File

@ -1,7 +1,4 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.0)
find_package(GTest REQUIRED)
include(GoogleTest)
project(bmrshared-test) project(bmrshared-test)
add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
@ -22,7 +19,10 @@ target_link_libraries(
${PROJECT_NAME} ${PROJECT_NAME}
PUBLIC PUBLIC
bmrshared bmrshared
GTest::gtest_main 3rdparty-googletest-main
GTest::gmock )
install(
TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin
) )

View File

@ -123,22 +123,3 @@ TEST(InvokeTest, Ok_Ptr_Member_Const)
flexible_value returnValue = bmrshared::invoke(functor, &TestAddition::AddNumbersConst, names, mockSrc); flexible_value returnValue = bmrshared::invoke(functor, &TestAddition::AddNumbersConst, names, mockSrc);
EXPECT_EQ(returnValue.as<uint64_t>(), 140); EXPECT_EQ(returnValue.as<uint64_t>(), 140);
} }
TEST(InvokeTest, Ok_ExtraArgumentByRefChanged)
{
auto fn = [](int64_t a, int64_t& lastArg)
{
lastArg = a;
return true;
};
std::array<std::string, 1> names = {"a"};
MockDataSource mockSrc;
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a"}));
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
int64_t lastArg = 0;
flexible_value returnValue = bmrshared::invoke(fn, names, mockSrc, lastArg);
EXPECT_EQ(returnValue.as<bool>(), true);
EXPECT_EQ(lastArg, 42);
}

View File

@ -31,17 +31,6 @@ class TestAddition
int64_t AddNumbersConst(int64_t left, int64_t right) const { return left + (right * 2); } int64_t AddNumbersConst(int64_t left, int64_t right) const { return left + (right * 2); }
}; };
class TestWriteOutputArgument
{
public:
bool WriteOutArg(int64_t a, int64_t& extraOutArg) const
{
return extraOutArg = a;
return true;
}
};
using TestWrapperType = function_wrapper<TestAddition>; using TestWrapperType = function_wrapper<TestAddition>;
using TestConstWrapperType = function_wrapper<const TestAddition>; using TestConstWrapperType = function_wrapper<const TestAddition>;
@ -88,20 +77,3 @@ TEST(WrapTest, Const_Ptr_to_member_as_non_const)
flexible_value returnValue = wrapped(obj, mockSrc); flexible_value returnValue = wrapped(obj, mockSrc);
EXPECT_EQ(returnValue.as<int64_t>(), 84); EXPECT_EQ(returnValue.as<int64_t>(), 84);
} }
TEST(WrapTest, WriteExtraOutArg)
{
const TestWriteOutputArgument obj;
using TestWrapperOutArgType = function_wrapper<const TestWriteOutputArgument, int64_t&>;
TestWrapperOutArgType::wrapper_type wrapped =
TestWrapperOutArgType::Wrap(&TestWriteOutputArgument::WriteOutArg, "a");
MockDataSource mockSrc;
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a"}));
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
int64_t lastArg = 0;
flexible_value returnValue = wrapped(obj, mockSrc, lastArg);
EXPECT_EQ(returnValue.as<bool>(), true);
EXPECT_EQ(lastArg, 42);
}

View File

@ -1,20 +0,0 @@
import os
from conan import ConanFile
from conan.tools.files import copy
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
class HelloConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
requires = "boost/1.84.0", "gtest/1.14.0", "libmagic/5.45"
generators = "CMakeDeps"
build_policy = "*"
def generate(self):
# We need to find the folder of libmagic and supply it to cmake so that
# we can deploy the magic file.
libmagic = self.dependencies["libmagic"]
tc = CMakeToolchain(self)
tc.variables["CONAN_LIBMAGIC_PACKAGE_FOLDER"] = libmagic.package_folder
tc.generate()