Skip to content

Commit

Permalink
Implement comp_double comparison function in certain tests
Browse files Browse the repository at this point in the history
This is the final fix for the openSUSE GCC13 i386 floating point
issues. This implements a special comp_double comparison function
for certain doubles to deal with the small errors introduced in
string to floating point conversions on openSUSE GCC13 x86 32-bit.
  • Loading branch information
jamescowens committed Feb 22, 2024
1 parent a6c2118 commit 7bfd1b4
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 31 deletions.
34 changes: 27 additions & 7 deletions src/test/gridcoin/claim_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,26 @@ static CKey GetTestPrivateKey()

return key;
}

// Unfortunately, GCC 13 on openSUSE i386 is misbehaving and exhibiting weird errors in the last decimal places for things
// even as straightforward as
//
// double foo = 0.0;
// text >> foo.
//
// This comparison function works around that by allowing a small error band to pass the tests, but not enough to invalidate
// the tests on compilers that work.
bool comp_double(double lhs, double rhs)
{
// Require exact match if 0=0.
if (std::min(lhs, rhs) == 0.0) {
return (lhs == rhs);
} else {
double unsigned_rel_error = std::abs(lhs - rhs) / std::min(lhs, rhs);

return (unsigned_rel_error <= double {1e-8});
}
}
} // anonymous namespace

// -----------------------------------------------------------------------------
Expand All @@ -118,7 +138,7 @@ BOOST_AUTO_TEST_CASE(it_initializes_to_an_empty_claim)

BOOST_CHECK(claim.m_magnitude == 0);
BOOST_CHECK(claim.m_research_subsidy == 0);
BOOST_CHECK(claim.m_magnitude_unit == 0.0);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0));

BOOST_CHECK(claim.m_signature.empty() == true);

Expand All @@ -141,7 +161,7 @@ BOOST_AUTO_TEST_CASE(it_initializes_to_the_specified_version)

BOOST_CHECK(claim.m_magnitude == 0);
BOOST_CHECK(claim.m_research_subsidy == 0);
BOOST_CHECK(claim.m_magnitude_unit == 0.0);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0));

BOOST_CHECK(claim.m_signature.empty() == true);

Expand Down Expand Up @@ -220,7 +240,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_legacy_boincblock_string_for_researcher)

BOOST_CHECK(claim.m_magnitude == 123);
BOOST_CHECK(claim.m_research_subsidy == 47.25 * COIN);
BOOST_CHECK(claim.m_magnitude_unit == 0.123456);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.123456));

BOOST_CHECK(claim.m_signature == signature);

Expand Down Expand Up @@ -503,7 +523,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_investor)

BOOST_CHECK(claim.m_research_subsidy == 0);
BOOST_CHECK(claim.m_magnitude == 0.0);
BOOST_CHECK(claim.m_magnitude_unit == 0.0);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0));
BOOST_CHECK(claim.m_signature.empty() == true);
BOOST_CHECK(claim.m_quorum_address.empty() == true);
BOOST_CHECK(claim.m_superblock->WellFormed() == false);
Expand Down Expand Up @@ -545,7 +565,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_investor_with_superblock)

BOOST_CHECK(claim.m_research_subsidy == 0);
BOOST_CHECK(claim.m_magnitude == 0.0);
BOOST_CHECK(claim.m_magnitude_unit == 0.0);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0));
BOOST_CHECK(claim.m_signature.empty() == true);
}

Expand Down Expand Up @@ -630,7 +650,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_researcher)

BOOST_CHECK(claim.m_research_subsidy == expected.m_research_subsidy);
BOOST_CHECK(claim.m_magnitude == 0.0);
BOOST_CHECK(claim.m_magnitude_unit == 0.0);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0));
BOOST_CHECK(claim.m_signature == expected.m_signature);

BOOST_CHECK(claim.m_quorum_hash == expected.m_quorum_hash);
Expand Down Expand Up @@ -670,7 +690,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_researcher_with_superbloc

BOOST_CHECK(claim.m_research_subsidy == expected.m_research_subsidy);
BOOST_CHECK(claim.m_magnitude == 0.0);
BOOST_CHECK(claim.m_magnitude_unit == 0.0);
BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0));
BOOST_CHECK(claim.m_signature == expected.m_signature);

BOOST_CHECK(claim.m_quorum_hash == expected.m_quorum_hash);
Expand Down
68 changes: 44 additions & 24 deletions src/test/gridcoin/researcher_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ void AddProtocolEntry(const uint32_t& payload_version, const std::string& key, c

registry.Add({contract, dummy_tx, &dummy_index});
}

// Unfortunately, GCC 13 on openSUSE i386 is misbehaving and exhibiting weird errors in the last decimal places for things
// even as straightforward as
//
// double foo = 0.0;
// text >> foo.
//
// This comparison function works around that by allowing a small error band to pass the tests, but not enough to invalidate
// the tests on compilers that work.
bool comp_double(double lhs, double rhs)
{
// Require exact match if 0=0.
if (std::min(lhs, rhs) == 0.0) {
return (lhs == rhs);
} else {
double unsigned_rel_error = std::abs(lhs - rhs) / std::min(lhs, rhs);

return (unsigned_rel_error <= double {1e-8});
}
}
} // anonymous namespace

// -----------------------------------------------------------------------------
Expand All @@ -205,7 +225,7 @@ BOOST_AUTO_TEST_CASE(it_initializes_with_project_data)
BOOST_CHECK(project.m_cpid == expected);
BOOST_CHECK(project.m_team == "team name");
BOOST_CHECK(project.m_url == "url");
BOOST_CHECK(project.m_rac == 0.0);
BOOST_CHECK(comp_double(project.m_rac, 0.0));
BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE);
}

Expand Down Expand Up @@ -234,7 +254,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_project_xml_string)
BOOST_CHECK(project.m_cpid == cpid);
BOOST_CHECK(project.m_team == "team name");
BOOST_CHECK(project.m_url == "https://example.com/");
BOOST_CHECK(project.m_rac == 123.45);
BOOST_CHECK(comp_double(project.m_rac, 123.45));
BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE);

// Clean up:
Expand Down Expand Up @@ -269,7 +289,7 @@ BOOST_AUTO_TEST_CASE(it_falls_back_to_compute_a_missing_external_cpid)
BOOST_CHECK(project.m_cpid == cpid);
BOOST_CHECK(project.m_team == "team name");
BOOST_CHECK(project.m_url == "https://example.com/");
BOOST_CHECK(project.m_rac == 123.45);
BOOST_CHECK(comp_double(project.m_rac, 123.45));
BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE);

// Clean up:
Expand Down Expand Up @@ -488,7 +508,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections)
BOOST_CHECK(project1->m_cpid == cpid_1);
BOOST_CHECK(project1->m_team == "gridcoin");
BOOST_CHECK(project1->m_url == "https://example.com/1");
BOOST_CHECK(project1->m_rac == 123.45);
BOOST_CHECK(comp_double(project1->m_rac, 123.45));
BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project1->Eligible() == true);
} else {
Expand All @@ -500,7 +520,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections)
BOOST_CHECK(project2->m_cpid == cpid_2);
BOOST_CHECK(project2->m_team == "gridcoin");
BOOST_CHECK(project2->m_url == "https://example.com/2");
BOOST_CHECK(project2->m_rac == 567.89);
BOOST_CHECK(comp_double(project2->m_rac, 567.89));
BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project2->Eligible() == true);
} else {
Expand Down Expand Up @@ -855,7 +875,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton)
BOOST_CHECK(project1->m_cpid == cpid_1);
BOOST_CHECK(project1->m_team == "gridcoin");
BOOST_CHECK(project1->m_url == "https://example.com/1");
BOOST_CHECK(project1->m_rac == 1.1);
BOOST_CHECK(comp_double(project1->m_rac, 1.1));
BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project1->Eligible() == true);
} else {
Expand All @@ -867,7 +887,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton)
BOOST_CHECK(project2->m_cpid == cpid_2);
BOOST_CHECK(project2->m_team == "gridcoin");
BOOST_CHECK(project2->m_url == "https://example.com/2");
BOOST_CHECK(project2->m_rac == 2.2);
BOOST_CHECK(comp_double(project2->m_rac, 2.2));
BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project2->Eligible() == true);
} else {
Expand Down Expand Up @@ -909,7 +929,7 @@ BOOST_AUTO_TEST_CASE(it_looks_up_loaded_boinc_projects_by_name)
BOOST_CHECK(project->m_cpid == cpid);
BOOST_CHECK(project->m_team == "gridcoin");
BOOST_CHECK(project->m_url == "https://example.com/");
BOOST_CHECK(project->m_rac == 1.1);
BOOST_CHECK(comp_double(project->m_rac, 1.1));
BOOST_CHECK(project->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project->Eligible() == true);
} else {
Expand Down Expand Up @@ -1048,7 +1068,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project1->m_name == "project name 1");
BOOST_CHECK(project1->m_cpid == cpid);
BOOST_CHECK(project1->m_team == "not gridcoin");
BOOST_CHECK(project1->m_rac == 1.1);
BOOST_CHECK(comp_double(project1->m_rac, 1.1));
BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::INVALID_TEAM);
BOOST_CHECK(project1->Eligible() == false);
} else {
Expand All @@ -1059,7 +1079,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project2->m_name == "project name 2");
BOOST_CHECK(project2->m_cpid == cpid);
BOOST_CHECK(project2->m_team.empty() == true);
BOOST_CHECK(project2->m_rac == 2.2);
BOOST_CHECK(comp_double(project2->m_rac, 2.2));
BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::INVALID_TEAM);
BOOST_CHECK(project2->Eligible() == false);
} else {
Expand All @@ -1070,7 +1090,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project3->m_name == "project name 3");
BOOST_CHECK(project3->m_cpid == GRC::Cpid());
BOOST_CHECK(project3->m_team == "gridcoin");
BOOST_CHECK(project3->m_rac == 3.3);
BOOST_CHECK(comp_double(project3->m_rac, 3.3));
BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::MALFORMED_CPID);
BOOST_CHECK(project3->Eligible() == false);
} else {
Expand All @@ -1081,7 +1101,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project4->m_name == "project name 4");
BOOST_CHECK(project4->m_cpid == GRC::Cpid());
BOOST_CHECK(project4->m_team == "gridcoin");
BOOST_CHECK(project4->m_rac == 4.4);
BOOST_CHECK(comp_double(project4->m_rac, 4.4));
BOOST_CHECK(project4->m_error == GRC::MiningProject::Error::MALFORMED_CPID);
BOOST_CHECK(project4->Eligible() == false);
} else {
Expand All @@ -1092,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project5->m_name == "project name 5");
BOOST_CHECK(project5->m_cpid == cpid);
BOOST_CHECK(project5->m_team == "gridcoin");
BOOST_CHECK(project5->m_rac == 5.5);
BOOST_CHECK(comp_double(project5->m_rac, 5.5));
BOOST_CHECK(project5->m_error == GRC::MiningProject::Error::MISMATCHED_CPID);
BOOST_CHECK(project5->Eligible() == false);
} else {
Expand All @@ -1103,7 +1123,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project6->m_name == "project name 6");
BOOST_CHECK(project6->m_cpid == cpid);
BOOST_CHECK(project6->m_team == "gridcoin");
BOOST_CHECK(project6->m_rac == 6.6);
BOOST_CHECK(comp_double(project6->m_rac, 6.6));
BOOST_CHECK(project6->m_error == GRC::MiningProject::Error::MISMATCHED_CPID);
BOOST_CHECK(project6->Eligible() == false);
} else {
Expand All @@ -1112,7 +1132,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)

if (const GRC::ProjectOption project7 = projects.Try("project name 7")) {
BOOST_CHECK(project7->m_name == "project name 7");
BOOST_CHECK(project7->m_rac == 7.7);
BOOST_CHECK(comp_double(project7->m_rac, 7.7));
BOOST_CHECK(project7->m_error == GRC::MiningProject::Error::POOL);
BOOST_CHECK(project7->Eligible() == false);
} else {
Expand All @@ -1122,7 +1142,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
if (const GRC::ProjectOption project8 = projects.Try("project name 8")) {
BOOST_CHECK(project8->m_name == "project name 8");
BOOST_CHECK(project8->m_cpid.IsZero() == true);
BOOST_CHECK(project8->m_rac == 8.8);
BOOST_CHECK(comp_double(project8->m_rac, 8.8));
BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::POOL);
BOOST_CHECK(project8->Eligible() == false);
} else {
Expand All @@ -1133,7 +1153,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml)
BOOST_CHECK(project9->m_name == "project name 9");
BOOST_CHECK(project9->m_cpid == cpid);
BOOST_CHECK(project9->m_team == "not gridcoin");
BOOST_CHECK(project9->m_rac == 0.0);
BOOST_CHECK(comp_double(project9->m_rac, 0.0));
BOOST_CHECK(project9->m_error == GRC::MiningProject::Error::INVALID_TEAM);
BOOST_CHECK(project9->Eligible() == false);
} else {
Expand Down Expand Up @@ -1212,7 +1232,7 @@ BOOST_AUTO_TEST_CASE(it_skips_the_team_requirement_when_set_by_protocol)
BOOST_CHECK(project1->m_name == "project name 1");
BOOST_CHECK(project1->m_cpid == cpid);
BOOST_CHECK(project1->m_team == "! not gridcoin !");
BOOST_CHECK(project1->m_rac == 1.1);
BOOST_CHECK(comp_double(project1->m_rac, 1.1));
BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project1->Eligible() == true);
} else {
Expand Down Expand Up @@ -1282,7 +1302,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol)
BOOST_CHECK(project1->m_name == "project name 1");
BOOST_CHECK(project1->m_cpid == cpid);
BOOST_CHECK(project1->m_team == "! not gridcoin !");
BOOST_CHECK(project1->m_rac == 1.1);
BOOST_CHECK(comp_double(project1->m_rac, 1.1));
BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::INVALID_TEAM);
BOOST_CHECK(project1->Eligible() == false);
} else {
Expand All @@ -1293,7 +1313,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol)
BOOST_CHECK(project2->m_name == "project name 2");
BOOST_CHECK(project2->m_cpid == cpid);
BOOST_CHECK(project2->m_team == "team 1");
BOOST_CHECK(project2->m_rac == 0);
BOOST_CHECK(comp_double(project2->m_rac, 0));
BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project2->Eligible() == true);
} else {
Expand All @@ -1304,7 +1324,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol)
BOOST_CHECK(project3->m_name == "project name 3");
BOOST_CHECK(project3->m_cpid == cpid);
BOOST_CHECK(project3->m_team == "team 2");
BOOST_CHECK(project3->m_rac == 0);
BOOST_CHECK(comp_double(project3->m_rac, 0));
BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project3->Eligible() == true);
} else {
Expand Down Expand Up @@ -1629,7 +1649,7 @@ void it_parses_project_xml_from_a_client_state_xml_file()
BOOST_CHECK(project1->m_name == "valid project 1");
BOOST_CHECK(project1->m_cpid == cpid_1);
BOOST_CHECK(project1->m_team == "gridcoin");
BOOST_CHECK(project1->m_rac == 1.1);
BOOST_CHECK(comp_double(project1->m_rac, 1.1));
BOOST_CHECK(project1->m_url == "https://project1.example.com/boinc/");
BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project1->Eligible() == true);
Expand All @@ -1641,7 +1661,7 @@ void it_parses_project_xml_from_a_client_state_xml_file()
BOOST_CHECK(project2->m_name == "valid project 2");
BOOST_CHECK(project2->m_cpid == cpid_2);
BOOST_CHECK(project2->m_team == "gridcoin");
BOOST_CHECK(project2->m_rac == 2.2);
BOOST_CHECK(comp_double(project2->m_rac, 2.2));
BOOST_CHECK(project2->m_url == "https://project2.example.com/boinc/");
BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE);
BOOST_CHECK(project2->Eligible() == true);
Expand All @@ -1654,7 +1674,7 @@ void it_parses_project_xml_from_a_client_state_xml_file()
BOOST_CHECK(project3->m_name == "invalid project 3");
BOOST_CHECK(project3->m_cpid == cpid_2);
BOOST_CHECK(project3->m_team == "gridcoin");
BOOST_CHECK(project3->m_rac == 3.3);
BOOST_CHECK(comp_double(project3->m_rac, 3.3));
BOOST_CHECK(project3->m_url == "https://project3.example.com/boinc/");
BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::MISMATCHED_CPID);
BOOST_CHECK(project3->Eligible() == false);
Expand Down

0 comments on commit 7bfd1b4

Please sign in to comment.