Skip to content

Commit 5e1a8fc

Browse files
committed
Adding in a locale test to ensure we aren't dependent on the system locale settings when converting floats
See #8 for an example
1 parent 8b92f62 commit 5e1a8fc

5 files changed

Lines changed: 111 additions & 11 deletions

File tree

‎include/libdbc/utils/utils.hpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class String {
4242
cont.push_back(token);
4343
}
4444
}
45+
46+
static double convert_to_double(const std::string& value, double default_value = 0);
4547
};
4648

4749
}

‎src/dbc.cpp‎

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#include <fast_float/fast_float.h>
21
#include <libdbc/dbc.hpp>
32
#include <libdbc/exceptions/error.hpp>
43
#include <libdbc/utils/utils.hpp>
@@ -139,7 +138,6 @@ bool parseVal(const std::string& str, VALObject& obj) {
139138
return false;
140139
}
141140

142-
143141
DbcParser::DbcParser()
144142
: version("")
145143
, nodes()
@@ -257,15 +255,12 @@ void DbcParser::parse_dbc_messages(const std::vector<std::string>& lines) {
257255
uint32_t size = std::stoul(match.str(4));
258256
bool is_bigendian = (std::stoul(match.str(5)) == 0);
259257
bool is_signed = (match.str(6) == "-");
260-
// Alternate groups because a group is for the decimal portion
261-
double factor;
262-
fast_float::from_chars(match.str(7).data(), match.str(7).data() + match.str(7).size(), factor);
263-
double offset;
264-
fast_float::from_chars(match.str(9).data(), match.str(9).data() + match.str(9).size(), offset);
265-
double min;
266-
fast_float::from_chars(match.str(11).data(), match.str(11).data() + match.str(11).size(), min);
267-
double max;
268-
fast_float::from_chars(match.str(13).data(), match.str(13).data() + match.str(13).size(), max);
258+
259+
double factor = utils::String::convert_to_double(match.str(7).data());
260+
double offset = utils::String::convert_to_double(match.str(9).data());
261+
double min = utils::String::convert_to_double(match.str(11).data());
262+
double max = utils::String::convert_to_double(match.str(13).data());
263+
269264
std::string unit = match.str(15);
270265

271266
std::vector<std::string> receivers;

‎src/utils.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#include <charconv>
2+
#include <exception>
3+
#include <fast_float/fast_float.h>
14
#include <libdbc/utils/utils.hpp>
25

36
#include <regex>
@@ -69,4 +72,11 @@ std::string String::trim(const std::string& line) {
6972
return start == end ? std::string() : line.substr(start, end - start + 1);
7073
}
7174

75+
double String::convert_to_double(const std::string& value, double default_value) {
76+
double converted_value = default_value;
77+
fast_float::from_chars(value.data(), value.data() + value.size(), converted_value);
78+
// converted_value = std::stod(value);
79+
return converted_value;
80+
}
81+
7282
} // Namespace Utils

‎test/CMakeLists.txt‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,16 @@ target_link_libraries(dbcParserTests PRIVATE dbc Catch2::Catch2WithMain)
2222
target_include_directories(dbcParserTests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
2323

2424
catch_discover_tests(dbcParserTests)
25+
26+
# We want a seperate binary for this test. We setup global locals which mess with all of the testing.
27+
# Opting for a sperate test running so we don't conflict
28+
add_executable(dbcLocaleTests
29+
locale_testing/test_locale_main.cpp
30+
common.cpp
31+
)
32+
33+
target_compile_definitions(dbcLocaleTests PRIVATE TESTDBCFILES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs")
34+
target_link_libraries(dbcLocaleTests PRIVATE dbc Catch2::Catch2WithMain)
35+
target_include_directories(dbcLocaleTests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
36+
37+
catch_discover_tests(dbcLocaleTests)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include "common.hpp"
2+
#include "defines.hpp"
3+
#include <libdbc/dbc.hpp>
4+
#include <libdbc/utils/utils.hpp>
5+
6+
#include <catch2/catch_approx.hpp>
7+
#include <catch2/catch_test_macros.hpp>
8+
#include <catch2/reporters/catch_reporter_event_listener.hpp>
9+
#include <catch2/reporters/catch_reporter_registrars.hpp>
10+
11+
class testRunListener : public Catch::EventListenerBase {
12+
public:
13+
using Catch::EventListenerBase::EventListenerBase;
14+
15+
void testRunStarting(Catch::TestRunInfo const&) override {
16+
prev_loc = std::setlocale(LC_ALL, nullptr);
17+
// Set the locale to something that has , instead of . for floats
18+
std::locale::global(std::locale("de_DE.UTF-8"));
19+
}
20+
21+
void testCaseEnded(Catch::TestCaseStats const&) override {
22+
// Restore the old locale
23+
std::locale::global(std::locale(prev_loc));
24+
}
25+
26+
private:
27+
std::string prev_loc;
28+
};
29+
30+
CATCH_REGISTER_LISTENER(testRunListener)
31+
32+
TEST_CASE("Should parse doubld string locale independently") {
33+
REQUIRE(Catch::Approx(utils::String::convert_to_double("6.82")) == 6.82);
34+
}
35+
36+
TEST_CASE("Should process message with floats locale indpendently") {
37+
const auto* filename = std::tmpnam(NULL);
38+
39+
create_tmp_dbc_with(filename, R"(BO_ 234 MSG1: 8 Vector__XXX
40+
SG_ Sig1 : 55|16@0- (0.1,0) [-3276.8|-3276.7] "C" Vector__XXX
41+
SG_ Sig2 : 39|16@0- (0.1,0) [-3276.8|-3276.7] "C" Vector__XXX
42+
SG_ Sig3 : 23|16@0- (10,0) [-3276.8|-3276.7] "C" Vector__XXX
43+
SG_ Sig4 : 7|16@0- (1,-10) [0|32767] "" Vector__XXX)");
44+
45+
auto parser = libdbc::DbcParser();
46+
parser.parse_file(filename);
47+
48+
REQUIRE(parser.get_messages().size() == 1);
49+
REQUIRE(parser.get_messages().at(0).name() == "MSG1");
50+
REQUIRE(parser.get_messages().at(0).getSignals().size() == 4);
51+
52+
SECTION("Evaluating first message") {
53+
const auto signal = parser.get_messages().at(0).getSignals().at(0);
54+
REQUIRE(signal.factor == 0.1);
55+
REQUIRE(signal.offset == 0);
56+
REQUIRE(signal.min == -3276.8);
57+
REQUIRE(signal.max == -3276.7);
58+
}
59+
SECTION("Evaluating second message") {
60+
const auto signal = parser.get_messages().at(0).getSignals().at(1);
61+
REQUIRE(signal.factor == 0.1);
62+
REQUIRE(signal.offset == 0);
63+
REQUIRE(signal.min == -3276.8);
64+
REQUIRE(signal.max == -3276.7);
65+
}
66+
SECTION("Evaluating third message") {
67+
const auto signal = parser.get_messages().at(0).getSignals().at(2);
68+
REQUIRE(signal.factor == 10);
69+
REQUIRE(signal.offset == 0);
70+
REQUIRE(signal.min == -3276.8);
71+
REQUIRE(signal.max == -3276.7);
72+
}
73+
SECTION("Evaluating fourth message") {
74+
const auto signal = parser.get_messages().at(0).getSignals().at(3);
75+
REQUIRE(signal.factor == 1);
76+
REQUIRE(signal.offset == -10);
77+
REQUIRE(signal.min == 0);
78+
REQUIRE(signal.max == 32767);
79+
}
80+
}

0 commit comments

Comments
 (0)