diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index ae83e9a..e880adb 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -1,4 +1,4 @@ -name: CMake +name: Build Debug on: push: @@ -8,7 +8,7 @@ on: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) - BUILD_TYPE: Release + BUILD_TYPE: Debug jobs: build: @@ -40,9 +40,3 @@ jobs: # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - - name: Test - working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{env.BUILD_TYPE}} - diff --git a/.github/workflows/cpack.yml b/.github/workflows/cpack.yml index 5c7676d..40dc4c7 100644 --- a/.github/workflows/cpack.yml +++ b/.github/workflows/cpack.yml @@ -1,4 +1,4 @@ -name: CMake +name: Build and Pack on: push: diff --git a/.github/workflows/gtest.yml b/.github/workflows/gtest.yml new file mode 100644 index 0000000..8e8cc04 --- /dev/null +++ b/.github/workflows/gtest.yml @@ -0,0 +1,48 @@ +name: Build and Test + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Debug + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - name: Install system dependencies + if: runner.os == 'Linux' + run: | + sudo apt update + sudo apt -y install can-utils libsocketcan-dev googletest + while read -r cmd + do + eval sudo $cmd + done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') + + - uses: actions/checkout@v3 + - uses: MarkusJx/googletest-installer@v1.1 + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + diff --git a/CMakeLists.txt b/CMakeLists.txt index c50e97e..cf1471e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,27 @@ cmake_minimum_required(VERSION 3.23) -project(sockcanpp LANGUAGES CXX VERSION 1.0) +project(sockcanpp LANGUAGES CXX VERSION 1.1.0) option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ON) +option(BUILD_TESTS "Build the tests" OFF) set(CMAKE_CXX_STANDARD 11) include(GNUInstallDirs) -add_library(${PROJECT_NAME}) -set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION}) -set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") +if (BUILD_SHARED_LIBS STREQUAL "ON") + add_library(${PROJECT_NAME}) + set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION}) + set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") +else() + add_library(${PROJECT_NAME} STATIC) +endif() + +### +# If BUILD_TESTS is set to ON, a static test library with the name of the project suffixed with "_test" will be created +### +if(BUILD_TESTS STREQUAL "ON") + add_library(${PROJECT_NAME}_test STATIC) +endif() add_subdirectory(include) add_subdirectory(src) @@ -57,4 +69,12 @@ add_custom_command( COMMENT "Generate Doxygen documentation for publication or reading" COMMAND doxygen ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) \ No newline at end of file +) + +### +# If the CMAKE_BUILD_TYPE is set to Debug, enable the tests +### +if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND BUILD_TESTS STREQUAL "ON") + enable_testing() + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index c98bc0b..95d9c4a 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -7,4 +7,15 @@ target_sources(${PROJECT_NAME} CanDriver.hpp CanId.hpp CanMessage.hpp -) \ No newline at end of file +) + +if (TARGET sockcanpp_test) + target_sources(sockcanpp_test + PUBLIC FILE_SET HEADERS + BASE_DIRS ${CMAKE_CURRENT_LIST_DIR} + FILES + CanDriver.hpp + CanId.hpp + CanMessage.hpp + ) +endif() \ No newline at end of file diff --git a/include/CanId.hpp b/include/CanId.hpp index 92d51df..d17f9f4 100644 --- a/include/CanId.hpp +++ b/include/CanId.hpp @@ -47,124 +47,115 @@ namespace sockcanpp { */ struct CanId { public: // +++ Constructors +++ - CanId(const CanId& orig): _identifier(orig._identifier), _isErrorFrame(orig._isErrorFrame), - _isRemoteTransmissionRequest(orig._isRemoteTransmissionRequest), _isStandardFrameId(orig._isStandardFrameId), - _isExtendedFrameId(orig._isExtendedFrameId) { /* copy */ } - - CanId(const uint32_t identifier): _identifier(identifier) { - // TODO: Switch to using bitmasks! - - if (isValidIdentifier(identifier)) { - if (((int32_t)log2(identifier) + 1) < 11) { - _isStandardFrameId = true; - } else { _isExtendedFrameId = true; } - } else if (isErrorFrame(identifier)) { - _isErrorFrame = true; - } else if (isRemoteTransmissionRequest(identifier)) { - _isRemoteTransmissionRequest = true; - } - } - - CanId(): _identifier(0), _isStandardFrameId(true) { } + constexpr CanId(const CanId& id) = default; + constexpr CanId() = default; + constexpr CanId(const canid_t id): m_identifier(id) { } + constexpr CanId(const int32_t id): m_identifier(id) { } public: // +++ Operators +++ + constexpr canid_t operator *() const { return m_identifier; } //!< Returns the raw CAN ID value. -#pragma region "Implicit Cast Operators" - operator int16_t() const { return isStandardFrameId() ? (int16_t)_identifier : throw system_error(error_code(0xbad1d, generic_category()), "INVALID CAST: ID is extended or invalid!"); } - operator uint16_t() const { return isStandardFrameId() ? (uint16_t)_identifier : throw system_error(error_code(0xbad1d, generic_category()), "INVALID CAST: ID is extended or invalid!"); } - operator int32_t() const { return _identifier; } - operator uint32_t() const { return _identifier; } +#pragma region "Conversions" + constexpr operator int16_t() const { return static_cast(m_identifier) & CAN_ERR_MASK; } + constexpr operator uint16_t() const { return static_cast(m_identifier) & CAN_ERR_MASK; } + constexpr operator int32_t() const { return m_identifier & CAN_ERR_MASK; } + constexpr operator canid_t() const { return m_identifier & CAN_ERR_MASK; } #pragma endregion #pragma region "Bitwise Operators" - CanId operator &(CanId& x) const { return _identifier & x._identifier; } - CanId operator &(const CanId x) const { return _identifier & x._identifier; } - CanId operator &(const int16_t x) const { return _identifier & x; } - CanId operator &(const uint16_t x) const { return _identifier & x; } - CanId operator &(const int32_t x) const { return _identifier & x; } - CanId operator &(const uint32_t x) const { return _identifier & x; } - CanId operator &(const int64_t x) const { return _identifier & x; } - CanId operator &(const uint64_t x) const { return _identifier & x; } - - CanId operator |(CanId& x) const { return _identifier | x._identifier; } - CanId operator |(const CanId x) const { return _identifier | x._identifier; } - CanId operator |(const int16_t x) const { return _identifier | x; } - CanId operator |(const uint16_t x) const { return _identifier | x; } - CanId operator |(const int32_t x) const { return _identifier | x; } - CanId operator |(const uint32_t x) const { return _identifier | x; } - CanId operator |(const int64_t x) const { return _identifier | x; } - CanId operator |(const uint64_t x) const { return _identifier | x; } + template + constexpr CanId operator &(const T x) const { return m_identifier & x; } //!< Performs a bitwise AND operation on this ID and another. + constexpr CanId operator &(const CanId& x) const { return m_identifier & x.m_identifier; } //!< Performs a bitwise AND operation on this ID and another. + + template + constexpr CanId operator |(const T x) const { return m_identifier | x; } //!< Performs a bitwise OR operation on this ID and a 16-bit integer. + constexpr CanId operator |(const CanId& x) const { return m_identifier | x.m_identifier; } //!< Performs a bitwise OR operation on this ID and another. + + template + constexpr CanId operator ^(const T x) const { return m_identifier ^ x; } //!< Performs a bitwise XOR operation on this ID and a 16-bit integer. + constexpr CanId operator ^(const CanId& x) const { return m_identifier ^ x.m_identifier; } //!< Performs a bitwise XOR operation on this ID and another. + + constexpr CanId operator ~() const { return ~m_identifier; } //!< Performs a bitwise NOT operation on this ID. + + template + constexpr CanId operator <<(const T x) const { return m_identifier << x; } //!< Shifts this ID to the left by a 16-bit integer. + constexpr CanId operator <<(const CanId& x) const { return m_identifier << x.m_identifier; } //!< Shifts this ID to the left by another. + + template + constexpr CanId operator >>(const T x) const { return m_identifier >> x; } //!< Shifts this ID to the right by a 16-bit integer. + constexpr CanId operator >>(const CanId& x) const { return m_identifier >> x.m_identifier; } //!< Shifts this ID to the right by another. + + template + CanId operator <<=(const T x) { return m_identifier <<= x; } //!< Shifts this ID to the left by a 16-bit integer. + CanId operator <<=(const CanId& x) { return m_identifier <<= x.m_identifier; } //!< Shifts this ID to the left by another. + + template + CanId operator >>=(const T x) { return m_identifier >>= x; } //!< Shifts this ID to the right by a 16-bit integer. + CanId operator >>=(const CanId& x) { return m_identifier >>= x.m_identifier; } //!< Shifts this ID to the right by another. + #pragma endregion #pragma region "Comparison Operators" - bool operator ==(CanId& x) const { return _identifier == x._identifier; } - bool operator ==(const CanId& x) const { return _identifier == x._identifier; } - bool operator ==(const int16_t x) const { return _identifier == x; } - bool operator ==(const uint16_t x) const { return _identifier == x; } - bool operator ==(const int32_t x) const { return _identifier == x; } - bool operator ==(const uint32_t x) const { return _identifier == x; } - bool operator ==(const int64_t x) const { return (x > UINT32_MAX || x < INT32_MIN) ? false : x == _identifier; } - bool operator ==(const uint64_t x) const { return x > UINT32_MAX ? false : x == _identifier; } - bool operator !=(CanId& x) const { return _identifier != x._identifier; } - bool operator !=(const CanId& x) const { return _identifier != x._identifier; } - bool operator !=(const int16_t x) const { return _identifier != x; } - bool operator !=(const uint16_t x) const { return _identifier != x; } - bool operator !=(const int32_t x) const { return _identifier != x; } - bool operator !=(const uint32_t x) const { return _identifier != x; } - bool operator !=(const int64_t x) const { return (x > UINT32_MAX || x < INT32_MIN) ? false : x != _identifier; } - bool operator !=(const uint64_t x) const { return x > UINT32_MAX ? false : x != _identifier; } - - bool operator <(CanId& x) const { return x._identifier < _identifier; } - bool operator <(int32_t x) const { return x < _identifier; } - bool operator <(uint32_t x) const { return x < _identifier; } - bool operator <(int16_t x) const { return x < _identifier; } - bool operator <(uint16_t x) const { return x < _identifier; } - bool operator <=(CanId& x) const { return x._identifier <= _identifier; } - bool operator >(CanId& x) const { return x._identifier > _identifier; } - bool operator >(int32_t x) const { return x > _identifier; } - bool operator >(uint32_t x) const { return x > _identifier; } - bool operator >(int16_t x) const { return x > _identifier; } - bool operator >(uint16_t x) const { return x > _identifier; } - bool operator >=(CanId& x) const { return x._identifier >= _identifier; } - bool operator <(const CanId& x) const { return x._identifier < _identifier; } - bool operator <=(const CanId& x) const { return x._identifier <= _identifier; } - bool operator >(const CanId& x) const { return x._identifier > _identifier; } - bool operator >=(const CanId& x) const { return x._identifier >= _identifier; } + constexpr bool operator ==(const CanId& x) const { return m_identifier == x.m_identifier; } //!< Compares this ID to another. + + template + constexpr bool operator ==(const T x) const { return m_identifier == static_cast(x); } //!< Compares this ID to another. + + constexpr bool operator !=(const CanId& x) const { return m_identifier != x.m_identifier; } //!< Compares this ID to another. + + template + constexpr bool operator !=(const T x) const { return m_identifier != static_cast(x); } //!< Compares this ID to another. + + template + constexpr bool operator <(T x) const { return static_cast(x) < m_identifier; } //!< Compares this ID to another. + + template + constexpr bool operator >(T x) const { return static_cast(x) > m_identifier; } //!< Compares this ID to a 32-bit integer. + + template + constexpr bool operator <=(const T x) const { return x.m_identifier <= m_identifier; } //!< Compares this ID to another. + + template + constexpr bool operator >=(const T x) const { return x.m_identifier >= m_identifier; } //!< Compares this ID to another. #pragma endregion #pragma region "Assignment Operators" - CanId operator =(const int32_t val) { - uint32_t tmpVal = val; - auto tmp = (isValidIdentifier(tmpVal) ? CanId(val) : throw system_error(error_code(0x5421, generic_category()), "INVALID CAST: ID is extended or invalid!")); - return tmp; - } - - CanId operator =(const uint32_t val) { - uint32_t tmp = val; - return (isValidIdentifier(tmp) ? CanId(val) : throw system_error(error_code(0x5421, generic_category()), "INVALID CAST: ID is extended or invalid!")); - } - - CanId operator =(const int64_t val) { return operator =((int32_t)val); } + template + constexpr CanId operator =(const T val) { return CanId(val); } //!< Assigns a new integer to this CanID + + constexpr CanId operator =(const int64_t val) { return operator =((canid_t)val); } //!< Assigns a 64-bit integer to this ID. #pragma endregion #pragma region "Arithmetic Operators" - CanId operator +(CanId& x) const { return _identifier + x._identifier; } - CanId operator +(const CanId& x) const { return _identifier + x._identifier; } - CanId operator +(const int16_t x) const { return _identifier + x; } - CanId operator +(const uint16_t x) const { return _identifier + x; } - CanId operator +(const int32_t x) const { return _identifier + x; } - CanId operator +(const uint32_t x) const { return _identifier + x; } - CanId operator +(const int64_t x) const { return _identifier + x; } - CanId operator +(const uint64_t x) const { return _identifier + x; } - - CanId operator -(CanId& x) const { return _identifier - x._identifier; } - CanId operator -(const CanId& x) const { return _identifier - x._identifier; } - CanId operator -(const int16_t x) const { return _identifier - x; } - CanId operator -(const uint16_t x) const { return _identifier - x; } - CanId operator -(const int32_t x) const { return _identifier - x; } - CanId operator -(const uint32_t x) const { return _identifier - x; } - CanId operator -(const int64_t x) const { return _identifier - x; } - CanId operator -(const uint64_t x) const { return _identifier - x; } + template + constexpr CanId operator +(const T x) const { return m_identifier + x; } + + template + constexpr CanId operator +=(const T x) { return m_identifier += x; } + + template + constexpr CanId operator -=(const T x) { return m_identifier -= x; } + + template + constexpr CanId operator -(const T x) const { return m_identifier - x; } + + template + constexpr CanId operator *(const T x) const { return m_identifier * x; } + + template + constexpr CanId operator *= (const T x) { return m_identifier *= x; } + + template + constexpr CanId operator /(const T x) const { return m_identifier / x; } + + template + constexpr CanId operator /=(const T x) { return m_identifier /= x; } + + template + constexpr CanId operator %(const T x) const { return m_identifier % x; } + + template + constexpr CanId operator %=(const T x) { return m_identifier %= x; } #pragma endregion public: // +++ Validity Checks +++ @@ -176,16 +167,9 @@ namespace sockcanpp { * @return true If value is a valid CAN identifier. * @return false Otherwise. */ - static bool isValidIdentifier(uint32_t value) { - int32_t tmpValue = ((int32_t)log2(value) + 2); // Get bit count - - // Check for extended frame flag - if (tmpValue >= 29) { - value = (value & CAN_EFF_FLAG) ? (value & CAN_EFF_MASK) : (value & CAN_SFF_MASK); - tmpValue = ((int32_t)log2(value) + 1); // Get bit count again - } - - return (value == 0) /* Default value, also valid ID */ || ((tmpValue <= 29 && tmpValue > 0)); + template + static constexpr bool isValidIdentifier(T value) { + return static_cast(value) <= CAN_EFF_MASK; } /** @@ -196,9 +180,9 @@ namespace sockcanpp { * @return true If value has the error frame flag (bit) set to 1. * @return false Otherwise. */ - static bool isErrorFrame(uint32_t value) { - try { return bitset(value).test(29); } - catch (...) { return false; /* Brute-force, but works. */ } + template + static constexpr bool isErrorFrame(T value) { + return static_cast(value) & CAN_ERR_FLAG; } /** @@ -209,27 +193,35 @@ namespace sockcanpp { * @return true If the frame is a remote transmission request. * @return false Otherwise. */ - static bool isRemoteTransmissionRequest(uint32_t value) { - try { return bitset(value).test(30); } - catch (...) { return false; /* Brute-force, but works. */ } + template + static constexpr bool isRemoteTransmissionRequest(T value) { + return static_cast(value) & CAN_RTR_FLAG; + } + + /** + * @brief Indicates whether or not a given integer is an extended frame ID. + * + * @param value The integer to check. + * + * @return true If the frame is in the extended format. + * @return false Otherwise. + */ + template + static constexpr bool isExtendedFrame(T value) { + return static_cast(value) & CAN_EFF_FLAG; } public: // +++ Getters +++ - bool hasErrorFrameFlag() const { return _isErrorFrame; } - bool hasRtrFrameFlag() const { return _isRemoteTransmissionRequest; } - bool isStandardFrameId() const { return _isStandardFrameId; } - bool isExtendedFrameId() const { return _isExtendedFrameId; } + constexpr bool hasErrorFrameFlag() const { return isErrorFrame(m_identifier); } //!< Indicates whether or not this ID is an error frame. + constexpr bool hasRtrFrameFlag() const { return isRemoteTransmissionRequest(m_identifier); } //!< Indicates whether or not this ID is a remote transmission request. + constexpr bool isStandardFrameId() const { return !isExtendedFrame(m_identifier); } //!< Indicates whether or not this ID is a standard frame ID. + constexpr bool isExtendedFrameId() const { return isExtendedFrame(m_identifier); } //!< Indicates whether or not this ID is an extended frame ID. public: // +++ Equality Checks +++ - bool equals(CanId otherId) const { return *this == otherId; } + constexpr bool equals(const CanId& otherId) const { return m_identifier == otherId.m_identifier; } //!< Compares this ID to another. private: // +++ Variables +++ - bool _isErrorFrame = false; - bool _isRemoteTransmissionRequest = false; - bool _isStandardFrameId = false; - bool _isExtendedFrameId = false; - - uint32_t _identifier = 0; + uint32_t m_identifier = 0; }; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7c45566..12dad56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,3 +2,14 @@ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/CanDriver.cpp ) + +if (TARGET sockcanpp_test) + target_sources(sockcanpp_test + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/CanDriver.cpp + ) +endif() + +add_compile_options( + -Wno-unknown-pragmas +) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ba94a46..7a18e6c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,29 +1,4 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.12) -project(testlibsockcanpp LANGUAGES CXX VERSION 1.0.0) -set(TARGET_NAME testsockcanpp.bin) - -set(CMAKE_CXX_STANDARD 14) - -include_directories( - include/ -) - -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/libsockcanpp) - -file(GLOB_RECURSE FILES ${CMAKE_CURRENT_SOURCE_DIR} src/*.cpp) - -add_executable(${TARGET_NAME} ${FILES}) - -target_link_libraries( - # Binary - ${TARGET_NAME} - - # Libs - sockcanpp - -lm - - -static - -static-libstdc++ - -static-libgcc -) \ No newline at end of file +add_subdirectory(app) +add_subdirectory(unit) \ No newline at end of file diff --git a/test/app/CMakeLists.txt b/test/app/CMakeLists.txt new file mode 100644 index 0000000..03938a7 --- /dev/null +++ b/test/app/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.14) + +project(testlibsockcanpp LANGUAGES CXX VERSION 1.0.0) +set(TARGET_NAME testsockcanpp.bin) + +set(CMAKE_CXX_STANDARD 14) + +include_directories( + include/ +) + +if (NOT TARGET sockcanpp) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/libsockcanpp) +endif() + +file(GLOB_RECURSE FILES ${CMAKE_CURRENT_SOURCE_DIR} src/*.cpp) + +add_executable(${TARGET_NAME} ${FILES}) + +target_link_libraries( + # Binary + ${TARGET_NAME} + + # Libs + sockcanpp_test + -lm + + -static + -static-libstdc++ + -static-libgcc +) \ No newline at end of file diff --git a/test/src/Main.cpp b/test/app/src/Main.cpp similarity index 100% rename from test/src/Main.cpp rename to test/app/src/Main.cpp diff --git a/test/unit/.gitignore b/test/unit/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/test/unit/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt new file mode 100644 index 0000000..ff313e9 --- /dev/null +++ b/test/unit/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.10) + +project(libsockcanpp_unittests LANGUAGES CXX VERSION 0.1) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(GTest REQUIRED) + +include_directories( + # none as of now +) + +if (NOT TARGET sockcanpp) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../ ${CMAKE_CURRENT_BINARY_DIR}/libsockcanpp) +endif() + +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + +add_compile_options( + -Wall + -Wextra + -Wpedantic + -Werror + -Wno-unknown-pragmas +) + +add_executable(${PROJECT_NAME} ${SOURCES}) + +target_link_libraries( + ${PROJECT_NAME} + + sockcanpp_test + ${GTEST_LIBRARIES} + pthread +) + +gtest_discover_tests(${PROJECT_NAME}) \ No newline at end of file diff --git a/test/unit/src/CanId_Tests.cpp b/test/unit/src/CanId_Tests.cpp new file mode 100644 index 0000000..7eb621d --- /dev/null +++ b/test/unit/src/CanId_Tests.cpp @@ -0,0 +1,278 @@ +/** + * @file CanId_Tests.cpp + * @author Simon Cahill (contact@simonc.eu) + * @brief Contains all the unit tests for the CanId structure. + * @version 0.1 + * @date 2024-05-29 + * + * @copyright Copyright (c) 2024 Simon Cahill and Contributors. + */ + +#include + +#include + +using sockcanpp::CanId; + +TEST(CanIdTests, CanId_invalidId_ExpectFalse) { + ASSERT_FALSE(CanId::isValidIdentifier(-1)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId) { + ASSERT_TRUE(CanId::isValidIdentifier(0x123)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId) { + ASSERT_TRUE(CanId::isValidIdentifier(0x123456)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ExplicitCast) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier((int32_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ExplicitCast) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier((int32_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ImplicitCast) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ImplicitCast) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ExplicitCastToInt16) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier((int16_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ExplicitCastToUint16) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier((uint16_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ExplicitCastToInt32) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier((int32_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ImplicitCastToInt16) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ImplicitCastToUint16) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ImplicitCastToInt32) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ExplicitCastToInt16) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier((int16_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ExplicitCastToUint16) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier((uint16_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ExplicitCastToInt32) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier((int32_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ImplicitCastToInt16) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ImplicitCastToUint16) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ImplicitCastToInt32) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ExplicitCastToUint32) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier((uint32_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ExplicitCastToUint32) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier((uint32_t)id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_StandardFrameId_ImplicitCastToUint32) { + CanId id(0x123); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_validId_ExpectTrue_ExtendedFrameId_ImplicitCastToUint32) { + CanId id(0x123456); + ASSERT_TRUE(CanId::isValidIdentifier(id)); +} + +TEST(CanIdTests, CanId_isErrorFrame_ExpectTrue) { + auto id = 0xe0000abc; + ASSERT_TRUE(CanId::isErrorFrame(id)); +} + +TEST(CanIdTests, CanId_isErrorFrame_ExpectFalse) { + auto id = 0x123; + ASSERT_FALSE(CanId::isErrorFrame(id)); +} + +TEST(CanIdTests, CanId_isErrorFrame_ExpectTrue_ExplicitCast) { + auto id = 0xe0000abc; + ASSERT_TRUE(CanId::isErrorFrame((int32_t)id)); +} + +TEST(CanIdTests, CanId_isErrorFrame_ExpectFalse_ExplicitCast) { + auto id = 0x123; + ASSERT_FALSE(CanId::isErrorFrame((int32_t)id)); +} + +TEST(CanIdTests, CanId_isExtendedFrame_ExpectTrue) { + auto id = 0xe0000abc; + ASSERT_TRUE(CanId::isExtendedFrame(id)); +} + +TEST(CanIdTests, CanId_isExtendedFrame_ExpectFalse) { + auto id = 0x123; + ASSERT_FALSE(CanId::isExtendedFrame(id)); +} + +TEST(CanIdTests, CanId_isRtr_ExpectTrue) { + auto id = 0x40000000; + ASSERT_TRUE(CanId::isRemoteTransmissionRequest(id)); +} + +TEST(CanIdTests, CanId_isRtr_ExpectFalse) { + auto id = 0x123; + ASSERT_FALSE(CanId::isRemoteTransmissionRequest(id)); +} + +// Test constexpr +TEST(CanIdTests, CanId_isErrorFrame_ExpectTrue_Constexpr) { + constexpr auto id = 0xe0000abc; + ASSERT_TRUE(CanId::isErrorFrame(id)); +} + +TEST(CanIdTests, CanId_isErrorFrame_ExpectFalse_Constexpr) { + constexpr auto id = 0x123; + ASSERT_FALSE(CanId::isErrorFrame(id)); +} + +// Test implicit operators +// Implicit operators strip out control bits + +TEST(CanIdTests, CanId_ImplicitOperatorInt32_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ((int32_t)id, 0x123); +} + +TEST(CanIdTests, CanId_ImplicitOperatorInt16_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ((int16_t)id, 0x123); +} + +TEST(CanIdTests, CanId_ImplicitOperatorUint16_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ((uint16_t)id, 0x123); +} + +TEST(CanIdTests, CanId_ImplicitOperatorUint32_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ((uint32_t)id, 0x123); +} + +// Test implicit operators with control bits set; these should be stripped. +TEST(CanIdTests, CanId_ImplicitOperatorInt32_ExpectTrue_ControlBits) { + CanId id(0x12345678); + ASSERT_EQ((int32_t)id, 0x12345678); +} + +TEST(CanIdTests, CanId_ImplicitOperatorInt16_ExpectTrue_ControlBits) { + CanId id(0x12345678); + ASSERT_EQ((int16_t)id, 0x5678); +} + +TEST(CanIdTests, CanId_ImplicitOperatorUint16_ExpectTrue_ControlBits) { + CanId id(0x12345678); + ASSERT_EQ((uint16_t)id, 0x5678); +} + +TEST(CanIdTests, CanId_ImplicitOperatorUint32_ExpectTrue_ControlBits) { + CanId id(0x12345678); + ASSERT_EQ((uint32_t)id, 0x12345678); +} + +// Test arithmetic operators +TEST(CanIdTests, CanId_ArithmeticOperatorPlus_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ(id + 0x123, 0x246); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorMinus_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ(id - 0x123, 0); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorPlusEquals_ExpectTrue) { + CanId id(0x123); + id += 0x123; + ASSERT_EQ(id, 0x246); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorMinusEquals_ExpectTrue) { + CanId id(0x123); + id -= 0x123; + ASSERT_EQ(id, 0); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorStar_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ(id * 2, 0x246); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorSlash_ExpectTrue) { + CanId id(0x246); + ASSERT_EQ(id / 2, 0x123); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorStarEquals_ExpectTrue) { + CanId id(0x123); + id *= 2; + ASSERT_EQ(id, 0x246); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorSlashEquals_ExpectTrue) { + CanId id(0x246); + id /= 2; + ASSERT_EQ(id, 0x123); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorModulo_ExpectTrue) { + CanId id(0x123); + ASSERT_EQ(id % 2, 1); +} + +TEST(CanIdTests, CanId_ArithmeticOperatorModuloEquals_ExpectTrue) { + CanId id(0x123); + id %= 2; + ASSERT_EQ(id, 1); +} \ No newline at end of file diff --git a/test/unit/src/main.cpp b/test/unit/src/main.cpp new file mode 100644 index 0000000..49c7a31 --- /dev/null +++ b/test/unit/src/main.cpp @@ -0,0 +1,16 @@ +/** + * @file main.cpp + * @author Simon Cahill (contact@simonc.eu) + * @brief Contains the main entry point for the unit tests. + * @version 0.1 + * @date 2024-05-29 + * + * @copyright Copyright (c) 2024 Simon Cahill and Contributors. + */ + +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file