Skip to content

Commit 97f6e9d

Browse files
authored
Use floor() for conversion, update tests (#725)
1 parent 6bd7a72 commit 97f6e9d

File tree

2 files changed

+72
-22
lines changed

2 files changed

+72
-22
lines changed

c/openlocationcode_test.cc

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Include the C library into this C++ test file.
22
extern "C" {
3-
#include "src/olc.h"
3+
#include "src/olc.h"
44
}
55

6+
#include <stdio.h>
7+
#include <stdlib.h>
68
#include <chrono>
7-
#include <cstring>
89
#include <cmath>
10+
#include <cstring>
911
#include <fstream>
10-
#include <stdio.h>
11-
#include <stdlib.h>
1212
#include <string>
1313

1414
#include "gtest/gtest.h"
@@ -72,14 +72,12 @@ std::vector<DecodingTestData> GetDecodingDataFromCsv() {
7272

7373
TEST_P(DecodingChecks, Decode) {
7474
DecodingTestData test_data = GetParam();
75-
OLC_CodeArea expected_area =
76-
OLC_CodeArea{
77-
OLC_LatLon{test_data.lo_lat_deg, test_data.lo_lng_deg},
78-
OLC_LatLon{test_data.hi_lat_deg, test_data.hi_lng_deg},
79-
test_data.length};
80-
OLC_LatLon expected_center = OLC_LatLon{
81-
(test_data.lo_lat_deg + test_data.hi_lat_deg)/2,
82-
(test_data.lo_lng_deg + test_data.hi_lng_deg)/2};
75+
OLC_CodeArea expected_area = OLC_CodeArea{
76+
OLC_LatLon{test_data.lo_lat_deg, test_data.lo_lng_deg},
77+
OLC_LatLon{test_data.hi_lat_deg, test_data.hi_lng_deg}, test_data.length};
78+
OLC_LatLon expected_center =
79+
OLC_LatLon{(test_data.lo_lat_deg + test_data.hi_lat_deg) / 2,
80+
(test_data.lo_lng_deg + test_data.hi_lng_deg) / 2};
8381
OLC_CodeArea got_area;
8482
OLC_LatLon got_center;
8583
OLC_Decode(test_data.code.c_str(), 0, &got_area);
@@ -99,12 +97,12 @@ INSTANTIATE_TEST_SUITE_P(OLC_Tests, DecodingChecks,
9997
struct EncodingTestData {
10098
double lat_deg;
10199
double lng_deg;
100+
long long int lat_int;
101+
long long int lng_int;
102102
size_t length;
103103
std::string code;
104104
};
105105

106-
class EncodingChecks : public ::testing::TestWithParam<EncodingTestData> {};
107-
108106
const std::string kEncodingTestsFile = "test_data/encoding.csv";
109107

110108
std::vector<EncodingTestData> GetEncodingDataFromCsv() {
@@ -115,22 +113,72 @@ std::vector<EncodingTestData> GetEncodingDataFromCsv() {
115113
EncodingTestData test_data = {};
116114
test_data.lat_deg = strtod(csv_records[i][0].c_str(), nullptr);
117115
test_data.lng_deg = strtod(csv_records[i][1].c_str(), nullptr);
118-
test_data.length = atoi(csv_records[i][2].c_str());
119-
test_data.code = csv_records[i][3];
116+
test_data.lat_int = strtoll(csv_records[i][2].c_str(), nullptr, 10);
117+
test_data.lng_int = strtoll(csv_records[i][3].c_str(), nullptr, 10);
118+
test_data.length = atoi(csv_records[i][4].c_str());
119+
test_data.code = csv_records[i][5];
120120
data_results.push_back(test_data);
121121
}
122122
return data_results;
123123
}
124124

125-
TEST_P(EncodingChecks, Encode) {
125+
// TolerantTestParams runs a test with the
126+
struct TolerantTestParams {
127+
double allowed_failure_rate;
128+
std::vector<EncodingTestData> test_data;
129+
};
130+
131+
class TolerantEncodingChecks
132+
: public ::testing::TestWithParam<TolerantTestParams> {};
133+
134+
TEST_P(TolerantEncodingChecks, EncodeDegrees) {
135+
const TolerantTestParams& test_params = GetParam();
136+
int failure_count = 0;
137+
138+
for (EncodingTestData tc : test_params.test_data) {
139+
OLC_LatLon loc = OLC_LatLon{tc.lat_deg, tc.lng_deg};
140+
char got_code[18];
141+
// Encode the test location and make sure we get the expected code.
142+
OLC_Encode(&loc, tc.length, got_code, 18);
143+
if (tc.code.compare(got_code) != 0) {
144+
failure_count ++;
145+
printf(" ENCODING FAILURE: Got: '%s', expected: '%s'\n", got_code, tc.code.c_str());
146+
}
147+
}
148+
double actual_failure_rate = double(failure_count) / test_params.test_data.size();
149+
EXPECT_LE(actual_failure_rate, test_params.allowed_failure_rate)
150+
<< "Failure rate " << actual_failure_rate << " exceeds allowed rate " << test_params.allowed_failure_rate;
151+
}
152+
153+
// Allow a 5% error rate encoding from degree coordinates (because of floating point precision).
154+
INSTANTIATE_TEST_SUITE_P(OLC_Tests, TolerantEncodingChecks,
155+
::testing::Values(TolerantTestParams{0.05, GetEncodingDataFromCsv()}));
156+
157+
class EncodingChecks : public ::testing::TestWithParam<EncodingTestData> {};
158+
159+
TEST_P(EncodingChecks, OLC_EncodeIntegers) {
126160
EncodingTestData test_data = GetParam();
127-
OLC_LatLon loc = OLC_LatLon{test_data.lat_deg, test_data.lng_deg};
161+
OLC_LatLonIntegers loc =
162+
OLC_LatLonIntegers{test_data.lat_int, test_data.lng_int};
128163
char got_code[18];
129164
// Encode the test location and make sure we get the expected code.
130-
OLC_Encode(&loc, test_data.length, got_code, 18);
165+
OLC_EncodeIntegers(&loc, test_data.length, got_code, 18);
131166
EXPECT_EQ(test_data.code, got_code);
132167
}
133168

169+
TEST_P(EncodingChecks, OLC_LocationToIntegers) {
170+
EncodingTestData test_data = GetParam();
171+
OLC_LatLon loc = OLC_LatLon{test_data.lat_deg, test_data.lng_deg};
172+
OLC_LatLonIntegers got;
173+
OLC_LocationToIntegers(&loc, &got);
174+
// Due to floating point precision limitations, we may get values 1 less than
175+
// expected.
176+
EXPECT_LE(got.lat, test_data.lat_int);
177+
EXPECT_GE(got.lat + 1, test_data.lat_int);
178+
EXPECT_LE(got.lon, test_data.lng_int);
179+
EXPECT_GE(got.lon + 1, test_data.lng_int);
180+
}
181+
134182
INSTANTIATE_TEST_SUITE_P(OLC_Tests, EncodingChecks,
135183
::testing::ValuesIn(GetEncodingDataFromCsv()));
136184

@@ -211,7 +259,8 @@ TEST_P(ShortCodeChecks, ShortCode) {
211259
// Now extend the code using the reference location and check.
212260
if (test_data.test_type == "B" || test_data.test_type == "R") {
213261
char got[18];
214-
OLC_RecoverNearest(test_data.short_code.c_str(), 0, &reference_loc, got, 18);
262+
OLC_RecoverNearest(test_data.short_code.c_str(), 0, &reference_loc, got,
263+
18);
215264
EXPECT_EQ(test_data.full_code, got);
216265
}
217266
}

c/src/olc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ void OLC_LocationToIntegers(const OLC_LatLon* degrees,
8787
// Multiply degrees by precision. Use lround to explicitly round rather than
8888
// truncate, which causes issues when using values like 0.1 that do not have
8989
// precise floating point representations.
90-
long long int lat = lround(degrees->lat * kGridLatPrecisionInverse);
91-
long long int lon = lround(degrees->lon * kGridLonPrecisionInverse);
90+
long long int lat = floorl(degrees->lat * kGridLatPrecisionInverse);
91+
long long int lon = floorl(degrees->lon * kGridLonPrecisionInverse);
92+
9293
// Convert latitude to positive range (0..2*degrees*precision) and clip.
9394
lat += OLC_kLatMaxDegrees * kGridLatPrecisionInverse;
9495
if (lat < 0) {

0 commit comments

Comments
 (0)