diff --git a/test/format-test.cc b/test/format-test.cc index a303cf0d..17432e2f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -307,7 +307,7 @@ TEST(memory_buffer_test, ctor) { EXPECT_EQ(123u, buffer.capacity()); } -using std_allocator = allocator_ref>; +using std_allocator = allocator_ref, true>; TEST(memory_buffer_test, move_ctor_inline_buffer) { auto check_move_buffer = @@ -351,6 +351,53 @@ TEST(memory_buffer_test, move_ctor_dynamic_buffer) { EXPECT_GT(buffer2.capacity(), 4u); } +using std_allocator_n = allocator_ref, false>; + +TEST(memory_buffer_test, move_ctor_inline_buffer_non_propagating) { + auto check_move_buffer = + [](const char* str, + basic_memory_buffer& buffer) { + std::allocator* original_alloc_ptr = buffer.get_allocator().get(); + basic_memory_buffer buffer2( + std::move(buffer)); + EXPECT_EQ(str, std::string(&buffer[0], buffer.size())); + EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size())); + EXPECT_EQ(5u, buffer2.capacity()); + // Allocators should NOT be transferred; they remain distinct instances. + // The original buffer's allocator pointer should still be valid (not + // nullptr). + EXPECT_EQ(original_alloc_ptr, buffer.get_allocator().get()); + EXPECT_NE(original_alloc_ptr, buffer2.get_allocator().get()); + }; + auto alloc = std::allocator(); + basic_memory_buffer buffer( + (std_allocator_n(&alloc))); + const char test[] = "test"; + buffer.append(string_view(test, 4)); + check_move_buffer("test", buffer); + buffer.push_back('a'); + check_move_buffer("testa", buffer); +} + +TEST(memory_buffer_test, move_ctor_dynamic_buffer_non_propagating) { + auto alloc = std::allocator(); + basic_memory_buffer buffer( + (std_allocator_n(&alloc))); + const char test[] = "test"; + buffer.append(test, test + 4); + const char* inline_buffer_ptr = &buffer[0]; + buffer.push_back('a'); + EXPECT_NE(&buffer[0], inline_buffer_ptr); + std::allocator* original_alloc_ptr = buffer.get_allocator().get(); + basic_memory_buffer buffer2(std::move(buffer)); + EXPECT_EQ(buffer.size(), 0); + EXPECT_EQ(std::string(&buffer2[0], buffer2.size()), "testa"); + EXPECT_GT(buffer2.capacity(), 4u); + EXPECT_NE(&buffer2[0], inline_buffer_ptr); + EXPECT_EQ(original_alloc_ptr, buffer.get_allocator().get()); + EXPECT_NE(original_alloc_ptr, buffer2.get_allocator().get()); +} + void check_move_assign_buffer(const char* str, basic_memory_buffer& buffer) { basic_memory_buffer buffer2; diff --git a/test/mock-allocator.h b/test/mock-allocator.h index 168d02a6..bcec3a2c 100644 --- a/test/mock-allocator.h +++ b/test/mock-allocator.h @@ -37,7 +37,8 @@ template class mock_allocator { MOCK_METHOD(void, deallocate, (T*, size_t)); }; -template class allocator_ref { +template +class allocator_ref { private: Allocator* alloc_; @@ -48,6 +49,9 @@ template class allocator_ref { public: using value_type = typename Allocator::value_type; + using propagate_on_container_move_assignment = + typename std::conditional::type; explicit allocator_ref(Allocator* alloc = nullptr) : alloc_(alloc) {} @@ -73,14 +77,16 @@ template class allocator_ref { } void deallocate(value_type* p, size_t n) { alloc_->deallocate(p, n); } - friend bool operator==(const allocator_ref& a, const allocator_ref& b) noexcept { + friend bool operator==(const allocator_ref& a, + const allocator_ref& b) noexcept { if (a.alloc_ == b.alloc_) return true; if (a.alloc_ == nullptr || b.alloc_ == nullptr) return false; - return *a.alloc_ == *b.alloc_; + return *a.alloc_ == *b.alloc_; } - friend bool operator!=(const allocator_ref& a, const allocator_ref& b) noexcept { + friend bool operator!=(const allocator_ref& a, + const allocator_ref& b) noexcept { return !(a == b); } };