Coverage report: + 100% +
+ + ++ coverage.py v7.3.2, + created at 2023-11-16 01:34 +0300 +
+diff --git a/testing_hw/issue-01/README.md b/testing_hw/issue-01/README.md new file mode 100644 index 0000000..4bf1248 --- /dev/null +++ b/testing_hw/issue-01/README.md @@ -0,0 +1,8 @@ +# issue-01 +При запуске в PyСharm все тесты проходят, но не выводится отчет. + +Для вывода отчета о пройденных тестах переходим в директории с файлом morse.py и в терминале выполнияем команду: + +```python -m doctest -o NORMALIZE_WHITESPACE -v morse.py``` + +(Добавляем ```-o NORMALIZE_WHITESPACE```, так как этот флаг позволяет не различать последовательности пробелов, что необходимо для одного из тестов) diff --git a/testing_hw/issue-01/morse.py b/testing_hw/issue-01/morse.py new file mode 100644 index 0000000..1e37d72 --- /dev/null +++ b/testing_hw/issue-01/morse.py @@ -0,0 +1,55 @@ +"""Encoding text according to Morse code table""" + +import doctest + +LETTER_TO_MORSE = {'A': '.-', 'B': '-...', + 'C': '-.-.', 'D': '-..', 'E': '.', + 'F': '..-.', 'G': '--.', 'H': '....', + 'I': '..', 'J': '.---', 'K': '-.-', + 'L': '.-..', 'M': '--', 'N': '-.', + 'O': '---', 'P': '.--.', 'Q': '--.-', + 'R': '.-.', 'S': '...', 'T': '-', + 'U': '..-', 'V': '...-', 'W': '.--', + 'X': '-..-', 'Y': '-.--', 'Z': '--..', + '1': '.----', '2': '..---', '3': '...--', + '4': '....-', '5': '.....', '6': '-....', + '7': '--...', '8': '---..', '9': '----.', + '0': '-----', ', ': '--..--', '.': '.-.-.-', + '?': '..--..', '/': '-..-.', '-': '-....-', + '(': '-.--.', ')': '-.--.-'} + + +def encode(message: str) -> str: + """ + Кодирует строку в соответсвии с таблицей азбуки Морзе + + >>> encode('SOS') # doctest: +NORMALIZE_WHITESPACE + '... --- ...' + >>> encode('SOS') + '... --- ...' + >>> encode(".)") + '.-.-.- -.--.-' + >>> encode('') + '' + >>> encode(911) + Traceback (most recent call last): + ... + TypeError: 'int' object is not iterable + >>> encode('sos') + Traceback (most recent call last): + ... + KeyError: 's' + >>> encode(';)') + Traceback (most recent call last): + ... + KeyError: ';' + """ + encoded_signs = [ + LETTER_TO_MORSE[letter] for letter in message + ] + + return ' '.join(encoded_signs) + + +if __name__ == "__main__": + doctest.testmod() diff --git a/testing_hw/issue-01/result.txt b/testing_hw/issue-01/result.txt new file mode 100644 index 0000000..5e455dc --- /dev/null +++ b/testing_hw/issue-01/result.txt @@ -0,0 +1,49 @@ +PS D:\python> python -m doctest -o NORMALIZE_WHITESPACE -v morse.py +Trying: + encode('SOS') # doctest: +NORMALIZE_WHITESPACE +Expecting: + '... --- ...' +ok +Trying: + encode('SOS') +Expecting: + '... --- ...' +ok +Trying: + encode(".)") +Expecting: + '.-.-.- -.--.-' +ok +Trying: + encode('') +Expecting: + '' +ok +Trying: + encode(911) +Expecting: + Traceback (most recent call last): + ... + TypeError: 'int' object is not iterable +ok +Trying: + encode('sos') +Expecting: + Traceback (most recent call last): + ... + KeyError: 's' +ok +Trying: + encode(';)') +Expecting: + Traceback (most recent call last): + ... + KeyError: ';' +ok +1 items had no tests: + morse +1 items passed all tests: + 7 tests in morse.encode +7 tests in 2 items. +7 passed and 0 failed. +Test passed. diff --git a/testing_hw/issue-02/README.md b/testing_hw/issue-02/README.md new file mode 100644 index 0000000..94665f8 --- /dev/null +++ b/testing_hw/issue-02/README.md @@ -0,0 +1,6 @@ +# issue-02 +Для начала нужно установить пакет **pytest** с помощью команды: ```pip install -U pytest``` + +Затем ```import pytest``` в рабочий файл. + +Для вывода отчета о пройденных тестах в терминал и выполнияем команду: ```python -m pytest -v morse_2.py``` diff --git a/testing_hw/issue-02/morse_2.py b/testing_hw/issue-02/morse_2.py new file mode 100644 index 0000000..0ac69d4 --- /dev/null +++ b/testing_hw/issue-02/morse_2.py @@ -0,0 +1,48 @@ +"""Decoding text according to Morse code table""" + +import pytest + + +LETTER_TO_MORSE = {'A': '.-', 'B': '-...', + 'C': '-.-.', 'D': '-..', 'E': '.', + 'F': '..-.', 'G': '--.', 'H': '....', + 'I': '..', 'J': '.---', 'K': '-.-', + 'L': '.-..', 'M': '--', 'N': '-.', + 'O': '---', 'P': '.--.', 'Q': '--.-', + 'R': '.-.', 'S': '...', 'T': '-', + 'U': '..-', 'V': '...-', 'W': '.--', + 'X': '-..-', 'Y': '-.--', 'Z': '--..', + '1': '.----', '2': '..---', '3': '...--', + '4': '....-', '5': '.....', '6': '-....', + '7': '--...', '8': '---..', '9': '----.', + '0': '-----', ', ': '--..--', '.': '.-.-.-', + '?': '..--..', '/': '-..-.', '-': '-....-', + '(': '-.--.', ')': '-.--.-'} + +MORSE_TO_LETTER = { + morse: symbol for symbol, morse in LETTER_TO_MORSE +} + + +def decode(morse_message: str) -> str: + """ + Декодирует строку из азбуки Морзе в английский + """ + decoded_letters = [ + MORSE_TO_LETTER[letter] for letter in morse_message.split() + ] + + return ''.join(decoded_letters) + + +@pytest.mark.parametrize( + "source_string,result", + [ + ('SOS', '... --- ...'), + ('', ''), + ('.)', '.-.-.- -.--.-'), + pytest.param(123, '', marks=pytest.mark.xfail), + ], +) +def test_decode(source_string, result): + assert decode(source_string) == result diff --git a/testing_hw/issue-02/result_2.txt b/testing_hw/issue-02/result_2.txt new file mode 100644 index 0000000..9fd1d3e --- /dev/null +++ b/testing_hw/issue-02/result_2.txt @@ -0,0 +1,13 @@ +PS D:\python> python -m pytest -v morse_2.py +================================================================= test session starts ================================================================= +platform win32 -- Python 3.10.7, pytest-7.4.3, pluggy-1.3.0 -- D:\python\python.exe +cachedir: .pytest_cache +rootdir: D:\python +collected 4 items + +morse.py::test_encode[SOS-... --- ...] PASSED [ 25%] +morse.py::test_encode[-] PASSED [ 50%] +morse.py::test_encode[.)-.-.-.- -.--.-] PASSED [ 75%] +morse.py::test_encode[123-] XFAIL [100%] + +============================================================ 3 passed, 1 xfailed in 0.09s ============================================================= diff --git a/testing_hw/issue-03/README.md b/testing_hw/issue-03/README.md new file mode 100644 index 0000000..f0e9482 --- /dev/null +++ b/testing_hw/issue-03/README.md @@ -0,0 +1,5 @@ +# issue-03 + +Для начала нужно испортировать пакет **unittest** с помощью команды: ```import unittest``` + +Для вывода отчета о пройденных тестах в терминале выполнияем команду: ```python -m unittest -v morse.TestOneHotEncoder``` diff --git a/testing_hw/issue-03/onehotencoding.py b/testing_hw/issue-03/onehotencoding.py new file mode 100644 index 0000000..f23bfe0 --- /dev/null +++ b/testing_hw/issue-03/onehotencoding.py @@ -0,0 +1,69 @@ +""" +Encoding a value into a binary representation +based on the ordinal number of the first element encountered +""" +from typing import List, Tuple +import unittest + + +def fit_transform(*args: str) -> List[Tuple[str, List[int]]]: + """ + fit_transform(iterable) + fit_transform(arg1, arg2, *args) + """ + if len(args) == 0: + raise TypeError('expected at least 1 arguments, got 0') + + categories = args if isinstance(args[0], str) else list(args[0]) + uniq_categories = set(categories) + bin_format = f'{{0:0{len(uniq_categories)}b}}' + + seen_categories = dict() + transformed_rows = [] + + for cat in categories: + bin_view_cat = (int(b) for b in bin_format.format(1 << len(seen_categories))) + seen_categories.setdefault(cat, list(bin_view_cat)) + transformed_rows.append((cat, seen_categories[cat])) + + return transformed_rows + + +class TestOneHotEncoder(unittest.TestCase): + def test_symbols(self): + """test transformation from list of strings""" + actual = ['.', ',', '.'] + expected = [('.', [0, 1]), (',', [1, 0]), ('.', [0, 1])] + self.assertEqual(fit_transform(actual), expected) + + def test_string(self): + """test transformation from string out of list""" + actual = '^' + expected = [('^', [1])] + self.assertEqual(fit_transform(actual), expected) + + def test_nums(self): + """test transformation from list of digits""" + actual = [3] + expected = [(3, [1])] + self.assertEqual(fit_transform(actual), expected) + + def test_num(self): + """test transformation from digit out of list""" + actual = 3 + self.assertRaises(TypeError, fit_transform, actual) + + def test_none(self): + """test transformation from none object""" + actual = None + self.assertIsNone(actual) + + def test_empty(self): + """test transformation from empty list""" + actual = [] + expected = [] + self.assertTrue(fit_transform(actual) == expected) + + +if __name__ == '__main__': + unittest.main() diff --git a/testing_hw/issue-03/result_3.txt b/testing_hw/issue-03/result_3.txt new file mode 100644 index 0000000..46dd4e3 --- /dev/null +++ b/testing_hw/issue-03/result_3.txt @@ -0,0 +1,12 @@ +PS D:\python> python -m unittest -v morse.TestOneHotEncoder +test_empty (morse.TestOneHotEncoder) ... ok +test_none (morse.TestOneHotEncoder) ... ok +test_num (morse.TestOneHotEncoder) ... ok +test_nums (morse.TestOneHotEncoder) ... ok +test_string (morse.TestOneHotEncoder) ... ok +test_symbols (morse.TestOneHotEncoder) ... ok + +---------------------------------------------------------------------- +Ran 6 tests in 0.004s + +OK diff --git a/testing_hw/issue-04/README.md b/testing_hw/issue-04/README.md new file mode 100644 index 0000000..5d61211 --- /dev/null +++ b/testing_hw/issue-04/README.md @@ -0,0 +1,7 @@ +# issue-04 + +Для начала нужно установить пакет **pytest** с помощью команды: ```pip install -U pytest``` + +Затем ```import pytest``` в рабочий файл. + +Для вывода отчета о пройденных тестах в терминале выполнияем команду: ```python -m pytest -v onehotencoding_pytest.py``` diff --git a/testing_hw/issue-04/onehotencoding_pytest.py b/testing_hw/issue-04/onehotencoding_pytest.py new file mode 100644 index 0000000..2604bcd --- /dev/null +++ b/testing_hw/issue-04/onehotencoding_pytest.py @@ -0,0 +1,56 @@ +""" +Encoding a value into a binary representation +based on the ordinal number of the first element encountered +""" +from typing import List, Tuple +import pytest + + +def fit_transform(*args: str) -> List[Tuple[str, List[int]]]: + """ + fit_transform(iterable) + fit_transform(arg1, arg2, *args) + """ + if len(args) == 0: + raise TypeError('expected at least 1 arguments, got 0') + + categories = args if isinstance(args[0], str) else list(args[0]) + uniq_categories = set(categories) + bin_format = f'{{0:0{len(uniq_categories)}b}}' + + seen_categories = dict() + transformed_rows = [] + + for cat in categories: + bin_view_cat = (int(b) for b in bin_format.format(1 << len(seen_categories))) + seen_categories.setdefault(cat, list(bin_view_cat)) + transformed_rows.append((cat, seen_categories[cat])) + + return transformed_rows + + +def test_int_raises_type_error(): + """test transformation from digit""" + with pytest.raises(TypeError): + fit_transform(3) + + +def test_none_raises_type_error(): + """test transformation from none object""" + with pytest.raises(TypeError): + fit_transform(None) + + +def test_string(): + """test transformation from string""" + assert fit_transform('^') == [('^', [1])] + + +def test_empty_list(): + """test transformation from empty list""" + assert fit_transform([]) == [] + + +def test_empty_list(): + """test transformation from list of strings""" + assert fit_transform(['.', ',', '.']) == [('.', [0, 1]), (',', [1, 0]), ('.', [0, 1])] diff --git a/testing_hw/issue-04/result_4.txt b/testing_hw/issue-04/result_4.txt new file mode 100644 index 0000000..4281273 --- /dev/null +++ b/testing_hw/issue-04/result_4.txt @@ -0,0 +1,9 @@ +PS D:\python> python -m pytest onehotencoding_pytest.py +================================================================= test session starts ================================================================= +platform win32 -- Python 3.10.7, pytest-7.4.3, pluggy-1.3.0 +rootdir: D:\python +collected 4 items + +onehotencoding_pytest.py .... [100%] + +================================================================== 4 passed in 0.09s ================================================================== diff --git a/testing_hw/issue-05/README.md b/testing_hw/issue-05/README.md new file mode 100644 index 0000000..3dfe9c4 --- /dev/null +++ b/testing_hw/issue-05/README.md @@ -0,0 +1,8 @@ +# issue-05 +Сначала устанавливаем плагин под названием *pytest-cov*, который позволит вам вызывать coverage.py от **pytest** с некоторыми дополнительными опциями pytest. +Поскольку coverage является одной из зависимостей *pytest-cov*, достаточно установить *pytest-cov* и он притянет за собой coverage.py: +```pip install pytest-cov```. + +Далее хотим вывести отчет о базовом покрытии в терминале нам поможет это сделать команда: ```pytest --cov=what_is_year_now```. + +Если вы снова запустите coverage.py с параметром --cov-report=html, будет создан отчет в формате HTML: ```pytest --cov=what_is_year_now --cov-report=html```. diff --git a/testing_hw/issue-05/index.html b/testing_hw/issue-05/index.html new file mode 100644 index 0000000..ba700c5 --- /dev/null +++ b/testing_hw/issue-05/index.html @@ -0,0 +1,109 @@ + + +
+ ++ coverage.py v7.3.2, + created at 2023-11-16 01:34 +0300 +
+| Module | +statements | +missing | +excluded | +coverage | +
|---|---|---|---|---|
| issue05\test_what_is_year_now.py | +27 | +0 | +0 | +100% | +
| issue05\what_is_year_now.py | +19 | +0 | +0 | +100% | +
| Total | +46 | +0 | +0 | +100% | +
+ No items found using the specified filter. +
++ « prev + ^ index + » next + + coverage.py v7.3.2, + created at 2023-11-16 01:33 +0300 +
+ +1import pytest
+2import urllib.request
+3from what_is_year_now import what_is_year_now
+4from unittest.mock import patch
+5from io import StringIO
+ + +8def test_format_yyyy_mm_dd():
+9 """
+10 Test checks date format: YYYY-MM-DD
+11 """
+12 date = StringIO('{"currentDateTime": "1980-01-01"}')
+13 expected = 1980
+14 with patch.object(urllib.request, 'urlopen', return_value=date):
+15 actual = what_is_year_now()
+16 assert expected == actual
+ + +19def test_format_dd_mm_yyyy():
+20 """
+21 Test checks date format: DD-MM-YYYY
+22 """
+23 date = StringIO('{"currentDateTime": "01.01.1980"}')
+24 expected = 1980
+25 with patch.object(urllib.request, 'urlopen', return_value=date):
+26 actual = what_is_year_now()
+27 assert expected == actual
+ + +30def test_invalid_data():
+31 """
+32 Test checks date is not valid
+33 """
+34 date = StringIO('{"currentDateTime": "ast$@%ro098123"}')
+35 with pytest.raises(ValueError):
+36 with patch.object(urllib.request, 'urlopen', return_value=date):
+37 what_is_year_now()
+ + +40def test_no_date_at_all():
+41 """
+42 Test checks json format with no date at all
+43 """
+44 date = StringIO('{"Russia": "Moscow"}')
+45 with pytest.raises(KeyError):
+46 with patch.object(urllib.request, 'urlopen', return_value=date):
+47 what_is_year_now()
+ ++ « prev + ^ index + » next + + coverage.py v7.3.2, + created at 2023-11-16 01:33 +0300 +
+ +1import urllib.request
+2import json
+ + +5API_URL = 'http://worldclockapi.com/api/json/utc/now'
+ +7YMD_SEP = '-'
+8YMD_SEP_INDEX = 4
+9YMD_YEAR_SLICE = slice(None, YMD_SEP_INDEX)
+ +11DMY_SEP = '.'
+12DMY_SEP_INDEX = 5
+13DMY_YEAR_SLICE = slice(DMY_SEP_INDEX + 1, DMY_SEP_INDEX + 5)
+ + +16def what_is_year_now() -> int:
+17 """
+18 Получает текущее время из API-worldclock и извлекает из поля 'currentDateTime' год
+19 Предположим, что currentDateTime может быть в двух форматах:
+20 * YYYY-MM-DD - 2019-03-01
+21 * DD.MM.YYYY - 01.03.2019
+22 """
+23 with urllib.request.urlopen(API_URL) as resp:
+24 resp_json = json.load(resp)
+ +26 datetime_str = resp_json['currentDateTime']
+27 if datetime_str[YMD_SEP_INDEX] == YMD_SEP:
+28 year_str = datetime_str[YMD_YEAR_SLICE]
+29 elif datetime_str[DMY_SEP_INDEX] == DMY_SEP:
+30 year_str = datetime_str[DMY_YEAR_SLICE]
+31 else:
+32 raise ValueError('Invalid format')
+ +34 return int(year_str)
+ +