From 43286e76bb5eae8220253c0faf3237e660387cf7 Mon Sep 17 00:00:00 2001 From: ricemaking Date: Mon, 4 Nov 2024 17:27:45 -0800 Subject: [PATCH 1/6] Added test for random util --- src/CMakeLists.txt | 6 +++++- tests/util/RandomTest.cpp | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/util/RandomTest.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b55de633..1a074f83 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -337,6 +337,7 @@ if(WITH_TESTS) ../tests/util/CoreTest.cpp ../tests/util/DataTest.cpp ../tests/util/MathTest.cpp + ../tests/util/RandomTest.cpp ../tests/util/TimeTest.cpp ../tests/util/SchedulerTest.cpp # Protocol/teleop tests @@ -344,7 +345,10 @@ if(WITH_TESTS) target_link_libraries(tests ${rover_libs} - stub_world_interface + stub_world_interface double sample0 = stdn(0); + double sample1 = stdn(1); + + REQUIRE(sample0 != sample1); ${OpenCV_LIBS}) include(CTest) include(Catch) diff --git a/tests/util/RandomTest.cpp b/tests/util/RandomTest.cpp new file mode 100644 index 00000000..5c4204ea --- /dev/null +++ b/tests/util/RandomTest.cpp @@ -0,0 +1,21 @@ +#include "../../src/utils/random.h" + +#include + +using namespace util; + +TEST_CASE("Test Standard Normal Distribution w/ different thread_ids", "[util][random]") { + double sample0 = stdn(0); + double sample1 = stdn(1); + + // samples should be different + REQUIRE(sample0 != sample1); +} + +TEST_CASE("Test Get Normal Seed", "[util][random]") { + double seed1 = getNormalSeed(); + double seed2 = getNormalSeed(); + + // seeds should be the same + REQUIRE(seed1 == seed2); +} \ No newline at end of file From a8de6bc46f11dc47a2494593c17b0e3aca01f2e2 Mon Sep 17 00:00:00 2001 From: ricemaking Date: Mon, 4 Nov 2024 18:06:25 -0800 Subject: [PATCH 2/6] Fixed formatting --- tests/util/RandomTest.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/util/RandomTest.cpp b/tests/util/RandomTest.cpp index 5c4204ea..78bd1504 100644 --- a/tests/util/RandomTest.cpp +++ b/tests/util/RandomTest.cpp @@ -5,17 +5,17 @@ using namespace util; TEST_CASE("Test Standard Normal Distribution w/ different thread_ids", "[util][random]") { - double sample0 = stdn(0); - double sample1 = stdn(1); + double sample0 = stdn(0); + double sample1 = stdn(1); - // samples should be different - REQUIRE(sample0 != sample1); + // samples should be different + REQUIRE(sample0 != sample1); } TEST_CASE("Test Get Normal Seed", "[util][random]") { - double seed1 = getNormalSeed(); - double seed2 = getNormalSeed(); + double seed1 = getNormalSeed(); + double seed2 = getNormalSeed(); - // seeds should be the same - REQUIRE(seed1 == seed2); -} \ No newline at end of file + // seeds should be the same + REQUIRE(seed1 == seed2); +} From 83754493327a57a3bd02d920462b1e616f0c124e Mon Sep 17 00:00:00 2001 From: ricemaking Date: Sat, 16 Nov 2024 11:41:20 -0800 Subject: [PATCH 3/6] created test for json util --- src/CMakeLists.txt | 7 ++--- tests/util/JsonTest.cpp | 65 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 tests/util/JsonTest.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a074f83..f3524b58 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -337,18 +337,15 @@ if(WITH_TESTS) ../tests/util/CoreTest.cpp ../tests/util/DataTest.cpp ../tests/util/MathTest.cpp - ../tests/util/RandomTest.cpp ../tests/util/TimeTest.cpp ../tests/util/SchedulerTest.cpp + ../tests/util/RandomTest.cpp + ../tests/util/JsonTest.cpp # Protocol/teleop tests ../tests/kinematics/DiffWristKinematicsTest.cpp) target_link_libraries(tests ${rover_libs} - stub_world_interface double sample0 = stdn(0); - double sample1 = stdn(1); - - REQUIRE(sample0 != sample1); ${OpenCV_LIBS}) include(CTest) include(Catch) diff --git a/tests/util/JsonTest.cpp b/tests/util/JsonTest.cpp new file mode 100644 index 00000000..400ecd89 --- /dev/null +++ b/tests/util/JsonTest.cpp @@ -0,0 +1,65 @@ +#include "../../src/utils/json.h" + +#include + +using namespace util; + +TEST_CASE("Test Has Key", "[util][json]") { + json j = {{"name", "huskyRobos"}, {"location", "University of Washington"}}; + + REQUIRE(hasKey(j, "name")); // has key of 'name' + REQUIRE_FALSE(hasKey(j, "numLosses")); // doesn't have key of 'numLosses' +} + +TEST_CASE("Test Validate Key (Given Individual Types)", "[util][json]") { + json j = {{"name", "huskyRobos"}, {"age", 11}, {"cool", true}}; + REQUIRE(validateKey(j, "name", val_t::string)); // has key of 'name' that is a string + REQUIRE_FALSE( + validateKey(j, "age", val_t::string)); // doesn't have key of 'age' that is a string + REQUIRE(validateKey(j, "cool", val_t::boolean)); // has key of 'cool' that is a boolean +} + +TEST_CASE("Test Validate Key (Given Set of Types)", "[util][json]") { + json j = {{"name", "huskyRobos"}, {"age", 11}, {"cool", true}}; + + std::unordered_set keyTypesAllowed = {val_t::string, val_t::number_integer}; + + REQUIRE(validateKey( + j, "name", keyTypesAllowed)); // has key of 'name' that is a type of the allowed types + REQUIRE(validateKey( + j, "age", keyTypesAllowed)); // has key of 'age' that is a type of the allowed types + REQUIRE_FALSE(validateKey( + j, "cool", + keyTypesAllowed)); // doesn't have key of 'cool' that is a type of the allowed types +} + +TEST_CASE("Test Validate One Of", "[util][json]") { + json j = {{"status", "active"}, {"subTeams", "software"}}; + + std::unordered_set statusValueTypesAllowed = {"active", "inactive"}; + std::unordered_set subTeamValueTypesAllowed = {"software", "electrical", + "mechanical"}; + + REQUIRE(validateOneOf(j, "status", + statusValueTypesAllowed)); // value of 'status' is a string in set of + // statusValueTypesAllowed + REQUIRE_FALSE(validateOneOf( + j, "status", {"pending", "closed"})); // value of 'status' is a string but not in set + // of statusValueTypesAllowed + REQUIRE(validateOneOf(j, "subTeams", + subTeamValueTypesAllowed)); // value of 'subTeams' is a string in set + // of subTeamValueTypesAllowed +} + +TEST_CASE("Test Validate Range", "[util][json]") { + json j = { + {"winLossRatio", 0.8375}, + {"avgGPA", 3.6}, + }; + + REQUIRE(validateRange(j, "winLossRatio", 0.0, + 1.0)); // 'winLossRatio' is in range from 0.0 to 1.0 + REQUIRE(validateRange(j, "avgGPA", 0.0, 4.0)); // 'avgGPA' is in range from 0.0 to 4.0 + REQUIRE_FALSE( + validateRange(j, "avgGPA", 0.0, 2.0)); // 'avgGPA' isnt in range of 0.0 to 2.0 +} \ No newline at end of file From bd563ada0d8a3bd0b83dae481569c3ce629498c0 Mon Sep 17 00:00:00 2001 From: ricemaking Date: Sat, 16 Nov 2024 12:54:34 -0800 Subject: [PATCH 4/6] added more tests to core testing file --- tests/util/CoreTest.cpp | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tests/util/CoreTest.cpp b/tests/util/CoreTest.cpp index 2839ed99..2517cb58 100644 --- a/tests/util/CoreTest.cpp +++ b/tests/util/CoreTest.cpp @@ -4,6 +4,87 @@ using namespace util; +TEST_CASE("Test almostEqual", "[util][core]") { + SECTION("Numbers are approximately equal") { + REQUIRE(almostEqual(1.000000001, 1.000000002)); + REQUIRE(almostEqual(1.0, 1.0, 1e-5)); + } + + SECTION("Numbers are not approximately equal") { + REQUIRE_FALSE(almostEqual(1.0, 1.1)); + REQUIRE_FALSE(almostEqual(1.0, 1.0 + 1e-5, 1e-6)); + } +} + +TEST_CASE("Test Key Set", "[util][core]") { + SECTION("Extracting keys from a given map") { + std::unordered_map inputtedMap = { + {"key1", 1}, + {"key2", 2}, + {"key3", 3} + }; + + auto keys = keySet(inputtedMap); + + std::unordered_set expectedSet = {"key1", "key2", "key3"}; + + REQUIRE(keys == expectedSet); + } + + SECTION("Empty map results in empty set") { + std::unordered_map emptyMap; + auto keys = keySet(emptyMap); + REQUIRE(keys.empty()); + } +} + +TEST_CASE("Test To String", "[util][core]") { + SECTION("Convert integers to strings") { + REQUIRE(to_string(69) == "69"); + REQUIRE(to_string(-1) == "-1"); + } + + SECTION("Convert floats to strings") { + REQUIRE(to_string(3.14).substr(0,4) == "3.14"); + REQUIRE(to_string(1e-6) == "0.000001"); + } + + SECTION("Convert booleans to strings") { + REQUIRE(to_string(true) == "true"); + REQUIRE(to_string(false) == "false"); + } +} + +TEST_CASE("Test Freeze String", "[util][core]") { + SECTION("Converting std::string to frozen::string") { + std::string stdString = "Test"; + auto frozenString = freezeStr(stdString); + REQUIRE(frozenString == frozen::string("Test")); + } + + SECTION("Converting empty std::string results in empty frozen::string") { + std::string stdString; + auto frozenString = freezeStr(stdString); + REQUIRE(frozenString == frozen::string("")); + } +} + +TEST_CASE("Test Pair To Tuple", "[util][core]") { + SECTION("Converting pair of integers to tuple") { + std::pair pair = {0,1}; + auto tuple = pairToTuple(pair); + REQUIRE(std::get<0>(tuple) == 0); + REQUIRE(std::get<1>(tuple) == 1); + } + + SECTION("Converting mixed pair of string and integer to tuple") { + std::pair pair = {"key0", 0}; + auto tuple = pairToTuple(pair); + REQUIRE(std::get<0>(tuple) == "key0"); + REQUIRE(std::get<1>(tuple) == 0); + } +} + TEST_CASE("Test RAIIHelper", "[util][core]") { SECTION("Test RAIIHelper executes") { bool called = false; From 439f74efe6321b52c3a5702a5d8e1b7f9f04ea92 Mon Sep 17 00:00:00 2001 From: ricemaking Date: Sat, 16 Nov 2024 13:16:54 -0800 Subject: [PATCH 5/6] created test file for threading header file --- src/CMakeLists.txt | 1 + tests/util/ThreadingTest.cpp | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 tests/util/ThreadingTest.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f3524b58..616e2c87 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -341,6 +341,7 @@ if(WITH_TESTS) ../tests/util/SchedulerTest.cpp ../tests/util/RandomTest.cpp ../tests/util/JsonTest.cpp + ../tests/util/ThreadingTest.cpp # Protocol/teleop tests ../tests/kinematics/DiffWristKinematicsTest.cpp) diff --git a/tests/util/ThreadingTest.cpp b/tests/util/ThreadingTest.cpp new file mode 100644 index 00000000..bee7a613 --- /dev/null +++ b/tests/util/ThreadingTest.cpp @@ -0,0 +1,102 @@ +#include "../../src/utils/threading.h" + +#include + +#include +#include + +using namespace util; + +using namespace std::chrono_literals; + +TEST_CASE("Test Wait", "[util][threading]") { + SECTION("Wait until latch unlocks when countdown reaches zero") { + latch l(3); + std::thread worker([&]() { + l.count_down(); + l.count_down(); + l.count_down(); + }); + + l.wait(); + + worker.join(); + + REQUIRE(true); // if thread isn't blocked, will be reached + } +} + +TEST_CASE("Test Wait For", "[util][threading]") { + SECTION("Wait for latch unlocks within timeout") { + latch l(1); + std::thread worker([&](){ + std::this_thread::sleep_for(50ms); + l.count_down(); + }); + + REQUIRE(l.wait_for(100ms)); + + worker.join(); + } + + SECTION("Wait for latch times out when not unlocked") { + latch l(1); + + REQUIRE_FALSE(l.wait_for(50ms)); + } + +} + +TEST_CASE("Test Wait Until", "[util][threading]") { + SECTION("Wait until latch unlocks before timeout") { + latch l(1); + std::thread worker([&]() { + std::this_thread::sleep_for(50ms); + l.count_down(); + }); + + auto timeout = std::chrono::steady_clock::now() + 100ms; + REQUIRE(l.wait_until(timeout)); + + worker.join(); + } + + SECTION("Wait until latch times out") { + latch l(1); + auto timeout = std::chrono::steady_clock::now() + 50ms; + REQUIRE_FALSE(l.wait_until(timeout)); + } +} + +TEST_CASE("Test Count Down", "[util][threading]") { + SECTION("Latch unlocks after enough countdowns") { + latch l(3); + + REQUIRE_FALSE(l.wait_for(10ms)); + + l.count_down(); + l.count_down(); + REQUIRE_FALSE(l.wait_for(10ms)); + + l.count_down(); + REQUIRE(l.wait_for(10ms)); + } + + SECTION("Latch remains locked if not counted down enough") { + latch l(3); + + l.count_down(); + l.count_down(); + REQUIRE_FALSE(l.wait_for(10ms)); + } + + SECTION("Latch can count down by more than 1") { + latch l(3); + + l.count_down(2); + REQUIRE_FALSE(l.wait_for(10ms)); + + l.count_down(1); + REQUIRE(l.wait_for(10ms)); + } +} \ No newline at end of file From ca0169d0f4efa07f1bb0cc4706b9933edc7b77c7 Mon Sep 17 00:00:00 2001 From: ricemaking Date: Sat, 16 Nov 2024 13:19:16 -0800 Subject: [PATCH 6/6] fixed formatting :( --- tests/util/CoreTest.cpp | 9 +-- tests/util/ThreadingTest.cpp | 139 +++++++++++++++++------------------ 2 files changed, 72 insertions(+), 76 deletions(-) diff --git a/tests/util/CoreTest.cpp b/tests/util/CoreTest.cpp index 2517cb58..db9f4ed9 100644 --- a/tests/util/CoreTest.cpp +++ b/tests/util/CoreTest.cpp @@ -19,10 +19,7 @@ TEST_CASE("Test almostEqual", "[util][core]") { TEST_CASE("Test Key Set", "[util][core]") { SECTION("Extracting keys from a given map") { std::unordered_map inputtedMap = { - {"key1", 1}, - {"key2", 2}, - {"key3", 3} - }; + {"key1", 1}, {"key2", 2}, {"key3", 3}}; auto keys = keySet(inputtedMap); @@ -45,7 +42,7 @@ TEST_CASE("Test To String", "[util][core]") { } SECTION("Convert floats to strings") { - REQUIRE(to_string(3.14).substr(0,4) == "3.14"); + REQUIRE(to_string(3.14).substr(0, 4) == "3.14"); REQUIRE(to_string(1e-6) == "0.000001"); } @@ -71,7 +68,7 @@ TEST_CASE("Test Freeze String", "[util][core]") { TEST_CASE("Test Pair To Tuple", "[util][core]") { SECTION("Converting pair of integers to tuple") { - std::pair pair = {0,1}; + std::pair pair = {0, 1}; auto tuple = pairToTuple(pair); REQUIRE(std::get<0>(tuple) == 0); REQUIRE(std::get<1>(tuple) == 1); diff --git a/tests/util/ThreadingTest.cpp b/tests/util/ThreadingTest.cpp index bee7a613..274df4be 100644 --- a/tests/util/ThreadingTest.cpp +++ b/tests/util/ThreadingTest.cpp @@ -1,102 +1,101 @@ #include "../../src/utils/threading.h" -#include - #include #include +#include + using namespace util; using namespace std::chrono_literals; TEST_CASE("Test Wait", "[util][threading]") { - SECTION("Wait until latch unlocks when countdown reaches zero") { - latch l(3); - std::thread worker([&]() { - l.count_down(); - l.count_down(); - l.count_down(); - }); - - l.wait(); - - worker.join(); - - REQUIRE(true); // if thread isn't blocked, will be reached - } + SECTION("Wait until latch unlocks when countdown reaches zero") { + latch l(3); + std::thread worker([&]() { + l.count_down(); + l.count_down(); + l.count_down(); + }); + + l.wait(); + + worker.join(); + + REQUIRE(true); // if thread isn't blocked, will be reached + } } TEST_CASE("Test Wait For", "[util][threading]") { - SECTION("Wait for latch unlocks within timeout") { - latch l(1); - std::thread worker([&](){ - std::this_thread::sleep_for(50ms); - l.count_down(); - }); - - REQUIRE(l.wait_for(100ms)); + SECTION("Wait for latch unlocks within timeout") { + latch l(1); + std::thread worker([&]() { + std::this_thread::sleep_for(50ms); + l.count_down(); + }); - worker.join(); - } + REQUIRE(l.wait_for(100ms)); - SECTION("Wait for latch times out when not unlocked") { - latch l(1); + worker.join(); + } - REQUIRE_FALSE(l.wait_for(50ms)); - } + SECTION("Wait for latch times out when not unlocked") { + latch l(1); + REQUIRE_FALSE(l.wait_for(50ms)); + } } TEST_CASE("Test Wait Until", "[util][threading]") { - SECTION("Wait until latch unlocks before timeout") { - latch l(1); - std::thread worker([&]() { - std::this_thread::sleep_for(50ms); - l.count_down(); - }); - - auto timeout = std::chrono::steady_clock::now() + 100ms; - REQUIRE(l.wait_until(timeout)); - - worker.join(); - } - - SECTION("Wait until latch times out") { - latch l(1); - auto timeout = std::chrono::steady_clock::now() + 50ms; - REQUIRE_FALSE(l.wait_until(timeout)); - } + SECTION("Wait until latch unlocks before timeout") { + latch l(1); + std::thread worker([&]() { + std::this_thread::sleep_for(50ms); + l.count_down(); + }); + + auto timeout = std::chrono::steady_clock::now() + 100ms; + REQUIRE(l.wait_until(timeout)); + + worker.join(); + } + + SECTION("Wait until latch times out") { + latch l(1); + auto timeout = std::chrono::steady_clock::now() + 50ms; + REQUIRE_FALSE(l.wait_until(timeout)); + } } TEST_CASE("Test Count Down", "[util][threading]") { - SECTION("Latch unlocks after enough countdowns") { - latch l(3); + SECTION("Latch unlocks after enough countdowns") { + latch l(3); - REQUIRE_FALSE(l.wait_for(10ms)); + REQUIRE_FALSE(l.wait_for(10ms)); - l.count_down(); - l.count_down(); - REQUIRE_FALSE(l.wait_for(10ms)); + l.count_down(); + l.count_down(); + REQUIRE_FALSE(l.wait_for(10ms)); - l.count_down(); - REQUIRE(l.wait_for(10ms)); - } + l.count_down(); + REQUIRE(l.wait_for(10ms)); + } - SECTION("Latch remains locked if not counted down enough") { - latch l(3); + SECTION("Latch remains locked if not counted down enough") { + latch l(3); - l.count_down(); - l.count_down(); - REQUIRE_FALSE(l.wait_for(10ms)); - } + l.count_down(); + l.count_down(); + REQUIRE_FALSE(l.wait_for(10ms)); + } - SECTION("Latch can count down by more than 1") { - latch l(3); + SECTION("Latch can count down by more than 1") { + latch l(3); - l.count_down(2); - REQUIRE_FALSE(l.wait_for(10ms)); + l.count_down(2); + REQUIRE_FALSE(l.wait_for(10ms)); - l.count_down(1); - REQUIRE(l.wait_for(10ms)); - } + l.count_down(1); + REQUIRE(l.wait_for(10ms)); + } } \ No newline at end of file