Repository: fmtlib/fmt
File: test/format-test.cc (C++)

Code before:
        // 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<char>();
  basic_memory_buffer<char, 5, std_allocator_n> 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<char>();
  basic_memory_buffer<char, 4, std_allocator_n> 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<char>* original_alloc_ptr = buffer.get_allocator().get();
  basic_memory_buffer<char, 4, std_allocator_n> 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<char, 5>& buffer) {
  basic_memory_buffer<char, 5> buffer2;
  buffer2 = std::move(buffer);
  // Move shouldn't destroy the inline content of the first buffer.
  EXPECT_EQ(str, std::string(&buffer[0], buffer.size()));
  EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size()));
  EXPECT_EQ(5u, buffer2.capacity());
}

TEST(memory_buffer_test, move_assignment) {
  basic_memory_buffer<char, 5> buffer;
  const char test[] = "test";
  buffer.append(test, test + 4);
  check_move_assign_buffer("test", buffer);
  // Adding one more character fills the inline buffer, but doesn't cause
  // dynamic allocation.

Review comment (suggestion):
This line highlights another non conformance in `basic_memory_buffer` not covered in #4487: its move ctor should always initialize its `alloc_` from `other.alloc_`. That can be addressed separately, but for the purpose of this test, it's better to create an empty `buffer2` instance, and then move-assign `buffer` to it.

Code after:
        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<char>();
  basic_memory_buffer<char, 5, std_allocator_n> 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<char>();
  basic_memory_buffer<char, 4, std_allocator_n> 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<char>* original_alloc_ptr = buffer.get_allocator().get();
  basic_memory_buffer<char, 4, std_allocator_n> buffer2;
  buffer2 = std::move(buffer);
  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<char, 5>& buffer) {
  basic_memory_buffer<char, 5> buffer2;
  buffer2 = std::move(buffer);
  // Move shouldn't destroy the inline content of the first buffer.
  EXPECT_EQ(str, std::string(&buffer[0], buffer.size()));
  EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size()));
  EXPECT_EQ(5u, buffer2.capacity());
}

TEST(memory_buffer_test, move_assignment) {
  basic_memory_buffer<char, 5> buffer;
  const char test[] = "test";
  buffer.append(test, test + 4);