diff --git a/src/klotski_core/common_code/common_code.cc b/src/klotski_core/common_code/common_code.cc index 573a783..5230c4f 100644 --- a/src/klotski_core/common_code/common_code.cc +++ b/src/klotski_core/common_code/common_code.cc @@ -1,4 +1,3 @@ -#include #include "common.h" #include "common_code.h" @@ -48,7 +47,7 @@ namespace klotski { CommonCode::CommonCode(uint64_t common_code) { if (!CommonCode::check(common_code)) { // check input common code - throw std::invalid_argument("invalid common code"); + throw klotski::CommonCodeException("common code invalid"); } code = common_code; } diff --git a/src/klotski_core/common_code/common_code.h b/src/klotski_core/common_code/common_code.h index a6f626a..6bf2f3c 100644 --- a/src/klotski_core/common_code/common_code.h +++ b/src/klotski_core/common_code/common_code.h @@ -38,9 +38,9 @@ /// Eg1: /// % # # % 2x2 -> head = 1 /// % # # % 2x1 2x1 2x1 1x2 2x1 1x1 1x1 1x1 space space 1x1 ... ... ... ... ... -/// @ $ $ @ 10 10 10 01 10 11 11 11 00 00 11 00 00 00 00 00 -/// @ & * @ 1010 1001 1011 1111 0000 1100 0000 0000 -/// * & A 9 B F 0 C 0 0 +/// @ $ $ @ 10 10 10 01 10 11 11 11 00 00 11 00 00 00 00 00 +/// @ & * @ 1010 1001 1011 1111 0000 1100 0000 0000 +/// * & A 9 B F 0 C 0 0 /// CommonCode = 0x1A9BF0C00 -> "1A9BF0C" /// Eg2: @@ -54,14 +54,22 @@ #include #include #include +#include #include "raw_code.h" #include "short_code.h" namespace klotski { - /// import for convert interface + // import for convert interface class RawCode; class ShortCode; + class CommonCodeException : public std::runtime_error { + public: + CommonCodeException() : std::runtime_error("invalid common code") {} + explicit CommonCodeException(const std::string &msg) : std::runtime_error(msg) {} + ~CommonCodeException() noexcept override = default; + }; + class CommonCode { public: bool valid() const; diff --git a/src/klotski_core/common_code/serialize.cc b/src/klotski_core/common_code/serialize.cc index 4ec63e6..e6a4097 100644 --- a/src/klotski_core/common_code/serialize.cc +++ b/src/klotski_core/common_code/serialize.cc @@ -1,6 +1,7 @@ #include "common_code.h" using klotski::CommonCode; +using klotski::CommonCodeException; inline uint8_t binary_count(uint32_t bin) { // get number of non-zero bits bin -= (bin >> 1) & 0x55'55'55'55; @@ -37,7 +38,7 @@ std::string CommonCode::to_string(bool shorten) const { // convert uint64_t code CommonCode::CommonCode(const std::string &common_code) { // convert from 1 ~ 9 bits string /// check string length if (common_code.length() > 9 || common_code.empty()) { // check string length - throw std::invalid_argument("common code format error"); + throw CommonCodeException("common code should length 1 ~ 9"); } /// check every characters uint64_t result = 0; @@ -50,13 +51,13 @@ CommonCode::CommonCode(const std::string &common_code) { // convert from 1 ~ 9 b } else if (bit >= 'a' && bit <= 'z') { // a ~ z result |= (bit - 87); } else { - throw std::invalid_argument("common code format error"); // unknown characters + throw CommonCodeException("common code with invalid character"); // unknown character } } result <<= (9 - common_code.length()) * 4; // low-bits fill with zero /// check whether common code is valid if (!CommonCode::check(result)) { // check converted common code - throw std::invalid_argument("invalid common code"); + throw CommonCodeException("common code invalid"); } code = result; } diff --git a/src/klotski_core/raw_code/convert.cc b/src/klotski_core/raw_code/convert.cc index 1fffff4..9f86417 100644 --- a/src/klotski_core/raw_code/convert.cc +++ b/src/klotski_core/raw_code/convert.cc @@ -4,11 +4,12 @@ using klotski::RawCode; using klotski::CommonCode; +using klotski::RawCodeException; /// RawCode to CommonCode CommonCode RawCode::to_common_code() const { if (!RawCode::check(code)) { - throw std::runtime_error("invalid raw code"); + throw RawCodeException("raw code invalid"); } /// pass raw code checker -> common code must valid return CommonCode::unsafe_create(RawCode::compact(code)); diff --git a/src/klotski_core/raw_code/raw_code.cc b/src/klotski_core/raw_code/raw_code.cc index fbb4ef2..aec594d 100644 --- a/src/klotski_core/raw_code/raw_code.cc +++ b/src/klotski_core/raw_code/raw_code.cc @@ -1,4 +1,3 @@ -#include #include "common.h" #include "raw_code.h" @@ -56,7 +55,7 @@ namespace klotski { RawCode::RawCode(uint64_t raw_code) { if (!RawCode::check(raw_code)) { // check input raw code - throw std::invalid_argument("invalid raw code"); + throw klotski::RawCodeException("raw code invalid"); } code = raw_code; } diff --git a/src/klotski_core/raw_code/raw_code.h b/src/klotski_core/raw_code/raw_code.h index 5b27c97..f6b7822 100644 --- a/src/klotski_core/raw_code/raw_code.h +++ b/src/klotski_core/raw_code/raw_code.h @@ -37,11 +37,18 @@ #include #include #include +#include #include "common_code.h" namespace klotski { - /// import for convert interface - class CommonCode; + class CommonCode; // import for convert interface + + class RawCodeException : public std::runtime_error { + public: + RawCodeException() : std::runtime_error("invalid raw code") {} + explicit RawCodeException(const std::string &msg) : std::runtime_error(msg) {} + ~RawCodeException() noexcept override = default; + }; class RawCode { public: diff --git a/src/klotski_core/short_code/serialize.cc b/src/klotski_core/short_code/serialize.cc index 114a1ef..fa9d44c 100644 --- a/src/klotski_core/short_code/serialize.cc +++ b/src/klotski_core/short_code/serialize.cc @@ -1,8 +1,8 @@ -#include #include "short_code.h" #include "serialize_chars.h" using klotski::ShortCode; +using klotski::ShortCodeException; ShortCode ShortCode::from_string(const std::string &short_code) { return ShortCode(short_code); // convert from string @@ -21,7 +21,7 @@ std::string ShortCode::to_string() const { // encode as 5-bits string ShortCode::ShortCode(const std::string &short_code) { // 5-bits string decode if (short_code.length() != 5) { // check string length - throw std::invalid_argument("short code format error"); + throw ShortCodeException("short code should length 5"); } uint64_t result = 0; for (auto bit : short_code) { @@ -32,12 +32,12 @@ ShortCode::ShortCode(const std::string &short_code) { // 5-bits string decode if (bit >= '1' && bit <= 'Z') { // valid characters result += (bit = SHORT_CODE_TABLE_REV[bit - 49]); // table convert if (bit == -1) { - throw std::invalid_argument("short code format error"); // unknown characters + throw ShortCodeException("short code with invalid character"); // unknown character } } } if (!ShortCode::check(result)) { // check converted short code - throw std::invalid_argument("invalid short code"); + throw ShortCodeException("short code invalid"); } code = result; // apply convert result } diff --git a/src/klotski_core/short_code/short_code.cc b/src/klotski_core/short_code/short_code.cc index 8389945..029cfbb 100644 --- a/src/klotski_core/short_code/short_code.cc +++ b/src/klotski_core/short_code/short_code.cc @@ -45,7 +45,7 @@ namespace klotski { ShortCode::ShortCode(uint32_t short_code) { if (!ShortCode::check(short_code)) { // check input short code - throw std::invalid_argument("invalid short code"); + throw klotski::ShortCodeException("short code invalid"); } code = short_code; } diff --git a/src/klotski_core/short_code/short_code.h b/src/klotski_core/short_code/short_code.h index 59726e5..05da00d 100644 --- a/src/klotski_core/short_code/short_code.h +++ b/src/klotski_core/short_code/short_code.h @@ -25,11 +25,19 @@ #include #include #include +#include +#include #include "common_code.h" namespace klotski { - /// import for convert interface - class CommonCode; + class CommonCode; // import for convert interface + + class ShortCodeException : public std::runtime_error { + public: + ShortCodeException() : std::runtime_error("invalid short code") {} + explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {} + ~ShortCodeException() noexcept override = default; + }; class ShortCode { public: diff --git a/test/codec/common_code.cc b/test/codec/common_code.cc index 3c93469..9f781c6 100644 --- a/test/codec/common_code.cc +++ b/test/codec/common_code.cc @@ -9,8 +9,9 @@ using klotski::AllCases; using klotski::ShortCode; using klotski::CommonCode; -const static uint64_t TEST_CODE = 0x1A9BF0C00; +const static uint64_t TEST_CODE = 0x1'A9BF'0C00; const static std::string TEST_CODE_STR = "1A9BF0C00"; +const static uint64_t TEST_ERR_CODE = 0x1'2190'2300; // TODO: test some invalid cases diff --git a/test/codec/raw_code.cc b/test/codec/raw_code.cc index 791e18e..d8b212d 100644 --- a/test/codec/raw_code.cc +++ b/test/codec/raw_code.cc @@ -8,6 +8,7 @@ using klotski::AllCases; using klotski::CommonCode; const static uint64_t TEST_CODE = 0x0603'EDF5'CAFF'F5E2; +const static uint64_t TEST_ERR_CODE = 0x0A34'182B'3810'2D21; // TODO: test some invalid cases diff --git a/test/codec/short_code.cc b/test/codec/short_code.cc index 01e30aa..3f9bc46 100644 --- a/test/codec/short_code.cc +++ b/test/codec/short_code.cc @@ -9,10 +9,29 @@ using klotski::ShortCode; using klotski::CommonCode; using klotski::BasicRanges; -const static uint64_t TEST_CODE = 4091296; +const static uint32_t TEST_CODE = 4091296; const static std::string TEST_CODE_STR = "4WVE1"; -// TODO: test some invalid cases +inline void SHOULD_PANIC(const std::function &func) { + bool panic_flag = false; + try { + func(); + } catch (klotski::ShortCodeException&) { + panic_flag = true; + } + EXPECT_EQ(panic_flag, true); +} + +TEST(ShortCode, invalid) { + EXPECT_NE(ShortCode::check(29670987), true); + + std::cout << ShortCode::from_string("R50EH") << std::endl; + + SHOULD_PANIC([](){ ShortCode::from_string("R50EH"); }); // with invalid `0` +// SHOULD_PANIC([](){ ShortCode::from_string("123456"); }); // length != 5 +// SHOULD_PANIC([](){ ShortCode::from_string("Z9EFV"); }); // out of short code range + +} TEST(ShortCode, speed_up) { std::thread threads[4]; diff --git a/test/ffi/codec.cc b/test/ffi/codec.cc index 11baa63..94a653d 100644 --- a/test/ffi/codec.cc +++ b/test/ffi/codec.cc @@ -1,12 +1,23 @@ #include "klotski.h" +#include "raw_code.h" #include "all_cases.h" #include "short_code.h" +#include "common_code.h" #include "gtest/gtest.h" +using klotski::RawCode; using klotski::AllCases; using klotski::ShortCode; using klotski::BasicRanges; +const static uint32_t TEST_SHORT_CODE_OK = 4091296; +const static uint64_t TEST_COMMON_CODE_OK = 0x1'A9BF'0C00; +const static uint64_t TEST_RAW_CODE_OK = 0x0603'EDF5'CAFF'F5E2; + +const static uint32_t TEST_SHORT_CODE_ERR = 29670987; +const static uint64_t TEST_COMMON_CODE_ERR = 0x1'2190'2300; +const static uint64_t TEST_RAW_CODE_ERR = 0x0A34'182B'3810'2D21; + TEST(FFI, codec_warm_up) { // short code normal mode check EXPECT_EQ(is_short_code_available(), BasicRanges::status() == BasicRanges::AVAILABLE); @@ -20,3 +31,14 @@ TEST(FFI, codec_warm_up) { EXPECT_EQ(is_short_code_available_fast(), true); EXPECT_EQ(is_short_code_available_fast(), AllCases::status() == AllCases::AVAILABLE); } + +TEST(FFI, codec_checker) { + EXPECT_EQ(raw_code_check(TEST_RAW_CODE_OK), true); + EXPECT_NE(raw_code_check(TEST_RAW_CODE_ERR), true); + + EXPECT_EQ(short_code_check(TEST_SHORT_CODE_OK), true); + EXPECT_NE(short_code_check(TEST_SHORT_CODE_ERR), true); + + EXPECT_EQ(common_code_check(TEST_COMMON_CODE_OK), true); + EXPECT_NE(common_code_check(TEST_COMMON_CODE_ERR), true); +}