Repository: andreypomortsev/yndx-python-handbook

Issue:
Feature: Add 5 solutions for 3.5 P-T
Выложить решения для задач P,Q,R,S,T параграфа 3.5
Покрыть тестами 100% решений, обновить README.md.
Добавить шаблон с названиями задач, ссылками на будущие файлы решений и тестов для 3.5 в README.md

Hints from issue comments:

Solution patch:
diff --git a/README.md b/README.md
index 899a3d9c..62f37030 100644
--- a/README.md
+++ b/README.md
@@ -467,11 +467,33 @@ def main():
 | M. [Обновление данных](./solutions/3.5/35_m.py) | [✅](./tests/3.5/test_35_m.py) |
 | N. [Слияние данных](./solutions/3.5/35_n.py) | [✅](./tests/3.5/test_35_n.py) |
 | O. [Поставь себя на моё место](./solutions/3.5/35_o.py) | [✅](./tests/3.5/test_35_o.py) |
-| P. [Найдётся всё 3.0](./solutions/3.5/35_p.py) | [❌](./tests/3.5/test_35_p.py) |
-| Q. [Прятки](./solutions/3.5/35_q.py) | [❌](./tests/3.5/test_35_q.py) |
-| R. [Сколько вешать в байтах?](./solutions/3.5/35_r.py) | [❌](./tests/3.5/test_35_r.py) |
-| S. [Это будет наш секрет](./solutions/3.5/35_s.py) | [❌](./tests/3.5/test_35_s.py) |
-| T. [Файловая сумма](./solutions/3.5/35_t.py) | [❌](./tests/3.5/test_35_t.py) |
+| P. [Найдётся всё 3.0](./solutions/3.5/35_p.py) | [✅](./tests/3.5/test_35_p.py) |
+| Q. [Прятки](./solutions/3.5/35_q.py) | [✅](./tests/3.5/test_35_q.py) |
+| R. [Сколько вешать в байтах?](./solutions/3.5/35_r.py) | [✅](./tests/3.5/test_35_r.py) |
+| S. [Это будет наш секрет](./solutions/3.5/35_s.py) | [✅](./tests/3.5/test_35_s.py) |
+| T. [Файловая сумма](./solutions/3.5/35_t.py) | [✅](./tests/3.5/test_35_t.py) |
+
+</details>
+
+<details>
+<summary><h3>4.1 Функции. Области видимости. Передача параметров в функции</h3></summary>
+
+- [4.1 Функции. Области видимости. Передача параметров в функции](https://education.yandex.ru/handbook/python/article/funkcii-oblasti-vidimosti-peredacha-parametrov-v-funkcii)
+
+### [Тестовые данные для задач](./tests/data/test_data_41.py)
+
+| Решение              | Тесты                |
+|----------------------|----------------------|
+| А. [Функциональное приветствие](./solutions/4.1/41_a.py) | [❌](./tests/4.1/test_41_a.py) |
+| B. [Функциональный НОД](./solutions/4.1/41_b.py) | [❌](./tests/4.1/test_41_b.py) |
+| C. [Длина числа](./solutions/4.1/41_c.py) | [❌](./tests/4.1/test_41_c.py) |
+| D. [Имя of the month](./solutions/4.1/41_d.py) | [❌](./tests/4.1/test_41_d.py) |
+| E. [Числовая строка](./solutions/4.1/41_e.py) | [❌](./tests/4.1/test_41_e.py) |
+| F. [Модернизация системы вывода](./solutions/4.1/41_f.py) | [❌](./tests/4.1/test_41_f.py) |
+| G. [Шахматный «обед»](./solutions/4.1/41_g.py) | [❌](./tests/4.1/test_41_g.py) |
+| H. [А роза упала на лапу Азора 7.0](./solutions/4.1/41_h.py) | [❌](./tests/4.1/test_41_h.py) |
+| I. [Простая задача 5.0](./solutions/4.1/41_i.py) | [❌](./tests/4.1/test_41_i.py) |
+| J. [Слияние](./solutions/4.1/41_j.py) | [❌](./tests/4.1/test_41_j.py) |
 
 </details>
 
@@ -481,4 +503,4 @@ def main():
 
 ### Зачем мне это?
 
-Для помощи начинающим разработчикам в решении задач учебника и пояснения логики этих решений, для некоторых заданий она не очевидна.
+Для помощи начинающим разработчикам в решении задач учебника и пояснения логики этих решений, для некоторых заданий она не очевидна, некоторые тесты Яндекса не полностью покрывают решения - пропуская не до конца корректные. А так же показать как примерно выглядят тесты для этих задач и тестовые данные для них.
diff --git a/fileTest.sh b/fileTest.sh
index c711895c..d62c5984 100755
--- a/fileTest.sh
+++ b/fileTest.sh
@@ -1,12 +1,12 @@
 #!/bin/sh
 
 # Делим аргумент (e.g., '2.1-a') на номер папки '2.1'
-DIR=$(echo $1 | cut -d'-' -f1)
+DIR=$(echo "$1" | cut -d'-' -f1)
 # И номер теста 'a', переводя букву в нижний регистр
-FILE=$(echo $1 | cut -d'-' -f2 | tr '[:upper:]' '[:lower:]')
+FILE=$(echo "$1" | cut -d'-' -f2 | tr '[:upper:]' '[:lower:]')
 
 # Убираем точку 'DIR' ('2.1' -> '21')
-DIR_NO_DOT=$(echo $DIR | sed 's/\.//g')
+DIR_NO_DOT=$(echo "$DIR" | sed 's/\.//g')
 
 # Запускаем pytest на выбранном файле
-pytest tests/$DIR/test_${DIR_NO_DOT}_$FILE.py
+pytest "tests/$DIR/test_${DIR_NO_DOT}_$FILE.py"
diff --git a/pytest.ini b/pytest.ini
index 052d3f59..3e360ca0 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,5 +1,5 @@
 [pytest]
-addopts = --disable-warnings --cov-config=.coveragerc --cov --spec
+addopts = --maxfail=3 --disable-warnings --cov-config=.coveragerc --cov --spec
 python_paths = .
 python_files = test_*.py
 python_classes = Test*
diff --git a/solutions/3.5/35_p.py b/solutions/3.5/35_p.py
new file mode 100644
index 00000000..ea1d890c
--- /dev/null
+++ b/solutions/3.5/35_p.py
@@ -0,0 +1,26 @@
+from sys import stdin
+
+searching_phrase = input().lower()
+
+files_with_the_phrase = []
+flag = True
+
+for file_name in stdin:
+    file_name = file_name.rstrip("\n")
+
+    with open(file_name, "r", encoding="UTF-8") as file:
+        clean_list = []
+
+        while line := file.readline():
+            clean_line = " ".join(line.replace("&nbsp;", " ").split())
+            if clean_line:
+                clean_list.append(clean_line)
+
+    clean_text = " ".join(clean_list).lower()
+
+    if searching_phrase in clean_text:
+        print(file_name)
+        flag = False
+
+if flag:
+    print("404. Not Found")
diff --git a/solutions/3.5/35_q.py b/solutions/3.5/35_q.py
new file mode 100644
index 00000000..900ae298
--- /dev/null
+++ b/solutions/3.5/35_q.py
@@ -0,0 +1,17 @@
+with open("secret.txt", "r", encoding="UTF-8") as file:
+    while line := file.readline():
+        hidden_word = []
+
+        for char in line:
+            code_point = ord(char)
+
+            if code_point < 128:
+                hidden_word.append(char)
+            else:
+                # Приемняем маску для получения младшего байта
+                # Тот же эффект даст: code_point % 256
+                lower_byte = code_point & 0xFF
+                hidden_char = chr(lower_byte)
+                hidden_word.append(hidden_char)
+
+        print("".join(hidden_word), end="")
diff --git a/solutions/3.5/35_r.py b/solutions/3.5/35_r.py
new file mode 100644
index 00000000..e1587959
--- /dev/null
+++ b/solutions/3.5/35_r.py
@@ -0,0 +1,16 @@
+import os
+
+file_name = input()
+file_size = os.path.getsize(file_name)
+
+UNITS = ("Б", "КБ", "МБ", "ГБ")
+unit_index = 0
+
+while file_size >= 1024 and unit_index < 3:
+    file_size /= 1024
+    unit_index += 1
+
+if file_size > int(file_size):
+    file_size = int((file_size + 1) // 1)
+
+print(f"{file_size:.0f}{UNITS[unit_index]}")
diff --git a/solutions/3.5/35_s.py b/solutions/3.5/35_s.py
new file mode 100644
index 00000000..f8f06653
--- /dev/null
+++ b/solutions/3.5/35_s.py
@@ -0,0 +1,30 @@
+LENGTH = 26  # Длина английского алфавита
+ENGLISH_Z = ord("z")  # 122
+
+shift = int(input()) % LENGTH
+
+with (
+    open("public.txt", "r", encoding="UTF-8") as file_in,
+    open("private.txt", "w", encoding="UTF-8") as file_out,
+):
+    while line := file_in.readline():
+        encrypted_line = []
+
+        for char in line:
+            if char.isalpha():
+                code_point = ord(char.lower())
+                shifted_code_point = code_point + shift
+
+                if shifted_code_point > ENGLISH_Z:
+                    shifted_code_point -= LENGTH
+
+                new_char = chr(shifted_code_point)
+
+                if char.isupper():
+                    new_char = new_char.upper()
+            else:
+                new_char = char
+
+            encrypted_line.append(new_char)
+
+        file_out.write("".join(encrypted_line))
diff --git a/solutions/3.5/35_t.py b/solutions/3.5/35_t.py
new file mode 100644
index 00000000..339909c3
--- /dev/null
+++ b/solutions/3.5/35_t.py
@@ -0,0 +1,10 @@
+CHUNK_SIZE = 4096
+sum_of_numbers = 0
+
+with open("numbers.num", "rb") as file:
+    while chunk := file.read(CHUNK_SIZE):
+        for i in range(0, len(chunk) - 1, 2):
+            two_bytes = chunk[i: i + 2]  # noqa E201
+            sum_of_numbers += int.from_bytes(two_bytes, byteorder="big")
+
+print(sum_of_numbers & 0xFFFF)


Test patch:
diff --git a/tests/3.5/test_35_f.py b/tests/3.5/test_35_f.py
index 8f65a96f..99e692a5 100644
--- a/tests/3.5/test_35_f.py
+++ b/tests/3.5/test_35_f.py
@@ -1,6 +1,6 @@
 import os
 from types import ModuleType
-from typing import Callable
+from typing import Callable, Optional
 
 import pytest
 
@@ -19,7 +19,7 @@ def test_input_output(
     mock_input_text: str,
     expected_output: str,
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
     temp_files: str,
 ) -> None:
     read_data, written_data = TEST_FILE_NAMES["3.5"]["f"]
diff --git a/tests/3.5/test_35_g.py b/tests/3.5/test_35_g.py
index 71ce4ebe..d0d5fddc 100644
--- a/tests/3.5/test_35_g.py
+++ b/tests/3.5/test_35_g.py
@@ -1,5 +1,5 @@
 from types import ModuleType
-from typing import Callable, Set, Union
+from typing import Callable, Optional, Set, Union
 
 import pytest
 
@@ -21,7 +21,7 @@ def test_input_output(
     mock_input_text: str,
     expected_output: Union[Set[str], str],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
 ) -> None:
 
     wrapped_module, _ = make_test_files(file_name, mock_input_text)
diff --git a/tests/3.5/test_35_h.py b/tests/3.5/test_35_h.py
index 444b3926..410a9f43 100644
--- a/tests/3.5/test_35_h.py
+++ b/tests/3.5/test_35_h.py
@@ -1,7 +1,7 @@
 import os
 from io import StringIO
 from types import ModuleType
-from typing import Callable, Set, Tuple, Union
+from typing import Callable, Optional, Set, Tuple, Union
 
 import pytest
 
@@ -22,7 +22,7 @@ def test_input_output(
     mock_input_texts: Union[Tuple[str], str],
     expected_output: Set[str],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
     temp_files: str,
 ) -> None:
     # Создаем файлы с тестовыми данными для функции
diff --git a/tests/3.5/test_35_i.py b/tests/3.5/test_35_i.py
index c842da1b..7ab400e7 100644
--- a/tests/3.5/test_35_i.py
+++ b/tests/3.5/test_35_i.py
@@ -1,7 +1,7 @@
 import os
 from io import StringIO
 from types import ModuleType
-from typing import Callable, Set, Tuple, Union
+from typing import Callable, Optional, Set, Tuple, Union
 
 import pytest
 
@@ -22,7 +22,7 @@ def test_input_output(
     mock_input_text: str,
     expected_output: Set[str],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
     temp_files: str,
 ) -> None:
     input_file, output_file = file_names
diff --git a/tests/3.5/test_35_j.py b/tests/3.5/test_35_j.py
index 74fe9bc5..2ccf44f8 100644
--- a/tests/3.5/test_35_j.py
+++ b/tests/3.5/test_35_j.py
@@ -1,5 +1,5 @@
 from types import ModuleType
-from typing import Callable, Set
+from typing import Callable, Optional, Set
 
 import pytest
 
@@ -22,7 +22,7 @@ def test_input_output(
     lines_to_read: str,
     expected_output: Set[str],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
 ) -> None:
 
     # Создаем файлы с тестовыми данными для функции
diff --git a/tests/3.5/test_35_k.py b/tests/3.5/test_35_k.py
index b9da180b..7b910cac 100644
--- a/tests/3.5/test_35_k.py
+++ b/tests/3.5/test_35_k.py
@@ -2,7 +2,7 @@
 import os
 from io import StringIO
 from types import ModuleType
-from typing import Callable, Dict, Tuple, Union
+from typing import Callable, Dict, Optional, Tuple, Union
 
 import pytest
 
@@ -23,7 +23,7 @@ def test_input_output(
     mock_input_text: str,
     expected_output: Dict[str, Union[int, float]],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
     temp_files: str,
 ) -> None:
     input_file, output_file = file_names
diff --git a/tests/3.5/test_35_l.py b/tests/3.5/test_35_l.py
index 15969103..105e14e6 100644
--- a/tests/3.5/test_35_l.py
+++ b/tests/3.5/test_35_l.py
@@ -1,7 +1,7 @@
 import os
 from io import StringIO
 from types import ModuleType
-from typing import Callable, List, Tuple
+from typing import Callable, List, Optional, Tuple
 
 import pytest
 
@@ -22,7 +22,7 @@ def test_input_output(
     mock_input_text: str,
     expected_outputs: List[str],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
     temp_files: str,
 ) -> None:
     input_file, output_files = file_names[0], file_names[1:]
diff --git a/tests/3.5/test_35_m.py b/tests/3.5/test_35_m.py
index fdac6ea9..9b6d191e 100644
--- a/tests/3.5/test_35_m.py
+++ b/tests/3.5/test_35_m.py
@@ -2,7 +2,7 @@
 import os
 from io import StringIO
 from types import ModuleType
-from typing import Any, Callable, Dict
+from typing import Any, Callable, Dict, Optional
 
 import pytest
 
@@ -24,7 +24,7 @@ def test_input_output(
     json_data: Dict[Any, Any],
     expected_output: Dict[Any, Any],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
 ) -> None:
     # Создаем файлы с тестовыми данными для функции
     wrapped_module, file_path = make_test_files(file_name, json_data)
diff --git a/tests/3.5/test_35_n.py b/tests/3.5/test_35_n.py
index cf3ee253..80719a0a 100644
--- a/tests/3.5/test_35_n.py
+++ b/tests/3.5/test_35_n.py
@@ -2,7 +2,7 @@
 import os
 from io import StringIO
 from types import ModuleType
-from typing import Callable, Dict, List, Tuple
+from typing import Callable, Dict, List, Optional, Tuple
 
 import pytest
 
@@ -23,7 +23,7 @@ def test_input_output(
     json_data: Tuple[List[Dict[str, str]]],
     expected_output: Dict[str, str],
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
 ) -> None:
     # Создаем файлы с тестовыми данными для функции
     wrapped_module, file_path = make_test_files(file_names, json_data)
diff --git a/tests/3.5/test_35_o.py b/tests/3.5/test_35_o.py
index b329f006..42a29d20 100644
--- a/tests/3.5/test_35_o.py
+++ b/tests/3.5/test_35_o.py
@@ -1,5 +1,5 @@
 from types import ModuleType
-from typing import Any, Callable, Dict, List
+from typing import Any, Callable, Dict, List, Optional
 
 import pytest
 
@@ -21,7 +21,7 @@ def test_input_output(
     json_data: List[Dict[str, Any]],
     expected_output: str,
     _: str,
-    make_test_files: Callable[[str, str], ModuleType],
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
 ) -> None:
     file_name = TEST_FILE_NAMES["3.5"]["o"]
 
diff --git a/tests/3.5/test_35_p.py b/tests/3.5/test_35_p.py
new file mode 100644
index 00000000..71af048c
--- /dev/null
+++ b/tests/3.5/test_35_p.py
@@ -0,0 +1,36 @@
+from types import ModuleType
+from typing import Callable, Optional, Tuple
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TIME_LIMIT
+from tests.data.test_data_35 import p_test_data
+from tests.utils import assert_equal
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "mock_input_texts, files_data, expected_output, _",
+    p_test_data,
+    ids=[i[-1] for i in p_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    mock_input_texts: str,
+    files_data: Tuple[str],
+    expected_output: str,
+    _: str,
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
+) -> None:
+    # Извлекаем и очищаем имена файлов
+    file_names = mock_input_texts.split("\n")[1:]
+
+    wrapped_module, _ = make_test_files(file_names, files_data)
+
+    assert_equal(
+        wrapped_module,
+        monkeypatch,
+        mock_input_texts,
+        expected_output,
+    )
diff --git a/tests/3.5/test_35_q.py b/tests/3.5/test_35_q.py
new file mode 100644
index 00000000..49ff3c5b
--- /dev/null
+++ b/tests/3.5/test_35_q.py
@@ -0,0 +1,34 @@
+from types import ModuleType
+from typing import Callable, Optional
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TEST_FILE_NAMES, TIME_LIMIT
+from tests.data.test_data_35 import q_test_data
+from tests.utils import assert_equal
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "file_data, expected_output, _",
+    q_test_data,
+    ids=[i[-1] for i in q_test_data],
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    file_data: str,
+    expected_output: str,
+    _: str,
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
+) -> None:
+    file_name = TEST_FILE_NAMES["3.5"]["q"]
+
+    wrapped_module, _ = make_test_files(file_name, file_data)
+
+    assert_equal(
+        wrapped_module,
+        monkeypatch,
+        None,
+        expected_output,
+    )
diff --git a/tests/3.5/test_35_r.py b/tests/3.5/test_35_r.py
new file mode 100644
index 00000000..3818c1b7
--- /dev/null
+++ b/tests/3.5/test_35_r.py
@@ -0,0 +1,42 @@
+from io import StringIO
+from types import ModuleType
+from typing import Tuple
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TIME_LIMIT
+from tests.data.test_data_35 import r_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "mock_input_text, mock_file_size, expected_output, _",
+    r_test_data,
+    ids=[i[-1] for i in r_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    setup_environment: Tuple[ModuleType, str],
+    mock_input_text: str,
+    mock_file_size: int,
+    expected_output: str,
+    _: str,
+) -> None:
+    wrapped_module, _ = setup_environment
+
+    # Патчим Input
+    mock_stdin = StringIO(mock_input_text)
+    monkeypatch.setattr("sys.stdin", mock_stdin)
+
+    # Патчим Output
+    mock_stdout = StringIO()
+    monkeypatch.setattr("sys.stdout", mock_stdout)
+
+    # Для решений через os.path.getsize
+    monkeypatch.setattr("os.path.getsize", lambda _: mock_file_size)
+
+    wrapped_module.main()
+    printed_output = mock_stdout.getvalue().rstrip("\n")
+
+    assert printed_output == expected_output
diff --git a/tests/3.5/test_35_s.py b/tests/3.5/test_35_s.py
new file mode 100644
index 00000000..783a6bdd
--- /dev/null
+++ b/tests/3.5/test_35_s.py
@@ -0,0 +1,46 @@
+import os
+from io import StringIO
+from types import ModuleType
+from typing import Callable, Optional
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TEST_FILE_NAMES, TIME_LIMIT
+from tests.data.test_data_35 import s_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "mock_input_text, mock_data_file_in, expected_output, _",
+    s_test_data,
+    ids=[i[-1] for i in s_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
+    temp_files: str,
+    mock_input_text: str,
+    mock_data_file_in: str,
+    expected_output: str,
+    _: str,
+) -> None:
+    input_file, output_file = TEST_FILE_NAMES["3.5"]["s"]
+
+    wrapped_module, file_path = make_test_files(input_file, mock_data_file_in)
+
+    # Патчим Input
+    mock_stdin = StringIO(mock_input_text)
+    monkeypatch.setattr("sys.stdin", mock_stdin)
+
+    wrapped_module.main()
+
+    # Добавляем файл созданный тестируемым файлом в список на удаление
+    directory_path = os.path.dirname(file_path)
+    answer_path = os.path.join(directory_path, "..", output_file)
+    temp_files(answer_path)
+
+    with open(output_file, "r", encoding="UTF-8") as file:
+        written_output = file.read()
+
+    assert written_output == expected_output
diff --git a/tests/3.5/test_35_t.py b/tests/3.5/test_35_t.py
new file mode 100644
index 00000000..8083d178
--- /dev/null
+++ b/tests/3.5/test_35_t.py
@@ -0,0 +1,37 @@
+from io import StringIO
+from types import ModuleType
+from typing import Callable, Optional
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TEST_FILE_NAMES, TIME_LIMIT
+from tests.data.test_data_35 import t_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "mock_data_file_in, expected_output, _",
+    t_test_data,
+    ids=[i[-1] for i in t_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    make_test_files: Callable[[str, str, Optional[str]], ModuleType],
+    mock_data_file_in: bytes,
+    expected_output: str,
+    _: str,
+) -> None:
+    input_file = TEST_FILE_NAMES["3.5"]["t"]
+
+    wrapped_module, _ = make_test_files(input_file, mock_data_file_in, "wb")
+
+    # Патчим Output
+    mock_stdout = StringIO()
+    monkeypatch.setattr("sys.stdout", mock_stdout)
+
+    wrapped_module.main()
+
+    printed_output = mock_stdout.getvalue()
+
+    assert printed_output == expected_output
diff --git a/tests/conftest.py b/tests/conftest.py
index 3b3c8b05..8b8a996c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -164,6 +164,7 @@ def make_test_files(
     def _create_test_file(
         file_names: Union[Tuple[str], str],
         mock_input_texts: Union[Tuple[str], str],
+        mode: str = "w",
     ) -> ModuleType:
         """
         Создаёт тестовый файл с указанным именем и записывает в него данные из
@@ -174,21 +175,28 @@ def _create_test_file(
             file_names (Union[Tuple[str], str]): Имена файлов
             mock_input_texts (Union[Tuple[str], str]): Данные для записи
                 в файлы.
+            mode (str): В каком режиме записывать файлы.
 
         Возвращает:
             ModuleType: Объект окружения тестирования.
         """
-        # Если условие выполняется, значит нужно создать несколько файлов
         if isinstance(file_names, str):
             file_names = (file_names,)
             mock_input_texts = (mock_input_texts,)
 
         for file_name, input_text in zip(file_names, mock_input_texts):
             if file_name.lower().endswith("json"):
-                with open(file_name, "w", encoding="UTF-8") as json_file:
+
+                with open(file_name, mode, encoding="UTF-8") as json_file:
                     json.dump(input_text, json_file)
+
             else:
-                with open(file_name, "w", encoding="UTF-8") as file:
+                if mode == "wb":
+                    encoding = None
+                else:
+                    encoding = "UTF-8"
+
+                with open(file_name, mode, encoding=encoding) as file:
                     file.write(input_text)
 
             utils.add_file_to_cleanup(request, file_name)
diff --git a/tests/constants.py b/tests/constants.py
index 6e7a970c..d642dd2c 100644
--- a/tests/constants.py
+++ b/tests/constants.py
@@ -2,5 +2,11 @@
 TIME_LIMIT = 1  # Временной лимит в сек
 
 TEST_FILE_NAMES = {
-    "3.5": {"f": ["cyrillic.txt", "transliteration.txt"], "o": "scoring.json"},
+    "3.5": {
+        "f": ("cyrillic.txt", "transliteration.txt"),
+        "o": "scoring.json",
+        "q": "secret.txt",
+        "s": ("public.txt", "private.txt"),
+        "t": "numbers.num",
+    },
 }
diff --git a/tests/data/test_data_35.py b/tests/data/test_data_35.py
index 5ad4eb17..f0f5308f 100644
--- a/tests/data/test_data_35.py
+++ b/tests/data/test_data_35.py
@@ -869,3 +869,178 @@
         "very imprtant test failed",
     ),
 ]
+
+p_test_data = [
+    (
+        "Мама мыла РАМУ\nfirst.txt\nsecond.txt\n",
+        (
+            "В этом файле говорится    о том что МАМА   \nмылА\nРаму\n",
+            "А в этом не говорится",
+        ),
+        "first.txt\n",
+        "first open test",
+    ),
+    (
+        "Where am I\nsecond.txt\nfirst.txt\n",
+        (
+            "В этом файле говорится    о том что МАМА   \nмылА\nРаму\n",
+            "А в этом не говорится",
+        ),
+        "404. Not Found\n",
+        "404",
+    ),
+    (
+        "Where am I\nsecond.txt\nfirst.txt\none more\nanother.log\none_more.csv\nemptyfile.txt\n",
+        (
+            "В этом файле говорится    о том что МАМА   \nмылА\nРаму\n",
+            "А в этом не говорится",
+            "where can I&nbsp;find\na cup of coffee\n\n\n\n at 10 AM\n",
+            "Where&nbsp;am&nbsp;I",
+            "&nbsp;&nbsp;&nbsp;&nbsp;",
+            "\n\n\n\n\n\n\n\n\n\n",
+        ),
+        "another.log\n",
+        "&nbsp; test",
+    ),
+]
+
+q_test_data = [
+    ("᥈୥ᙬᱬᝯ, ᭷ᝯ୲੬๤!", {"Hello, world!", "Hello, world!\n"}, "first open test"),
+    (
+        "䥉†䑄楩獳汬楩歫敥†瑴潯†睷牲楩瑴敥†瑴敥獳瑴獳†晦潯牲†瑴桨楩獳†敥硸敥牲捣楩獳敥",
+        {
+            "I Dislike to write tests for this exercise",
+            "I Dislike to write tests for this exercise\n",
+        },
+        "chinesse",
+    ),
+    (
+        "I Dislike to write tests for this exercise!",
+        {
+            "I Dislike to write tests for this exercise!",
+            "I Dislike to write tests for this exercise!\n",
+        },
+        "english",
+    ),
+    ("", {"", "\n"}, "empty"),
+    (
+        "乎潯ਊ煱畵楩敥牲潯ਊ灰牲潯扢慡牲ਊ敥獳瑴敥ਊ灰牲潯扢汬敥浭慡⸮ਊ",
+        {
+            "No\nquiero\nprobar\neste\nproblema.",
+            "No\nquiero\nprobar\neste\nproblema.\n",
+        },
+        "spanish",
+    ),
+]
+
+r_test_data = [
+    ("file.txt\n", 67, "67Б", "first open test"),
+    ("another_file.txt\n", 193, "193Б", "second open test"),
+    ("temp.log\n", 1023, "1023Б", "almost Kb"),
+    ("empty.sql\n", 1024, "1КБ", "one Kb"),
+    ("query.sql\n", 102400, "100КБ", "Kb"),
+    ("procedures.sql\n", 1047552, "1023КБ", "almost Mb"),
+    ("photo.jpg\n", 1048576, "1МБ", "one Mb"),
+    ("photo.raw\n", 138412032, "132МБ", "few Mb"),
+    ("photo.mpeg\n", 138412037, "133МБ", "a few Mb more"),
+    ("photos.tar\n", 1072693248, "1023МБ", "1023 Mb"),
+    ("a_file.mp4\n", 1073741824, "1ГБ", "one Gb"),
+    ("another_file.mp4\n", 20401094656, "19ГБ", "few Gb"),
+    ("another_file.avro\n", 1099511627776, "1024ГБ", "1024 Gb"),
+]
+
+s_test_data = [
+    ("3\n", "Hello, world!", "Khoor, zruog!", "first open test"),
+    (
+        "-10\n",
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+        "QRSTUVWXYZABCDEFGHIJKLMNOP",
+        "second open test",
+    ),
+    ("0\n", "Hello, world!", "Hello, world!", "zero shift"),
+    ("26\n", "Hello, world!", "Hello, world!", "26 shift"),
+    ("-26\n", "Hello, world!", "Hello, world!", "-26 shift"),
+    ("0\n", "Hello,\nworld!", "Hello,\nworld!", "zero shift two line"),
+    ("26\n", "Hello,\nworld!", "Hello,\nworld!", "26 shift two lines"),
+    ("-26\n", "Hello,\nworld!", "Hello,\nworld!", "-26 shift two lines"),
+    (
+        "-30\n",
+        "abcdefghijklmnopqrstuvwxyz",
+        "wxyzabcdefghijklmnopqrstuv",
+        "big negative shift",
+    ),
+    (
+        "-4\n",
+        "abcdefghijklmnopqrstuvwxyz",
+        "wxyzabcdefghijklmnopqrstuv",
+        "small negative shift",
+    ),
+    (
+        "4\n",
+        "abcdefghijklmnopqrstuvwxyz",
+        "efghijklmnopqrstuvwxyzabcd",
+        "small positive shift",
+    ),
+    (
+        "30\n",
+        "abcdefghi\njklmnopqrstuvwxyz",
+        "efghijklm\nnopqrstuvwxyzabcd",
+        "big positive shift",
+    ),
+]
+
+t_test_data = [
+    (
+        b"".join(
+            map(lambda x: x.to_bytes(2, byteorder="big"), [1, 2, 3, 4, 5])
+        ),
+        "15\n",
+        "first open test",
+    ),
+    (
+        bytes.fromhex("00ff0101"),
+        "512\n",
+        "second open test",
+    ),
+    (
+        int(0).to_bytes(2, byteorder="big"),
+        "0\n",
+        "zero",
+    ),
+    (
+        int(65535).to_bytes(2, byteorder="big"),
+        "65535\n",
+        "16 bit",
+    ),
+    (
+        b"".join(
+            map(
+                lambda x: x.to_bytes(2, byteorder="big"),
+                [60000, 5000, 500, 30, 6],
+            )
+        ),
+        "0\n",
+        "cut to 0",
+    ),
+    # Исправить измерение памяти при тестах
+    # (
+    #     b"".join(
+    #         map(
+    #             lambda x: x.to_bytes(2, byteorder="big"),
+    #             (1 for _ in range(262144)),
+    #         )
+    #     ),
+    #     "0\n",
+    #     "long file to zero",
+    # ),
+    # (
+    #     b"".join(
+    #         map(
+    #             lambda x: x.to_bytes(2, byteorder="big"),
+    #             (1 for _ in range(262143)),
+    #         )
+    #     ),
+    #     "65535\n",
+    #     "long file",
+    # ),
+]
diff --git a/tests/utils.py b/tests/utils.py
index 9d41cd04..c13202e3 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -140,7 +140,7 @@ def compare_output(
 def assert_equal(
     wrapped_module: ModuleType,
     monkeypatch: Any,
-    mock_input_text: str,
+    mock_input_text: Union[str, None],
     expected_output: Union[str, set, tuple, list],
 ) -> None:
     """