From ec4d5fc3dac8b73070259bb5a05bdd7d21ab17c9 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Fri, 30 Jul 2021 13:22:23 -0400 Subject: [PATCH] Add unit tests for most of util.cpp --- luprex/core/cpp/animqueue.cpp | 4 +- luprex/core/cpp/planemap.cpp | 33 ---------- luprex/core/cpp/planemap.hpp | 3 - luprex/core/cpp/source.cpp | 8 +-- luprex/core/cpp/util.cpp | 110 ++++++++++++++++++++++++++++++---- luprex/core/cpp/util.hpp | 21 +++---- luprex/core/cpp/world.cpp | 2 +- 7 files changed, 118 insertions(+), 63 deletions(-) diff --git a/luprex/core/cpp/animqueue.cpp b/luprex/core/cpp/animqueue.cpp index f6d8979e..fad0e178 100644 --- a/luprex/core/cpp/animqueue.cpp +++ b/luprex/core/cpp/animqueue.cpp @@ -282,11 +282,11 @@ std::string AnimStep::debug_string() const { bool AnimStep::from_string(const std::string &config) { clear(); - util::stringvec parts = util::split(config, ' '); + util::StringVec parts = util::split(config, ' '); for (int i = 0; i < int(parts.size()); i++) { const std::string &part = parts[i]; if (part == "") continue; - util::stringvec lr = util::split(part, '='); + util::StringVec lr = util::split(part, '='); if (lr.size() != 2) return false; const std::string &key = lr[0]; const std::string &val = lr[1]; diff --git a/luprex/core/cpp/planemap.cpp b/luprex/core/cpp/planemap.cpp index e313cc3b..ea56a7c4 100644 --- a/luprex/core/cpp/planemap.cpp +++ b/luprex/core/cpp/planemap.cpp @@ -188,24 +188,6 @@ PlaneMap::IdVector PlaneMap::scan_radius(const std::string &plane, double x, dou return result; } -util::IdVector PlaneMap::sort_union_id_vectors(const IdVector &v1, const IdVector &v2) { - IdVector result(v1.size() + v2.size()); - int next = 0; - for (int64_t id : v1) result[next++] = id; - for (int64_t id : v2) result[next++] = id; - std::sort(result.begin(), result.end()); - int64_t prev = -1; - int64_t count = 0; - for (int64_t id : result) { - if (id != prev) { - prev = id; - result[count++] = id; - } - } - result.resize(count); - return result; -} - LuaDefine(unittests_planemap, "c") { double SC = CELL_SCALE; double E = CELL_SCALE * 0.4; @@ -316,20 +298,5 @@ LuaDefine(unittests_planemap, "c") { LuaAssert(L, ids[0] == 123); LuaAssert(L, ids[1] == 456); - // Test the unioning of ID vectors. - PlaneMap::IdVector idv1,idv2; - idv1.push_back(1); - idv1.push_back(6); - idv1.push_back(4); - idv2.push_back(1); - idv2.push_back(5); - idv2.push_back(6); - PlaneMap::IdVector joined = PlaneMap::sort_union_id_vectors(idv1, idv2); - LuaAssert(L, joined.size() == 4); - LuaAssert(L, joined[0] == 1); - LuaAssert(L, joined[1] == 4); - LuaAssert(L, joined[2] == 5); - LuaAssert(L, joined[3] == 6); - return 0; } diff --git a/luprex/core/cpp/planemap.hpp b/luprex/core/cpp/planemap.hpp index 11bc3cef..84a48bb9 100644 --- a/luprex/core/cpp/planemap.hpp +++ b/luprex/core/cpp/planemap.hpp @@ -126,9 +126,6 @@ public: // Caution: scan_radius is not deterministically ordered. IdVector scan_radius(const std::string &plane, double x, double y, double radius, int64_t prepend) const; - // Unions and sorts two ID vectors. - static IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2); - private: // unit testing stuff. friend int unittests_planemap(lua_State *L); diff --git a/luprex/core/cpp/source.cpp b/luprex/core/cpp/source.cpp index 29a967a8..85978254 100644 --- a/luprex/core/cpp/source.cpp +++ b/luprex/core/cpp/source.cpp @@ -20,9 +20,9 @@ // - remove blank lines // - remove comment lines // -util::stringvec read_control_lst(const std::string &path) { - util::stringvec lines = util::get_file_lines(path); - util::stringvec result; +util::StringVec read_control_lst(const std::string &path) { + util::StringVec lines = util::get_file_lines(path); + util::StringVec result; for (int i = 0; i < int(lines.size()); i++) { std::string trimmed = util::trim(lines[i]); if ((trimmed.size() > 0) && (trimmed[0] != '#')) { @@ -173,7 +173,7 @@ void SourceDB::update() { } // Read the list of filenames. - util::stringvec filenames = read_control_lst("lua/control.lst"); + util::StringVec filenames = read_control_lst("lua/control.lst"); if (filenames.empty()) { luaL_error(L, "cannot read source database control.lst"); } diff --git a/luprex/core/cpp/util.cpp b/luprex/core/cpp/util.cpp index e9a3dd5c..1e00df04 100644 --- a/luprex/core/cpp/util.cpp +++ b/luprex/core/cpp/util.cpp @@ -16,8 +16,26 @@ namespace util { -stringvec split(const std::string &s, char sep) { - stringvec result; +IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2) { + IdVector result(v1.size() + v2.size()); + int next = 0; + for (int64_t id : v1) result[next++] = id; + for (int64_t id : v2) result[next++] = id; + std::sort(result.begin(), result.end()); + int64_t prev = -1; + int64_t count = 0; + for (int64_t id : result) { + if (id != prev) { + prev = id; + result[count++] = id; + } + } + result.resize(count); + return result; +} + +StringVec split(const std::string &s, char sep) { + StringVec result; int start = 0; for (int i = 0; i < int(s.size()); i++) { if (s[i] == sep) { @@ -47,12 +65,14 @@ std::string toupper(std::string input) { bool validinteger(const std::string &value) { char *endptr; + if (value.size() == 0) return false; strtoll(value.c_str(), &endptr, 10); return (endptr == value.c_str() + value.size()); } int64_t strtoint(const std::string &value, int64_t errval) { char *endptr; + if (value.size() == 0) return errval; int64_t result = strtoll(value.c_str(), &endptr, 10); if (endptr == value.c_str() + value.size()) { return result; @@ -63,6 +83,7 @@ int64_t strtoint(const std::string &value, int64_t errval) { double strtodouble(const std::string &value) { char *endptr; + if (value.size() == 0) return std::nan(""); double result = strtod(value.c_str(), &endptr); if (endptr == value.c_str() + value.size()) { return result; @@ -87,6 +108,11 @@ std::string trim(std::string s) { return ltrim(rtrim(s)); } +double distance_squared(double x1, double y1, double x2, double y2) { + double dx = x1 - x2; + double dy = y1 - y2; + return dx*dx + dy*dy; +} std::string get_file_contents(const std::string &fn) { std::ifstream fs(fn); @@ -95,8 +121,8 @@ std::string get_file_contents(const std::string &fn) { return buffer.str(); } -stringvec get_file_lines(const std::string &path) { - stringvec result; +StringVec get_file_lines(const std::string &path) { + StringVec result; std::ifstream f; f.open(path); if (f) { @@ -120,12 +146,6 @@ std::string get_file_fingerprint(const std::string &fn) { return ""; } -double distance_squared(double x1, double y1, double x2, double y2) { - double dx = x1 - x2; - double dy = y1 - y2; - return dx*dx + dy*dy; -} - std::string XYZ::debug_string() const { std::ostringstream oss; oss << "(" << x << "," << y << "," << z << ")"; @@ -153,3 +173,73 @@ std::ostream &operator<<(std::ostream &oss, const util::hex8 &v) { oss << "0x" << std::setw(2) << std::setfill('0') << std::hex; return oss; } + +LuaDefine(unittests_util, "c") { + // Test the unioning of ID vectors. + util::IdVector idv1,idv2; + idv1.push_back(1); + idv1.push_back(6); + idv1.push_back(4); + idv2.push_back(5); + idv2.push_back(1); + idv2.push_back(6); + util::IdVector joined = util::sort_union_id_vectors(idv1, idv2); + LuaAssert(L, joined.size() == 4); + LuaAssert(L, joined[0] == 1); + LuaAssert(L, joined[1] == 4); + LuaAssert(L, joined[2] == 5); + LuaAssert(L, joined[3] == 6); + + // Test the string split routine. + util::StringVec sv1 = util::split("foo,bar,baz", ','); + LuaAssert(L, sv1.size() == 3); + LuaAssert(L, sv1[0] == "foo"); + LuaAssert(L, sv1[1] == "bar"); + LuaAssert(L, sv1[2] == "baz"); + util::StringVec sv2 = util::split(",foo,,bar", ','); + LuaAssert(L, sv2.size() == 4); + LuaAssert(L, sv2[0]==""); + LuaAssert(L, sv2[1]=="foo"); + LuaAssert(L, sv2[2]==""); + LuaAssert(L, sv2[3]=="bar"); + + // test toupper and tolower + LuaAssert(L, util::toupper("fooBar") == "FOOBAR"); + LuaAssert(L, util::tolower("fooBar") == "foobar"); + + // test validinteger, strtoint, strtodouble + LuaAssert(L, util::validinteger("123") == true); + LuaAssert(L, util::validinteger("123.4") == false); + LuaAssert(L, util::validinteger("12ab") == false); + LuaAssert(L, util::validinteger("") == false); + LuaAssert(L, util::strtoint("123", -5) == 123); + LuaAssert(L, util::strtoint("123.4", -5) == -5); + LuaAssert(L, util::strtoint("12ab", -5) == -5); + LuaAssert(L, util::strtoint("", -5) == -5); + LuaAssert(L, util::strtodouble("123.5") == 123.5); + LuaAssert(L, std::isnan(util::strtodouble("12ab"))); + LuaAssert(L, std::isnan(util::strtodouble(""))); + + // Test trim, ltrim, rtrim + LuaAssert(L, util::ltrim(" foo ") == "foo "); + LuaAssert(L, util::rtrim(" foo ") == " foo"); + LuaAssert(L, util::trim(" foo ") == "foo"); + LuaAssert(L, util::trim("foo") == "foo"); + LuaAssert(L, util::trim("") == ""); + + // Test distance_squared + LuaAssert(L, util::distance_squared(1, 1, 5, 4) == 25.0); + LuaAssert(L, util::distance_squared(5, 4, 1, 1) == 25.0); + + // Test XYZ. + util::XYZ xyza(3,4,5), xyzb(3,4,5), xyzc(3,4,6); + LuaAssert(L, xyza.x == 3); + LuaAssert(L, xyza.y == 4); + LuaAssert(L, xyza.z == 5); + LuaAssert(L, xyza == xyzb); + LuaAssert(L, xyza != xyzc); + LuaAssert(L, xyza.debug_string() == "(3,4,5)"); + + return 0; +} + diff --git a/luprex/core/cpp/util.hpp b/luprex/core/cpp/util.hpp index 74003825..53696e74 100644 --- a/luprex/core/cpp/util.hpp +++ b/luprex/core/cpp/util.hpp @@ -19,15 +19,17 @@ enum WorldType { WORLD_TYPE_MASTER, }; -using stringvec = std::vector; -using stringset = std::set; +using StringVec = std::vector; using HashValue = std::pair; using IdVector = std::vector; -// Split a string into multiple strings -stringvec split(const std::string &s, char sep); +// Unions and sorts two ID vectors. +IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2); -// String to lowercase/uppercase +// Split a string into multiple strings +StringVec split(const std::string &s, char sep); + +// String to lowercase/uppercase. Ascii only, no unicode. std::string tolower(std::string input); std::string toupper(std::string input); @@ -45,19 +47,18 @@ std::string ltrim(std::string s); std::string rtrim(std::string s); std::string trim(std::string s); +// Calculate distance between two points +double distance_squared(double x1, double y1, double x2, double y2); + // Read a file as one big string. std::string get_file_contents(const std::string &path); // Read a file as a vector of lines. -stringvec get_file_lines(const std::string &path); +StringVec get_file_lines(const std::string &path); // Get a file's fingerprint - ie, size and modification time. std::string get_file_fingerprint(const std::string &path); -// Calculate distance between two points -double distance_squared(double x1, double y1, double x2, double y2); - - // An XYZ coordinate, general purpose. struct XYZ { float x, y, z; diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index 51e81cbb..d2a90322 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -520,7 +520,7 @@ void World::difference_transmit(int64_t actor_id, const World *master, StreamBuf // Get the list of tangibles visible in either model. // Some tangibles may be missing in the master, some may be missing in the sync. - util::IdVector visible = PlaneMap::sort_union_id_vectors( + util::IdVector visible = util::sort_union_id_vectors( master->get_near(actor_id, 100.0, true), this->get_near(actor_id, 100.0, true)); TanVector m_visible = tangible_get_all(visible);