Advertisement
anechka_ne_plach

Untitled

Sep 23rd, 2021
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.92 KB | None | 0 0
  1. #include <catch.hpp>
  2.  
  3. #include <string_operations.h>
  4.  
  5. #include <atomic>
  6. #include <string>
  7. #include <string_view>
  8. #include <vector>
  9. #include <functional>
  10. #include <tuple>
  11. #include <type_traits>
  12. #include <unistd.h>
  13.  
  14. #if defined(__has_feature)
  15. #if __has_feature(address_sanitizer)
  16. #define ASAN_ENABLED
  17. #include <sanitizer/allocator_interface.h>
  18. #endif
  19. #endif
  20.  
  21. using namespace std::string_view_literals;
  22. using namespace std::string_literals;
  23.  
  24. std::atomic<size_t> allocations_count{0};
  25.  
  26. void MallocHook(const volatile void*, size_t) {
  27.     allocations_count.fetch_add(1);
  28. }
  29.  
  30. void FreeHook(const volatile void*) {
  31. }
  32.  
  33. #ifdef ASAN_ENABLED
  34. [[maybe_unused]] const auto kInit = [] {
  35.     int res = __sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
  36.     if (res == 0) {
  37.         throw std::runtime_error{"Failed to install ASan allocator hooks"};  // just terminate
  38.     }
  39.     return 0;
  40. }();
  41. #else
  42. void* operator new(size_t size) {
  43.     void* p = malloc(size);
  44.     MallocHook(p, size);
  45.     return p;
  46. }
  47.  
  48. void* operator new(size_t size, const std::nothrow_t&) noexcept {
  49.     void* p = malloc(size);
  50.     MallocHook(p, size);
  51.     return p;
  52. }
  53.  
  54. void operator delete(void* p) noexcept {
  55.     FreeHook(p);
  56.     free(p);
  57. }
  58.  
  59. void operator delete(void* p, size_t) noexcept {
  60.     FreeHook(p);
  61.     free(p);
  62. }
  63. #endif
  64.  
  65. #define EXPECT_ZERO_ALLOCATIONS(X)                  \
  66.     do {                                            \
  67.         auto __xxx = allocations_count.load();      \
  68.         X;                                          \
  69.         REQUIRE(allocations_count.load() == __xxx); \
  70.     } while (0)
  71.  
  72. #define EXPECT_ONE_ALLOCATION(X)                        \
  73.     do {                                                \
  74.         auto __xxx = allocations_count.load();          \
  75.         X;                                              \
  76.         REQUIRE(allocations_count.load() == __xxx + 1); \
  77.     } while (0)
  78.  
  79. #define EXPECT_NO_MORE_THAN_ONE_ALLOCATION(X)           \
  80.     do {                                                \
  81.         auto __xxx = allocations_count.load();          \
  82.         X;                                              \
  83.         REQUIRE(allocations_count.load() <= __xxx + 1); \
  84.     } while (0)
  85.  
  86. template <typename T>
  87. struct FunctionTraits;
  88.  
  89. template <typename R, typename... Args>
  90. struct FunctionTraits<R(Args...)> {
  91.     static constexpr bool kIsNoexcept = false;
  92.     static constexpr size_t kNargs = sizeof...(Args);
  93.  
  94.     typedef R ResultType;
  95.  
  96.     template <size_t i>
  97.     struct Arg {
  98.         typedef typename std::tuple_element<i, std::tuple<Args...>>::type Type;
  99.     };
  100. };
  101.  
  102. // What if a student is pedantic and adds noexcept?
  103. template <typename R, typename... Args>
  104. struct FunctionTraits<R(Args...) noexcept> {
  105.     static constexpr bool kIsNoexcept = true;
  106.     static constexpr size_t kNargs = sizeof...(Args);
  107.  
  108.     typedef R ResultType;
  109.  
  110.     template <size_t i>
  111.     struct Arg {
  112.         typedef typename std::tuple_element<i, std::tuple<Args...>>::type Type;
  113.     };
  114. };
  115.  
  116. template <typename... Types, typename Func>
  117. void ReturnTypeCheckerOr(Func*) {
  118.     static_assert(!FunctionTraits<Func>::kIsNoexcept ||
  119.                       !std::is_same_v<typename FunctionTraits<Func>::ResultType, std::string>,
  120.                   "Noexcept function cannot return std::string");
  121.     static_assert((std::is_same_v<typename FunctionTraits<Func>::ResultType, Types> || ...),
  122.                   "Return type is incorrect!");
  123. }
  124.  
  125. template <typename Func, size_t I, typename... Types>
  126. void ArgCheckerOr() {
  127.     static_assert(
  128.         (std::is_same_v<typename FunctionTraits<Func>::template Arg<I>::Type, Types> || ...),
  129.         "One of the argument is not correct!");
  130. }
  131.  
  132. template <typename Func, typename... Types, size_t... I>
  133. void AllArgCheckerOr(std::index_sequence<I...>) {
  134.     (ArgCheckerOr<Func, I, Types...>(), ...);
  135. }
  136.  
  137. // Checks whether all arguments are at least one of Types.
  138. template <typename... Types, typename Func>
  139. void ArgsCheckerOr(Func*) {
  140.     AllArgCheckerOr<Func, Types...>(std::make_index_sequence<FunctionTraits<Func>::kNargs>{});
  141. }
  142.  
  143. static constexpr const char kVeryLongString[] =
  144.     "What is love? Baby don't hurt me. Don't hurt me. No more";
  145. static_assert(std::string_view(kVeryLongString).size() > sizeof(std::string));
  146.  
  147. TEST_CASE("EndsStarts") {
  148.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StartsWith("test", "te")));
  149.     EXPECT_ZERO_ALLOCATIONS(REQUIRE_FALSE(StartsWith("", kVeryLongString)));
  150.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StartsWith(kVeryLongString, kVeryLongString)));
  151.     EXPECT_ZERO_ALLOCATIONS(REQUIRE_FALSE(StartsWith(kVeryLongString, "What is luf")));
  152.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StartsWith("", "")));
  153.     ReturnTypeCheckerOr<bool>(StartsWith);
  154.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(StartsWith);
  155.  
  156.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(EndsWith("test", "st")));
  157.     EXPECT_ZERO_ALLOCATIONS(REQUIRE_FALSE(EndsWith("", kVeryLongString)));
  158.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(EndsWith(kVeryLongString, kVeryLongString)));
  159.     EXPECT_ZERO_ALLOCATIONS(REQUIRE_FALSE(EndsWith(kVeryLongString, "Noo more")));
  160.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(EndsWith("", "")));
  161.     ReturnTypeCheckerOr<bool>(EndsWith);
  162.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(EndsWith);
  163. }
  164.  
  165. TEST_CASE("Strip") {
  166.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("st" == StripPrefix("test", "te")));
  167.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StripPrefix("", kVeryLongString).empty()));
  168.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StripPrefix(kVeryLongString, kVeryLongString).empty()));
  169.     EXPECT_ZERO_ALLOCATIONS(
  170.         REQUIRE(kVeryLongString == StripPrefix(kVeryLongString, "What is luf")));
  171.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StripPrefix("", "").empty()));
  172.     ReturnTypeCheckerOr<std::string, std::string_view>(StripPrefix);
  173.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(StripPrefix);
  174.  
  175.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("te" == StripSuffix("test", "st")));
  176.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StripSuffix("", kVeryLongString).empty()));
  177.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StripSuffix(kVeryLongString, kVeryLongString).empty()));
  178.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(kVeryLongString == StripSuffix(kVeryLongString, "Noo more")));
  179.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(StripSuffix("", "").empty()));
  180.     ReturnTypeCheckerOr<std::string, std::string_view>(StripSuffix);
  181.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(StripSuffix);
  182.  
  183.     EXPECT_ZERO_ALLOCATIONS(
  184.         REQUIRE(StripAsciiWhitespace("                                   ").empty()));
  185.     EXPECT_ZERO_ALLOCATIONS(
  186.         REQUIRE("some very long words, trust me, you will doom me after this" ==
  187.                 StripAsciiWhitespace("  \n\r\n\t\f   some very long words, trust me, you will doom "
  188.                                      "me after this \n\n\t\f")));
  189.     ReturnTypeCheckerOr<std::string, std::string_view>(StripAsciiWhitespace);
  190.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(
  191.         StripAsciiWhitespace);
  192.  
  193.     // EASY.
  194.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(kVeryLongString == ClippedSubstr(kVeryLongString, 0, 100500)));
  195.     EXPECT_ZERO_ALLOCATIONS(
  196.         REQUIRE("t is love? Baby don't hu" == ClippedSubstr(kVeryLongString, 3, 24)));
  197.     ReturnTypeCheckerOr<std::string_view>(ClippedSubstr);
  198.     ArgsCheckerOr<std::string_view, const std::string_view, size_t>(ClippedSubstr);
  199. }
  200.  
  201. TEST_CASE("FileSystems") {
  202.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("/" == RemoveSlash("/")));
  203.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("/danlark/is/creating/awesome/tests" ==
  204.                                     RemoveSlash("/danlark/is/creating/awesome/tests")));
  205.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("/danlark/is/creating/awesome/tests" ==
  206.                                     RemoveSlash("/danlark/is/creating/awesome/tests/")));
  207.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("/" == AddSlash("/")));
  208.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(
  209.         REQUIRE("/danlark/is/creating/even/more/awesome/tests/" ==
  210.                 AddSlash("/danlark/is/creating/even/more/awesome/tests")));
  211.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(
  212.         REQUIRE("/danlark/is/creating/even/more/awesome/tests/" ==
  213.                 AddSlash("/danlark/is/creating/even/more/awesome/tests/")));
  214.     auto path = "/a/b"s;
  215.     for (size_t i = 0; i < 512; ++i) {
  216.         path += "a";
  217.         auto slashed = path + "/";
  218.         EXPECT_ZERO_ALLOCATIONS(REQUIRE(path == RemoveSlash(slashed)));
  219.         EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(slashed == AddSlash(path)));
  220.         EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(slashed == AddSlash(slashed.data())));
  221.         EXPECT_ZERO_ALLOCATIONS(REQUIRE(path.data() == RemoveSlash(path)));
  222.     }
  223.     ReturnTypeCheckerOr<std::string, std::string_view>(AddSlash);
  224.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(AddSlash);
  225.     ReturnTypeCheckerOr<std::string, std::string_view>(RemoveSlash);
  226.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(RemoveSlash);
  227. }
  228.  
  229. TEST_CASE("FileSystemsSplits") {
  230.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("file" == Basename("/file")));
  231.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("/" == Dirname("/very_very_very_stylish_file")));
  232.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(
  233.         "iiiiiiiiiiii\0iiiiiiiiiiiiiiiiiiiiin" ==
  234.         Basename("/dir/dir/dir/dir/dir/dir/danlark/let/me/iiiiiiiiiiii\0iiiiiiiiiiiiiiiiiiiiin")));
  235.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(
  236.         "/dir/dir/dir/dir/dir/dir/danlark/let/me" ==
  237.         Dirname("/dir/dir/dir/dir/dir/dir/danlark/let/me/iiiiiiiiiiii\0iiiiiiiiiiiiiiiiiiiiin")));
  238.     ReturnTypeCheckerOr<std::string, std::string_view>(Basename);
  239.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(Basename);
  240.     ReturnTypeCheckerOr<std::string, std::string_view>(Dirname);
  241.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(Dirname);
  242.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(
  243.         "/a/" == CollapseSlashes("///////////////////////////////////////////////////////a//"
  244.                                  "/////////////////////////////////////")));
  245.     EXPECT_ONE_ALLOCATION(REQUIRE(
  246.         "/a/b/c/d/e/f/g/h/aa/bb/cc/dd/ee/ff/gg/a/heh" ==
  247.         CollapseSlashes(
  248.             "/a/b/c/d/e/f/g/h/aa/bb//cc/dd/ee/ff//gg////////////////////////////////////////a//"
  249.             "/////////////////////////////////////heh")));
  250.     EXPECT_ZERO_ALLOCATIONS(REQUIRE("/" == CollapseSlashes("//////")));
  251.     EXPECT_ZERO_ALLOCATIONS(REQUIRE(CollapseSlashes("").empty()));
  252.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(
  253.         REQUIRE(kVeryLongString == CollapseSlashes(kVeryLongString)));
  254.     ReturnTypeCheckerOr<std::string, std::string_view>(CollapseSlashes);
  255.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(CollapseSlashes);
  256. }
  257.  
  258. TEST_CASE("Join") {
  259.     std::vector v = {"a"sv, "b"sv, "c"sv, "d"sv, "e"sv, "z"sv, "p"sv};
  260.     auto ans = "ahehehehbhehehehchehehehdhehehehehehehehzhehehehp"s;
  261.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(ans == StrJoin(v, "heheheh")));
  262.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(
  263.         REQUIRE(ans != StrJoin(v,
  264.                                "hehehehhehehehhehehehhehehehhehehehhehehehhehehehhehehehhehehehhehe"
  265.                                "hehhehehehhehehehhehehehhehehehheheheh")));
  266.     for (int i = 0; i < 100; ++i) {
  267.         v.emplace_back(kVeryLongString);
  268.         ans += "heheheh"s + v.back().data();
  269.         EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(ans == StrJoin(v, "heheheh")));
  270.     }
  271.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(StrJoin({}, "danlark").empty()));
  272.     ReturnTypeCheckerOr<std::string>(StrJoin);
  273.     ArgsCheckerOr<const std::vector<std::string>&, const std::vector<std::string_view>&,
  274.                   std::string, std::string_view, const std::string&>(StrJoin);
  275. }
  276.  
  277. TEST_CASE("ReadN") {
  278.     std::string_view almost_urandom = "/dev/urandom\0/haha"sv;
  279.     almost_urandom.remove_suffix(5);
  280.     for (int i = 0; i < 100; ++i) {
  281.         auto once = ReadN(almost_urandom.data(), 100);
  282.         EXPECT_ZERO_ALLOCATIONS(REQUIRE(!once.empty()));
  283.     }
  284.     std::string urandom = std::string(almost_urandom);
  285.     for (int i = 0; i < 100; ++i) {
  286.         auto once = ReadN(urandom, 100);
  287.         EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(once != ReadN(urandom, 100)));
  288.     }
  289.     ReturnTypeCheckerOr<std::string, std::string_view>(ReadN);
  290.     ArgsCheckerOr<const std::string&, size_t>(ReadN);
  291. }
  292.  
  293. TEST_CASE("Split") {
  294.     {
  295.         std::vector<std::string> expected{"aba", "caba", "1"};
  296.         EXPECT_ONE_ALLOCATION(auto result = StrSplit("aba caba 1", " "); REQUIRE(std::equal(
  297.             expected.begin(), expected.end(), result.begin(), result.end())));
  298.     }
  299.     {
  300.         std::vector<std::string> expected{"aba"};
  301.         EXPECT_ONE_ALLOCATION(auto result = StrSplit("aba", " "); REQUIRE(std::equal(
  302.             expected.begin(), expected.end(), result.begin(), result.end())));
  303.     }
  304.     {
  305.         std::vector<std::string> expected{""};
  306.         EXPECT_ONE_ALLOCATION(auto result = StrSplit("", " "); REQUIRE(std::equal(
  307.             expected.begin(), expected.end(), result.begin(), result.end())));
  308.     }
  309.     {
  310.         std::vector<std::string> expected{"", ""};
  311.         EXPECT_ONE_ALLOCATION(
  312.             auto result = StrSplit("full match", "full match");
  313.             REQUIRE(std::equal(expected.begin(), expected.end(), result.begin(), result.end())));
  314.     }
  315.     {
  316.         std::vector<std::string> expected{"", ""};
  317.         EXPECT_ONE_ALLOCATION(
  318.             auto result = StrSplit(kVeryLongString, kVeryLongString);
  319.             REQUIRE(std::equal(expected.begin(), expected.end(), result.begin(), result.end())));
  320.     }
  321.     {
  322.         std::vector<std::string> expected{"just", "", "a", "test", ""};
  323.         EXPECT_ONE_ALLOCATION(auto result = StrSplit("just  a test ", " "); REQUIRE(std::equal(
  324.             expected.begin(), expected.end(), result.begin(), result.end())));
  325.     }
  326.     {
  327.         std::vector<std::string> expected{"hello", "world,no split here", "", "1", ""};
  328.         EXPECT_ONE_ALLOCATION(
  329.             auto result = StrSplit("hello, world,no split here, , 1, ", ", ");
  330.             REQUIRE(std::equal(expected.begin(), expected.end(), result.begin(), result.end())));
  331.     }
  332.     {
  333.         std::vector<std::string> expected{"", "a", "b c", "def", "g h "};
  334.         EXPECT_ONE_ALLOCATION(
  335.             auto result = StrSplit("  a  b c  def  g h ", "  ");
  336.             REQUIRE(std::equal(expected.begin(), expected.end(), result.begin(), result.end())));
  337.     }
  338.     ReturnTypeCheckerOr<std::vector<std::string>, std::vector<std::string_view>>(StrSplit);
  339.     ArgsCheckerOr<const std::string&, std::string_view, const std::string_view>(StrSplit);
  340. }
  341.  
  342. TEST_CASE("StrCat") {
  343.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(
  344.         REQUIRE("abc 5 abcd 12" == StrCat("abc ", 5u, " abcd "sv, 12ull)));
  345.     std::string s = kVeryLongString;
  346.     EXPECT_ONE_ALLOCATION(REQUIRE(
  347.         "What is love? Baby don't hurt me. Don't hurt me. No more1112What is love? Baby don't "
  348.         "hurt me. Don't hurt me. No more0" == StrCat(s, 11l, 12u, kVeryLongString, 0ull)));
  349.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(
  350.         REQUIRE("-9223372036854775808" == StrCat(std::numeric_limits<long long>::min())));
  351.     EXPECT_ONE_ALLOCATION(
  352.         REQUIRE("-922337203685477580809223372036854775807-2147483648" ==
  353.                 StrCat(std::numeric_limits<long long>::min(), 0,
  354.                        std::numeric_limits<long long>::max(), std::numeric_limits<int>::min())));
  355.     EXPECT_ONE_ALLOCATION(
  356.         REQUIRE("18446744073709551615042949672952147483647" ==
  357.                 StrCat(std::numeric_limits<unsigned long long>::max(), 0,
  358.                        std::numeric_limits<unsigned int>::max(), std::numeric_limits<int>::max())));
  359.     EXPECT_NO_MORE_THAN_ONE_ALLOCATION(REQUIRE(StrCat().empty()));
  360.     ReturnTypeCheckerOr<std::string, std::string_view>(StrCat<int>);
  361.     ReturnTypeCheckerOr<std::string>(StrCat<>);
  362. }
  363.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement