llvm/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/replace_with_range.pass.cpp

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=10000000
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=70000000

// template<container-compatible-range<charT> R>
//   constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); // C++23

#include <string>
#include <utility>

#include "../../../../containers/sequences/insert_range_sequence_containers.h"
#include "test_macros.h"

template <class Range>
concept HasReplaceWithRange =
    requires(std::string& c, Range&& range) { c.replace_with_range(c.end(), c.end(), std::forward<Range>(range)); };

constexpr bool test_constraints_replace_with_range() {
  // Input range with the same value type.
  static_assert(HasReplaceWithRange<InputRange<char>>);
  // Input range with a convertible value type.
  static_assert(HasReplaceWithRange<InputRange<unsigned char>>);
  // Input range with a non-convertible value type.
  static_assert(!HasReplaceWithRange<InputRange<Empty>>);
  // Not an input range.
  static_assert(!HasReplaceWithRange<InputRangeNotDerivedFrom>);
  static_assert(!HasReplaceWithRange<InputRangeNotIndirectlyReadable>);
  static_assert(!HasReplaceWithRange<InputRangeNotInputOrOutputIterator>);

  return true;
}

using StrBuffer = Buffer<char, 256>;

struct TestCaseReplacement {
  StrBuffer initial;
  std::size_t from = 0;
  std::size_t to   = 0;
  StrBuffer input;
  StrBuffer expected;
};

// Permutation matrix:
// - initial string: empty / one-element / n elements;
// - cut starts from: beginning / middle / end;
// - cut size: empty / one-element / several elements / until the end;
// - input range: empty / one-element / middle-sized / longer than SSO / longer than the current string capacity.

// Empty string.

constexpr TestCaseReplacement EmptyString_End_EmptyCut_EmptyRange{
    .initial = "", .from = 0, .to = 0, .input = "", .expected = ""};

constexpr TestCaseReplacement EmptyString_End_EmptyCut_OneElementRange{
    .initial = "", .from = 0, .to = 0, .input = "a", .expected = "a"};

constexpr TestCaseReplacement EmptyString_End_EmptyCut_MidRange{
    .initial = "", .from = 0, .to = 0, .input = "aeiou", .expected = "aeiou"};

constexpr TestCaseReplacement EmptyString_End_EmptyCut_LongRange{
    .initial  = "",
    .from     = 0,
    .to       = 0,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789"};

// One-element string.

constexpr TestCaseReplacement OneElementString_Begin_EmptyCut_EmptyRange{
    .initial = "B", .from = 0, .to = 0, .input = "", .expected = "B"};

constexpr TestCaseReplacement OneElementString_Begin_EmptyCut_OneElementRange{
    .initial = "B", .from = 0, .to = 0, .input = "a", .expected = "aB"};

constexpr TestCaseReplacement OneElementString_Begin_EmptyCut_MidRange{
    .initial = "B", .from = 0, .to = 0, .input = "aeiou", .expected = "aeiouB"};

constexpr TestCaseReplacement OneElementString_Begin_EmptyCut_LongRange{
    .initial  = "B",
    .from     = 0,
    .to       = 0,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789B"};

constexpr TestCaseReplacement OneElementString_Begin_OneElementCut_EmptyRange{
    .initial = "B", .from = 0, .to = 1, .input = "", .expected = ""};

constexpr TestCaseReplacement OneElementString_Begin_OneElementCut_OneElementRange{
    .initial = "B", .from = 0, .to = 1, .input = "a", .expected = "a"};

constexpr TestCaseReplacement OneElementString_Begin_OneElementCut_MidRange{
    .initial = "B", .from = 0, .to = 1, .input = "aeiou", .expected = "aeiou"};

constexpr TestCaseReplacement OneElementString_Begin_OneElementCut_LongRange{
    .initial  = "B",
    .from     = 0,
    .to       = 1,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789"};

constexpr TestCaseReplacement OneElementString_End_EmptyCut_EmptyRange{
    .initial = "B", .from = 1, .to = 1, .input = "", .expected = "B"};

constexpr TestCaseReplacement OneElementString_End_EmptyCut_OneElementRange{
    .initial = "B", .from = 1, .to = 1, .input = "a", .expected = "Ba"};

constexpr TestCaseReplacement OneElementString_End_EmptyCut_MidRange{
    .initial = "B", .from = 1, .to = 1, .input = "aeiou", .expected = "Baeiou"};

constexpr TestCaseReplacement OneElementString_End_EmptyCut_LongRange{
    .initial  = "B",
    .from     = 1,
    .to       = 1,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "Babcdefghijklmnopqrstuvwxyz0123456789"};

// Short string (using SSO).

// Replace at the beginning.

constexpr TestCaseReplacement ShortString_Begin_EmptyCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 0, .input = "", .expected = "_BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_EmptyCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 0, .input = "a", .expected = "a_BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_EmptyCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 0, .input = "aeiou", .expected = "aeiou_BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_EmptyCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 0,
    .to       = 0,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789_BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_OneElementCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 1, .input = "", .expected = "BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_OneElementCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 1, .input = "a", .expected = "aBCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_OneElementCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 1, .input = "aeiou", .expected = "aeiouBCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_OneElementCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 0,
    .to       = 1,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_MidSizedCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 3, .input = "", .expected = "DFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_MidSizedCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 3, .input = "a", .expected = "aDFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_MidSizedCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 3, .input = "aeiou", .expected = "aeiouDFGHJ_"};

// Note: this test case switches from SSO to non-SSO.
constexpr TestCaseReplacement ShortString_Begin_MidSizedCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 0,
    .to       = 3,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789DFGHJ_"};

constexpr TestCaseReplacement ShortString_Begin_CutToEnd_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 9, .input = "", .expected = ""};

constexpr TestCaseReplacement ShortString_Begin_CutToEnd_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 9, .input = "a", .expected = "a"};

constexpr TestCaseReplacement ShortString_Begin_CutToEnd_MidRange{
    .initial = "_BCDFGHJ_", .from = 0, .to = 9, .input = "aeiou", .expected = "aeiou"};

// Note: this test case switches from SSO to non-SSO.
constexpr TestCaseReplacement ShortString_Begin_CutToEnd_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 0,
    .to       = 9,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789"};

// Replace in the middle.

constexpr TestCaseReplacement ShortString_Mid_EmptyCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 4, .input = "", .expected = "_BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_EmptyCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 4, .input = "a", .expected = "_BCDaFGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_EmptyCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 4, .input = "aeiou", .expected = "_BCDaeiouFGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_EmptyCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 4,
    .to       = 4,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_BCDabcdefghijklmnopqrstuvwxyz0123456789FGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_OneElementCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 5, .input = "", .expected = "_BCDGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_OneElementCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 5, .input = "a", .expected = "_BCDaGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_OneElementCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 5, .input = "aeiou", .expected = "_BCDaeiouGHJ_"};

constexpr TestCaseReplacement ShortString_Mid_OneElementCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 4,
    .to       = 5,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_BCDabcdefghijklmnopqrstuvwxyz0123456789GHJ_"};

constexpr TestCaseReplacement ShortString_Mid_MidSizedCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 7, .input = "", .expected = "_BCDJ_"};

constexpr TestCaseReplacement ShortString_Mid_MidSizedCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 7, .input = "a", .expected = "_BCDaJ_"};

constexpr TestCaseReplacement ShortString_Mid_MidSizedCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 7, .input = "aeiou", .expected = "_BCDaeiouJ_"};

constexpr TestCaseReplacement ShortString_Mid_MidSizedCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 4,
    .to       = 7,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_BCDabcdefghijklmnopqrstuvwxyz0123456789J_"};

constexpr TestCaseReplacement ShortString_Mid_CutToEnd_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 9, .input = "", .expected = "_BCD"};

constexpr TestCaseReplacement ShortString_Mid_CutToEnd_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 9, .input = "a", .expected = "_BCDa"};

constexpr TestCaseReplacement ShortString_Mid_CutToEnd_MidRange{
    .initial = "_BCDFGHJ_", .from = 4, .to = 9, .input = "aeiou", .expected = "_BCDaeiou"};

constexpr TestCaseReplacement ShortString_Mid_CutToEnd_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 4,
    .to       = 9,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_BCDabcdefghijklmnopqrstuvwxyz0123456789"};

// Replace at the end.

constexpr TestCaseReplacement ShortString_End_EmptyCut_EmptyRange{
    .initial = "_BCDFGHJ_", .from = 9, .to = 9, .input = "", .expected = "_BCDFGHJ_"};

constexpr TestCaseReplacement ShortString_End_EmptyCut_OneElementRange{
    .initial = "_BCDFGHJ_", .from = 9, .to = 9, .input = "a", .expected = "_BCDFGHJ_a"};

constexpr TestCaseReplacement ShortString_End_EmptyCut_MidRange{
    .initial = "_BCDFGHJ_", .from = 9, .to = 9, .input = "aeiou", .expected = "_BCDFGHJ_aeiou"};

constexpr TestCaseReplacement ShortString_End_EmptyCut_LongRange{
    .initial  = "_BCDFGHJ_",
    .from     = 9,
    .to       = 9,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_BCDFGHJ_abcdefghijklmnopqrstuvwxyz0123456789"};

// Long string (no SSO).

// Replace at the beginning.

constexpr TestCaseReplacement LongString_Begin_EmptyCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 0,
    .input    = "",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_EmptyCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 0,
    .input    = "a",
    .expected = "a_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_EmptyCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 0,
    .input    = "aeiou",
    .expected = "aeiou_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_EmptyCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 0,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_EmptyCut_LongerThanCapacityRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 0,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789"
                "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_OneElementCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 1,
    .input    = "",
    .expected = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_OneElementCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 1,
    .input    = "a",
    .expected = "aABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_OneElementCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 1,
    .input    = "aeiou",
    .expected = "aeiouABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_OneElementCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 1,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_OneElementCut_LongerThanCapacityRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 1,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_MidSizedCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 3,
    .input    = "",
    .expected = "CDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_MidSizedCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 3,
    .input    = "a",
    .expected = "aCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_MidSizedCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 3,
    .input    = "aeiou",
    .expected = "aeiouCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_MidSizedCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 3,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789CDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_MidSizedCut_LongerThanCapacityRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 3,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789"
                "CDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Begin_CutToEnd_EmptyRange{
    .initial = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", .from = 0, .to = 38, .input = "", .expected = ""};

constexpr TestCaseReplacement LongString_Begin_CutToEnd_OneElementRange{
    .initial = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", .from = 0, .to = 38, .input = "a", .expected = "a"};

constexpr TestCaseReplacement LongString_Begin_CutToEnd_MidRange{
    .initial = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", .from = 0, .to = 38, .input = "aeiou", .expected = "aeiou"};

constexpr TestCaseReplacement LongString_Begin_CutToEnd_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 38,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789"};

constexpr TestCaseReplacement LongString_Begin_CutToEnd_LongerThanCapacityRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 0,
    .to       = 38,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789"};

// Replace in the middle.

constexpr TestCaseReplacement LongString_Mid_EmptyCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 18,
    .input    = "",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_EmptyCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 18,
    .input    = "a",
    .expected = "_ABCDEFGHIJKLMNOPQaRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_EmptyCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 18,
    .input    = "aeiou",
    .expected = "_ABCDEFGHIJKLMNOPQaeiouRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_EmptyCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 18,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQabcdefghijklmnopqrstuvwxyz0123456789RSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_EmptyCut_LongerThanCapacityRange{
    .initial = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from    = 18,
    .to      = 18,
    .input   = "abcdefghijklmnopqrstuvwxyz0123456789_"
               "abcdefghijklmnopqrstuvwxyz0123456789_"
               "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected =
        "_ABCDEFGHIJKLMNOPQ"
        "abcdefghijklmnopqrstuvwxyz0123456789_"
        "abcdefghijklmnopqrstuvwxyz0123456789_"
        "abcdefghijklmnopqrstuvwxyz0123456789"
        "RSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_OneElementCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 19,
    .input    = "",
    .expected = "_ABCDEFGHIJKLMNOPQSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_OneElementCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 19,
    .input    = "a",
    .expected = "_ABCDEFGHIJKLMNOPQaSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_OneElementCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 19,
    .input    = "aeiou",
    .expected = "_ABCDEFGHIJKLMNOPQaeiouSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_OneElementCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 19,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQabcdefghijklmnopqrstuvwxyz0123456789STUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_OneElementCut_LongerThanCapacityRange{
    .initial = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from    = 18,
    .to      = 19,
    .input   = "abcdefghijklmnopqrstuvwxyz0123456789_"
               "abcdefghijklmnopqrstuvwxyz0123456789_"
               "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected =
        "_ABCDEFGHIJKLMNOPQ"
        "abcdefghijklmnopqrstuvwxyz0123456789_"
        "abcdefghijklmnopqrstuvwxyz0123456789_"
        "abcdefghijklmnopqrstuvwxyz0123456789"
        "STUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_MidSizedCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 21,
    .input    = "",
    .expected = "_ABCDEFGHIJKLMNOPQUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_MidSizedCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 21,
    .input    = "a",
    .expected = "_ABCDEFGHIJKLMNOPQaUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_MidSizedCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 21,
    .input    = "aeiou",
    .expected = "_ABCDEFGHIJKLMNOPQaeiouUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_MidSizedCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 21,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQabcdefghijklmnopqrstuvwxyz0123456789UVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_MidSizedCut_LongerThanCapacityRange{
    .initial = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from    = 18,
    .to      = 21,
    .input   = "abcdefghijklmnopqrstuvwxyz0123456789_"
               "abcdefghijklmnopqrstuvwxyz0123456789_"
               "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected =
        "_ABCDEFGHIJKLMNOPQ"
        "abcdefghijklmnopqrstuvwxyz0123456789_"
        "abcdefghijklmnopqrstuvwxyz0123456789_"
        "abcdefghijklmnopqrstuvwxyz0123456789"
        "UVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_Mid_CutToEnd_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 38,
    .input    = "",
    .expected = "_ABCDEFGHIJKLMNOPQ"};

constexpr TestCaseReplacement LongString_Mid_CutToEnd_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 38,
    .input    = "a",
    .expected = "_ABCDEFGHIJKLMNOPQa"};

constexpr TestCaseReplacement LongString_Mid_CutToEnd_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 38,
    .input    = "aeiou",
    .expected = "_ABCDEFGHIJKLMNOPQaeiou"};

constexpr TestCaseReplacement LongString_Mid_CutToEnd_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 38,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQabcdefghijklmnopqrstuvwxyz0123456789"};

constexpr TestCaseReplacement LongString_Mid_CutToEnd_LongerThanCapacityRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 18,
    .to       = 38,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQ"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789"};

// Replace at the end.

constexpr TestCaseReplacement LongString_End_EmptyCut_EmptyRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 38,
    .to       = 38,
    .input    = "",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"};

constexpr TestCaseReplacement LongString_End_EmptyCut_OneElementRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 38,
    .to       = 38,
    .input    = "a",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_a"};

constexpr TestCaseReplacement LongString_End_EmptyCut_MidRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 38,
    .to       = 38,
    .input    = "aeiou",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_aeiou"};

constexpr TestCaseReplacement LongString_End_EmptyCut_LongRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 38,
    .to       = 38,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_abcdefghijklmnopqrstuvwxyz0123456789"};

constexpr TestCaseReplacement LongString_End_EmptyCut_LongerThanCapacityRange{
    .initial  = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
    .from     = 38,
    .to       = 38,
    .input    = "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789",
    .expected = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789_"
                "abcdefghijklmnopqrstuvwxyz0123456789"};

template <class Iter, class Sent, class Alloc>
constexpr void test_string_replace_with_range() {
  auto test = [&](const TestCaseReplacement& test_case) {
    using Container = std::basic_string<char, std::char_traits<char>, Alloc>;

    auto get_pos = [](auto& c, auto index) { return std::ranges::next(c.begin(), index); };
    Container c(test_case.initial.begin(), test_case.initial.end());
    auto in   = wrap_input<Iter, Sent>(test_case.input);
    auto from = get_pos(c, test_case.from);
    auto to   = get_pos(c, test_case.to);

    Container& result = c.replace_with_range(from, to, in);
    assert(&result == &c);
    LIBCPP_ASSERT(c.__invariants());
    return std::ranges::equal(c, test_case.expected);
  };

  { // Empty string.
    // empty_str.replace_with_range(end, end, empty_range)
    assert(test(EmptyString_End_EmptyCut_EmptyRange));
    // empty_str.replace_with_range(end, end, one_element_range)
    assert(test(EmptyString_End_EmptyCut_OneElementRange));
    // empty_str.replace_with_range(end, end, mid_range)
    assert(test(EmptyString_End_EmptyCut_MidRange));
    // empty_str.replace_with_range(end, end, long_range)
    assert(test(EmptyString_End_EmptyCut_LongRange));
  }

  { // One-element string.
    // one_element_str.replace_with_range(begin, begin, empty_range)
    assert(test(OneElementString_Begin_EmptyCut_EmptyRange));
    // one_element_str.replace_with_range(begin, begin, one_element_range)
    assert(test(OneElementString_Begin_EmptyCut_OneElementRange));
    // one_element_str.replace_with_range(begin, begin, mid_range)
    assert(test(OneElementString_Begin_EmptyCut_MidRange));
    // one_element_str.replace_with_range(begin, begin, long_range)
    assert(test(OneElementString_Begin_EmptyCut_LongRange));
    // one_element_str.replace_with_range(begin, begin + 1, empty_range)
    assert(test(OneElementString_Begin_OneElementCut_EmptyRange));
    // one_element_str.replace_with_range(begin, begin + 1, one_element_range)
    assert(test(OneElementString_Begin_OneElementCut_OneElementRange));
    // one_element_str.replace_with_range(begin, begin + 1, mid_range)
    assert(test(OneElementString_Begin_OneElementCut_MidRange));
    // one_element_str.replace_with_range(begin, begin + 1, long_range)
    assert(test(OneElementString_Begin_OneElementCut_LongRange));
    // one_element_str.replace_with_range(end, end, empty_range)
    assert(test(OneElementString_End_EmptyCut_EmptyRange));
    // one_element_str.replace_with_range(end, end, one_element_range)
    assert(test(OneElementString_End_EmptyCut_OneElementRange));
    // one_element_str.replace_with_range(end, end, mid_range)
    assert(test(OneElementString_End_EmptyCut_MidRange));
    // one_element_str.replace_with_range(end, end, long_range)
    assert(test(OneElementString_End_EmptyCut_LongRange));
  }

  { // Short string.
    // Replace at the beginning.

    // short_str.replace_with_range(begin, begin, empty_range)
    assert(test(ShortString_Begin_EmptyCut_EmptyRange));
    // short_str.replace_with_range(begin, begin, one_element_range)
    assert(test(ShortString_Begin_EmptyCut_OneElementRange));
    // short_str.replace_with_range(begin, begin, mid_range)
    assert(test(ShortString_Begin_EmptyCut_MidRange));
    // short_str.replace_with_range(begin, begin, long_range)
    assert(test(ShortString_Begin_EmptyCut_LongRange));
    // short_str.replace_with_range(begin, begin + 1, empty_range)
    assert(test(ShortString_Begin_OneElementCut_EmptyRange));
    // short_str.replace_with_range(begin, begin + 1, one_element_range)
    assert(test(ShortString_Begin_OneElementCut_OneElementRange));
    // short_str.replace_with_range(begin, begin + 1, mid_range)
    assert(test(ShortString_Begin_OneElementCut_MidRange));
    // short_str.replace_with_range(begin, begin + 1, long_range)
    assert(test(ShortString_Begin_OneElementCut_LongRange));
    // short_str.replace_with_range(begin, begin + 3, empty_range)
    assert(test(ShortString_Begin_MidSizedCut_EmptyRange));
    // short_str.replace_with_range(begin, begin + 3, one_element_range)
    assert(test(ShortString_Begin_MidSizedCut_OneElementRange));
    // short_str.replace_with_range(begin, begin + 3, mid_range)
    assert(test(ShortString_Begin_MidSizedCut_MidRange));
    // short_str.replace_with_range(begin, begin + 3, long_range)
    assert(test(ShortString_Begin_MidSizedCut_LongRange));
    // short_str.replace_with_range(begin, end, empty_range)
    assert(test(ShortString_Begin_CutToEnd_EmptyRange));
    // short_str.replace_with_range(begin, end, one_element_range)
    assert(test(ShortString_Begin_CutToEnd_OneElementRange));
    // short_str.replace_with_range(begin, end, mid_range)
    assert(test(ShortString_Begin_CutToEnd_MidRange));
    // short_str.replace_with_range(begin, end, long_range)
    assert(test(ShortString_Begin_CutToEnd_LongRange));

    // Replace in the middle.

    // short_str.replace_with_range(mid, mid, empty_range)
    assert(test(ShortString_Mid_EmptyCut_EmptyRange));
    // short_str.replace_with_range(mid, mid, one_element_range)
    assert(test(ShortString_Mid_EmptyCut_OneElementRange));
    // short_str.replace_with_range(mid, mid, mid_range)
    assert(test(ShortString_Mid_EmptyCut_MidRange));
    // short_str.replace_with_range(mid, mid, long_range)
    assert(test(ShortString_Mid_EmptyCut_LongRange));
    // short_str.replace_with_range(mid, mid + 1, empty_range)
    assert(test(ShortString_Mid_OneElementCut_EmptyRange));
    // short_str.replace_with_range(mid, mid + 1, one_element_range)
    assert(test(ShortString_Mid_OneElementCut_OneElementRange));
    // short_str.replace_with_range(mid, mid + 1, mid_range)
    assert(test(ShortString_Mid_OneElementCut_MidRange));
    // short_str.replace_with_range(mid, mid + 1, long_range)
    assert(test(ShortString_Mid_OneElementCut_LongRange));
    // short_str.replace_with_range(mid, mid + 3, empty_range)
    assert(test(ShortString_Mid_MidSizedCut_EmptyRange));
    // short_str.replace_with_range(mid, mid + 3, one_element_range)
    assert(test(ShortString_Mid_MidSizedCut_OneElementRange));
    // short_str.replace_with_range(mid, mid + 3, mid_range)
    assert(test(ShortString_Mid_MidSizedCut_MidRange));
    // short_str.replace_with_range(mid, mid + 3, long_range)
    assert(test(ShortString_Mid_MidSizedCut_LongRange));
    // short_str.replace_with_range(mid, end, empty_range)
    assert(test(ShortString_Mid_CutToEnd_EmptyRange));
    // short_str.replace_with_range(mid, end, one_element_range)
    assert(test(ShortString_Mid_CutToEnd_OneElementRange));
    // short_str.replace_with_range(mid, end, mid_range)
    assert(test(ShortString_Mid_CutToEnd_MidRange));
    // short_str.replace_with_range(mid, end, long_range)
    assert(test(ShortString_Mid_CutToEnd_LongRange));

    // Replace at the end.

    // short_str.replace_with_range(end, end, empty_range)
    assert(test(ShortString_End_EmptyCut_EmptyRange));
    // short_str.replace_with_range(end, end, one_element_range)
    assert(test(ShortString_End_EmptyCut_OneElementRange));
    // short_str.replace_with_range(end, end, mid_range)
    assert(test(ShortString_End_EmptyCut_MidRange));
    // short_str.replace_with_range(end, end, long_range)
    assert(test(ShortString_End_EmptyCut_LongRange));
  }

  { // Long string.
    // Replace at the beginning.

    // long_str.replace_with_range(begin, begin, empty_range)
    assert(test(LongString_Begin_EmptyCut_EmptyRange));
    // long_str.replace_with_range(begin, begin, one_element_range)
    assert(test(LongString_Begin_EmptyCut_OneElementRange));
    // long_str.replace_with_range(begin, begin, mid_range)
    assert(test(LongString_Begin_EmptyCut_MidRange));
    // long_str.replace_with_range(begin, begin, long_range)
    assert(test(LongString_Begin_EmptyCut_LongRange));
    // long_str.replace_with_range(begin, begin, longer_than_capacity_range)
    assert(test(LongString_Begin_EmptyCut_LongerThanCapacityRange));
    // long_str.replace_with_range(begin, begin + 1, empty_range)
    assert(test(LongString_Begin_OneElementCut_EmptyRange));
    // long_str.replace_with_range(begin, begin + 1, one_element_range)
    assert(test(LongString_Begin_OneElementCut_OneElementRange));
    // long_str.replace_with_range(begin, begin + 1, mid_range)
    assert(test(LongString_Begin_OneElementCut_MidRange));
    // long_str.replace_with_range(begin, begin + 1, long_range)
    assert(test(LongString_Begin_OneElementCut_LongRange));
    // long_str.replace_with_range(begin, begin + 1, longer_than_capacity_range)
    assert(test(LongString_Begin_OneElementCut_LongerThanCapacityRange));
    // long_str.replace_with_range(begin, begin + 3, empty_range)
    assert(test(LongString_Begin_MidSizedCut_EmptyRange));
    // long_str.replace_with_range(begin, begin + 3, one_element_range)
    assert(test(LongString_Begin_MidSizedCut_OneElementRange));
    // long_str.replace_with_range(begin, begin + 3, mid_range)
    assert(test(LongString_Begin_MidSizedCut_MidRange));
    // long_str.replace_with_range(begin, begin + 3, long_range)
    assert(test(LongString_Begin_MidSizedCut_LongRange));
    // long_str.replace_with_range(begin, begin + 3, longer_than_capacity_range)
    assert(test(LongString_Begin_MidSizedCut_LongerThanCapacityRange));
    // long_str.replace_with_range(begin, end, empty_range)
    assert(test(LongString_Begin_CutToEnd_EmptyRange));
    // long_str.replace_with_range(begin, end, one_element_range)
    assert(test(LongString_Begin_CutToEnd_OneElementRange));
    // long_str.replace_with_range(begin, end, mid_range)
    assert(test(LongString_Begin_CutToEnd_MidRange));
    // long_str.replace_with_range(begin, end, long_range)
    assert(test(LongString_Begin_CutToEnd_LongRange));
    // long_str.replace_with_range(begin, end, longer_than_capacity_range)
    assert(test(LongString_Begin_CutToEnd_LongerThanCapacityRange));

    // Replace in the middle.

    // long_str.replace_with_range(mid, mid, empty_range)
    assert(test(LongString_Mid_EmptyCut_EmptyRange));
    // long_str.replace_with_range(mid, mid, one_element_range)
    assert(test(LongString_Mid_EmptyCut_OneElementRange));
    // long_str.replace_with_range(mid, mid, mid_range)
    assert(test(LongString_Mid_EmptyCut_MidRange));
    // long_str.replace_with_range(mid, mid, long_range)
    assert(test(LongString_Mid_EmptyCut_LongRange));
    // long_str.replace_with_range(mid, mid, longer_than_capacity_range)
    assert(test(LongString_Mid_EmptyCut_LongerThanCapacityRange));
    // long_str.replace_with_range(mid, mid + 1, empty_range)
    assert(test(LongString_Mid_OneElementCut_EmptyRange));
    // long_str.replace_with_range(mid, mid + 1, one_element_range)
    assert(test(LongString_Mid_OneElementCut_OneElementRange));
    // long_str.replace_with_range(mid, mid + 1, mid_range)
    assert(test(LongString_Mid_OneElementCut_MidRange));
    // long_str.replace_with_range(mid, mid + 1, long_range)
    assert(test(LongString_Mid_OneElementCut_LongRange));
    // long_str.replace_with_range(mid, mid + 1, longer_than_capacity_range)
    assert(test(LongString_Mid_OneElementCut_LongerThanCapacityRange));
    // long_str.replace_with_range(mid, mid + 3, empty_range)
    assert(test(LongString_Mid_MidSizedCut_EmptyRange));
    // long_str.replace_with_range(mid, mid + 3, one_element_range)
    assert(test(LongString_Mid_MidSizedCut_OneElementRange));
    // long_str.replace_with_range(mid, mid + 3, mid_range)
    assert(test(LongString_Mid_MidSizedCut_MidRange));
    // long_str.replace_with_range(mid, mid + 3, long_range)
    assert(test(LongString_Mid_MidSizedCut_LongRange));
    // long_str.replace_with_range(mid, mid + 3, longer_than_capacity_range)
    assert(test(LongString_Mid_MidSizedCut_LongerThanCapacityRange));
    // long_str.replace_with_range(mid, end, empty_range)
    assert(test(LongString_Mid_CutToEnd_EmptyRange));
    // long_str.replace_with_range(mid, end, one_element_range)
    assert(test(LongString_Mid_CutToEnd_OneElementRange));
    // long_str.replace_with_range(mid, end, mid_range)
    assert(test(LongString_Mid_CutToEnd_MidRange));
    // long_str.replace_with_range(mid, end, long_range)
    assert(test(LongString_Mid_CutToEnd_LongRange));
    // long_str.replace_with_range(mid, end, longer_than_capacity_range)
    assert(test(LongString_Mid_CutToEnd_LongerThanCapacityRange));

    // Replace at the end.

    // long_str.replace_with_range(end, end, empty_range)
    assert(test(LongString_End_EmptyCut_EmptyRange));
    // long_str.replace_with_range(end, end, one_element_range)
    assert(test(LongString_End_EmptyCut_OneElementRange));
    // long_str.replace_with_range(end, end, mid_range)
    assert(test(LongString_End_EmptyCut_MidRange));
    // long_str.replace_with_range(end, end, long_range)
    assert(test(LongString_End_EmptyCut_LongRange));
    // long_str.replace_with_range(end, end, longer_than_capacity_range)
    assert(test(LongString_End_EmptyCut_LongerThanCapacityRange));
  }
}

constexpr void test_string_replace_with_range_rvalue_range() {
  // Make sure that the input range can be passed by both an lvalue and an rvalue reference and regardless of constness.

  { // Lvalue.
    std::string in = "abc";
    std::string c  = "123";
    c.replace_with_range(c.begin(), c.end(), in);
  }

  { // Const lvalue.
    const std::string in = "abc";
    std::string c        = "123";
    c.replace_with_range(c.begin(), c.end(), in);
  }

  { // Rvalue.
    std::string in = "abc";
    std::string c  = "123";
    c.replace_with_range(c.begin(), c.end(), std::move(in));
  }

  { // Const rvalue.
    const std::string in = "abc";
    std::string c        = "123";
    c.replace_with_range(c.begin(), c.end(), std::move(in));
  }
}

constexpr bool test_constexpr() {
  for_all_iterators_and_allocators_constexpr<char, const char*>([]<class Iter, class Sent, class Alloc>() {
    test_string_replace_with_range<Iter, Sent, Alloc>();
  });
  test_string_replace_with_range_rvalue_range();

  return true;
}

// Tested cases:
// - different kinds of replacements (varying the size of the initial string, the cut point and the cut size, and the
//   size of the input range);
// - an exception is thrown when allocating new elements.
int main(int, char**) {
  static_assert(test_constraints_replace_with_range());

  for_all_iterators_and_allocators<char, const char*>([]<class Iter, class Sent, class Alloc>() {
    test_string_replace_with_range<Iter, Sent, Alloc>();
  });
  test_string_replace_with_range_rvalue_range();
  static_assert(test_constexpr());

  // Note: `test_string_replace_with_range_exception_safety_throwing_copy` doesn't apply because copying chars cannot
  // throw.
  {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
    // Note: the input string must be long enough to prevent SSO, otherwise the allocator won't be used.
    std::string in(64, 'a');

    try {
      ThrowingAllocator<char> alloc;

      globalMemCounter.reset();
      std::basic_string<char, std::char_traits<char>, ThrowingAllocator<char>> c(alloc);
      c.replace_with_range(c.end(), c.end(), in);
      assert(false); // The function call above should throw.

    } catch (int) {
      assert(globalMemCounter.new_called == globalMemCounter.delete_called);
    }
#endif
  }

  return 0;
}