From d8d1e33168bf0fafe80e75bd3195a018f8654d43 Mon Sep 17 00:00:00 2001 From: fattybobcat Date: Tue, 25 May 2021 10:57:30 +0300 Subject: [PATCH 1/8] add test coverage 100% --- .gitignore | 1 + code.py | 3 +- requirements.txt | 6 ++ setup.cfg | 2 + tests/__init__.py | 0 tests/conftest.py | 15 ++++ tests/test_code_function.py | 175 ++++++++++++++++++++++++++++++++++++ 7 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 setup.cfg create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_code_function.py diff --git a/.gitignore b/.gitignore index 307e001..b79e5c5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ wheels/ *.egg-info/ .installed.cfg *.egg +.idea/ # PyInstaller # Usually these files are written by a python script from a template diff --git a/code.py b/code.py index 784807b..e2e2d37 100644 --- a/code.py +++ b/code.py @@ -2,7 +2,7 @@ import datetime import io import re -from typing import Iterable, Any, Optional, Union, Generator +from typing import Iterable, Any, Optional, Generator from PIL import Image from requests import get @@ -107,4 +107,3 @@ def max_with_default(items: Iterable, default: Optional = None): def is_python_class_name(name: str) -> bool: return name[0] == name[0].upper() and name[1:] == name[1:].lower() - diff --git a/requirements.txt b/requirements.txt index f045283..2328862 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,8 @@ Pillow==8.1.2 requests==2.25.1 +flake8==3.9.2 +pytest==6.2.4 +pytest-cov==2.12.0 +pytest-mock==3.6.1 +requests-mock==1.9.2 + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..6deafc2 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..e2a389a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest +from PIL import Image + + +SIZE_IMAGE = 100 + + +class MyTestClass: + pass + + +@pytest.fixture() +def create_image(): + image = Image.new('RGBA', size=(SIZE_IMAGE, SIZE_IMAGE)) + return image diff --git a/tests/test_code_function.py b/tests/test_code_function.py new file mode 100644 index 0000000..4293753 --- /dev/null +++ b/tests/test_code_function.py @@ -0,0 +1,175 @@ +import pytest +import ast +import datetime + +from code import (flat, is_python_class_name, parse_iso_datetime, chunks, + is_camel_case_word, if_logs_has_any_of_commands, is_path_in_exclude_list, + get_full_class_name, max_with_default, split_camel_case_words, extract_all_constants_from_ast, + has_recursive_calls, get_image_height_in_pixels) +from .conftest import MyTestClass + + +@pytest.mark.parametrize( + 'some_list, expected', + [ + ([['People'], ['Name', 'Job']], ['People', 'Name', 'Job']), + ([[], [1, 'a']], [1, 'a']), + ], +) +def test_flat(some_list, expected): + assert flat(some_list) == expected + + +@pytest.mark.parametrize( + 'some_name, expected', + [ + ('User', True), + ('name', False), + ('userName', False) + ], +) +def test_is_python_class_name(some_name, expected): + assert is_python_class_name(some_name) == expected + + +@pytest.mark.parametrize( + 'iso_datetime, expected', + [ + ('2008-09-03T20:56:35.450686Z', datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)), + ('name', None), + ('2018-11-11', datetime.datetime(2018, 11, 11, 0, 0)), + ('2010-09-03T20:56:35.45', None), + ], +) +def test_parse_iso_datetime(iso_datetime, expected): + assert parse_iso_datetime(iso_datetime) == expected + + +@pytest.mark.parametrize( + 'some_list, chunk_size, expected', + [ + ([1, 2, 3, 4, 5, 6, 7, 8, 9], 4, [[1, 2, 3, 4], [5, 6, 7, 8], [9]]), + ([1, 2, 3, 4, 5], 3, [[1, 2, 3], [4, 5]]), + ([], 3, []), + ] + +) +def test_chunks(some_list, chunk_size, expected): + assert list(chunks(some_list, chunk_size)) == expected + + +@pytest.mark.parametrize( + 'log, some_commands, expected', + [ + (['update photo', 'delete'], ['update', 'read', 'exit'], True), + (['user post new recipes', 'user read url'], ['update', 'read', 'exit'], True), + (['delete', 'send'], ['update'], False), + ([], ['read'], False), + ], +) +def test_if_logs_has_any_of_commands(log, some_commands, expected): + assert if_logs_has_any_of_commands(log, some_commands) == expected + + +@pytest.mark.parametrize( + 'some_word, expected', + [ + ('CamelCaps', True), + ('camelcaps', False), + ('CamelHumpedWord', True), + ('Ca', False), + ('cA', True), + ('', False), + ], +) +def test_is_camel_case_word(some_word, expected): + assert is_camel_case_word(some_word) == expected + + +@pytest.mark.parametrize( + 'some_path, exclude, expected', + [ + ('some_path', ['some', 'path'], True), + ('some path', ['path'], True), + ('some path', [''], True), + ('some path', [], False), + ('', [], False), + ('', [''], True), + ] +) +def test_is_path_in_exclude_list(some_path, exclude, expected): + assert is_path_in_exclude_list(some_path, exclude) == expected + + +@pytest.mark.parametrize( + 'some_obj, expected', + [ + (4.3, 'float'), + ('text', 'str'), + ([2], 'list'), + (MyTestClass(), 'tests.conftest.MyTestClass'), + ] +) +def test_get_full_class_name(some_obj, expected): + assert get_full_class_name(some_obj) == expected + + +@pytest.mark.parametrize( + 'some_items, default, expected', + [ + ([1, -2, 3], 1, 3), + ('', None, 0), + ([], 15, 15), + ('AaBbCcXxYyZz', None, 'z'), + ] +) +def test_max_with_default(some_items, default, expected): + assert max_with_default(some_items, default) == expected + + +@pytest.mark.parametrize( + 'camel_cased_word, expected', + [ + ('SomeCamelCasedWord', ['some', 'camel', 'cased', 'word']), + (' CamelCasedWord', [' ', 'camel', 'cased', 'word']), + ('CamelCasedsoMeWorD', ['camel', 'casedso', 'me', 'wor', 'd']), + ] +) +def test_split_camel_case_words(camel_cased_word, expected): + assert split_camel_case_words(camel_cased_word) == expected + + +@pytest.mark.parametrize( + 'ast_tree, expected', + [ + ("fruits = ['mango', 'grapes']", {'mango', 'grapes'}), + ("a = 'Bob'", {'Bob'}), + ] + +) +def test_extract_all_constants_from_ast(ast_tree, expected): + assert {*extract_all_constants_from_ast(ast.parse(ast_tree))} == expected + + +@pytest.mark.parametrize( + 'some_funcdef, expected', + [ + ('def func(n):\n\treturn func(n/2)', True), + ('def func(n):\n\treturn n/2', False), + ] +) +def test_has_recursive_calls(some_funcdef, expected): + assert has_recursive_calls(ast.parse(some_funcdef).body[0]) == expected + + +@pytest.mark.parametrize( + 'some_url, expected', + [ + ('url', None), + ('http://climbhub.com/', 100), + ], +) +def test_get_image_height_in_pixels(some_url, expected, create_image, requests_mock, mocker): + requests_mock.get(some_url, content=b"request") + mocker.patch('PIL.Image.open', return_value=create_image) + assert get_image_height_in_pixels(some_url) == expected From 1e9fac62f18f7ee323f38a7094f040c6941bfcff Mon Sep 17 00:00:00 2001 From: fattybobcat Date: Tue, 25 May 2021 19:31:56 +0300 Subject: [PATCH 2/8] add travis.yml --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..05f0e8f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: python +python: + - "3.9" +install: + - pip install -r requirements.txt +script: + - flake8 . + - pytest --cov=code tests/ + - coverage run -m --branch pytest +after_success: + - bash <(curl -s https://codecov.io/bash) From ee3cd50ffff7243c8ea8aecbfccbcf95b8f47f4d Mon Sep 17 00:00:00 2001 From: fattybobcat Date: Tue, 25 May 2021 19:45:17 +0300 Subject: [PATCH 3/8] add travis.yml --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2328862..22f023e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,3 @@ pytest==6.2.4 pytest-cov==2.12.0 pytest-mock==3.6.1 requests-mock==1.9.2 - From 9215a10e75f7718a6f63d6e19fdba331557ff7b0 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 25 May 2021 19:48:38 +0300 Subject: [PATCH 4/8] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aedb07d..8cd1319 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.com/fattybobcat/level_1.svg?branch=main)](https://travis-ci.com/fattybobcat/level_1) + # Testing sandbox level 1 Welcome to the testing sandbox: practice-driven testing instrument. From 18fe7b3bca66b55ebea88fce7454cf4385ebe255 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 25 May 2021 19:52:20 +0300 Subject: [PATCH 5/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8cd1319..256a402 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.com/fattybobcat/level_1.svg?branch=main)](https://travis-ci.com/fattybobcat/level_1) +[![codecov](https://codecov.io/gh/fattybobcat/level_1/branch/main/graph/badge.svg?token=D44NANH2J6)](https://codecov.io/gh/fattybobcat/level_1) # Testing sandbox level 1 From d7554784e0fde825a1c62e14d1a03afd1eebfb1a Mon Sep 17 00:00:00 2001 From: fattybobcat Date: Tue, 25 May 2021 19:58:39 +0300 Subject: [PATCH 6/8] try add 1% test --- tests/test_code_function.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_code_function.py b/tests/test_code_function.py index 4293753..6113bc1 100644 --- a/tests/test_code_function.py +++ b/tests/test_code_function.py @@ -133,6 +133,8 @@ def test_max_with_default(some_items, default, expected): ('SomeCamelCasedWord', ['some', 'camel', 'cased', 'word']), (' CamelCasedWord', [' ', 'camel', 'cased', 'word']), ('CamelCasedsoMeWorD', ['camel', 'casedso', 'me', 'wor', 'd']), + ('aCa', ['a', 'ca']), + (" Camel Case WordCase case wordCase", [' ', 'camel ', 'case ', 'word', 'case case word', 'case']) ] ) def test_split_camel_case_words(camel_cased_word, expected): From 7eb1e9dcd3eeaba02e614e7f3dcc36197c23d3ae Mon Sep 17 00:00:00 2001 From: fattybobcat Date: Thu, 27 May 2021 08:14:44 +0300 Subject: [PATCH 7/8] ignore pragma --- code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code.py b/code.py index e2e2d37..07bf82b 100644 --- a/code.py +++ b/code.py @@ -78,7 +78,7 @@ def split_camel_case_words(camel_cased_word: str) -> list[str]: words_start_indexes = [m.start(0) for m in re.finditer(r'[A-Z]', camel_cased_word)] if words_start_indexes[0] > 0: words_start_indexes.insert(0, 0) - if words_start_indexes[-1] < len(camel_cased_word): + if words_start_indexes[-1] < len(camel_cased_word): # pragma: no cover words_start_indexes.append(len(camel_cased_word)) words = [] for word_start_index, word_end_index in zip(words_start_indexes, words_start_indexes[1:]): From 4eb36b30f081254baa75f2dc966a07a0d20acc4d Mon Sep 17 00:00:00 2001 From: fattybobcat Date: Tue, 1 Jun 2021 08:21:21 +0300 Subject: [PATCH 8/8] add test after review --- tests/test_code_function.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_code_function.py b/tests/test_code_function.py index 6113bc1..c2a2e9b 100644 --- a/tests/test_code_function.py +++ b/tests/test_code_function.py @@ -14,6 +14,8 @@ [ ([['People'], ['Name', 'Job']], ['People', 'Name', 'Job']), ([[], [1, 'a']], [1, 'a']), + ([[], {}], []), + ([{}, [1, 2, {'a': 4}]], [1, 2, {'a': 4}]) ], ) def test_flat(some_list, expected): @@ -65,6 +67,7 @@ def test_chunks(some_list, chunk_size, expected): (['user post new recipes', 'user read url'], ['update', 'read', 'exit'], True), (['delete', 'send'], ['update'], False), ([], ['read'], False), + (['start'], ['start'], True) ], ) def test_if_logs_has_any_of_commands(log, some_commands, expected):