Refactored namespaces

This commit is contained in:
emeric
2024-03-12 08:32:08 +01:00
parent 487960b413
commit 4b7c4295ec
501 changed files with 12605 additions and 12631 deletions
+22
View File
@@ -0,0 +1,22 @@
include(GoogleTest)
add_executable(test-core
EnumSet.cpp
LiteralString.cpp
Path.cpp
RecursiveSharedMutex.cpp
String.cpp
TraceLogger.cpp
Utils.cpp
)
target_link_libraries(test-core PRIVATE
lmscore
Threads::Threads
GTest::GTest
)
if (NOT CMAKE_CROSSCOMPILING)
gtest_discover_tests(test-core)
endif()
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>
#include "core/EnumSet.hpp"
namespace lms::core
{
TEST(EnumSet, ctr)
{
enum class Foo
{
One,
Two,
};
{
constexpr EnumSet<Foo> test{ Foo::One };
static_assert(!test.empty());
static_assert(test.contains(Foo::One));
static_assert(!test.contains(Foo::Two));
EXPECT_TRUE(!test.empty());
EXPECT_TRUE(test.contains(Foo::One));
EXPECT_FALSE(test.contains(Foo::Two));
static_assert(test.getBitfield() != 0);
}
{
constexpr EnumSet<Foo> test{ Foo::One, Foo::Two };
constexpr auto bitfield{ test.getBitfield() };
EnumSet<Foo> test2;
EXPECT_FALSE(test2.contains(Foo::One));
EXPECT_FALSE(test2.contains(Foo::Two));
test2.setBitfield(bitfield);
EXPECT_TRUE(test2.contains(Foo::One));
EXPECT_TRUE(test2.contains(Foo::Two));
EXPECT_EQ(test, test2);
}
}
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unordered_map>
#include <gtest/gtest.h>
#include "core/LiteralString.hpp"
namespace lms::core
{
TEST(LiteralString, ctr)
{
{
constexpr LiteralString foo{ "abc" };
static_assert(foo.length() == 3);
static_assert(foo == "abc");
static_assert(foo == LiteralString{ "abc" });
static_assert(foo < LiteralString{ "abcd" });
static_assert(foo > LiteralString{ "aac" });
EXPECT_EQ(::strlen(foo.c_str()), 3);
EXPECT_EQ(foo, LiteralString{ "abc" });
EXPECT_GT(foo, LiteralString{ "abb" });
EXPECT_LT(foo, LiteralString{ "abcd" });
}
{
constexpr LiteralString foo{ "" };
static_assert(foo.length() == 0);
static_assert(foo == "");
static_assert(foo == LiteralString{ "" });
static_assert(foo < LiteralString{ "a" });
EXPECT_EQ(::strlen(foo.c_str()), 0);
}
}
TEST(LiteralString, unordered_map)
{
{
std::unordered_map<LiteralString, int> myMap{ {"abc", 42} };
EXPECT_TRUE(myMap.contains("abc"));
EXPECT_TRUE(myMap.contains(LiteralString{ "abc" }));
EXPECT_FALSE(myMap.contains("abcd"));
}
{
std::unordered_map<LiteralString, int, LiteralStringHash, LiteralStringEqual> myMap{ {"abc", 42} };
EXPECT_TRUE(myMap.contains(std::string{ "abc" }));
EXPECT_TRUE(myMap.contains(std::string_view{ "abc" }));
EXPECT_FALSE(myMap.contains(std::string{ "abcd" }));
EXPECT_FALSE(myMap.contains(std::string_view{ "abcd" }));
}
}
}
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>
#include "core/Path.hpp"
namespace lms::core::pathUtils::tests
{
TEST(Path, getLongestCommonPath)
{
struct TestCase
{
std::filesystem::path path1;
std::filesystem::path path2;
std::filesystem::path expectedCommonPath;
};
TestCase tests[]
{
{"foo.txt", "/foo/foo.txt", ""},
{"/", "/file.txt", "/"},
{"/foo/bar/file1.txt", "/foo/bar/file2.txt", "/foo/bar"},
{"/foo/bar/file.txt", "/foo/bar/file.txt", "/foo/bar/file.txt"},
{"/dir1/file.txt", "/dir2/file.txt", "/"},
{"/prefix/folder/file.txt", "/prefix/folder/subfolder/file.txt", "/prefix/folder"},
};
for (const TestCase& test : tests)
{
EXPECT_EQ(core::pathUtils::getLongestCommonPath(test.path1, test.path2), test.expectedCommonPath);
}
}
TEST(Path, getLongestCommonPathIterator)
{
struct TestCase
{
std::vector<std::filesystem::path> paths;
std::filesystem::path expectedCommonPath;
};
TestCase tests[]
{
{{}, ""},
{{"/"}, "/"},
{{"/foo", "/bar"}, "/"},
{{"/foo/bar/file1.txt", "/foo/bar/file2.txt"}, "/foo/bar"},
{{"/foo", "/foo/"}, "/foo"},
{{"/foo", "/foo"}, "/foo"},
{{"/foo/", "/foo/"}, "/foo/"},
{{"/foo/", "/foo/", "/bar"}, "/"},
{{"/foo/", "/foo/", "/foo/bar"}, "/foo"},
};
for (const TestCase& test : tests)
{
EXPECT_EQ(core::pathUtils::getLongestCommonPath(std::cbegin(test.paths), std::cend(test.paths)), test.expectedCommonPath);
}
}
TEST(Path, isPathInRootPath)
{
struct TestCase
{
std::filesystem::path path;
std::filesystem::path rootPath;
bool expectedResult;
};
TestCase tests[]
{
{"/file.txt", "/", true},
{"/root/folder/file.txt", "/root", true},
{"/root/file.txt", "/root", true},
{"/root/file.txt", "/root/", true},
{"/root", "/root", true},
{"/root", "/root/", true},
{"/root/", "/root", true},
{"/root/", "/root/", true},
{"/folder/file.txt", "/root", false},
{"/folder/file.txt", "/root/", false},
{"", "/root", false},
};
for (const TestCase& test : tests)
{
EXPECT_EQ(core::pathUtils::isPathInRootPath(test.path, test.rootPath), test.expectedResult) << "Failed: path = " << test.path << ", rootPath = " << test.rootPath;
}
}
}
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <atomic>
#include <chrono>
#include <thread>
#include <vector>
#include <gtest/gtest.h>
#include "core/RecursiveSharedMutex.hpp"
namespace lms::core
{
TEST(RecursiveSharedMutex, SingleThreaded)
{
RecursiveSharedMutex mutex;
{
std::unique_lock lock{ mutex };
}
{
std::shared_lock lock{ mutex };
}
{
std::unique_lock lock1{ mutex };
std::unique_lock lock2{ mutex };
}
{
std::shared_lock lock1{ mutex };
std::shared_lock lock2{ mutex };
}
{
std::unique_lock lock1{ mutex };
std::shared_lock lock2{ mutex };
}
}
TEST(RecursiveSharedMutex, MultiThreaded)
{
constexpr std::size_t nbThreads{ 10 };
std::vector<std::thread> threads;
RecursiveSharedMutex mutex;
std::atomic<std::size_t> nbUnique{};
std::atomic<std::size_t> nbShared{};
for (std::size_t i{}; i < nbThreads; ++i)
{
threads.emplace_back([&]
{
{
std::unique_lock lock{ mutex };
std::shared_lock lock2{ mutex };
assert(nbUnique == 0);
assert(nbShared == 0);
nbUnique++;
std::this_thread::sleep_for(std::chrono::milliseconds(5));
assert(nbUnique == 1);
assert(nbShared == 0);
nbUnique--;
}
{
std::shared_lock lock{ mutex };
std::shared_lock lock2{ mutex };
assert(nbUnique == 0);
nbShared++;
std::this_thread::sleep_for(std::chrono::milliseconds(15));
assert(nbShared > 0);
assert(nbShared <= nbThreads);
assert(nbUnique == 0);
nbShared--;
}
});
}
for (std::thread& t : threads)
t.join();
}
}
+297
View File
@@ -0,0 +1,297 @@
/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>
#include <Wt/WDateTime.h>
#include <Wt/WDate.h>
#include <Wt/WTime.h>
#include "core/String.hpp"
namespace lms::core::stringUtils::tests
{
TEST(StringUtils, splitString_charDelim)
{
struct TestCase
{
std::string_view input;
char delimiter;
std::vector<std::string_view> expectedOutput;
};
TestCase tests[]
{
{"abc", '-', {"abc"}},
{"a", '-', {"a"}},
{"", '-', {""}},
{"a-b-c", '-', {"a", "b", "c"}},
{"a|b|c", '|', {"a", "b", "c"}},
{"a;b;c", ';', {"a", "b", "c"}},
{";b;c", ';', {"", "b", "c"}},
{" ;b;c", ';', {" ", "b", "c"}},
{" ;;c", ';', {" ", "", "c"}},
{" ; ;c", ';', {" ", " ", "c"}},
{"a;b; ", ';', {"a", "b", " "}},
{"a;b", ';', {"a", "b"}},
{";b", ';', {"", "b"}},
{";", ';', {"", ""}},
{";;", ';', {"", "", ""}},
{";;;", ';', {"", "", "", ""}},
{";;a;;b;;", ';', {"", "", "a", "", "b", "", ""}},
{"a b", ' ', {"a", "b"}},
{"", ' ', {""}},
{"a-b|c", '-', {"a","b|c"}},
{"a|b-c", '-', {"a|b", "c"}},
{"test=foo bar", '=', {"test", "foo bar"}},
};
for (const TestCase& test : tests)
{
const std::vector<std::string_view> res{ splitString(test.input, test.delimiter) };
EXPECT_EQ(res, test.expectedOutput) << "Input = '" << test.input << "', delims = '" << test.delimiter << "'";
}
}
TEST(StringUtils, splitString_stringDelim)
{
struct TestCase
{
std::string_view input;
std::string_view delimiter;
std::vector<std::string_view> expectedOutput;
};
TestCase tests[]
{
{"abc", "", {"abc"}},
{"abc", "-", {"abc"}},
{"abc", "b", {"a", "c"}},
{"ab/cd", "/", {"ab", "cd"}},
{"ab/cd", "/ ", {"ab/cd"}},
{"ab/cd", " /", {"ab/cd"}},
{"ab /cd", " /", {"ab", "cd"}},
{"ab/ cd", "/ ", {"ab", "cd"}},
{"ab / cd", " / ", {"ab", "cd"}},
{"ab/cd", " / ", {"ab/cd"}},
{"ab/cd / ", " / ", {"ab/cd", ""}},
};
for (const TestCase& test : tests)
{
const std::vector<std::string_view> res{ splitString(test.input, test.delimiter) };
EXPECT_EQ(res, test.expectedOutput) << "Input = '" << test.input << "', delims = '" << test.delimiter << "'";
}
}
TEST(StringUtils, joinStrings)
{
struct TestCase
{
std::vector<std::string_view> input;
std::string delimiter;
std::string expectedOutput;
};
TestCase tests[]
{
{{"a", "b", "c"}, "-", "a-b-c"},
{{"a", "b", "c"}, ",", "a,b,c"},
{{"a", "b", "c"}, "***", "a***b***c"},
{{"a", "", "c"}, "-", "a--c"},
{{"", "b", "c"}, "-", "-b-c"},
{{"a"}, "-", "a"},
{{"a"}, ",", "a"},
};
for (const TestCase& test : tests)
{
const std::string str{ joinStrings(test.input, test.delimiter) };
EXPECT_EQ(str, test.expectedOutput);
}
}
TEST(StringUtils, escapeAndJoinStrings)
{
struct TestCase
{
std::vector<std::string_view> input;
char delimiter;
char escapeChar;
std::string expectedOutput;
};
TestCase tests[]
{
{{""}, ';', '\\', ""},
{{";"}, ';', '\\', "\\;"},
{{";;"}, ';', '\\', "\\;\\;"},
{{"a;", "b"}, ';', '\\', "a\\;;b"},
{{"a;", "b;"}, ';', '\\', "a\\;;b\\;"},
};
for (const TestCase& test : tests)
{
const std::string str{ escapeAndJoinStrings(test.input, test.delimiter, test.escapeChar) };
EXPECT_EQ(str, test.expectedOutput);
}
}
TEST(StringUtils, splitEscapedStrings)
{
struct TestCase
{
std::string input;
char delimiter;
char escapeChar;
std::vector<std::string> expectedOutput;
};
TestCase tests[]
{
{"", ';', '\\', {}},
{"\\;", ';', '\\', {";"}},
{"\\;\\;", ';', '\\', {";;"}},
{"a\\;;b", ';', '\\', {"a;", "b"}},
{"a\\;;b\\;", ';', '\\', {"a;", "b;"}},
};
for (const TestCase& test : tests)
{
const std::vector<std::string> str{ splitEscapedStrings(test.input, test.delimiter, test.escapeChar) };
EXPECT_EQ(str, test.expectedOutput);
}
}
TEST(StringUtils, escapeJSString)
{
EXPECT_EQ(jsEscape(""), "");
EXPECT_EQ(jsEscape(R"(Test'.mp3)"), R"(Test\'.mp3)");
EXPECT_EQ(jsEscape(R"(Test"".mp3)"), R"(Test\"\".mp3)");
EXPECT_EQ(jsEscape(R"(\Test\.mp3)"), R"(\\Test\\.mp3)");
}
TEST(StringUtils, escapeJsonString)
{
EXPECT_EQ(jsonEscape(""), "");
EXPECT_EQ(jsonEscape(R"(Test'.mp3)"), R"(Test'.mp3)");
EXPECT_EQ(jsonEscape(R"(Test"".mp3)"), R"(Test\"\".mp3)");
EXPECT_EQ(jsonEscape(R"(\Test\.mp3)"), R"(\\Test\\.mp3)");
}
TEST(StringUtils, escapeString)
{
EXPECT_EQ(escapeString("", "*", ' '), "");
EXPECT_EQ(escapeString("", "", ' '), "");
EXPECT_EQ(escapeString("a", "", ' '), "a");
EXPECT_EQ(escapeString("*", "*", '_'), "_*");
EXPECT_EQ(escapeString("*a*", "*", '_'), "_*a_*");
EXPECT_EQ(escapeString("*a|", "*|", '_'), "_*a_|");
EXPECT_EQ(escapeString("**||", "*|", '_'), "_*_*_|_|");
EXPECT_EQ(escapeString("one;two", ";", '\\'), "one\\;two");
EXPECT_EQ(escapeString("one\\;two", ";", '\\'), "one\\\\;two");
EXPECT_EQ(escapeString("one;", ";", '\\'), "one\\;");
}
TEST(StringUtils, unescapeString)
{
EXPECT_EQ(unescapeString("one\\", '\\'), "one\\");
EXPECT_EQ(unescapeString("\\\\one", '\\'), "\\one");
EXPECT_EQ(unescapeString("one\\;two", '\\'), "one;two");
EXPECT_EQ(unescapeString("one\\\\;two", '\\'), "one\\;two");
}
TEST(StringUtils, readAs_bool)
{
EXPECT_EQ(readAs<bool>("true"), true);
EXPECT_EQ(readAs<bool>("1"), true);
EXPECT_EQ(readAs<bool>("false"), false);
EXPECT_EQ(readAs<bool>("0"), false);
EXPECT_EQ(readAs<bool>("foo"), std::nullopt);
EXPECT_EQ(readAs<bool>(""), std::nullopt);
}
TEST(StringUtils, readAs_int)
{
EXPECT_EQ(readAs<int>("1024"), 1024);
EXPECT_EQ(readAs<int>("0"), 0);
EXPECT_EQ(readAs<int>("-0"), 0);
EXPECT_EQ(readAs<int>("-1"), -1);
EXPECT_EQ(readAs<int>(""), std::nullopt);
EXPECT_EQ(readAs<int>("a"), std::nullopt);
EXPECT_EQ(readAs<int>("-"), std::nullopt);
EXPECT_EQ(readAs<int>("1024-1"), 1024);
EXPECT_EQ(readAs<int>("1024-"), 1024);
EXPECT_EQ(readAs<int>("1024/5"), 1024);
EXPECT_EQ(readAs<int>("1024a"), 1024);
EXPECT_EQ(readAs<int>("a1024a"), std::nullopt);
}
TEST(StringUtils, capitalize)
{
struct TestCase
{
std::string input;
std::string expectedOutput;
};
TestCase tests[]
{
{"", ""},
{"C", "C"},
{"c", "C"},
{" c", " C"},
{" cc", " Cc"},
{"(c", "(c"},
{"1c", "1c"},
{"&c", "&c"},
{"c c", "C c"}
};
for (const TestCase& test : tests)
{
std::string str{ test.input };
capitalize(str);
EXPECT_EQ(str, test.expectedOutput) << " str was '" << test.input << "'";
}
}
TEST(Stringutils, date)
{
const Wt::WDate date{ 2020, 01, 03 };
EXPECT_EQ(toISO8601String(date), "2020-01-03");
}
TEST(Stringutils, dateTime)
{
const Wt::WDateTime dateTime{ Wt::WDate {2020, 01, 03 }, Wt::WTime{9, 8, 11, 75} };
EXPECT_EQ(toISO8601String(dateTime), "2020-01-03T09:08:11.075");
}
TEST(StringUtils, stringEndsWith)
{
EXPECT_TRUE(stringEndsWith("FooBar", "Bar"));
EXPECT_TRUE(stringEndsWith("FooBar", ""));
EXPECT_TRUE(stringEndsWith("", ""));
EXPECT_TRUE(stringEndsWith("FooBar", "ar"));
EXPECT_TRUE(stringEndsWith("FooBar", "FooBar"));
EXPECT_FALSE(stringEndsWith("FooBar", "1FooBar"));
EXPECT_FALSE(stringEndsWith("FooBar", "1FooBar"));
EXPECT_FALSE(stringEndsWith("FooBar", "R"));
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2024 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sstream>
#include <thread>
#include <gtest/gtest.h>
#include "core/ITraceLogger.hpp"
namespace lms::core::tracing::tests
{
// not much can be tested with this implementation
TEST(TraceLogger, MultipleThreads)
{
auto traceLogger{ createTraceLogger(Level::Overview) };
std::vector<std::thread> threads;
for (std::size_t i{}; i < 16; ++i)
{
threads.emplace_back([&]
{
ScopedTrace loggedEvent{ "MyCategory", Level::Overview, "MyEventLogged", traceLogger.get() };
ScopedTrace notLoggedEvent{ "MyCategory", Level::Detailed, "MyEventNotLogged", traceLogger.get() };
});
}
for (std::thread& t : threads)
t.join();
std::ostringstream oss;
traceLogger->dumpCurrentBuffer(oss);
EXPECT_NE(oss.str().find("MyEventLogged"), std::string::npos);
EXPECT_EQ(oss.str().find("MyEventNotLogged"), std::string::npos);
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2021 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}