From abca51d3311fbda17496981786820429a43828c3 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 26 Jun 2020 15:56:00 +0200 Subject: [PATCH] Large rework of the project, specifically the String classes. --- .gitignore | 1 + CMakeLists.txt | 4 +- src/ConstString.cpp | 4 - src/ConstString.hpp | 65 --------------- src/Enum.hpp | 12 +-- src/String/BasicStringView.hpp | 35 +++++++++ src/String/StringView.cpp | 4 + src/String/StringView.hpp | 104 ++++++++++++++++++++++++ src/String/StringViewLiteral.hpp | 46 +++++++++++ src/StringView.hpp | 6 ++ src/__ConstStringCore.hpp | 131 ------------------------------- tests/ConstStringTests.cpp | 54 +++---------- tests/EnumTests.cpp | 26 +++--- tests/ListTests.cpp | 7 ++ tests/UniquePtrListTests.cpp | 11 +++ 15 files changed, 250 insertions(+), 260 deletions(-) delete mode 100644 src/ConstString.cpp delete mode 100644 src/ConstString.hpp create mode 100644 src/String/BasicStringView.hpp create mode 100644 src/String/StringView.cpp create mode 100644 src/String/StringView.hpp create mode 100644 src/String/StringViewLiteral.hpp create mode 100644 src/StringView.hpp delete mode 100644 src/__ConstStringCore.hpp diff --git a/.gitignore b/.gitignore index baf251a..a3eeb06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /cmake-build-debug/ +/cmake-build-debug-coverage/ /cmake-build-release/ /build-release-windows/ /.idea/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b24907b..1b3ef40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(Arbutils) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) if (WINDOWS) ADD_DEFINITIONS(-D WINDOWS=1) @@ -11,7 +11,7 @@ endif (WINDOWS) file(GLOB_RECURSE SRC_FILES "src/*.cpp" "src/*.hpp") set(LIBTYPE STATIC) if (SHARED) - set(LIBTYPE SHARED) + set(LIBTYPE SHARED src/StringView.hpp src/String/BasicStringView.hpp src/String/StringViewLiteral.hpp) endif(SHARED) add_library(Arbutils ${LIBTYPE} ${SRC_FILES}) diff --git a/src/ConstString.cpp b/src/ConstString.cpp deleted file mode 100644 index 873e636..0000000 --- a/src/ConstString.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "ConstString.hpp" - -ArbUt::__ConstStringCharHolder* ArbUt::CaseInsensitiveConstString::__emptyString = new __ConstStringCharHolder("", 0); -ArbUt::__ConstStringCharHolder* ArbUt::ConstString::__emptyString = new __ConstStringCharHolder("", 0); \ No newline at end of file diff --git a/src/ConstString.hpp b/src/ConstString.hpp deleted file mode 100644 index 546e69a..0000000 --- a/src/ConstString.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef ARBUTILS_CONSTSTRING_HPP -#define ARBUTILS_CONSTSTRING_HPP - -#include -#include -#include -#include -#include -#include "__ConstStringCore.hpp" - -namespace ArbUt { - class __ConstStringCharHolder { - char* _value; - std::atomic _references; - - __ConstStringCharHolder(const __ConstStringCharHolder& o) = delete; - __ConstStringCharHolder& operator=(const __ConstStringCharHolder& other) = delete; - - public: - __ConstStringCharHolder(const char* value, size_t size) noexcept : _value(new char[size + 1]), _references(1) { - strncpy(_value, value, size + 1); - } - - ~__ConstStringCharHolder() noexcept { delete[] _value; } - - inline void RemoveReference() noexcept { - if (--_references <= 0) { - delete this; - } - } - inline void AddReference() noexcept { _references++; } - inline constexpr const char* GetValue() const noexcept { return _value; } - }; -} - -ConstStringCore( - ConstString, - inline static uint32_t constexpr Hash(char const* input) { - return (*input) ? static_cast((*input)) + 33 * Hash(input + 1) : 5381; - };) - - inline constexpr ArbUt::ConstString_Literal - operator"" _const(const char* c, size_t l) { - return ArbUt::ConstString_Literal(c, l); -} -inline constexpr ArbUt::ConstString_Literal operator"" _c(const char* c, size_t l) { - return ArbUt::ConstString_Literal(c, l); -} - -ConstStringCore( - CaseInsensitiveConstString, - inline static constexpr char charToLower(const char c) { - return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; - } inline static uint32_t constexpr Hash(char const* input) { - return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * Hash(input + 1) : 5381; - };); - -inline constexpr ArbUt::CaseInsensitiveConstString_Literal operator"" _const_nocase(const char* c, size_t l) { - return ArbUt::CaseInsensitiveConstString_Literal(c, l); -} -inline constexpr ArbUt::CaseInsensitiveConstString_Literal operator"" _cnc(const char* c, size_t l) { - return ArbUt::CaseInsensitiveConstString_Literal(c, l); -} - -#endif // ARBUTILS_CONSTSTRING_HPP diff --git a/src/Enum.hpp b/src/Enum.hpp index 3cd042f..9458280 100644 --- a/src/Enum.hpp +++ b/src/Enum.hpp @@ -4,12 +4,13 @@ #include #include #include "MacroUtils.hpp" +#include "StringView.hpp" #define ENUM_VALUE(x, value) x = value, # #define ENUM_CASE(x, name) \ case name::x: \ - return #x; + return ArbUt::StringViewLiteral(#x); # #define ENUM_PARSE_CASE(x, name) \ case ConstHash(#x): \ @@ -64,14 +65,9 @@ } \ \ public: \ - constexpr static const char* ToString(name value) noexcept { \ + constexpr static ArbUt::StringViewLiteral ToString(name value) noexcept { \ switch (value) { MACRO_UTILS_FOR_EACH(ENUM_CASE, name, values) } \ - /*If we haven't found a value, we want to stringify the number*/ \ - auto v = static_cast(value); \ - auto size = (int)((ceil(log10(v)) + 1) * sizeof(char)); \ - char* snum = new char[size + 1]; \ - sprintf(snum, "%d", v); \ - return snum; \ + return "out of bounds"_cnc; \ } \ constexpr static name Parse(const char* input, bool caseInsensitive = false) { \ if (caseInsensitive) \ diff --git a/src/String/BasicStringView.hpp b/src/String/BasicStringView.hpp new file mode 100644 index 0000000..b7dfca8 --- /dev/null +++ b/src/String/BasicStringView.hpp @@ -0,0 +1,35 @@ +#ifndef ARBUTILS_BASICSTRINGVIEW_HPP +#define ARBUTILS_BASICSTRINGVIEW_HPP +#include + +namespace ArbUt { + class BasicStringView { + protected: + size_t _length; + uint32_t _hash; + + constexpr BasicStringView(size_t length, uint32_t hash) : _length(length), _hash(hash) {} + public: + + [[nodiscard]] inline constexpr size_t Length() const noexcept { return _length; } + [[nodiscard]] inline constexpr uint32_t GetHash() const noexcept { return _hash; } + [[nodiscard]] inline constexpr std::size_t operator()(BasicStringView const& s) const noexcept { return _hash; } + [[nodiscard]] inline constexpr operator uint32_t() const noexcept { return _hash; } + [[nodiscard]] inline constexpr bool operator==(const BasicStringView& rhs) const noexcept { + return _hash == rhs._hash; + } + inline constexpr bool operator!=(const BasicStringView& rhs) const noexcept { return _hash != rhs._hash; } + inline constexpr bool Empty() const noexcept { return Length() == 0; } + + [[nodiscard]] virtual constexpr const char* c_str() const noexcept = 0; + [[nodiscard]] virtual constexpr std::string_view std_str() const noexcept = 0; + + virtual constexpr bool operator==(const std::string_view& rhs) const noexcept = 0; + virtual constexpr bool operator!=(const std::string_view& rhs) const noexcept = 0; + virtual constexpr bool operator==(const char* rhs) const noexcept = 0; + virtual constexpr bool operator!=(const char* rhs) const noexcept = 0; + + }; +} + +#endif // ARBUTILS_BASICSTRINGVIEW_HPP diff --git a/src/String/StringView.cpp b/src/String/StringView.cpp new file mode 100644 index 0000000..ed82824 --- /dev/null +++ b/src/String/StringView.cpp @@ -0,0 +1,4 @@ +#include "StringView.hpp" + +ArbUt::__ConstStringCharHolder* ArbUt::StringView::__emptyString = + new __ConstStringCharHolder(std::string_view("", 0)); diff --git a/src/String/StringView.hpp b/src/String/StringView.hpp new file mode 100644 index 0000000..d4502c2 --- /dev/null +++ b/src/String/StringView.hpp @@ -0,0 +1,104 @@ +#ifndef ARBUTILS_STRINGVIEW_HPP +#define ARBUTILS_STRINGVIEW_HPP + +#include +#include +#include +#include +#include +#include "BasicStringView.hpp" + +#if WINDOWS +#define STDSTRINGCONSTEXPR +#else +#define STDSTRINGCONSTEXPR constexpr +#endif + +namespace ArbUt { + class __ConstStringCharHolder { + std::string_view _value; + std::atomic _references; + + __ConstStringCharHolder(const __ConstStringCharHolder& o) = delete; + __ConstStringCharHolder& operator=(const __ConstStringCharHolder& other) = delete; + + public: + __ConstStringCharHolder(const std::string_view& value) noexcept : _value(value), _references(1) {} + + inline void RemoveReference() noexcept { + if (--_references <= 0) { + delete this; + } + } + inline void AddReference() noexcept { _references++; } + inline constexpr const std::string_view& GetValue() const noexcept { return _value; } + }; +} + +inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; } +static uint32_t constexpr Hash(char const* input) { + return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * Hash(input + 1) : 5381; +}; +static int constexpr CalcLength(const char* str) { return *str ? 1 + CalcLength(str + 1) : 0; } + +namespace ArbUt { + class StringView : public BasicStringView { + private: + static __ConstStringCharHolder* __emptyString; + static inline __ConstStringCharHolder* GetEmptyString() { return __emptyString; } + + __ConstStringCharHolder* _str; + + inline __ConstStringCharHolder* CloneHolder() const noexcept { + _str->AddReference(); + return _str; + } + + public: + StringView(const std::string_view& str) noexcept + : BasicStringView(str.length(), Hash(str.data())), _str(new __ConstStringCharHolder(str)) {} + + StringView() noexcept : BasicStringView(0, Hash("")), _str(GetEmptyString()) { + GetEmptyString()->AddReference(); + } + + /* Copy operators */ + StringView(const StringView& other) noexcept + : BasicStringView(other._length, other._hash), _str(other.CloneHolder()) {} + StringView& operator=(const StringView& other) noexcept { + if (_str == other._str) { + _str->AddReference(); + return *this; + } + _str->RemoveReference(); + _str = other.CloneHolder(); + _length = other._length; + _hash = other._hash; + return *this; + } + + ~StringView() noexcept { _str->RemoveReference(); } + + [[nodiscard]] inline constexpr const char* c_str() const noexcept override { return _str->GetValue().data(); } + [[nodiscard]] inline std::string_view std_str() const noexcept override { return _str->GetValue(); } + + inline constexpr bool operator==(const std::string_view& rhs) const noexcept override { + return _hash == Hash(rhs.data()); + } + inline constexpr bool operator!=(const std::string_view& rhs) const noexcept override { + return _hash != Hash(rhs.data()); + } + inline constexpr bool operator==(const char* rhs) const noexcept override { return _hash == Hash(rhs); } + inline constexpr bool operator!=(const char* rhs) const noexcept override { return _hash != Hash(rhs); } + + inline static constexpr uint32_t CalculateHash(const char* val) noexcept { return Hash(val); } + inline static constexpr uint32_t CalculateHash(const std::string_view& val) noexcept { return Hash(val.data()); } + }; +} + +namespace std { + template <> struct hash { + constexpr std::size_t operator()(ArbUt::StringView const& s) const noexcept { return s.GetHash(); } + }; +} +#endif // ARBUTILS_STRINGVIEW_HPP diff --git a/src/String/StringViewLiteral.hpp b/src/String/StringViewLiteral.hpp new file mode 100644 index 0000000..c3c00c2 --- /dev/null +++ b/src/String/StringViewLiteral.hpp @@ -0,0 +1,46 @@ +#ifndef ARBUTILS_STRINGVIEWLITERAL_HPP +#define ARBUTILS_STRINGVIEWLITERAL_HPP + +#include +#include "BasicStringView.hpp" +#include "StringView.hpp" + +namespace ArbUt { + class StringViewLiteral : public BasicStringView { + private: + const char* _str; + + public: + constexpr StringViewLiteral(const char* str, size_t size) noexcept + : BasicStringView(size, Hash(str)), _str(str) {} + constexpr StringViewLiteral(const char* str) noexcept : StringViewLiteral(str, CalcLength(str)){}; + [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str; } + constexpr std::string_view std_str() const noexcept { return std::string_view(_str, _length); } + constexpr std::size_t operator()(StringViewLiteral const& s) const noexcept { return s.GetHash(); } + inline operator StringView() const noexcept { return StringView(std::string_view(_str, _length)); } + + inline constexpr bool operator==(const std::string_view& rhs) const noexcept { + return _hash == Hash(rhs.data()); + } + inline constexpr bool operator!=(const std::string_view& rhs) const noexcept { + return _hash != Hash(rhs.data()); + } + inline constexpr bool operator==(const char* rhs) const noexcept { return _hash == Hash(rhs); } + inline constexpr bool operator!=(const char* rhs) const noexcept { return _hash != Hash(rhs); } + }; +} + +namespace std { + template <> struct hash { + constexpr std::size_t operator()(ArbUt::StringViewLiteral const& s) const noexcept { return s.GetHash(); } + }; +} + +inline constexpr ArbUt::StringViewLiteral operator"" _const_nocase(const char* c, size_t l) { + return ArbUt::StringViewLiteral(c, l); +} +inline constexpr ArbUt::StringViewLiteral operator"" _cnc(const char* c, size_t l) { + return ArbUt::StringViewLiteral(c, l); +} + +#endif // ARBUTILS_STRINGVIEWLITERAL_HPP diff --git a/src/StringView.hpp b/src/StringView.hpp new file mode 100644 index 0000000..0aa4c0c --- /dev/null +++ b/src/StringView.hpp @@ -0,0 +1,6 @@ +#include "String/StringView.hpp" +#include "String/StringViewLiteral.hpp" + +namespace ArbUt { + [[deprecated("Moved to StringView")]] typedef StringView CaseInsensitiveConstString; +} diff --git a/src/__ConstStringCore.hpp b/src/__ConstStringCore.hpp deleted file mode 100644 index cd25aae..0000000 --- a/src/__ConstStringCore.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef ARBUTILS_CONSTSTRINGCORE_HPP -#define ARBUTILS_CONSTSTRINGCORE_HPP - -#if WINDOWS -#define STDSTRINGCONSTEXPR -#else -#define STDSTRINGCONSTEXPR constexpr -#endif - -#define ConstStringCore(name, hashFunction) \ - namespace ArbUt { \ - class name { \ - private: \ - __ConstStringCharHolder* _str; \ - size_t _length; \ - uint32_t _hash; \ - hashFunction; \ - \ - static __ConstStringCharHolder* __emptyString; \ - static inline __ConstStringCharHolder* GetEmptyString() { return __emptyString; } \ - \ - inline static int constexpr Length(const char* str) { return *str ? 1 + Length(str + 1) : 0; } \ - inline __ConstStringCharHolder* CloneHolder() const noexcept { \ - _str->AddReference(); \ - return _str; \ - } \ - \ - public: \ - name(const char* str, size_t size) noexcept \ - : _str(new __ConstStringCharHolder(str, size)), _length(size), _hash(Hash(str)) {} \ - \ - name() noexcept : _str(GetEmptyString()), _length(0), _hash(Hash("")) { \ - GetEmptyString()->AddReference(); \ - }; \ - explicit name(const char* str) noexcept : name(str, Length(str)){}; \ - explicit name(const std::string& str) noexcept : name(str.c_str(), str.size()){}; \ - \ - /* Copy operators */ \ - name(const name& other) noexcept \ - : _str(other.CloneHolder()), _length(other._length), _hash(other._hash) {} \ - name& operator=(const name& other) noexcept { \ - if (_str == other._str) { \ - _str->AddReference(); \ - return *this; \ - } \ - _str->RemoveReference(); \ - _str = other.CloneHolder(); \ - _length = other._length; \ - _hash = other._hash; \ - return *this; \ - } \ - \ - ~name() noexcept { _str->RemoveReference(); } \ - \ - [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str->GetValue(); } \ - [[nodiscard]] inline std::string std_str() const noexcept { \ - return std::string(_str->GetValue(), _length); \ - } \ - \ - [[nodiscard]] inline constexpr size_t Length() const noexcept { return _length; } \ - \ - [[nodiscard]] inline constexpr uint32_t GetHash() const noexcept { return _hash; } \ - inline constexpr bool Empty() const noexcept { return _length == 0; } \ - \ - constexpr std::size_t operator()(name const& s) const noexcept { return s.GetHash(); } \ - inline constexpr operator uint32_t() const noexcept { return _hash; } \ - \ - inline constexpr bool operator==(const name& rhs) const noexcept { return _hash == rhs._hash; } \ - inline constexpr bool operator!=(const name& rhs) const noexcept { return _hash != rhs._hash; } \ - inline STDSTRINGCONSTEXPR bool operator==(const std::string& rhs) const noexcept { \ - return _hash == Hash(rhs.c_str()); \ - } \ - inline STDSTRINGCONSTEXPR bool operator!=(const std::string& rhs) const noexcept { \ - return _hash != Hash(rhs.c_str()); \ - } \ - inline constexpr bool operator==(const char* rhs) const noexcept { return _hash == Hash(rhs); } \ - inline constexpr bool operator!=(const char* rhs) const noexcept { return _hash != Hash(rhs); } \ - \ - inline static constexpr uint32_t GetHash(const char* val) noexcept { return Hash(val); } \ - inline static STDSTRINGCONSTEXPR uint32_t GetHash(const std::string& val) noexcept { \ - return Hash(val.c_str()); \ - } \ - }; \ - \ - class name##_Literal { \ - private: \ - const char* _str; \ - size_t _length; \ - uint32_t _hash; \ - \ - hashFunction; \ - \ - inline static int constexpr Length(const char* str) noexcept { return *str ? 1 + Length(str + 1) : 0; } \ - \ - public: \ - constexpr name##_Literal(const char* str, size_t size) noexcept \ - : _str(str), _length(size), _hash(Hash(str)) {} \ - explicit name##_Literal(const char* str) noexcept : name##_Literal(str, Length(str)){}; \ - [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str; } \ - [[nodiscard]] inline constexpr size_t Length() const noexcept { return _length; } \ - \ - [[nodiscard]] inline constexpr uint32_t GetHash() const noexcept { return _hash; } \ - inline constexpr bool Empty() const noexcept { return _length == 0; } \ - \ - constexpr std::size_t operator()(name##_Literal const& s) const noexcept { return s.GetHash(); } \ - inline constexpr operator uint32_t() const noexcept { return _hash; } \ - inline operator name() const noexcept { return name(_str, _length); } \ - \ - inline constexpr bool operator==(const name##_Literal& rhs) const noexcept { return _hash == rhs._hash; } \ - inline constexpr bool operator!=(const name##_Literal& rhs) const noexcept { return _hash != rhs._hash; } \ - inline STDSTRINGCONSTEXPR bool operator==(const std::string& rhs) const noexcept { \ - return _hash == Hash(rhs.c_str()); \ - } \ - inline STDSTRINGCONSTEXPR bool operator!=(const std::string& rhs) const noexcept { \ - return _hash != Hash(rhs.c_str()); \ - } \ - inline constexpr bool operator==(const char* rhs) const noexcept { return _hash == Hash(rhs); } \ - inline constexpr bool operator!=(const char* rhs) const noexcept { return _hash != Hash(rhs); } \ - }; \ - } \ - \ - namespace std { \ - template <> struct hash { \ - constexpr std::size_t operator()(ArbUt::name const& s) const noexcept { return s.GetHash(); } \ - }; \ - template <> struct hash { \ - constexpr std::size_t operator()(ArbUt::name##_Literal const& s) const noexcept { return s.GetHash(); } \ - }; \ - } - -#endif \ No newline at end of file diff --git a/tests/ConstStringTests.cpp b/tests/ConstStringTests.cpp index 1a2edbc..e45b6bb 100644 --- a/tests/ConstStringTests.cpp +++ b/tests/ConstStringTests.cpp @@ -2,29 +2,23 @@ #include #include #include "../extern/catch.hpp" -#include "../src/ConstString.hpp" +#include "../src/StringView.hpp" -TEST_CASE("Use const string in unordered_map", "[Utilities]") { - std::unordered_map map; - map.insert({"foo"_c, 1}); - map.insert({"bar"_c, 5}); - - CHECK(map["bar"_c] == 5); - CHECK(map["foo"_c] == 1); +TEST_CASE("Initialize compile time", "[Utilities]") { + static_assert("foo"_cnc.Length() == 3); + static_assert("bar"_cnc.Length() == 3); } -TEST_CASE("Use const string in switch case", "[Utilities]") { - auto val = ArbUt::ConstString("foobar"); - switch (val) { - case "foo"_c: FAIL(); break; - case "bar"_c: FAIL(); break; - case "foobar"_c: SUCCEED(); break; - default: FAIL(); break; - } +TEST_CASE("Compare compile time", "[Utilities]") { + static_assert("foo"_cnc != "bar"_cnc); +} + +TEST_CASE("Compare compile time with CaseInsensitiveConstString", "[Utilities]") { + static_assert("foo"_cnc == ArbUt::StringViewLiteral("foo")); } TEST_CASE("Use insensitive const string in unordered_map", "[Utilities]") { - std::unordered_map map; + std::unordered_map map; map.insert({"foO"_cnc, 1}); map.insert({"bAR"_cnc, 5}); @@ -33,7 +27,7 @@ TEST_CASE("Use insensitive const string in unordered_map", "[Utilities]") { } TEST_CASE("Use case insensitive const string in switch case", "[Utilities]") { - auto val = ArbUt::CaseInsensitiveConstString("foobar"); + auto val = ArbUt::StringView("foobar"); switch (val) { case "foo"_cnc: FAIL(); break; case "bar"_cnc: FAIL(); break; @@ -42,30 +36,8 @@ TEST_CASE("Use case insensitive const string in switch case", "[Utilities]") { } } -#ifndef WINDOWS -__attribute__((optnone)) -#endif -static ArbUt::CaseInsensitiveConstString -TestCreateConstString() { - char originalVal[7]; - originalVal[0] = 'f'; - originalVal[1] = 'o'; - originalVal[2] = 'o'; - originalVal[3] = 'b'; - originalVal[4] = 'a'; - originalVal[5] = 'r'; - originalVal[6] = '\0'; - return ArbUt::CaseInsensitiveConstString(originalVal); -} - -TEST_CASE("Out of scope char* doesn't lose reference", "[Utilities]") { - ArbUt::CaseInsensitiveConstString val = TestCreateConstString(); - INFO(val.c_str()); - REQUIRE(strcmp(val.c_str(), "foobar") == 0); -} - TEST_CASE("Literal conststring to non literal, then use", "[Utilities]") { - ArbUt::CaseInsensitiveConstString val; + ArbUt::StringView val; { val = "foobar"_cnc; } INFO(val.c_str()); REQUIRE(strcmp(val.c_str(), "foobar") == 0); diff --git a/tests/EnumTests.cpp b/tests/EnumTests.cpp index 7f0f320..085d91b 100644 --- a/tests/EnumTests.cpp +++ b/tests/EnumTests.cpp @@ -1,14 +1,15 @@ #ifdef TESTS_BUILD #include #include "../extern/catch.hpp" +#include "../src/StringView.hpp" #include "../src/Enum.hpp" ENUM(TestEnum, uint8_t, Val1, Val2, Val3) TEST_CASE("Parse Enum case sensitive", "[Utilities]") { - CHECK(TestEnumHelper::Parse("Val1") == TestEnum::Val1); - CHECK(TestEnumHelper::Parse("Val2") == TestEnum::Val2); - CHECK(TestEnumHelper::Parse("Val3") == TestEnum::Val3); + STATIC_REQUIRE(TestEnumHelper::Parse("Val1") == TestEnum::Val1); + STATIC_REQUIRE(TestEnumHelper::Parse("Val2") == TestEnum::Val2); + STATIC_REQUIRE(TestEnumHelper::Parse("Val3") == TestEnum::Val3); CHECK_THROWS(TestEnumHelper::Parse("Val4")); CHECK_THROWS(TestEnumHelper::Parse("val1")); } @@ -53,12 +54,11 @@ TEST_CASE("Try Parse Enum case insensitive", "[Utilities]") { } TEST_CASE("Enum To String", "[Utilities]") { - CHECK(strcmp(TestEnumHelper::ToString(TestEnum::Val1), "Val1") == 0); - CHECK(strcmp(TestEnumHelper::ToString(TestEnum::Val2), "Val2") == 0); - CHECK(strcmp(TestEnumHelper::ToString(TestEnum::Val3), "Val3") == 0); - auto s = TestEnumHelper::ToString((TestEnum)100); - CHECK(strcmp(s, "100") == 0); - delete[] s; + STATIC_REQUIRE(TestEnumHelper::ToString(TestEnum::Val1) == "Val1"); + STATIC_REQUIRE(TestEnumHelper::ToString(TestEnum::Val2) == "Val2"); + STATIC_REQUIRE(TestEnumHelper::ToString(TestEnum::Val3) == "Val3"); + + CHECK(TestEnumHelper::ToString((TestEnum)100) == "out of bounds"); } TEST_CASE("Enum Get Values", "[Utilities]") { @@ -69,4 +69,12 @@ TEST_CASE("Enum Get Values", "[Utilities]") { CHECK(vec[2] == TestEnum::Val3); } +TEST_CASE("Enum Get Highest", "[Utilities]") { STATIC_REQUIRE(TestEnumHelper::Highest() == TestEnum::Val3); } + +TEST_CASE("Enum Get Lowest", "[Utilities]") { STATIC_REQUIRE(TestEnumHelper::Lowest() == TestEnum::Val1); } + +TEST_CASE("Enum Get First", "[Utilities]") { STATIC_REQUIRE(TestEnumHelper::First() == TestEnum::Val1); } + +TEST_CASE("Enum Get Last", "[Utilities]") { STATIC_REQUIRE(TestEnumHelper::Last() == TestEnum::Val3); } + #endif \ No newline at end of file diff --git a/tests/ListTests.cpp b/tests/ListTests.cpp index 68a31ff..3495dd8 100644 --- a/tests/ListTests.cpp +++ b/tests/ListTests.cpp @@ -67,4 +67,11 @@ TEST_CASE("Test IndexOf", "[Utilities]") { CHECK(ls.IndexOf(684) == -1); } +TEST_CASE("Test list out of bounds", "[Utilities]") { + auto ls = List({5, 200, 1500, -500, 5, 300, -500}); + REQUIRE_THROWS(ls.At(-1)); + REQUIRE_THROWS(ls.At(7)); +} + + #endif \ No newline at end of file diff --git a/tests/UniquePtrListTests.cpp b/tests/UniquePtrListTests.cpp index bf65d49..d125cfa 100644 --- a/tests/UniquePtrListTests.cpp +++ b/tests/UniquePtrListTests.cpp @@ -41,4 +41,15 @@ TEST_CASE("Create Unique Ptr list, append, iterate") { } } +TEST_CASE("Test unique ptr list out of bounds", "[Utilities]") { + auto ls = UniquePtrList(); + auto v1 = new uint32_t(100); + auto v2 = new uint32_t(5000); + ls.Append(v1); + ls.Append(v2); + REQUIRE_THROWS(ls.At(-1)); + REQUIRE_THROWS(ls.At(2)); +} + + #endif \ No newline at end of file