From e96e8d9ad7bc13b458d4a77ff883285167a835b9 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 22 Mar 2024 21:24:11 +0800 Subject: [PATCH] feat test base64 --- CMakeLists.txt | 15 +++++++++- include/sled/strings/base64.h | 7 +++-- include/sled/synchronization/call_once.h | 20 ++++++++++++++ include/sled/uri.h | 6 ++-- src/strings/base64.cc | 35 +++++++++++++++--------- src/strings/base64_fuzz.cc | 18 ++++++++++++ src/strings/base64_test.cc | 15 +++++----- 7 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 include/sled/synchronization/call_once.h create mode 100644 src/strings/base64_fuzz.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b7fa641..23ec73e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ set(CMAKE_CXX_STANDARD_EXTENSIONS OFF) option(SLED_BUILD_BENCHMARK "Build benchmark" OFF) option(SLED_BUILD_TESTS "Build tests" OFF) +option(SLED_BUILD_FUZZ "Build fuzzer test" OFF) option(SLED_LOCATION_PATH "" "sled/src/system/location.cc") set(BUILD_STATIC ON) @@ -119,7 +120,7 @@ if(SLED_BUILD_TESTS) ) FetchContent_MakeAvailable(googletest) add_executable(sled_tests - src/exec/just_test.cc + # src/exec/just_test.cc src/any_test.cc src/filesystem/path_test.cc src/futures/future_test.cc @@ -135,3 +136,15 @@ if(SLED_BUILD_TESTS) target_link_libraries(sled_tests PRIVATE sled GTest::gtest GTest::gtest_main) add_test(NAME sled_tests COMMAND sled_tests) endif(SLED_BUILD_TESTS) + +if (SLED_BUILD_FUZZ) + +macro(add_fuzz_test name sources) + add_executable(${name} ${sources}) + target_link_libraries(${name} PRIVATE sled) + target_compile_options(${name} PRIVATE -g -O1 -fsanitize=fuzzer,address -fsanitize-coverage=trace-cmp) + target_link_options(${name} PRIVATE -fsanitize=fuzzer,address -fsanitize-coverage=trace-cmp) +endmacro() + +add_fuzz_test(base64_fuzz src/strings/base64_fuzz.cc) +endif (SLED_BUILD_FUZZ) diff --git a/include/sled/strings/base64.h b/include/sled/strings/base64.h index e37f2b8..f96738e 100644 --- a/include/sled/strings/base64.h +++ b/include/sled/strings/base64.h @@ -10,13 +10,16 @@ #include "sled/status_or.h" #include +#include namespace sled { class Base64 { public: - static std::string Encode(const std::string &input); - static StatusOr Decode(const std::string &input); + static std::string Encode(void *ptr, size_t len); + static std::string Encode(const std::vector &data); + static std::string Encode(const std::string &data); + static StatusOr Decode(const std::string &base64); }; }// namespace sled diff --git a/include/sled/synchronization/call_once.h b/include/sled/synchronization/call_once.h new file mode 100644 index 0000000..3b09769 --- /dev/null +++ b/include/sled/synchronization/call_once.h @@ -0,0 +1,20 @@ +#ifndef SLED_SYNCHRONIZATION_CALL_ONCE_H +#define SLED_SYNCHRONIZATION_CALL_ONCE_H +#pragma once + +#include + +namespace sled { + +struct OnceFlag { + std::once_flag flag; +}; + +template +void +CallOnce(OnceFlag &flag, F &&f, Args &&...args) +{ + std::call_once(flag.flag, std::forward(f), std::forward(args)...); +} +}// namespace sled +#endif// SLED_SYNCHRONIZATION_CALL_ONCE_H diff --git a/include/sled/uri.h b/include/sled/uri.h index 3f4f6b1..d5ae9cc 100644 --- a/include/sled/uri.h +++ b/include/sled/uri.h @@ -20,11 +20,11 @@ public: // using ParamType = std::pair; using ParamMap = std::map; // http://xxx.com/index.html?field=value - static URI ParseAbsoluteURI(const std::string &uri); + static URI ParseAbsoluteURI(const std::string &uri_str); // http://xxx.com/index.html?field=value#download - static URI ParseURI(const std::string &uri); + static URI ParseURI(const std::string &uri_str); // http://xxx.com/index.html - static URI ParseURIReference(const std::string &uri); + static URI ParseURIReference(const std::string &uri_str); // setter getter __SLED_URI_GETTER_AND_SETTER(std::string, scheme) diff --git a/src/strings/base64.cc b/src/strings/base64.cc index 65c4dad..0a2ba58 100644 --- a/src/strings/base64.cc +++ b/src/strings/base64.cc @@ -1,20 +1,12 @@ #include "sled/strings/base64.h" +#include "sled/synchronization/call_once.h" #include #include namespace sled { const char kBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -const int kInvBase64Chars[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; +static int kInvBase64Chars[(1 << sizeof(char))]; +static OnceFlag once_flag; inline bool IsBase64(char c) @@ -22,14 +14,26 @@ IsBase64(char c) return isalnum(c) || c == '+' || c == '/'; } +std::string +Base64::Encode(void *ptr, size_t len) +{ + auto data = reinterpret_cast(ptr); + return Encode(std::vector(data, data + len)); +} + std::string Base64::Encode(const std::string &input) +{ + return Encode((void *) input.data(), input.length()); +} + +std::string +Base64::Encode(const std::vector &data) { std::stringstream ss; - const unsigned char *data = reinterpret_cast(input.c_str()); int value = 0; int value_bits = 0; - for (unsigned char c : input) { + for (unsigned char c : data) { value = (value << 8) + c; value_bits += 8; while (value_bits >= 6) { @@ -52,6 +56,11 @@ Base64::Encode(const std::string &input) StatusOr Base64::Decode(const std::string &input) { + CallOnce(once_flag, [&] { + std::fill(kInvBase64Chars, kInvBase64Chars + sizeof(kInvBase64Chars), -1); + for (int i = 0; i < sizeof(kBase64Chars); i++) { kInvBase64Chars[kBase64Chars[i]] = i; } + }); + std::stringstream ss; int value = 0; int value_bits = 0; diff --git a/src/strings/base64_fuzz.cc b/src/strings/base64_fuzz.cc new file mode 100644 index 0000000..cd5e652 --- /dev/null +++ b/src/strings/base64_fuzz.cc @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + std::string encoded = sled::Base64::Encode((void *) data, size); + + auto decoded_or = sled::Base64::Decode(encoded); + + ASSERT(decoded_or.ok(), "decoded failed"); + auto decoded = decoded_or.value(); + ASSERT(decoded.size() == size, "decoded size mismatch"); + ASSERT(memcmp(decoded.data(), data, size) == 0, "decoded data mismatch"); + return 0; +} diff --git a/src/strings/base64_test.cc b/src/strings/base64_test.cc index d8c2963..5513b93 100644 --- a/src/strings/base64_test.cc +++ b/src/strings/base64_test.cc @@ -4,19 +4,20 @@ #define CONCAT_IMPL(A, B) A##B #define CONCAT(A, B) CONCAT_IMPL(A, B) -#define TEST_ENCODE_DECODE(base64, text) \ - do { \ - ASSERT_EQ(sled::Base64::Encode(text), base64); \ - auto CONCAT(res, __LINE__) = sled::Base64::Decode(base64); \ - ASSERT_TRUE(CONCAT(res, __LINE__).ok()); \ - ASSERT_EQ(CONCAT(res, __LINE__).value(), text); \ +#define TEST_ENCODE_DECODE(base64, text) \ + do { \ + ASSERT_EQ(sled::Base64::Encode(text), base64); \ + auto CONCAT(res, __LINE__) = sled::Base64::Decode(base64); \ + ASSERT_TRUE(CONCAT(res, __LINE__).ok()); \ + ASSERT_EQ(CONCAT(res, __LINE__).value(), text); \ } while (0) TEST(Base64, EncodeAndDecode) { TEST_ENCODE_DECODE("aGVsbG8gd29ybGQK", "hello world\n"); - TEST_ENCODE_DECODE("U2VuZCByZWluZm9yY2VtZW50cwo=", "Send reinforcements\n"); TEST_ENCODE_DECODE("", ""); + TEST_ENCODE_DECODE("U2VuZCByZWluZm9yY2VtZW50cwo=", "Send reinforcements\n"); + TEST_ENCODE_DECODE(" ", " "); TEST_ENCODE_DECODE("AA==", std::string("\0", 1)); TEST_ENCODE_DECODE("AAA=", std::string("\0\0", 2)); TEST_ENCODE_DECODE("AAAA", std::string("\0\0\0", 3));