def test_replace_types_with_user_defined_generic_type_field():  # noqa: C901
    """Test that using user defined generic types as generic model fields are handled correctly."""
    T = TypeVar('T')
    KT = TypeVar('KT')
    VT = TypeVar('VT')

    class CustomCounter(Counter[T]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(Counter[get_args(source_type)[0]]))

    class CustomDefaultDict(defaultdict[KT, VT]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            keys_type, values_type = get_args(source_type)
            return core_schema.no_info_after_validator_function(
                lambda x: cls(x.default_factory, x), handler(defaultdict[keys_type, values_type])
            )

    class CustomDeque(deque[T]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(deque[get_args(source_type)[0]]))

    class CustomDict(dict[KT, VT]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            keys_type, values_type = get_args(source_type)
            return core_schema.no_info_after_validator_function(cls, handler(dict[keys_type, values_type]))

    class CustomFrozenset(frozenset[T]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(frozenset[get_args(source_type)[0]]))

    class CustomIterable(Iterable[T]):
        def __init__(self, iterable):
            self.iterable = iterable

        def __iter__(self):
            return self

        def __next__(self):
            return next(self.iterable)

        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(Iterable[get_args(source_type)[0]]))

    class CustomList(list[T]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(list[get_args(source_type)[0]]))

    class CustomMapping(Mapping[KT, VT]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            keys_type, values_type = get_args(source_type)
            return handler(Mapping[keys_type, values_type])

    class CustomOrderedDict(OrderedDict[KT, VT]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            keys_type, values_type = get_args(source_type)
            return core_schema.no_info_after_validator_function(cls, handler(OrderedDict[keys_type, values_type]))

    class CustomSet(set[T]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(set[get_args(source_type)[0]]))

    class CustomTuple(tuple[T]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(tuple[get_args(source_type)[0]]))

    class CustomLongTuple(tuple[T, VT]):
        @classmethod
        def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
            return core_schema.no_info_after_validator_function(cls, handler(tuple[get_args(source_type)]))

    class Model(BaseModel, Generic[T, KT, VT]):
        counter_field: CustomCounter[T]
        default_dict_field: CustomDefaultDict[KT, VT]
        deque_field: CustomDeque[T]
        dict_field: CustomDict[KT, VT]
        frozenset_field: CustomFrozenset[T]
        iterable_field: CustomIterable[T]
        list_field: CustomList[T]
        mapping_field: CustomMapping[KT, VT]
        ordered_dict_field: CustomOrderedDict[KT, VT]
        set_field: CustomSet[T]
        tuple_field: CustomTuple[T]
        long_tuple_field: CustomLongTuple[T, VT]

    assert replace_types(Model, {T: bool, KT: str, VT: int}) == Model[bool, str, int]
    assert replace_types(Model[T, KT, VT], {T: bool, KT: str, VT: int}) == Model[bool, str, int]
    assert replace_types(Model[T, VT, KT], {T: bool, KT: str, VT: int}) == Model[T, VT, KT][bool, int, str]

    m = Model[bool, str, int](
        counter_field=Counter([True, False]),
        default_dict_field={'a': 1},
        deque_field=[True, False],
        dict_field={'a': 1},
        frozenset_field=frozenset([True, False]),
        iterable_field=[True, False],
        list_field=[True, False],
        mapping_field={'a': 2},
        ordered_dict_field=OrderedDict([('a', 1)]),
        set_field={True, False},
        tuple_field=(True,),
        long_tuple_field=(True, 42),
    )

    # The following assertions are just to document the current behavior, and should
    # be updated if/when we do a better job of respecting the exact annotated type
    assert type(m.counter_field) is CustomCounter
    # assert type(m.default_dict_field) is CustomDefaultDict
    assert type(m.deque_field) is CustomDeque
    assert type(m.dict_field) is CustomDict
    assert type(m.frozenset_field) is CustomFrozenset
    assert type(m.iterable_field) is CustomIterable
    assert type(m.list_field) is CustomList
    assert type(m.mapping_field) is dict  # this is determined in CustomMapping.__get_pydantic_core_schema__
    assert type(m.ordered_dict_field) is CustomOrderedDict
    assert type(m.set_field) is CustomSet
    assert type(m.tuple_field) is CustomTuple
    assert type(m.long_tuple_field) is CustomLongTuple

    assert m.model_dump() == {
        'counter_field': {False: 1, True: 1},
        'default_dict_field': {'a': 1},
        'deque_field': deque([True, False]),
        'dict_field': {'a': 1},
        'frozenset_field': frozenset({False, True}),
        'iterable_field': HasRepr(IsStr(regex=r'SerializationIterator\(index=0, iterator=.*CustomIterable.*')),
        'list_field': [True, False],
        'mapping_field': {'a': 2},
        'ordered_dict_field': {'a': 1},
        'set_field': {False, True},
        'tuple_field': (True,),
        'long_tuple_field': (True, 42),
    }
Test that using user defined generic types as generic model fields are handled correctly.
tests/test_generics.py