diff options
Diffstat (limited to 'tests/string_test.cpp')
-rw-r--r-- | tests/string_test.cpp | 359 |
1 files changed, 236 insertions, 123 deletions
diff --git a/tests/string_test.cpp b/tests/string_test.cpp index f1ac9dd..1d63c76 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -14,15 +14,22 @@ * limitations under the License. */ -#include <gtest/gtest.h> +#define _GNU_SOURCE 1 + +#include <string.h> #include <errno.h> +#include <gtest/gtest.h> #include <malloc.h> #include <math.h> -#include <string.h> #include "buffer_tests.h" +#if defined(__BIONIC__) +#define STRLCPY_SUPPORTED +#define STRLCAT_SUPPORTED +#endif + #define KB 1024 #define SMALL 1*KB #define MEDIUM 4*KB @@ -68,32 +75,38 @@ TEST(string, strerror_concurrent) { ASSERT_STREQ("Unknown error 1001", strerror1001); #else // __BIONIC__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; + GTEST_LOG_(INFO) << "Skipping test, requires a thread safe strerror."; #endif // __BIONIC__ } -TEST(string, strerror_r) { -#if defined(__BIONIC__) // glibc's strerror_r doesn't even have the same signature as the POSIX one. +TEST(string, gnu_strerror_r) { char buf[256]; + // Note that glibc doesn't necessarily write into the buffer. + // Valid. - ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf))); + ASSERT_STREQ("Success", strerror_r(0, buf, sizeof(buf))); +#if defined(__BIONIC__) ASSERT_STREQ("Success", buf); - ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf))); +#endif + ASSERT_STREQ("Operation not permitted", strerror_r(1, buf, sizeof(buf))); +#if defined(__BIONIC__) ASSERT_STREQ("Operation not permitted", buf); +#endif // Invalid. - ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf))); + ASSERT_STREQ("Unknown error -1", strerror_r(-1, buf, sizeof(buf))); ASSERT_STREQ("Unknown error -1", buf); - ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf))); + ASSERT_STREQ("Unknown error 1234", strerror_r(1234, buf, sizeof(buf))); ASSERT_STREQ("Unknown error 1234", buf); // Buffer too small. - ASSERT_EQ(-1, strerror_r(0, buf, 2)); - ASSERT_EQ(ERANGE, errno); -#else // __BIONIC__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif // __BIONIC__ + errno = 0; + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(buf, strerror_r(4567, buf, 2)); + ASSERT_STREQ("U", buf); + // The GNU strerror_r doesn't set errno (the POSIX one sets it to ERANGE). + ASSERT_EQ(0, errno); } TEST(string, strsignal) { @@ -129,8 +142,7 @@ TEST(string, strsignal_concurrent) { ASSERT_STREQ("Unknown signal 1001", strsignal1001); } -// TODO: where did these numbers come from? -#define POS_ITER 10 +// TODO: where did this number come from? #define ITER 500 // For every length we want to test, vary and change alignment @@ -139,8 +151,9 @@ TEST(string, strsignal_concurrent) { // These tests contributed by Intel Corporation. // TODO: make these tests more intention-revealing and less random. template<class Character> -struct StringTestState { - StringTestState(size_t MAX_LEN) : MAX_LEN(MAX_LEN) { +class StringTestState { + public: + StringTestState(size_t MAX_LEN) : MAX_LEN(MAX_LEN), align1_index_(0), align2_index_(0) { int max_alignment = 64; // TODO: fix the tests to not sometimes use twice their specified "MAX_LEN". @@ -159,15 +172,30 @@ struct StringTestState { free(glob_ptr2); } - void NewIteration() { - int alignments[] = { 24, 32, 16, 48, 1, 2, 3, 0, 5, 11 }; - int usable_alignments = 10; - int align1 = alignments[random() % (usable_alignments - 1)]; - int align2 = alignments[random() % (usable_alignments - 1)]; + void BeginIterations() { + align1_index_ = 0; + align2_index_ = 0; + + ResetPointers(); + } + + bool HasNextIteration() { + return (align1_index_ != (alignments_size - 1) || align2_index_ != (alignments_size - 1)); + } + + void NextIteration() { + if (align1_index_ == (alignments_size - 1) && align2_index_ == (alignments_size - 1)) { + return; + } + + if (align1_index_ == (alignments_size - 1)) { + align1_index_ = 0; + align2_index_++; + } else { + align1_index_++; + } - ptr = glob_ptr + align1; - ptr1 = glob_ptr1 + align1; - ptr2 = glob_ptr2 + align2; + ResetPointers(); } const size_t MAX_LEN; @@ -176,7 +204,10 @@ struct StringTestState { size_t len[ITER + 1]; private: + static size_t alignments[]; + static size_t alignments_size; Character *glob_ptr, *glob_ptr1, *glob_ptr2; + size_t align1_index_, align2_index_; // Calculate input lengths and fill state.len with them. // Test small lengths with more density than big ones. Manually push @@ -193,19 +224,33 @@ struct StringTestState { } len[n++] = MAX_LEN; } + + void ResetPointers() { + if (align1_index_ == alignments_size || align2_index_ == alignments_size) { + ptr = ptr1 = ptr2 = nullptr; + } else { + ptr = glob_ptr + alignments[align1_index_]; + ptr1 = glob_ptr1 + alignments[align1_index_]; + ptr2 = glob_ptr2 + alignments[align2_index_]; + } + } }; +template<class Character> +size_t StringTestState<Character>::alignments[] = { 24, 32, 16, 48, 0, 1, 2, 3, 4, 5, 6, 7, 11 }; + +template<class Character> +size_t StringTestState<Character>::alignments_size = sizeof(alignments)/sizeof(size_t); + TEST(string, strcat) { StringTestState<char> state(SMALL); for (size_t i = 1; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr2, '\2', state.MAX_LEN); state.ptr2[state.MAX_LEN - 1] = '\0'; memcpy(state.ptr, state.ptr2, 2 * state.MAX_LEN); - memset(state.ptr1, random() & 255, state.len[i]); + memset(state.ptr1, 'L', state.len[i]); state.ptr1[random() % state.len[i]] = '\0'; state.ptr1[state.len[i] - 1] = '\0'; @@ -378,13 +423,11 @@ TEST(string, strchr_multiple) { } TEST(string, strchr) { - int seek_char = random() & 255; + int seek_char = 'R'; StringTestState<char> state(SMALL); for (size_t i = 1; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { if (~seek_char > 0) { memset(state.ptr1, ~seek_char, state.len[i]); } else { @@ -413,9 +456,7 @@ TEST(string, strchr) { TEST(string, strcmp) { StringTestState<char> state(SMALL); for (size_t i = 1; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr1, 'v', state.MAX_LEN); memset(state.ptr2, 'n', state.MAX_LEN); state.ptr1[state.len[i] - 1] = '\0'; @@ -449,9 +490,7 @@ TEST(string, strcmp) { TEST(string, stpcpy) { StringTestState<char> state(SMALL); - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { size_t pos = random() % state.MAX_LEN; memset(state.ptr1, '\2', pos); @@ -475,9 +514,7 @@ TEST(string, stpcpy) { TEST(string, strcpy) { StringTestState<char> state(SMALL); - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { size_t pos = random() % state.MAX_LEN; memset(state.ptr1, '\2', pos); @@ -500,12 +537,10 @@ TEST(string, strcpy) { } TEST(string, strlcat) { -#if defined(__BIONIC__) +#if defined(STRLCAT_SUPPORTED) StringTestState<char> state(SMALL); for (size_t i = 0; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr2, '\2', state.MAX_LEN + state.len[i]); state.ptr2[state.MAX_LEN - 1] = '\0'; memcpy(state.ptr, state.ptr2, state.MAX_LEN + state.len[i]); @@ -525,21 +560,16 @@ TEST(string, strlcat) { ASSERT_TRUE(memcmp(state.ptr, state.ptr2, state.MAX_LEN + state.len[i]) == 0); } } -#else // __BIONIC__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif // __BIONIC__ +#else + GTEST_LOG_(INFO) << "Skipping test, strlcat not supported on this platform."; +#endif } TEST(string, strlcpy) { -#if defined(__BIONIC__) +#if defined(STRLCPY_SUPPORTED) StringTestState<char> state(SMALL); - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - - int rand = random() & 255; - if (rand < 1) { - rand = 1; - } + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { + int rand = 'O'; memset(state.ptr1, rand, state.MAX_LEN); size_t pos = random() % state.MAX_LEN; @@ -548,7 +578,7 @@ TEST(string, strlcpy) { } memcpy(state.ptr, state.ptr1, state.MAX_LEN); - memset(state.ptr2, random() & 255, state.MAX_LEN); + memset(state.ptr2, 'I', state.MAX_LEN); memcpy(state.ptr + state.MAX_LEN, state.ptr2, state.MAX_LEN); if (pos > state.MAX_LEN - 1) { @@ -562,22 +592,20 @@ TEST(string, strlcpy) { ASSERT_FALSE((memcmp(state.ptr1, state.ptr, state.MAX_LEN) != 0) || (memcmp(state.ptr2, state.ptr + state.MAX_LEN, state.MAX_LEN) != 0)); } -#else // __BIONIC__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif // __BIONIC__ +#else + GTEST_LOG_(INFO) << "Skipping test, strlcpy not supported on this platform."; +#endif } TEST(string, strncat) { StringTestState<char> state(SMALL); for (size_t i = 1; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr2, '\2', state.MAX_LEN); state.ptr2[state.MAX_LEN - 1] = '\0'; memcpy(state.ptr, state.ptr2, 2 * state.MAX_LEN); - memset(state.ptr1, random() & 255, state.len[i]); + memset(state.ptr1, 'I', state.len[i]); state.ptr1[random() % state.len[i]] = '\0'; state.ptr1[state.len[i] - 1] = '\0'; @@ -596,9 +624,7 @@ TEST(string, strncat) { TEST(string, strncmp) { StringTestState<char> state(SMALL); for (size_t i = 1; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr1, 'v', state.MAX_LEN); memset(state.ptr2, 'n', state.MAX_LEN); state.ptr1[state.len[i] - 1] = '\0'; @@ -632,12 +658,8 @@ TEST(string, strncmp) { TEST(string, stpncpy) { StringTestState<char> state(SMALL); - for (size_t j = 0; j < ITER; j++) { - state.NewIteration(); - - // Choose a random value to fill the string, except \0 (string terminator), - // or \1 (guarantees it's different from anything in ptr2). - memset(state.ptr1, (random() % 254) + 2, state.MAX_LEN); + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { + memset(state.ptr1, 'J', state.MAX_LEN); // Choose a random size for our src buffer. size_t ptr1_len = random() % state.MAX_LEN; state.ptr1[ptr1_len] = '\0'; @@ -671,12 +693,10 @@ TEST(string, stpncpy) { TEST(string, strncpy) { StringTestState<char> state(SMALL); - for (size_t j = 0; j < ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { // Choose a random value to fill the string, except \0 (string terminator), // or \1 (guarantees it's different from anything in ptr2). - memset(state.ptr1, (random() % 254) + 2, state.MAX_LEN); + memset(state.ptr1, 'K', state.MAX_LEN); // Choose a random size for our src buffer. size_t ptr1_len = random() % state.MAX_LEN; state.ptr1[ptr1_len] = '\0'; @@ -709,12 +729,10 @@ TEST(string, strncpy) { } TEST(string, strrchr) { - int seek_char = random() & 255; + int seek_char = 'M'; StringTestState<char> state(SMALL); for (size_t i = 1; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { if (~seek_char > 0) { memset(state.ptr1, ~seek_char, state.len[i]); } else { @@ -741,12 +759,10 @@ TEST(string, strrchr) { } TEST(string, memchr) { - int seek_char = random() & 255; + int seek_char = 'N'; StringTestState<char> state(SMALL); for (size_t i = 0; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr1, ~seek_char, state.len[i]); size_t pos = random() % state.MAX_LEN; @@ -772,12 +788,10 @@ TEST(string, memchr_zero) { } TEST(string, memrchr) { - int seek_char = random() & 255; + int seek_char = 'P'; StringTestState<char> state(SMALL); for (size_t i = 0; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr1, ~seek_char, state.len[i]); size_t pos = random() % state.MAX_LEN; @@ -797,11 +811,9 @@ TEST(string, memrchr) { TEST(string, memcmp) { StringTestState<char> state(SMALL); for (size_t i = 0; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - - int c1 = random() & 0xff; - int c2 = random() & 0xff; + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { + int c1 = 'A'; + int c2 = 'N'; memset(state.ptr1, c1, state.MAX_LEN); memset(state.ptr2, c1, state.MAX_LEN); @@ -820,9 +832,7 @@ TEST(string, wmemcmp) { StringTestState<wchar_t> state(SMALL); for (size_t i = 0; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { long long mask = ((long long) 1 << 8 * sizeof(wchar_t)) - 1; int c1 = rand() & mask; int c2 = rand() & mask; @@ -842,11 +852,9 @@ TEST(string, wmemcmp) { TEST(string, memcpy) { StringTestState<char> state(LARGE); - int rand = random() & 255; + int rand = 4; for (size_t i = 0; i < state.n - 1; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { size_t pos = random() % (state.MAX_LEN - state.len[i]); memset(state.ptr1, rand, state.len[i]); @@ -864,11 +872,9 @@ TEST(string, memcpy) { TEST(string, memset) { StringTestState<char> state(LARGE); - char ch = random () & 255; + char ch = 'P'; for (size_t i = 0; i < state.n - 1; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { memset(state.ptr1, ~ch, state.MAX_LEN); memcpy(state.ptr2, state.ptr1, state.MAX_LEN); @@ -887,14 +893,12 @@ TEST(string, memset) { TEST(string, memmove) { StringTestState<char> state(LARGE); for (size_t i = 0; i < state.n - 1; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - - memset(state.ptr1, random() & 255, 2 * state.MAX_LEN); + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { + memset(state.ptr1, 'Q', 2 * state.MAX_LEN); size_t pos = random() % (state.MAX_LEN - state.len[i]); - memset(state.ptr1, random() & 255, state.len[i]); + memset(state.ptr1, 'R', state.len[i]); memcpy(state.ptr2, state.ptr1, 2 * state.MAX_LEN); memcpy(state.ptr, state.ptr1, state.len[i]); memcpy(state.ptr1 + pos, state.ptr, state.len[i]); @@ -920,8 +924,8 @@ TEST(string, memmove_cache_size) { for (int i = 0; i < 5; i++) { char* ptr2 = glob_ptr2 + alignments[i]; - memset(ptr1, random() & 255, 2 * len); - memset(ptr1, random() & 255, len); + memset(ptr1, 'S', 2 * len); + memset(ptr1, 'T', len); memcpy(ptr2, ptr1, 2 * len); memcpy(ptr, ptr1, len); memcpy(ptr1 + pos, ptr, len); @@ -987,11 +991,9 @@ TEST(string, memmove_check) { TEST(string, bcopy) { StringTestState<char> state(LARGE); for (size_t i = 0; i < state.n; i++) { - for (size_t j = 0; j < POS_ITER; j++) { - state.NewIteration(); - - memset(state.ptr1, random() & 255, state.MAX_LEN); - memset(state.ptr1 + state.MAX_LEN, random() & 255, state.MAX_LEN); + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { + memset(state.ptr1, '4', state.MAX_LEN); + memset(state.ptr1 + state.MAX_LEN, 'a', state.MAX_LEN); memcpy(state.ptr2, state.ptr1, 2 * state.MAX_LEN); size_t start = random() % (2 * state.MAX_LEN - state.len[i]); @@ -1005,10 +1007,8 @@ TEST(string, bcopy) { TEST(string, bzero) { StringTestState<char> state(LARGE); - for (size_t j = 0; j < ITER; j++) { - state.NewIteration(); - - memset(state.ptr1, random() & 255, state.MAX_LEN); + for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) { + memset(state.ptr1, 'R', state.MAX_LEN); size_t start = random() % state.MAX_LEN; size_t end = start + random() % (state.MAX_LEN - start); @@ -1105,6 +1105,36 @@ TEST(string, strcpy_overread) { RunSrcDstBufferOverreadTest(DoStrcpyTest); } +#if defined(STRLCPY_SUPPORTED) +static void DoStrlcpyTest(uint8_t* src, uint8_t* dst, size_t len) { + if (len >= 1) { + memset(src, (32 + (len % 96)), len - 1); + src[len-1] = '\0'; + memset(dst, 0, len); + ASSERT_EQ(len-1, strlcpy(reinterpret_cast<char*>(dst), + reinterpret_cast<char*>(src), len)); + ASSERT_TRUE(memcmp(src, dst, len) == 0); + } +} +#endif + +TEST(string, strlcpy_align) { +#if defined(STRLCPY_SUPPORTED) + RunSrcDstBufferAlignTest(LARGE, DoStrlcpyTest); +#else + GTEST_LOG_(INFO) << "Skipping test, strlcpy not supported on this platform."; +#endif +} + +TEST(string, strlcpy_overread) { +#if defined(STRLCPY_SUPPORTED) + RunSrcDstBufferOverreadTest(DoStrlcpyTest); +#else + GTEST_LOG_(INFO) << "Skipping test, strlcpy not supported on this platform."; +#endif +} + + static void DoStpcpyTest(uint8_t* src, uint8_t* dst, size_t len) { if (len >= 1) { memset(src, (32 + (len % 96)), len - 1); @@ -1177,6 +1207,55 @@ TEST(string, strcat_overread) { RunSrcDstBufferOverreadTest(DoStrcatTest); } +#if defined(STRLCAT_SUPPORTED) +static void DoStrlcatTest(uint8_t* src, uint8_t* dst, size_t len) { + if (len >= 1) { + int value = 32 + (len % 96); + memset(src, value, len - 1); + src[len-1] = '\0'; + + if (len >= STRCAT_DST_LEN) { + // Create a small buffer for doing quick compares in each loop. + uint8_t cmp_buf[STRCAT_DST_LEN]; + // Make sure dst string contains a different value then the src string. + int value2 = 32 + (value + 2) % 96; + memset(cmp_buf, value2, sizeof(cmp_buf)); + + for (size_t i = 1; i <= STRCAT_DST_LEN; i++) { + memset(dst, value2, i-1); + memset(dst+i-1, 0, len-i); + src[len-i] = '\0'; + ASSERT_EQ(len-1, strlcat(reinterpret_cast<char*>(dst), + reinterpret_cast<char*>(src), len)); + ASSERT_TRUE(memcmp(dst, cmp_buf, i-1) == 0); + ASSERT_TRUE(memcmp(src, dst+i-1, len-i+1) == 0); + } + } else { + dst[0] = '\0'; + ASSERT_EQ(len-1, strlcat(reinterpret_cast<char*>(dst), + reinterpret_cast<char*>(src), len)); + ASSERT_TRUE(memcmp(src, dst, len) == 0); + } + } +} +#endif + +TEST(string, strlcat_align) { +#if defined(STRLCAT_SUPPORTED) + RunSrcDstBufferAlignTest(MEDIUM, DoStrlcatTest, LargeSetIncrement); +#else + GTEST_LOG_(INFO) << "Skipping test, strlcat not supported on this platform."; +#endif +} + +TEST(string, strlcat_overread) { +#if defined(STRLCAT_SUPPORTED) + RunSrcDstBufferOverreadTest(DoStrlcatTest); +#else + GTEST_LOG_(INFO) << "Skipping test, strlcat not supported on this platform."; +#endif +} + static void DoStrcmpTest(uint8_t* buf1, uint8_t* buf2, size_t len) { if (len >= 1) { memset(buf1, (32 + (len % 96)), len - 1); @@ -1287,3 +1366,37 @@ TEST(string, strchr_align) { TEST(string, strchr_overread) { RunSingleBufferOverreadTest(DoStrchrTest); } + +static void TestBasename(const char* in, const char* expected_out) { + errno = 0; + const char* out = basename(in); + ASSERT_STREQ(expected_out, out) << in; + ASSERT_EQ(0, errno) << in; +} + +TEST(string, __gnu_basename) { + TestBasename("", ""); + TestBasename("/usr/lib", "lib"); + TestBasename("/usr/", ""); + TestBasename("usr", "usr"); + TestBasename("/", ""); + TestBasename(".", "."); + TestBasename("..", ".."); + TestBasename("///", ""); + TestBasename("//usr//lib//", ""); +} + +TEST(string, strnlen_147048) { + // https://code.google.com/p/android/issues/detail?id=147048 + char stack_src[64] = {0}; + EXPECT_EQ(0U, strnlen(stack_src, 1024*1024*1024)); + char* heap_src = new char[1]; + *heap_src = '\0'; + EXPECT_EQ(0U, strnlen(heap_src, 1024*1024*1024)); + delete[] heap_src; +} + +TEST(string, mempcpy) { + char dst[6]; + ASSERT_EQ(&dst[4], reinterpret_cast<char*>(mempcpy(dst, "hello", 4))); +} |