Repository: andreypomortsev/yndx-python-handbook

Issue:
Feature: Add 5 solutions for 3.5 K-O
1. Выложить решения для задач K,L,M,N,O параграфа 3.5
2. Покрыть тестами 100% решений, обновить README.md.

Hints from issue comments:

Solution patch:
diff --git a/README.md b/README.md
index cfc8707f..899a3d9c 100644
--- a/README.md
+++ b/README.md
@@ -462,11 +462,11 @@ def main():
 | H. [Файловая разница](./solutions/3.5/35_h.py) | [✅](./tests/3.5/test_35_h.py) |
 | I. [Файловая чистка](./solutions/3.5/35_i.py) | [✅](./tests/3.5/test_35_i.py) |
 | J. [Хвост](./solutions/3.5/35_j.py) | [✅](./tests/3.5/test_35_j.py) |
-| K. [Файловая статистика 2.0](./solutions/3.5/35_k.py) | [❌](./tests/3.5/test_35_k.py) |
-| L. [Разделяй и властвуй](./solutions/3.5/35_l.py) | [❌](./tests/3.5/test_35_l.py) |
-| 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) |
+| K. [Файловая статистика 2.0](./solutions/3.5/35_k.py) | [✅](./tests/3.5/test_35_k.py) |
+| L. [Разделяй и властвуй](./solutions/3.5/35_l.py) | [✅](./tests/3.5/test_35_l.py) |
+| 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) |
diff --git a/solutions/3.5/35_k.py b/solutions/3.5/35_k.py
new file mode 100644
index 00000000..9d72246b
--- /dev/null
+++ b/solutions/3.5/35_k.py
@@ -0,0 +1,34 @@
+import json
+
+file_name = input()
+file_output = input()
+
+counter = 0
+positive_count = 0
+total_sum = 0
+minimum = float("inf")
+maximum = float("-inf")
+
+with open(file_name, "r", encoding="UTF-8") as file:
+    while line := file.readline():
+        for number in line.split():
+            number = int(number)
+            positive_count += number > 0
+            total_sum += number
+            minimum = min(minimum, number)
+            maximum = max(maximum, number)
+            counter += 1
+
+average = round(total_sum / counter, 2)
+
+json_like = {
+    "count": counter,
+    "positive_count": positive_count,
+    "min": minimum,
+    "max": maximum,
+    "sum": total_sum,
+    "average": average,
+}
+
+with open(file_output, "w", encoding="UTF-8") as json_file:
+    json.dump(json_like, json_file, indent=4)
diff --git a/solutions/3.5/35_l.py b/solutions/3.5/35_l.py
new file mode 100644
index 00000000..606e24a8
--- /dev/null
+++ b/solutions/3.5/35_l.py
@@ -0,0 +1,34 @@
+numbers_file = input()
+even_file = input()
+odd_file = input()
+eq_file = input()
+
+with (
+    open(numbers_file, "r", encoding="UTF-8") as file_in,
+    open(even_file, "w", encoding="UTF-8") as even_out,
+    open(odd_file, "w", encoding="UTF-8") as odd_out,
+    open(eq_file, "w", encoding="UTF-8") as equal_out,
+):
+
+    while line := file_in.readline():
+        even_list, odd_list, equal_list = [], [], []
+        for str_number in line.split():
+            length = len(str_number)
+            even, odd = 0, 0
+
+            for i in range(length):
+                digit = int(str_number[i])
+
+                even += digit % 2 == 0
+                odd += digit % 2 != 0
+
+            if even == odd:
+                equal_list.append(str_number)
+            elif even > odd:
+                even_list.append(str_number)
+            else:
+                odd_list.append(str_number)
+
+        even_out.write(f"{' '.join(even_list)}\n")
+        odd_out.write(f"{' '.join(odd_list)}\n")
+        equal_out.write(f"{' '.join(equal_list)}\n")
diff --git a/solutions/3.5/35_m.py b/solutions/3.5/35_m.py
new file mode 100644
index 00000000..33b93d45
--- /dev/null
+++ b/solutions/3.5/35_m.py
@@ -0,0 +1,24 @@
+import ast
+import json
+from sys import stdin
+
+json_file = input()
+with open(json_file, "r+", encoding="UTF-8") as file:
+    json_to_update = json.load(file)
+
+    for line in stdin:
+        key, value = line.rstrip("\n").split(" == ")
+        try:
+            value = ast.literal_eval(value)
+        except (ValueError, SyntaxError):
+            pass
+        json_to_update[key] = value
+
+    # Двигаем указатель в начало файла
+    file.seek(0)
+
+    # Записываем обновленное содержание в файл
+    json.dump(json_to_update, file, ensure_ascii=False, indent=4)
+
+    # Обрезаем все отсатки "старого файла"
+    file.truncate()
diff --git a/solutions/3.5/35_n.py b/solutions/3.5/35_n.py
new file mode 100644
index 00000000..24dc5b96
--- /dev/null
+++ b/solutions/3.5/35_n.py
@@ -0,0 +1,27 @@
+import json
+
+users_file = input()
+updates_file = input()
+
+with (
+    open(users_file, "r+", encoding="UTF-8") as file_one,
+    open(updates_file, "r", encoding="UTF-8") as file_two,
+):
+    users = json.load(file_one)
+    updates = json.load(file_two)
+
+    users += updates
+    updated_users = {}
+
+    for user in users:
+        name = user["name"]
+        updated_users[name] = updated_users.get(name, {})
+        for key, value in user.items():
+            if key != "name":
+                flag = updated_users[name].get(key, "")
+                if flag < value:
+                    updated_users[name][key] = value
+
+    file_one.seek(0)
+    json.dump(updated_users, file_one, ensure_ascii=False, indent=4)
+    file_one.truncate()
diff --git a/solutions/3.5/35_o.py b/solutions/3.5/35_o.py
new file mode 100644
index 00000000..602fac79
--- /dev/null
+++ b/solutions/3.5/35_o.py
@@ -0,0 +1,23 @@
+import json
+from sys import stdin
+
+student_answers = [line.rstrip("\n") for line in stdin]
+
+with open("scoring.json", "r", encoding="UTF-8") as json_file:
+    scoring = json.load(json_file)
+
+student_grade = 0
+index = 0
+
+for problem in scoring:
+    point_per_test = problem["points"] // len(problem["tests"])
+
+    for test in problem["tests"]:
+        studen_answer = student_answers[index]
+        right_answer = test["pattern"]
+
+        if studen_answer == right_answer:
+            student_grade += point_per_test
+        index += 1
+
+print(student_grade)


Test patch:
diff --git a/tests/3.5/test_35_k.py b/tests/3.5/test_35_k.py
new file mode 100644
index 00000000..b9da180b
--- /dev/null
+++ b/tests/3.5/test_35_k.py
@@ -0,0 +1,49 @@
+import json
+import os
+from io import StringIO
+from types import ModuleType
+from typing import Callable, Dict, Tuple, Union
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TIME_LIMIT
+from tests.data.test_data_35 import k_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "file_names, mock_input_text, expected_output, _",  # _ - название теста
+    k_test_data,
+    ids=[i[-1] for i in k_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    file_names: Union[Tuple[str], str],
+    mock_input_text: str,
+    expected_output: Dict[str, Union[int, float]],
+    _: str,
+    make_test_files: Callable[[str, str], ModuleType],
+    temp_files: str,
+) -> None:
+    input_file, output_file = file_names
+
+    # Создаем файлы с тестовыми данными для функции
+    wrapped_module, file_path = make_test_files(input_file, mock_input_text)
+
+    # Мокаем input()
+    mock_input = StringIO("\n".join(file_names) + "\n")
+    monkeypatch.setattr("sys.stdin", mock_input)
+
+    wrapped_module.main()
+
+    directory_path = os.path.dirname(file_path)
+
+    # Файл лежит в root дериктории проекта
+    answer_path = os.path.join(directory_path, "..", output_file)
+    temp_files(answer_path)
+
+    with open(answer_path, "r", encoding="UTF-8") as json_file:
+        actual_output = json.load(json_file)
+
+    assert actual_output == expected_output
diff --git a/tests/3.5/test_35_l.py b/tests/3.5/test_35_l.py
new file mode 100644
index 00000000..15969103
--- /dev/null
+++ b/tests/3.5/test_35_l.py
@@ -0,0 +1,48 @@
+import os
+from io import StringIO
+from types import ModuleType
+from typing import Callable, List, Tuple
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TIME_LIMIT
+from tests.data.test_data_35 import l_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "file_names, mock_input_text, expected_outputs, _",  # _ - название теста
+    l_test_data,
+    ids=[i[-1] for i in l_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    file_names: Tuple[str],
+    mock_input_text: str,
+    expected_outputs: List[str],
+    _: str,
+    make_test_files: Callable[[str, str], ModuleType],
+    temp_files: str,
+) -> None:
+    input_file, output_files = file_names[0], file_names[1:]
+
+    # Создаем файлы с тестовыми данными для функции
+    wrapped_module, file_path = make_test_files(input_file, mock_input_text)
+
+    # Мокаем input()
+    mock_input = StringIO("\n".join(file_names) + "\n")
+    monkeypatch.setattr("sys.stdin", mock_input)
+
+    wrapped_module.main()
+
+    directory_path = os.path.dirname(file_path)
+
+    for output_file, expected_output in zip(output_files, expected_outputs):
+        answer_path = os.path.join(directory_path, "..", output_file)
+        temp_files(answer_path)
+
+        with open(answer_path, "r", encoding="UTF-8") as file:
+            actual_output = file.read()
+
+        assert actual_output == expected_output
diff --git a/tests/3.5/test_35_m.py b/tests/3.5/test_35_m.py
new file mode 100644
index 00000000..fdac6ea9
--- /dev/null
+++ b/tests/3.5/test_35_m.py
@@ -0,0 +1,46 @@
+import json
+import os
+from io import StringIO
+from types import ModuleType
+from typing import Any, Callable, Dict
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TIME_LIMIT
+from tests.data.test_data_35 import m_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "file_name, mock_users_input, json_data, expected_output, _",
+    m_test_data,
+    ids=[i[-1] for i in m_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    file_name: str,
+    mock_users_input: str,
+    json_data: Dict[Any, Any],
+    expected_output: Dict[Any, Any],
+    _: str,
+    make_test_files: Callable[[str, str], ModuleType],
+) -> None:
+    # Создаем файлы с тестовыми данными для функции
+    wrapped_module, file_path = make_test_files(file_name, json_data)
+
+    user_input = f"{file_name}\n{mock_users_input}"
+
+    # Мокаем input()
+    mock_input = StringIO(user_input)
+    monkeypatch.setattr("sys.stdin", mock_input)
+
+    wrapped_module.main()
+
+    directory_path = os.path.dirname(file_path)
+    answer_path = os.path.join(directory_path, "..", file_name)
+
+    with open(answer_path, "r", encoding="UTF-8") as json_file:
+        actual_output = json.load(json_file)
+
+    assert actual_output == expected_output
diff --git a/tests/3.5/test_35_n.py b/tests/3.5/test_35_n.py
new file mode 100644
index 00000000..cf3ee253
--- /dev/null
+++ b/tests/3.5/test_35_n.py
@@ -0,0 +1,45 @@
+import json
+import os
+from io import StringIO
+from types import ModuleType
+from typing import Callable, Dict, List, Tuple
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TIME_LIMIT
+from tests.data.test_data_35 import n_test_data
+
+
+@pytest.mark.memory_limit(MEMORY_LIMIT)
+@pytest.mark.time_limit(TIME_LIMIT)
+@pytest.mark.parametrize(
+    "file_names, json_data, expected_output, _",
+    n_test_data,
+    ids=[i[-1] for i in n_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    file_names: Tuple[str],
+    json_data: Tuple[List[Dict[str, str]]],
+    expected_output: Dict[str, str],
+    _: str,
+    make_test_files: Callable[[str, str], ModuleType],
+) -> None:
+    # Создаем файлы с тестовыми данными для функции
+    wrapped_module, file_path = make_test_files(file_names, json_data)
+
+    user_input = f"{file_names[0]}\n{file_names[1]}\n"
+
+    # Мокаем input()
+    mock_input = StringIO(user_input)
+    monkeypatch.setattr("sys.stdin", mock_input)
+
+    wrapped_module.main()
+
+    directory_path = os.path.dirname(file_path)
+    answer_path = os.path.join(directory_path, "..", file_names[0])
+
+    with open(answer_path, "r", encoding="UTF-8") as json_file:
+        actual_output = json.load(json_file)
+
+    assert actual_output == expected_output
diff --git a/tests/3.5/test_35_o.py b/tests/3.5/test_35_o.py
new file mode 100644
index 00000000..b329f006
--- /dev/null
+++ b/tests/3.5/test_35_o.py
@@ -0,0 +1,35 @@
+from types import ModuleType
+from typing import Any, Callable, Dict, List
+
+import pytest
+
+from tests.constants import MEMORY_LIMIT, TEST_FILE_NAMES, TIME_LIMIT
+from tests.data.test_data_35 import o_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_text, json_data, expected_output, _",
+    o_test_data,
+    ids=[i[-1] for i in o_test_data],  # Считываем названия тестов
+)
+def test_input_output(
+    monkeypatch: pytest.MonkeyPatch,
+    mock_input_text: str,
+    json_data: List[Dict[str, Any]],
+    expected_output: str,
+    _: str,
+    make_test_files: Callable[[str, str], ModuleType],
+) -> None:
+    file_name = TEST_FILE_NAMES["3.5"]["o"]
+
+    wrapped_module, _ = make_test_files(file_name, json_data)
+
+    assert_equal(
+        wrapped_module,
+        monkeypatch,
+        mock_input_text,
+        expected_output,
+    )
diff --git a/tests/conftest.py b/tests/conftest.py
index 07204597..3b3c8b05 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,5 @@
 import importlib
+import json
 import os
 import sys
 from types import ModuleType
@@ -183,8 +184,12 @@ def _create_test_file(
             mock_input_texts = (mock_input_texts,)
 
         for file_name, input_text in zip(file_names, mock_input_texts):
-            with open(file_name, "w", encoding="UTF-8") as file:
-                file.write(input_text)
+            if file_name.lower().endswith("json"):
+                with open(file_name, "w", encoding="UTF-8") as json_file:
+                    json.dump(input_text, json_file)
+            else:
+                with open(file_name, "w", encoding="UTF-8") 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 f683c857..6e7a970c 100644
--- a/tests/constants.py
+++ b/tests/constants.py
@@ -2,5 +2,5 @@
 TIME_LIMIT = 1  # Временной лимит в сек
 
 TEST_FILE_NAMES = {
-    "3.5": {"f": ["cyrillic.txt", "transliteration.txt"]},
+    "3.5": {"f": ["cyrillic.txt", "transliteration.txt"], "o": "scoring.json"},
 }
diff --git a/tests/data/test_data_35.py b/tests/data/test_data_35.py
index 6da3964f..5ad4eb17 100644
--- a/tests/data/test_data_35.py
+++ b/tests/data/test_data_35.py
@@ -352,3 +352,520 @@
         "few empty plus text",
     ),
 ]
+
+k_test_data = [
+    (
+        ("numbers.txt", "statistics.json"),
+        "1 2 3 4 5\n-5 -4 -3 -2 -1\n10 20\n20 10\n",
+        {
+            "count": 14,
+            "positive_count": 9,
+            "min": -5,
+            "max": 20,
+            "sum": 60,
+            "average": 4.29,
+        },
+        "first open test",
+    ),
+    (
+        ("numbers.txt", "statistics.json"),
+        "1 2 3 4 5 -5 -4 -3 -2 -1 10 20 20 10\n",
+        {
+            "count": 14,
+            "positive_count": 9,
+            "min": -5,
+            "max": 20,
+            "sum": 60,
+            "average": 4.29,
+        },
+        "first open test one line",
+    ),
+    (
+        ("numbers.txt", "statistics.json"),
+        "1 2 3 4 5\n-5 -4 -3 -2 -1\n10 20\n-20 -10\n",
+        {
+            "count": 14,
+            "positive_count": 7,
+            "min": -20,
+            "max": 20,
+            "sum": 0,
+            "average": 0.0,
+        },
+        "average 0",
+    ),
+    (
+        ("1.txt", "2.json"),
+        "1 2 3 4 5 -5 -4 -3 -2 -1 10 20 -20 -10\n",
+        {
+            "count": 14,
+            "positive_count": 7,
+            "min": -20,
+            "max": 20,
+            "sum": 0,
+            "average": 0.0,
+        },
+        "one line average 0",
+    ),
+    (
+        ("numbers.txt", "statistics.json"),
+        "\n-5 -4 -3 -2 -1\n\n-20 -10\n",
+        {
+            "count": 7,
+            "positive_count": 0,
+            "min": -20,
+            "max": -1,
+            "sum": -45,
+            "average": -6.43,
+        },
+        "only negative numbers",
+    ),
+    (
+        ("only positive numbers.txt", "num-statistics.json"),
+        "\n5 4 3 2 1\n\n20 10\n",
+        {
+            "count": 7,
+            "positive_count": 7,
+            "min": 1,
+            "max": 20,
+            "sum": 45,
+            "average": 6.43,
+        },
+        "only positive numbers",
+    ),
+    (
+        ("only positive numbers.txt", "num-statistics.json"),
+        "0 0 0 0 0 0 0 0\n5 4 3 2 1\n\n20 10\n",
+        {
+            "count": 15,
+            "positive_count": 7,
+            "min": 0,
+            "max": 20,
+            "sum": 45,
+            "average": 3.0,
+        },
+        "positive numbers and zeros",
+    ),
+    (
+        ("zeros", "indeed.json"),
+        "0 0 0 0 0 0 0 0\n-5 -4 -3 -2 -1\n\n-20 -10\n",
+        {
+            "count": 15,
+            "positive_count": 0,
+            "min": -20,
+            "max": 0,
+            "sum": -45,
+            "average": -3.0,
+        },
+        "negative numbers and zeros",
+    ),
+    (
+        ("one_negative_num", "indeed.json"),
+        "-10\n",
+        {
+            "count": 1,
+            "positive_count": 0,
+            "min": -10,
+            "max": -10,
+            "sum": -10,
+            "average": -10.0,
+        },
+        "one negative number",
+    ),
+    (
+        ("one_positive_num.log", "indeed.json"),
+        "330\n",
+        {
+            "count": 1,
+            "positive_count": 1,
+            "min": 330,
+            "max": 330,
+            "sum": 330,
+            "average": 330.0,
+        },
+        "one positive number",
+    ),
+]
+
+l_test_data = [
+    (
+        ("numbers.txt", "even.txt", "odd.txt", "eq.txt"),
+        "650975472 591084323 629700 1504180 577023\n"
+        "8460612246 42161437 29409368 58531725 5725268 2198001838\n"
+        "796451 69358 7195510 975628465 9756641\n"
+        "44200289 126541 979391 93479581 291170 28987042 86139603\n",
+        (
+            "629700 1504180\n"
+            "8460612246 29409368 5725268 2198001838\n"
+            "975628465\n"
+            "44200289 28987042\n",
+            "650975472 591084323 577023\n"
+            "58531725\n"
+            "796451 69358 7195510 9756641\n"
+            "979391 93479581 291170\n",
+            "\n42161437\n\n126541 86139603\n",
+        ),
+        "first open test",
+    ),
+    (
+        ("1", "2", "3", "RESULT"),
+        "1\n2\n3\n\n4\n",
+        (
+            "\n2\n\n\n4\n",
+            "1\n\n3\n\n\n",
+            "\n\n\n\n\n",
+        ),
+        "one empty line single nums",
+    ),
+    (
+        ("input.txt", "even.txt", "odd.txt", "eq.txt"),
+        "650975472 591084323 629700 1504180 577023\n"
+        "8460612246 42161437 29409368 58531725 5725268 2198001838\n\n"
+        "796451 69358 7195510 975628465 9756641\n"
+        "44200289 126541 979391 93479581 291170 28987042 86139603\n",
+        (
+            "629700 1504180\n"
+            "8460612246 29409368 5725268 2198001838\n\n"
+            "975628465\n"
+            "44200289 28987042\n",
+            "650975472 591084323 577023\n"
+            "58531725\n\n"
+            "796451 69358 7195510 9756641\n"
+            "979391 93479581 291170\n",
+            "\n42161437\n\n\n126541 86139603\n",
+        ),
+        "one empty line big nums",
+    ),
+    (
+        ("input", "even.txt", "odd.txt", "eq.txt"),
+        "3223244435694 0 0 0 0\n"
+        "111111 333333 3333333 333330000000\n"
+        "100 2200144\n",
+        (
+            "3223244435694 0 0 0 0\n" "333330000000\n" "100 2200144\n",
+            "\n" "111111 333333 3333333\n" "\n",
+            "\n\n\n",
+        ),
+        "even or odd nums",
+    ),
+    (
+        ("input", "even", "odd.txt", "eq.txt"),
+        "21 21 21 21\n"
+        "36 67 89 90\n"
+        "12\n"
+        "29\n"
+        "90\n"
+        "98\n"
+        "21\n"
+        "16\n"
+        "9023\n",
+        (
+            "\n\n\n\n\n\n\n\n\n",
+            "\n\n\n\n\n\n\n\n\n",
+            "21 21 21 21\n"
+            "36 67 89 90\n"
+            "12\n"
+            "29\n"
+            "90\n"
+            "98\n"
+            "21\n"
+            "16\n"
+            "9023\n",
+        ),
+        "equal nums",
+    ),
+    (
+        ("input", "even", "odd.txt", "eq.txt"),
+        "2 62 26 24\n"
+        "436 267 892 290\n"
+        "212\n"
+        "292\n"
+        "904\n"
+        "698\n"
+        "216\n"
+        "616\n"
+        "90238\n",
+        (
+            "2 62 26 24\n"
+            "436 267 892 290\n"
+            "212\n"
+            "292\n"
+            "904\n"
+            "698\n"
+            "216\n"
+            "616\n"
+            "90238\n",
+            "\n\n\n\n\n\n\n\n\n",
+            "\n\n\n\n\n\n\n\n\n",
+        ),
+        "all even nums",
+    ),
+    (
+        ("input", "even.log", "odd", "equal"),
+        "231 13623 23136 31924\n"
+        "43576 27967 97892 27909\n"
+        "29253 7521279\n"
+        "698335 29253\n"
+        "90455 6165533\n"
+        "698335 2925312111\n"
+        "216535 7521279\n"
+        "6165533 6165533\n"
+        "902385353\n",
+        (
+            "\n\n\n\n\n\n\n\n\n",
+            "231 13623 23136 31924\n"
+            "43576 27967 97892 27909\n"
+            "29253 7521279\n"
+            "698335 29253\n"
+            "90455 6165533\n"
+            "698335 2925312111\n"
+            "216535 7521279\n"
+            "6165533 6165533\n"
+            "902385353\n",
+            "\n\n\n\n\n\n\n\n\n",
+        ),
+        "all odd nums",
+    ),
+]
+
+m_test_data = [
+    (
+        "data.json",
+        "one == один\ntwo == два\nthree == три\n",
+        {"one": 1, "three": 2},
+        {"one": "один", "three": "три", "two": "два"},
+        "first open test",
+    ),
+    (
+        "another_data.json",
+        "21 == двадцать-один\n",
+        {"21": 1, "three": 2},
+        {"21": "двадцать-один", "three": 2},
+        "one line",
+    ),
+    (
+        "yet_another_data.json",
+        "' ' == empty string\n",
+        {"21": 21, "three": 2},
+        {"' '": "empty string", "21": 21, "three": 2},
+        "add a value",
+    ),
+    (
+        "fancy_data.json",
+        'language_info == {"name": "python", "user": None}\n'
+        'metadata == {"kernelspec": {"name": "python3", "display_name": "Python 3"}}\n',
+        {
+            "type": "notebook",
+            "metadata": {
+                "kernelspec": {"name": "python3", "display_name": "Python 3"},
+                "language_info": {"name": "python"},
+            },
+        },
+        {
+            "type": "notebook",
+            "metadata": {
+                "kernelspec": {"name": "python3", "display_name": "Python 3"}
+            },
+            "language_info": {"name": "python", "user": None},
+        },
+        "moving jsons",
+    ),
+    (
+        "yet_another_data.json",
+        "' ' == ['empty string']\n",
+        {"21": 21, "three": 2},
+        {"' '": ["empty string"], "21": 21, "three": 2},
+        "add a list as a value",
+    ),
+]
+
+n_test_data = [
+    (
+        ("users.json", "updates.json"),
+        (
+            [
+                {"name": "Ann", "address": "Flower st."},
+                {
+                    "name": "Bob",
+                    "address": "Summer st.",
+                    "phone": "+7 (123) 456-78-90",
+                },
+            ],
+            [
+                {
+                    "name": "Ann",
+                    "address": "Awesome st.",
+                    "phone": "+7 (098) 765-43-21",
+                },
+                {"name": "Bob", "address": "Winter st."},
+            ],
+        ),
+        {
+            "Ann": {
+                "address": "Flower st.",
+                "phone": "+7 (098) 765-43-21",
+            },
+            "Bob": {
+                "address": "Winter st.",
+                "phone": "+7 (123) 456-78-90",
+            },
+        },
+        "first open test",
+    ),
+    (
+        ("1.json", "2.json"),
+        (
+            [
+                {"name": "Ann", "address": "Flower st."},
+                {"name": "Vova", "address": "Bunker st."},
+                {
+                    "name": "Bob",
+                    "address": "Summer st.",
+                    "phone": "+7 (123) 456-78-90",
+                },
+            ],
+            [
+                {
+                    "name": "Ann",
+                    "address": "Awesome st.",
+                    "phone": "+7 (098) 765-43-21",
+                },
+                {"name": "Bob", "address": "Winter st."},
+                {
+                    "name": "Vova",
+                    "phone": "+ 31 (0)70 515 8515",
+                    "address": "Oude Waalsdorperweg st.",
+                },
+            ],
+        ),
+        {
+            "Ann": {
+                "address": "Flower st.",
+                "phone": "+7 (098) 765-43-21",
+            },
+            "Bob": {
+                "address": "Winter st.",
+                "phone": "+7 (123) 456-78-90",
+            },
+            "Vova": {
+                "address": "Oude Waalsdorperweg st.",
+                "phone": "+ 31 (0)70 515 8515",
+            },
+        },
+        "more users",
+    ),
+]
+
+o_test_data = [
+    (
+        "4\n12\n3\n100\n0\n",
+        [
+            {
+                "points": 10,
+                "tests": [
+                    {"input": "2 2", "pattern": "4"},
+                    {"input": "4 3", "pattern": "7"},
+                ],
+            },
+            {
+                "points": 30,
+                "tests": [
+                    {"input": "2 1", "pattern": "3"},
+                    {"input": "25 4", "pattern": "29"},
+                    {"input": "3 -3", "pattern": "0"},
+                ],
+            },
+        ],
+        "25\n",
+        "first open test",
+    ),
+    (
+        "12\n4\n7\n3\n29\n0\n987\n229\n100\n2210\n",
+        [
+            {
+                "points": 60,
+                "tests": [
+                    {"input": "22 -2", "pattern": "12"},
+                    {"input": "2 2", "pattern": "4"},
+                    {"input": "4 3", "pattern": "7"},
+                ],
+            },
+            {
+                "points": 30,
+                "tests": [
+                    {"input": "2 1", "pattern": "3"},
+                    {"input": "25 4", "pattern": "29"},
+                    {"input": "3 -3", "pattern": "0"},
+                ],
+            },
+            {
+                "points": 4,
+                "tests": [
+                    {"input": "32 12", "pattern": "987"},
+                    {"input": "235 -114", "pattern": "229"},
+                    {"input": "30 -93", "pattern": "100"},
+                    {"input": "1093 34343", "pattern": "2210"},
+                ],
+            },
+        ],
+        "94\n",
+        "nailed it!",
+    ),
+    (
+        "120\n40\n70\n30\n290\n90\n9807\n2029\n10\n210\n",
+        [
+            {
+                "points": 60,
+                "tests": [
+                    {"input": "22 -2", "pattern": "12"},
+                    {"input": "2 2", "pattern": "4"},
+                    {"input": "4 3", "pattern": "7"},
+                ],
+            },
+            {
+                "points": 30,
+                "tests": [
+                    {"input": "2 1", "pattern": "3"},
+                    {"input": "25 4", "pattern": "29"},
+                    {"input": "3 -3", "pattern": "0"},
+                ],
+            },
+            {
+                "points": 4,
+                "tests": [
+                    {"input": "32 12", "pattern": "987"},
+                    {"input": "235 -114", "pattern": "229"},
+                    {"input": "30 -93", "pattern": "100"},
+                    {"input": "1093 34343", "pattern": "2210"},
+                ],
+            },
+        ],
+        "0\n",
+        "failed it!",
+    ),
+    (
+        "4\n",
+        [
+            {
+                "points": 100,
+                "tests": [
+                    {"input": "2 2", "pattern": "4"},
+                ],
+            }
+        ],
+        "100\n",
+        "very imprtant test passed",
+    ),
+    (
+        "4\n",
+        [
+            {
+                "points": 100,
+                "tests": [
+                    {"input": "2 2", "pattern": "24"},
+                ],
+            }
+        ],
+        "0\n",
+        "very imprtant test failed",
+    ),
+]