1*431ea2d0SNick Desaulniers //===-- Unittests for bcopy -----------------------------------------------===// 2*431ea2d0SNick Desaulniers // 3*431ea2d0SNick Desaulniers // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*431ea2d0SNick Desaulniers // See https://llvm.org/LICENSE.txt for license information. 5*431ea2d0SNick Desaulniers // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*431ea2d0SNick Desaulniers // 7*431ea2d0SNick Desaulniers //===----------------------------------------------------------------------===// 8*431ea2d0SNick Desaulniers 9*431ea2d0SNick Desaulniers #include "src/strings/bcopy.h" 10*431ea2d0SNick Desaulniers 11*431ea2d0SNick Desaulniers #include "src/__support/CPP/span.h" 12*431ea2d0SNick Desaulniers #include "src/__support/macros/config.h" 13*431ea2d0SNick Desaulniers #include "test/UnitTest/MemoryMatcher.h" 14*431ea2d0SNick Desaulniers #include "test/UnitTest/Test.h" 15*431ea2d0SNick Desaulniers #include "test/src/string/memory_utils/memory_check_utils.h" 16*431ea2d0SNick Desaulniers 17*431ea2d0SNick Desaulniers using LIBC_NAMESPACE::cpp::array; 18*431ea2d0SNick Desaulniers using LIBC_NAMESPACE::cpp::span; 19*431ea2d0SNick Desaulniers 20*431ea2d0SNick Desaulniers namespace LIBC_NAMESPACE_DECL { 21*431ea2d0SNick Desaulniers 22*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, MoveZeroByte) { 23*431ea2d0SNick Desaulniers char Buffer[] = {'a', 'b', 'y', 'z'}; 24*431ea2d0SNick Desaulniers const char Expected[] = {'a', 'b', 'y', 'z'}; 25*431ea2d0SNick Desaulniers void *const Dst = Buffer; 26*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(Buffer + 2, Dst, 0); 27*431ea2d0SNick Desaulniers ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected)); 28*431ea2d0SNick Desaulniers } 29*431ea2d0SNick Desaulniers 30*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, DstAndSrcPointToSameAddress) { 31*431ea2d0SNick Desaulniers char Buffer[] = {'a', 'b'}; 32*431ea2d0SNick Desaulniers const char Expected[] = {'a', 'b'}; 33*431ea2d0SNick Desaulniers void *const Dst = Buffer; 34*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(Buffer, Dst, 1); 35*431ea2d0SNick Desaulniers ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected)); 36*431ea2d0SNick Desaulniers } 37*431ea2d0SNick Desaulniers 38*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, DstStartsBeforeSrc) { 39*431ea2d0SNick Desaulniers // Set boundary at beginning and end for not overstepping when 40*431ea2d0SNick Desaulniers // copy forward or backward. 41*431ea2d0SNick Desaulniers char Buffer[] = {'z', 'a', 'b', 'c', 'z'}; 42*431ea2d0SNick Desaulniers const char Expected[] = {'z', 'b', 'c', 'c', 'z'}; 43*431ea2d0SNick Desaulniers void *const Dst = Buffer + 1; 44*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(Buffer + 2, Dst, 2); 45*431ea2d0SNick Desaulniers ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected)); 46*431ea2d0SNick Desaulniers } 47*431ea2d0SNick Desaulniers 48*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, DstStartsAfterSrc) { 49*431ea2d0SNick Desaulniers char Buffer[] = {'z', 'a', 'b', 'c', 'z'}; 50*431ea2d0SNick Desaulniers const char Expected[] = {'z', 'a', 'a', 'b', 'z'}; 51*431ea2d0SNick Desaulniers void *const Dst = Buffer + 2; 52*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(Buffer + 1, Dst, 2); 53*431ea2d0SNick Desaulniers ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected)); 54*431ea2d0SNick Desaulniers } 55*431ea2d0SNick Desaulniers 56*431ea2d0SNick Desaulniers // e.g. `Dst` follow `src`. 57*431ea2d0SNick Desaulniers // str: [abcdefghij] 58*431ea2d0SNick Desaulniers // [__src_____] 59*431ea2d0SNick Desaulniers // [_____Dst__] 60*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, SrcFollowDst) { 61*431ea2d0SNick Desaulniers char Buffer[] = {'z', 'a', 'b', 'z'}; 62*431ea2d0SNick Desaulniers const char Expected[] = {'z', 'b', 'b', 'z'}; 63*431ea2d0SNick Desaulniers void *const Dst = Buffer + 1; 64*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(Buffer + 2, Dst, 1); 65*431ea2d0SNick Desaulniers ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected)); 66*431ea2d0SNick Desaulniers } 67*431ea2d0SNick Desaulniers 68*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, DstFollowSrc) { 69*431ea2d0SNick Desaulniers char Buffer[] = {'z', 'a', 'b', 'z'}; 70*431ea2d0SNick Desaulniers const char Expected[] = {'z', 'a', 'a', 'z'}; 71*431ea2d0SNick Desaulniers void *const Dst = Buffer + 2; 72*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(Buffer + 1, Dst, 1); 73*431ea2d0SNick Desaulniers ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected)); 74*431ea2d0SNick Desaulniers } 75*431ea2d0SNick Desaulniers 76*431ea2d0SNick Desaulniers // Adapt CheckMemmove signature to bcopy. 77*431ea2d0SNick Desaulniers static inline void Adaptor(cpp::span<char> dst, cpp::span<char> src, 78*431ea2d0SNick Desaulniers size_t size) { 79*431ea2d0SNick Desaulniers LIBC_NAMESPACE::bcopy(src.begin(), dst.begin(), size); 80*431ea2d0SNick Desaulniers } 81*431ea2d0SNick Desaulniers 82*431ea2d0SNick Desaulniers TEST(LlvmLibcBcopyTest, SizeSweep) { 83*431ea2d0SNick Desaulniers static constexpr int kMaxSize = 400; 84*431ea2d0SNick Desaulniers static constexpr int kDenseOverlap = 15; 85*431ea2d0SNick Desaulniers using LargeBuffer = array<char, 2 * kMaxSize + 1>; 86*431ea2d0SNick Desaulniers LargeBuffer Buffer; 87*431ea2d0SNick Desaulniers Randomize(Buffer); 88*431ea2d0SNick Desaulniers for (int Size = 0; Size < kMaxSize; ++Size) 89*431ea2d0SNick Desaulniers for (int Overlap = -1; Overlap < Size;) { 90*431ea2d0SNick Desaulniers ASSERT_TRUE(CheckMemmove<Adaptor>(Buffer, Size, Overlap)); 91*431ea2d0SNick Desaulniers // Prevent quadratic behavior by skipping offset above kDenseOverlap. 92*431ea2d0SNick Desaulniers if (Overlap > kDenseOverlap) 93*431ea2d0SNick Desaulniers Overlap *= 2; 94*431ea2d0SNick Desaulniers else 95*431ea2d0SNick Desaulniers ++Overlap; 96*431ea2d0SNick Desaulniers } 97*431ea2d0SNick Desaulniers } 98*431ea2d0SNick Desaulniers 99*431ea2d0SNick Desaulniers } // namespace LIBC_NAMESPACE_DECL 100