from терминал import печать
def содержит(что, где, игнорировать_регистр=False):
    # функция проверяет, что хотя бы один элемент из "что" (или вся переменная целиком) содержится хотя бы в одном элементе из "где" (или является частью самой переменной "где")

    # функция возвращает True или False
    # переменные "что" и "где" могут быть двух видов:
        # 1. итерируемые объекты (кортеж или список), всеми элементами которых являются строки (текст)
        # 2. сама переменная может быть строкой (текстом)
        # при нарушении любого из этих пунктов будет вызвана ошибка с описанием проблемы
    # переменная "игнорировать_регистр" может принимать только True, или быть по умолчанию False. При передаче другого типа данных будет вызвана ошибка.
    # при получении в "что" или "где" пустых строк или пустых списков будет возвращаться False
    if type(что) not in [str, list, tuple]:
        ошибка = f'Переменная "что" может быть только текстом, списком или кортежем. По факту у неё тип {type(что)}'
        raise TypeError(печать(ошибка, красный=True, стиль="жч", не_печатать=True))
    if type(где) not in [str, list, tuple]:
        ошибка = f'Переменная "где" может быть только текстом, списком или кортежем. По факту у неё тип {type(где)}'
        raise TypeError(печать(ошибка, красный=True, стиль="жч", не_печатать=True))
    if type(игнорировать_регистр) != bool:
        ошибка = f'Переменная "игнорировать_регистр" может быть только True или False, списком или кортежем. По факту у неё тип {type(игнорировать_регистр)}'
        raise TypeError(печать(ошибка, красный=True, стиль="жч", не_печатать=True))   
    if type(что) != str:
        for элемент in что:
            if type(элемент) != str:
                ошибка = f'В переменной "что" может быть только True или False. По факту у неё тип {type(что)}'
                raise TypeError(печать(ошибка, красный=True, стиль="жч", не_печатать=True))  
    if type(где) != str:
        for элемент in где:
            if type(элемент) != str:
                ошибка = f'В переменной "где" может быть только True или False. По факту у неё тип {type(где)}'
                raise TypeError(печать(ошибка, красный=True, стиль="жч", не_печатать=True))  

    if игнорировать_регистр:
        if type(что) == str:
            что = что.lower()
        else:
            новый_список = []
            for элемент in что:
                новый_список.append(элемент.lower())
            что = новый_список
    if игнорировать_регистр:
        if type(где) == str:
            где = где.lower()
        else:
            новый_список = []
            for элемент in где:
                новый_список.append(элемент.lower())
            гд = новый_список
    if type(что) == type(где) == str:
        if что in где:
            return True
    if type(что) == str and type(где) != str:
        for элемент in где:
            if что in элемент:
                return True
    if type(что) != str and type(где) == str:
        for элемент in что:
            if элемент in где:
                return True
    if type(что) != str and type(где) != str:
        for элемент_что in что:
            for элемент_где in где:
                if элемент_что in элемент_где:
                    return True
            
    return False
    # TDD - Test Driven Development
    # разработка функций после написания тестов к ней
    # согласно этому принципу нужно сначала написать тесты, которые проверят каждый аспект работы функции. каждый раз при доработке этой функции необходимо заново запускать тесты - есть они все пройдены, значит функция точно работает правильно.
    # при разработке тестов недопустимо использование вычисляемых переменных - тестируемая функция принять заранее подготовленные данные, а тест проверяет, согласуется ли её ответ с ожиданием.
    # например, при тестировании функции "сумма" ей в аргументы передаются числа 15 и 10, и сравнивается её ответ с числом 25, а не с вычислением 15 + 10
def тесты():
    пройдено = []
    не_пройдено = []
    def тест(что, где, игнорировать_регистр, ожидаемый_ответ, название_теста):
        try:
            ответ = содержит(что, где, игнорировать_регистр)
            текст_ошибки = None
        except Exception as ошибка:
            текст_ошибки = ошибка
            ответ = "ошибка"
        if ответ == ожидаемый_ответ:
            печать(название_теста, зелёный = True)
            пройдено.append(1)
        else:

            печать(название_теста, красный = True)
            print(f"ожидаемый - {ожидаемый_ответ}")
            print(f"ответ     - {ответ}")
            if текст_ошибки:
                print(текст_ошибки)
            print()
            не_пройдено.append("-")
    
    тест(123, "где", True, "ошибка", "неправильный тип что")
    тест("что", 123, True, "ошибка", "неправильный тип где")
    тест("что", "где", "текст", "ошибка", "неправильный тип регистр - игнорировать регистр")
#    тест("что", "где", True, None, "все типы верны, функция ничего не вернула")
    тест(["текст", "не цифра", 23], "где", False, "ошибка", "в переменной 'что' есть не str")
    тест(
        что="что",
        где=["текст", "не цифра", 23],
        игнорировать_регистр=False,
        ожидаемый_ответ="ошибка",
        название_теста='в переменной "где" есть не str'
    )
    варианты = [
        ["сырники", "кто-то ест Сырники", True, True, "что - строка; где - строка; игн_регистр - True; ответ - True"],
        ["сырники", "кто-то ест грибы", True, False, "что - строка; где - строка; игн_регистр - True; ответ - False"],
        ["Сырники", "кто-то ест Сырники", False, True, "что - строка; где - строка; игн_регистр - False; ответ - True"],
        ["сырники", "кто-то ест Сырники", False, False, "что - строка; где - строка; игн_регистр - False; ответ - False"],
        ["Сырники", ["кто-то ест Сырники", "кто-то ест грибы"], False, True, "что - строка; где - список; игн_регистр - False; ответ - True"],
        ["сырники", ["кто-то ест Сырники", "кто-то ест грибы"], False, False, "что - строка; где - список; игн_регистр - False; ответ - False"],
        ["сырники", ["кто-то ест Сырники", "кто-то ест грибы"], True, True, "что - строка; где - список; игн_регистр - True; ответ - True"],
        ["пряники", ["кто-то ест Сырники", "кто-то ест грибы"], True, False, "что - строка; где - список; игн_регистр - True; ответ - False"],
        [["Грибы", "Сырники"], "Кто-то ест Грибы", False, True, "что - список; где - строка; игн_регистр - False; ответ - True"],
        [["Грибы", "Сырники"], "Кто-то ест грибы", False, False, "что - список; где - строка; игн_регистр - False; ответ - False"],
        [["Грибы", "Сырники"], "Кто-то ест грибы", True, True, "что - список; где - строка; игн_регистр - True; ответ - True"],
        [["Грибы", "Сырники"], "Кто-то ест пряники", True, False, "что - список; где - строка; игн_регистр - True; ответ - False"],
        [["Грибы", "Сырники"], ["кто-то ест Сырники", "кто-то ест Грибы"], False, True, "что - список; где - список; игн_регистр - False; ответ - True"],
        [["Грибы", "Сырники"], ["кто-то ест сырники", "кто-то ест грибы"], False, False, "что - список; где - список; игн_регистр - False; ответ - False"],
        [["Грибы", "Сырники"], ["кто-то ест сырники", "кто-то ест грибы"], True, True, "что - список; где - список; игн_регистр - True; ответ - True"],
        [["Грибы", "Сырники"], ["кто-то ест пряники", "кто-то ест пельмени"], True, False, "что - список; где - список; игн_регистр - True; ответ - False"],
    ]
    for вариант in варианты:
        что, где, игн_регистр, ответ, название = вариант
        тест(что, где, игн_регистр, ответ, название)
    print("---------------------")
    print(f"Всего текста - {len(пройдено) + len(не_пройдено)}")
    print(f"Из них пройдено - {len(пройдено)}")
    print(f"Не пройдено - {len(не_пройдено)}")
тесты()