Added line numbers and function names to unit test failures

Turned off the deprecated compare warning with explanation
Made a small start on getting names in correct order in the display_wallet
Unit test and create new wallet is still broken if wallet file does
not already exist
This commit is contained in:
Cheng 2023-09-16 18:49:43 +10:00
parent 23e95c16ba
commit 3dbd15d27e
No known key found for this signature in database
GPG Key ID: 571C3A9C3B9E6FCA
7 changed files with 100 additions and 23 deletions

View File

@ -38,3 +38,12 @@ void queue_fatal_error(const char* psz) {
queue_error_message(psz); queue_error_message(psz);
singletonFrame->Close(); singletonFrame->Close();
} }
MyException::MyException(const char* sz, int i, const char* func__, const char* FILE__) noexcept :
// usage
// throw MyException("Expected wallet file not found", __LINE__, __func__, __FILE__);
err_number(i) {
char buff[20];
snprintf(buff, 20, "%d", i);
err = std::string(sz) + "\nline " + buff + ", function " + func__ + ", file " + FILE__;
}

View File

@ -22,6 +22,8 @@ public:
explicit MyException(const std::string &m) noexcept :err(m.c_str()),err_number(-1){} explicit MyException(const std::string &m) noexcept :err(m.c_str()),err_number(-1){}
explicit MyException(const char* sz) noexcept :err(sz),err_number(-1) {} explicit MyException(const char* sz) noexcept :err(sz),err_number(-1) {}
explicit MyException(const char* sz, int i) noexcept :err(sz), err_number(i) {} explicit MyException(const char* sz, int i) noexcept :err(sz), err_number(i) {}
explicit MyException(const char* sz, int i, const char*, const char*) noexcept;
// usage throw MyException("error", __LINE__, __func__, __FILE__);
explicit MyException(int, sqlite3*) noexcept; explicit MyException(int, sqlite3*) noexcept;
virtual const char* what() const override { virtual const char* what() const override {
return err.c_str(); return err.c_str();

View File

@ -24,6 +24,9 @@ display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
SetSizer(sizer); SetSizer(sizer);
ro::sql read_keys(m_db, R"|(SELECT * FROM "Keys";)|"); ro::sql read_keys(m_db, R"|(SELECT * FROM "Keys";)|");
sql_read_name read_name(m_db); //*It would be better to have a select statement goes through the name table, in name order. This is unit test code wrongly repurposed. sql_read_name read_name(m_db); //*It would be better to have a select statement goes through the name table, in name order. This is unit test code wrongly repurposed.
/* ro::sql sql_read_names(
m_db,
R"|(SELECT Names.name, Keys.pubkey FROM Names INNER JOIN Keys ON Names.ROWID=Keys.id AND Keys.use=1 ORDER BY Names.name;)|"){} */
// m_db.reset(nullptr);// Force error of premature destruction of Isqlite3 // m_db.reset(nullptr);// Force error of premature destruction of Isqlite3
while (read_keys.step() == Icompiled_sql::ROW) { while (read_keys.step() == Icompiled_sql::ROW) {
auto pubkey = read_keys.column<ristretto255::point>(1); auto pubkey = read_keys.column<ristretto255::point>(1);
@ -106,4 +109,4 @@ void display_wallet::OnClose(wxCloseEvent& event) {
// replacing the default handler.' // replacing the default handler.'
if (singletonFrame->m_panel ==this)singletonFrame->m_panel = nullptr; if (singletonFrame->m_panel ==this)singletonFrame->m_panel = nullptr;
} }

View File

@ -256,6 +256,7 @@ CREATE TABLE "Keys"(
"use" INTEGER NOT NULL); "use" INTEGER NOT NULL);
CREATE UNIQUE INDEX i_pubkey ON Keys (pubkey); CREATE UNIQUE INDEX i_pubkey ON Keys (pubkey);
CREATE UNIQUE INDEX i_id ON Keys (use, id);
CREATE TABLE "Names"( CREATE TABLE "Names"(
"ROWID" INTEGER PRIMARY KEY, "ROWID" INTEGER PRIMARY KEY,

View File

@ -169,3 +169,8 @@ std::enable_if_t<!ro::has_spaceship_v<T, U>, decltype(std::span(declval<T>())[0]
} }
return retval; return retval;
} }
#pragma warning(disable : 5056)
// This header file turns off deprecation of array type compares, because
// it provides an array spaceship operator that solves the inconsistency
// problem in a better way. Spaceship compares of arrays in my code are
// no longer ill formed.

View File

@ -62,7 +62,6 @@ constexpr bool b_WINDOWS = false;
static_assert(wxUSE_UNSAFE_WXSTRING_CONV == 1, static_assert(wxUSE_UNSAFE_WXSTRING_CONV == 1,
R"(In fully utf environment, (wallet.manifest plus R"(In fully utf environment, (wallet.manifest plus
/utf-8 compile option) all string conversions are safe.)"); /utf-8 compile option) all string conversions are safe.)");
static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 0 && wxSUBRELEASE_NUMBER == 1 && wxVERSION_STRING == wxT("wxWidgets 3.2.0"), "expecting wxWidgets 3.2.0");
static_assert(wxUSE_IPV6 == 1, "IP6 unavailable in wxWidgets"); static_assert(wxUSE_IPV6 == 1, "IP6 unavailable in wxWidgets");
static_assert(WXWIN_COMPATIBILITY_3_0 == 0, "wxWidgets api out of date"); static_assert(WXWIN_COMPATIBILITY_3_0 == 0, "wxWidgets api out of date");
static_assert(wxUSE_COMPILER_TLS == (b_WINDOWS ? 2 : 1), "out of date workarounds in wxWidgets for windows bugs"); static_assert(wxUSE_COMPILER_TLS == (b_WINDOWS ? 2 : 1), "out of date workarounds in wxWidgets for windows bugs");
@ -85,6 +84,11 @@ std::span<uint8_t>& operator^=(std::span<byte>&, byte *);
#pragma comment(lib, "libsodium.lib") #pragma comment(lib, "libsodium.lib")
inline wxString _wx(const char* sz) { return wxString::FromUTF8Unchecked(sz); } inline wxString _wx(const char* sz) { return wxString::FromUTF8Unchecked(sz); }
#include "introspection_of_standard_C_types.h" #include "introspection_of_standard_C_types.h"
// This header file turns off deprecation of array type compares, because
// it provides an array spaceship operator that solves the inconsistency
// problem in a better way. Spaceship compares of arrays in my code are
// no longer ill formed.
static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 0 && wxSUBRELEASE_NUMBER == 1 && wxVERSION_STRING == wxT("wxWidgets 3.2.0"), "expecting wxWidgets 3.2.0");
#include "rotime.h" #include "rotime.h"
#include "slash6.h" #include "slash6.h"
#include "ISqlite3.h" #include "ISqlite3.h"

View File

@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
static constexpr char SrcFilename[]{ "src/unit_test.cpp" };
using ro::msec, ro::msec_since_epoch, ro::bin2hex, ro::to_base64_string, ristretto255::hash, using ro::msec, ro::msec_since_epoch, ro::bin2hex, ro::to_base64_string, ristretto255::hash,
ristretto255::hsh, ristretto255::scalar, ristretto255::hsh, ristretto255::scalar,
ristretto255::point, ro::base58; ristretto255::point, ro::base58;
@ -68,6 +69,11 @@ static bool EndUnitTest() {
throw EndUnitTestOfExceptions(); throw EndUnitTestOfExceptions();
} }
catch (const EndUnitTestOfExceptions&) {} catch (const EndUnitTestOfExceptions&) {}
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception& e) { catch (const std::exception& e) {
errorCode = 1001; errorCode = 1001;
szError = intestbed + e.what(); szError = intestbed + e.what();
@ -105,7 +111,7 @@ static bool curve_order(void) {
mpz_get_str(sz, 16, mpir::ristretto25519_curve_order); mpz_get_str(sz, 16, mpir::ristretto25519_curve_order);
wxString curve_order_as_mpir_bigint{ _wx(sz) }; wxString curve_order_as_mpir_bigint{ _wx(sz) };
if (curve_order_as_unreduced_scalar != curve_order_as_mpir_bigint){ if (curve_order_as_unreduced_scalar != curve_order_as_mpir_bigint){
throw MyException("inconsistent curve order"); throw MyException("inconsistent curve order", __LINE__, __func__, SrcFilename);
} }
scalar sc_zero{ 0 }; scalar sc_zero{ 0 };
scalar sc_one{ 1 }; scalar sc_one{ 1 };
@ -138,7 +144,12 @@ static bool curve_order(void) {
&& sc1.valid()) && sc1.valid())
&& !scalar::scOrder.valid() && !scalar::scOrder.valid()
&& !scalar(0).valid(); && !scalar(0).valid();
if (!f)throw MyException("scalar range and validation messed up"); if (!f)throw MyException("scalar range and validation messed up", __LINE__, __func__, SrcFilename);
}
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
} }
catch (const std::exception& e) { catch (const std::exception& e) {
errorCode = 30; errorCode = 30;
@ -180,14 +191,14 @@ static bool checkDataConversionsProduceExpected(void){
|| hash(p_brownfox) != hash(hsh() << ar_brownfox << wx_over.ToUTF8()) || hash(p_brownfox) != hash(hsh() << ar_brownfox << wx_over.ToUTF8())
|| hash(p_brownfox) != hash(ar_brownfox, wx_over.ToUTF8()) || hash(p_brownfox) != hash(ar_brownfox, wx_over.ToUTF8())
|| hash(brownfox) != hash(ar_brownfox, p_over) || hash(brownfox) != hash(ar_brownfox, p_over)
)throw MyException(sz_inconsistent_hash); )throw MyException(sz_inconsistent_hash, __LINE__, __func__, SrcFilename);
{ {
scalar scl_b{ scalar::random() }; scalar scl_b{ scalar::random() };
point pt_a{ scl_b.timesBase() }; point pt_a{ scl_b.timesBase() };
std::string str_pt_a{ &(base58(pt_a))[0] }; std::string str_pt_a{ &(base58(pt_a))[0] };
if (pt_a != base58<point>::bin(str_pt_a.c_str())){ if (pt_a != base58<point>::bin(str_pt_a.c_str())){
throw MyException("Round trip from and two base 58 representation failed"); throw MyException("Round trip from and two base 58 representation failed", __LINE__, __func__, SrcFilename);
} }
} }
{ {
@ -231,9 +242,14 @@ static bool checkDataConversionsProduceExpected(void){
if (base58(hash_b).operator std::string() != if (base58(hash_b).operator std::string() !=
"i22EVNPsKRjdxYTZrPPu9mx6vnrBjosFix5F4gn2mb2kF" "i22EVNPsKRjdxYTZrPPu9mx6vnrBjosFix5F4gn2mb2kF"
){ ){
throw MyException("unexpected hash of transformations"); throw MyException("unexpected hash of transformations", __LINE__, __func__, SrcFilename);
} }
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception& e) { catch (const std::exception& e) {
errorCode = 27; errorCode = 27;
szError = e.what(); szError = e.what();
@ -277,6 +293,11 @@ static bool CheckForUtfEnvironment(void) {
} }
if (!utfEnvironment) { throw MyException(utfError); } if (!utfEnvironment) { throw MyException(utfError); }
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception& e) { catch (const std::exception& e) {
errorCode = 24; errorCode = 24;
szError = e.what(); szError = e.what();
@ -386,12 +407,12 @@ static bool OpenWallet(void) {
else fWalletNameOk = true; else fWalletNameOk = true;
std::unique_ptr<ISqlite3> db; std::unique_ptr<ISqlite3> db;
if (fWalletNameOk) { if (fWalletNameOk) {
if (!LastUsedSqlite.FileExists()) throw MyException("Expected wallet file not found"); if (!LastUsedSqlite.FileExists()) throw MyException("Expected wallet file not found", __LINE__, __func__, SrcFilename);
db.reset(Sqlite3_open(LastUsedSqlite.GetFullPath().ToUTF8())); db.reset(Sqlite3_open(LastUsedSqlite.GetFullPath().ToUTF8()));
sql_read_from_misc read_from_misc(db.get()); sql_read_from_misc read_from_misc(db.get());
if(!read_from_misc(1) || read_from_misc.value<int64_t>() != WALLET_FILE_IDENTIFIER)throw MyException("Unrecognizable wallet file format"); if(!read_from_misc(1) || read_from_misc.value<int64_t>() != WALLET_FILE_IDENTIFIER)throw MyException("Unrecognizable wallet file format", __LINE__, __func__, SrcFilename);
if(!read_from_misc(2) || read_from_misc.value<int64_t>() != WALLET_FILE_SCHEMA_VERSION_0_0)throw MyException("Unrecognized wallet schema"); if(!read_from_misc(2) || read_from_misc.value<int64_t>() != WALLET_FILE_SCHEMA_VERSION_0_0)throw MyException("Unrecognized wallet schema", __LINE__, __func__, SrcFilename);
if (!read_from_misc(4)) throw MyException("Mastersecret missing"); if (!read_from_misc(4)) throw MyException("Mastersecret missing", __LINE__, __func__, SrcFilename);
ristretto255::CMasterSecret MasterSecret(*read_from_misc.value<ristretto255::scalar>()); ristretto255::CMasterSecret MasterSecret(*read_from_misc.value<ristretto255::scalar>());
ro::sql read_keys(db.get(), R"|(SELECT * FROM "Keys" LIMIT 5;)|"); ro::sql read_keys(db.get(), R"|(SELECT * FROM "Keys" LIMIT 5;)|");
sql_read_name read_name(db.get()); sql_read_name read_name(db.get());
@ -400,10 +421,10 @@ static bool OpenWallet(void) {
auto pubkey = read_keys.column<ristretto255::point>(1); auto pubkey = read_keys.column<ristretto255::point>(1);
auto id = read_keys.column<int>(2); auto id = read_keys.column<int>(2);
auto use = read_keys.column<int>(3); auto use = read_keys.column<int>(3);
if (use != 1)throw MyException(sz_unknown_secret_key_algorithm); if (use != 1)throw MyException(sz_unknown_secret_key_algorithm, __LINE__, __func__, SrcFilename);
if (!read_name(id)) throw MyException(sz_no_corresponding_entry); if (!read_name(id)) throw MyException(sz_no_corresponding_entry, __LINE__, __func__, SrcFilename);
const char* name = read_name.name(); const char* name = read_name.name();
if(MasterSecret(name).timesBase()!=*pubkey)throw MyException(R"|(Public key of name fails to correspond)|"); if(MasterSecret(name).timesBase()!=*pubkey)throw MyException(R"|(Public key of name fails to correspond)|", __LINE__, __func__, SrcFilename);
wxLogMessage(wxT("\t\t\"%s\" has expected public key 0x%s"), name, (wxString)(bin2hex(*pubkey))); wxLogMessage(wxT("\t\t\"%s\" has expected public key 0x%s"), name, (wxString)(bin2hex(*pubkey)));
} }
} }
@ -428,6 +449,7 @@ CREATE TABLE "Keys"(
"use" INTEGER NOT NULL); "use" INTEGER NOT NULL);
CREATE UNIQUE INDEX i_pubkey ON Keys (pubkey); CREATE UNIQUE INDEX i_pubkey ON Keys (pubkey);
CREATE UNIQUE INDEX i_id ON Keys (use, id);
CREATE TABLE "Names"( CREATE TABLE "Names"(
"ROWID" INTEGER PRIMARY KEY, "ROWID" INTEGER PRIMARY KEY,
@ -470,6 +492,11 @@ COMMIT;)|");
} }
} // End of wallet creation branch } // End of wallet creation branch
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception & e) { catch (const std::exception & e) {
errorCode = 20; errorCode = 20;
szError = e.what(); szError = e.what();
@ -516,11 +543,11 @@ namespace ristretto255 {
szError = "Fail\tUnexpected text secret from scalar(7)"; szError = "Fail\tUnexpected text secret from scalar(7)";
ILogError(szError.c_str()); ILogError(szError.c_str());
} }
if (std::popcount(0x0123456789ABCDEFu) != 0x20)throw MyException(sz_bitcount_incorrect); if (std::popcount(0x0123456789ABCDEFu) != 0x20)throw MyException(sz_bitcount_incorrect, __LINE__, __func__, SrcFilename);
if (rounded_log2(0x345678u) != 22) throw MyException(sz_rounded_log2_incorrect); if (rounded_log2(0x345678u) != 22) throw MyException(sz_rounded_log2_incorrect, __LINE__, __func__, SrcFilename);
{ uint64_t v{ 0x123456789ABCDEFu }; { uint64_t v{ 0x123456789ABCDEFu };
for (unsigned int i = 0; i <= 64; i++) { for (unsigned int i = 0; i <= 64; i++) {
if (i != std::countr_zero(v))throw MyException(sz_count_of_trailing_zero_bits_incorrect); if (i != std::countr_zero(v))throw MyException(sz_count_of_trailing_zero_bits_incorrect, __LINE__, __func__, SrcFilename);
v <<= 1; v <<= 1;
} }
} }
@ -556,6 +583,11 @@ namespace ristretto255 {
ILogMessage("\t\tSkipping test of strong secret generation in quick unit test, because strong secret generation is deliberately slow."); ILogMessage("\t\tSkipping test of strong secret generation in quick unit test, because strong secret generation is deliberately slow.");
} }
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception & e) { catch (const std::exception & e) {
errorCode = 16; errorCode = 16;
szError = e.what(); szError = e.what();
@ -573,7 +605,7 @@ namespace ristretto255 {
static bool TestShareSecretGenerationSpeed(void) { static bool TestShareSecretGenerationSpeed(void) {
ILogMessage("\tTest shared secret generation speed."); ILogMessage("\tTest shared secret generation speed.");
try { try {
// throw MyException("fake failure to test failure handling"); // throw MyException("fake failure to test failure handling", __LINE__, __func__, SrcFilename);
unsigned int secrets{ 10 }; unsigned int secrets{ 10 };
scalar a{ scalar::random() }; scalar a{ scalar::random() };
scalar b{ scalar::random() }; scalar b{ scalar::random() };
@ -590,7 +622,8 @@ static bool TestShareSecretGenerationSpeed(void) {
B = b * A; B = b * A;
} }
auto end_time{ std::chrono::high_resolution_clock::now() }; auto end_time{ std::chrono::high_resolution_clock::now() };
if (!B.valid()) { throw MyException("Unexpected invalid scalar"); } if (!B.valid()) { throw MyException("Unexpected invalid scalar", __LINE__, __func__, SrcFilename);
}
auto time_taken{ std::chrono::duration_cast<std::chrono::microseconds> (end_time - start_time) }; auto time_taken{ std::chrono::duration_cast<std::chrono::microseconds> (end_time - start_time) };
wxLogMessage("\t\t%d shared secrets from public and private keys took %lld microseconds", secrets * 3, time_taken.count()); wxLogMessage("\t\t%d shared secrets from public and private keys took %lld microseconds", secrets * 3, time_taken.count());
if (time_taken.count()) { if (time_taken.count()) {
@ -600,6 +633,11 @@ static bool TestShareSecretGenerationSpeed(void) {
); );
} }
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception& e) { catch (const std::exception& e) {
errorCode = 23; errorCode = 23;
szError = e.what(); szError = e.what();
@ -738,6 +776,11 @@ static bool TestShareSecretGenerationSpeed(void) {
wxLogMessage(wxT("\t\tcrypto_shorthash_KEYBYTES\t== %08x"), crypto_shorthash_KEYBYTES); wxLogMessage(wxT("\t\tcrypto_shorthash_KEYBYTES\t== %08x"), crypto_shorthash_KEYBYTES);
wxLogMessage(wxT("\t\tcrypto_auth_BYTES\t\t== %08x"), crypto_auth_BYTES); wxLogMessage(wxT("\t\tcrypto_auth_BYTES\t\t== %08x"), crypto_auth_BYTES);
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception & e) { catch (const std::exception & e) {
errorCode = 15; errorCode = 15;
szError = e.what(); szError = e.what();
@ -790,9 +833,9 @@ static bool TestShareSecretGenerationSpeed(void) {
auto start_time{ std::chrono::high_resolution_clock::now() }; auto start_time{ std::chrono::high_resolution_clock::now() };
auto sclr_a = scalar::random(); auto sclr_a = scalar::random();
auto sclr_b = scalar::random(); auto sclr_b = scalar::random();
if (sclr_a == sclr_b)throw MyException("random not very random"); if (sclr_a == sclr_b)throw MyException("random not very random", __LINE__, __func__, SrcFilename);
auto sclr_c = sclr_a * sclr_b; auto sclr_c = sclr_a * sclr_b;
if (sclr_b != sclr_c / sclr_a)throw MyException("multiplicative inverse not inverse"); if (sclr_b != sclr_c / sclr_a)throw MyException("multiplicative inverse not inverse", __LINE__, __func__, SrcFilename);
if (false if (false
|| !scalar::random().valid() || !scalar::random().valid()
|| point::ptBase - point::ptBase != point::ptZero || point::ptBase - point::ptBase != point::ptZero
@ -894,13 +937,13 @@ static bool TestShareSecretGenerationSpeed(void) {
hash( hash(
hsh() << first << second hsh() << first << second
) )
) throw MyException("inconsistent hashes generated on strings"); ) throw MyException("inconsistent hashes generated on strings", __LINE__, __func__, SrcFilename);
const char* _ = "hello"; const char* _ = "hello";
hash a(_); hash a(_);
hash b(a); hash b(a);
hash c(b); hash c(b);
if (hash(b, c) != hash(hsh() << b << c) if (hash(b, c) != hash(hsh() << b << c)
) throw MyException("inconsistent hashes generated"); ) throw MyException("inconsistent hashes generated", __LINE__, __func__, SrcFilename);
constexpr int hashes{ 3000 }; constexpr int hashes{ 3000 };
start_time = std::chrono::high_resolution_clock::now(); start_time = std::chrono::high_resolution_clock::now();
for (int i{ 0 }; i < hashes; i++) { for (int i{ 0 }; i < hashes; i++) {
@ -937,6 +980,11 @@ static bool TestShareSecretGenerationSpeed(void) {
} }
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception & e) { catch (const std::exception & e) {
errorCode = 10; errorCode = 10;
szError = e.what(); szError = e.what();
@ -1083,6 +1131,11 @@ static bool slash6UnitTest(void) {
} }
// If you touch the slash6 encoding, try retesting with the number of tests tries set to one hundred thousand instead of five, to catch all code paths and weird special cases. // If you touch the slash6 encoding, try retesting with the number of tests tries set to one hundred thousand instead of five, to catch all code paths and weird special cases.
} }
catch (const MyException& e) {
errorCode = e.what_num();
szError = e.what();
ILogError(szError.c_str());
}
catch (const std::exception & e) { catch (const std::exception & e) {
errorCode = 12; errorCode = 12;
szError = e.what(); szError = e.what();