From c0819c278463f47048b27c3d675f684e2955f9e6 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Wed, 26 May 2021 14:52:14 +0900 Subject: [PATCH 01/16] Pass unit test levev 1 --- test_code.py | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 test_code.py diff --git a/test_code.py b/test_code.py new file mode 100644 index 0000000..b2f1fe1 --- /dev/null +++ b/test_code.py @@ -0,0 +1,125 @@ +import pytest +import ast + +from code import chunks, flat, has_recursive_calls, parse_iso_datetime, get_image_height_in_pixels +from code import if_logs_has_any_of_commands, extract_all_constants_from_ast, is_camel_case_word +from code import split_camel_case_words, is_path_in_exclude_list, get_full_class_name, max_with_default +from code import is_python_class_name + + +def test_chunk_iteration(): + some_list = [1, 2, 3, 4, 5] + chunk_size = 1 + some_chunks = chunks(some_list, chunk_size) + with pytest.raises(StopIteration): + while True: + next(some_chunks) + + +def test_flat(): + some_list = ['hello' 'world'] + some_flat = flat(some_list) + assert type(some_flat) == list + + +def test_has_recursive_calls(): + expression = '5/3+8' + funcdef = ast.parse(expression) + calls = has_recursive_calls(funcdef) + assert calls == False + + +def test_parse_iso_datetime(): + iso_datetime = '2021-05-24T10:34:25.518993Z' + assert parse_iso_datetime(iso_datetime).year == 2021 + iso_datetime = '2021' + assert parse_iso_datetime(iso_datetime) is None + + +@pytest.mark.parametrize( + 'image_url, expected', + [ + ('some.url', None), + ('https://via.placeholder.com/140x100', 100), + ] +) +def test_get_image_height_in_pixels(image_url, expected): + assert get_image_height_in_pixels(image_url) == expected + + +@pytest.mark.parametrize( + 'log, commands, expected', + [ + (['move forward'], ['move'], True), + (['variable set on'], ['set'], True), + (['put'], ['put'], True) + ] +) +def test_if_logs_has_any_of_commands(log, commands, expected): + assert if_logs_has_any_of_commands(log, commands) == expected + + +def test_extract_all_constants_from_ast(): + expression = '5/3+8' + ast_tree = ast.parse(expression) + const = extract_all_constants_from_ast(ast_tree) + assert type(const) == list + + +@pytest.mark.parametrize( + 'word, expected', + [ + ('SuperClass', True), + ('nonameclass', False) + ] +) +def test_is_camel_case_word(word, expected): + assert is_camel_case_word(word) == expected + + +@pytest.mark.parametrize( + 'camel_cased_word, expected', + [ + ('SuperMegaClass', ['super', 'mega', 'class']), + ('userName', ['user', 'name']) + ] +) +def test_split_camel_case_words(camel_cased_word, expected): + assert split_camel_case_words(camel_cased_word) == expected + + +@pytest.mark.parametrize( + 'path, exclude, expected', + [ + ('user/project/template', ['project', 'projects'], True), + ('lib/bin/', ['project', 'projects'], False) + ] +) +def test_is_path_in_exclude_list(path, exclude, expected): + assert is_path_in_exclude_list(path, exclude) == expected + + +def test_get_full_class_name(): + class SomeClass(): + pass + + x = SomeClass() + y = 'Hello World' + assert get_full_class_name(x) == 'test_code.SomeClass' + assert get_full_class_name(y) == 'str' + + +@pytest.mark.parametrize( + 'items, default, expected', + [ + ([], 1, 1), + ([1, 2], None, 2), + ] +) +def test_max_with_default(items, default, expected): + assert max_with_default(items, default) == expected + + +def test_is_python_class_name(): + name = 'List' + assert is_python_class_name(name) == True From 0bbd92392550e2a611616509715ce6a60416519c Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Wed, 26 May 2021 14:52:31 +0900 Subject: [PATCH 02/16] Update requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index f045283..624f453 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ Pillow==8.1.2 requests==2.25.1 +pytest==6.2.4 +coverage==5.5 From c4f9c012cddb1d52ecd8674f3e582313e9481b5e Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Wed, 26 May 2021 14:52:57 +0900 Subject: [PATCH 03/16] Initial commit --- conftest.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 conftest.py diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..e69de29 From 800059dae9fabffef69553488a74897dc556de10 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:20:03 +0900 Subject: [PATCH 04/16] Update requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 624f453..794040d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ Pillow==8.1.2 requests==2.25.1 pytest==6.2.4 coverage==5.5 +pytest-cov==2.12.0 +flake8==3.9.2 From 28d87e9d97907cb07acc8d628ad7dd9a3c1d7390 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:20:21 +0900 Subject: [PATCH 05/16] Add flake8 config --- .flake8 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..4bb06ec --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 120 +exclude = venv From 352ec5f97fdf5377ada6b6ca1a1aa21ccb284d78 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:20:37 +0900 Subject: [PATCH 06/16] Add CI integrations --- .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..0c2c9c4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: python +python: + - "3.9" +install: + - pip install -r requirements.txt +script: + - flake8 . + - coverage run -m pytest +after_success: + - bash <(curl -s https://codecov.io/bash) + From 01a48573b96366d394eae33847f0f413119b585e Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:23:08 +0900 Subject: [PATCH 07/16] Fix import --- code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code.py b/code.py index 784807b..737b0dd 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 From 53e7643daa5a2fda3497c8324d29efde065f54a3 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:28:22 +0900 Subject: [PATCH 08/16] Fix flake8 bugs --- test_code.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_code.py b/test_code.py index b2f1fe1..a5e95a3 100644 --- a/test_code.py +++ b/test_code.py @@ -26,7 +26,7 @@ def test_has_recursive_calls(): expression = '5/3+8' funcdef = ast.parse(expression) calls = has_recursive_calls(funcdef) - assert calls == False + assert not calls def test_parse_iso_datetime(): @@ -122,4 +122,4 @@ def test_max_with_default(items, default, expected): def test_is_python_class_name(): name = 'List' - assert is_python_class_name(name) == True + assert is_python_class_name(name) From e96932d152919a3957b33870008b4a21709a6f3a Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:31:17 +0900 Subject: [PATCH 09/16] Fix flake8 bugs --- code.py | 1 - 1 file changed, 1 deletion(-) diff --git a/code.py b/code.py index 737b0dd..e2e2d37 100644 --- a/code.py +++ b/code.py @@ -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() - From 586fda454943eeb4cd2b20242478c4c82bf1b2a5 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Thu, 27 May 2021 17:52:33 +0900 Subject: [PATCH 10/16] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index aedb07d..1adc609 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Testing sandbox level 1 +[![Build Status](https://travis-ci.com/DmitryTokyo/level_1.svg?branch=main)](https://travis-ci.com/DmitryTokyo/level_1) +[![codecov](https://codecov.io/gh/DmitryTokyo/level_1/branch/main/graph/badge.svg?token=25YKHAMA72)](https://codecov.io/gh/DmitryTokyo/level_1) + Welcome to the testing sandbox: practice-driven testing instrument. It can help you to get more comfortable and skilful at writing different types of tests. From 389f872c4c3c4f7c96f769c2bc1d03ccf71ffbb3 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Mon, 31 May 2021 21:15:01 +0900 Subject: [PATCH 11/16] Add flake8 config --- .flake8 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 4bb06ec..7a2df47 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,4 @@ [flake8] max-line-length = 120 -exclude = venv +exclude = venv, code.py +ignore = C812, D103, TAE001, D100, D101 From 17b1501e2b9428f2455aeaafa5aa52b7e4c3636d Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Mon, 31 May 2021 21:15:18 +0900 Subject: [PATCH 12/16] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 307e001..2b35e36 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,4 @@ make.exe *.json *sqlite3 +practice.py From 4995c11c355f0906913e09b29da3ec4d054560a5 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Mon, 31 May 2021 21:15:37 +0900 Subject: [PATCH 13/16] update requirements.txt --- requirements.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/requirements.txt b/requirements.txt index 794040d..c9d4376 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,36 @@ requests==2.25.1 pytest==6.2.4 coverage==5.5 pytest-cov==2.12.0 +requests-mock==1.9.3 +pytest-mock==3.6.1 + flake8==3.9.2 +flake8-2020==1.6.0 +flake8-blind-except==0.2.0 +flake8-bugbear==20.11.1 +flake8-builtins==1.5.3 +flake8-commas==2.0.0 +flake8-comprehensions==3.3.1 +flake8-debugger==4.0.0 +flake8-docstrings==1.5.0 +flake8-eradicate==1.0.0 +flake8-polyfill==1.0.2 +flake8-print==4.0.0 +flake8-quotes==3.2.0 +flake8-string-format==0.3.0 +flake8-fixme==1.1.1 +flake8-annotations-complexity==0.0.6 +flake8-variables-names==0.0.4 +flake8-class-attributes-order==0.1.2 +flake8-broken-line==0.3.0 +flake8-tidy-imports==4.2.1 +flake8-typing-imports==1.10.1 +flake8-if-statements==0.1.0 +flake8-functions==0.0.5 +flake8-annotations-coverage==0.0.5 +flake8-expression-complexity==0.0.9 +flake8-printf-formatting==1.1.2 +flake8-multiline-containers==0.0.17 +flake8-absolute-import==1.0 +flake8-simplify==0.13.0 +flake8-functions-names==0.0.5 From 6bced3c0f7056bce822009dfc8be2baff6a32630 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Mon, 31 May 2021 21:16:00 +0900 Subject: [PATCH 14/16] Add fixture and class --- conftest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/conftest.py b/conftest.py index e69de29..8d0476a 100644 --- a/conftest.py +++ b/conftest.py @@ -0,0 +1,12 @@ +import pytest +from PIL import Image + + +@pytest.fixture +def get_fixture_image_object(): + im = Image.new('1', (100, 100)) + return im + + +class SomeClass: + pass From 123833e02c9648fb7867239fe25b41c8573cb813 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Mon, 31 May 2021 21:16:16 +0900 Subject: [PATCH 15/16] Update all test functions --- test_code.py | 158 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 56 deletions(-) diff --git a/test_code.py b/test_code.py index a5e95a3..cf6efbe 100644 --- a/test_code.py +++ b/test_code.py @@ -1,50 +1,64 @@ +import datetime import pytest import ast -from code import chunks, flat, has_recursive_calls, parse_iso_datetime, get_image_height_in_pixels -from code import if_logs_has_any_of_commands, extract_all_constants_from_ast, is_camel_case_word -from code import split_camel_case_words, is_path_in_exclude_list, get_full_class_name, max_with_default -from code import is_python_class_name +from code import (chunks, flat, has_recursive_calls, parse_iso_datetime, get_image_height_in_pixels, + if_logs_has_any_of_commands, extract_all_constants_from_ast, is_camel_case_word, + split_camel_case_words, is_path_in_exclude_list, get_full_class_name, max_with_default, + is_python_class_name) +from conftest import SomeClass -def test_chunk_iteration(): - some_list = [1, 2, 3, 4, 5] - chunk_size = 1 - some_chunks = chunks(some_list, chunk_size) - with pytest.raises(StopIteration): - while True: - next(some_chunks) - +@pytest.mark.parametrize( + 'somelist, chunk_size, expected', + [ + ([1, 2, 3, 4, 5], 2, [[1, 2], [3, 4], [5]]), + ([], 3, []), + (['a', 'b'], 3, [['a', 'b']]), + ] +) +def test_chunk_iteration(somelist, chunk_size, expected): + some_chunks = chunks(somelist, chunk_size) + assert list(some_chunks) == expected -def test_flat(): - some_list = ['hello' 'world'] - some_flat = flat(some_list) - assert type(some_flat) == list +@pytest.mark.parametrize( + 'some_list, expected', + [ + ([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'j']], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j']), + ([], []), + ([{1: 'a', 2: 'b'}, {3: 'q', 4: 'w'}], [1, 2, 3, 4]), + ] +) +def test_flat(some_list, expected): + assert flat(some_list) == expected -def test_has_recursive_calls(): - expression = '5/3+8' - funcdef = ast.parse(expression) - calls = has_recursive_calls(funcdef) - assert not calls +@pytest.mark.parametrize( + 'expression, expected', + [ + ('5/3+8', False), + ('def foo(): return foo()', True), -def test_parse_iso_datetime(): - iso_datetime = '2021-05-24T10:34:25.518993Z' - assert parse_iso_datetime(iso_datetime).year == 2021 - iso_datetime = '2021' - assert parse_iso_datetime(iso_datetime) is None + ] +) +def test_has_recursive_calls(expression, expected): + funcdef = ast.parse(expression).body[0] + assert has_recursive_calls(funcdef) == expected @pytest.mark.parametrize( - 'image_url, expected', + 'some_datetime, expected', [ - ('some.url', None), - ('https://via.placeholder.com/140x100', 100), + ('2021-05-24T10:34:25.518993Z', datetime.datetime(2021, 5, 24, 10, 34, 25, 518993)), + ('2021.05.28', None), + ('', None), + ('2021-05-24T10:34:25.518993', datetime.datetime(2021, 5, 24, 10, 34, 25, 518993)), + ] ) -def test_get_image_height_in_pixels(image_url, expected): - assert get_image_height_in_pixels(image_url) == expected +def test_parse_iso_datetime(some_datetime, expected): + assert parse_iso_datetime(some_datetime) == expected @pytest.mark.parametrize( @@ -52,36 +66,46 @@ def test_get_image_height_in_pixels(image_url, expected): [ (['move forward'], ['move'], True), (['variable set on'], ['set'], True), - (['put'], ['put'], True) + (['put'], ['put'], True), + (['some text'], ['erase'], False), ] ) def test_if_logs_has_any_of_commands(log, commands, expected): assert if_logs_has_any_of_commands(log, commands) == expected -def test_extract_all_constants_from_ast(): - expression = '5/3+8' - ast_tree = ast.parse(expression) - const = extract_all_constants_from_ast(ast_tree) - assert type(const) == list +@pytest.mark.parametrize( + 'expression, expected', + [ + ('def foo(): return foo()', []), + ('def foo(): return "text"', ['text']), + ] +) +def test_extract_all_constants_from_ast(expression, expected): + tree = ast.parse(expression).body[0] + assert extract_all_constants_from_ast(tree) == expected @pytest.mark.parametrize( - 'word, expected', + 'some_word, expected', [ ('SuperClass', True), - ('nonameclass', False) + ('nonameclass', False), + ('email_address', False), + ('EmailVerification', True), + ('oldEmail', True), ] ) -def test_is_camel_case_word(word, expected): - assert is_camel_case_word(word) == expected +def test_is_camel_case_word(some_word, expected): + assert is_camel_case_word(some_word) == expected @pytest.mark.parametrize( 'camel_cased_word, expected', [ ('SuperMegaClass', ['super', 'mega', 'class']), - ('userName', ['user', 'name']) + ('userName', ['user', 'name']), + ('Sometext', ['sometext']), ] ) def test_split_camel_case_words(camel_cased_word, expected): @@ -92,23 +116,15 @@ def test_split_camel_case_words(camel_cased_word, expected): 'path, exclude, expected', [ ('user/project/template', ['project', 'projects'], True), - ('lib/bin/', ['project', 'projects'], False) + ('lib/bin/', ['project', 'projects'], False), + ('C:\\User\\Documents', ['User'], True), + ('D:\\Game\\Civilization', ['Program', 'User'], False), ] ) def test_is_path_in_exclude_list(path, exclude, expected): assert is_path_in_exclude_list(path, exclude) == expected -def test_get_full_class_name(): - class SomeClass(): - pass - - x = SomeClass() - y = 'Hello World' - assert get_full_class_name(x) == 'test_code.SomeClass' - assert get_full_class_name(y) == 'str' - - @pytest.mark.parametrize( 'items, default, expected', [ @@ -120,6 +136,36 @@ def test_max_with_default(items, default, expected): assert max_with_default(items, default) == expected -def test_is_python_class_name(): - name = 'List' - assert is_python_class_name(name) +@pytest.mark.parametrize( + 'classname, expected', + [ + ('List', True), + ('car', False), + ] +) +def test_is_python_class_name(classname, expected): + assert is_python_class_name(classname) == expected + + +@pytest.mark.parametrize( + 'image_url, expected', + [ + ('some.url', None), + ('https://fake.url', 100), + ] +) +def test_get_image_height_in_pixels(requests_mock, mocker, get_fixture_image_object, image_url, expected): + requests_mock.get(image_url, content=b'fakeurl') + mocker.patch('PIL.Image.open', return_value=get_fixture_image_object) + assert get_image_height_in_pixels(image_url) == expected + + +@pytest.mark.parametrize( + 'obj, expected', + [ + ('Hello World', 'str'), + (SomeClass(), 'conftest.SomeClass') + ] +) +def test_get_full_class_name(obj, expected): + assert get_full_class_name(obj) == expected From 3d9ae26a063f094e6cda77835514b2ec1d6e08b1 Mon Sep 17 00:00:00 2001 From: andimeon-ubuntu Date: Mon, 31 May 2021 21:20:17 +0900 Subject: [PATCH 16/16] Update requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index c9d4376..4f841be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,3 +36,5 @@ flake8-multiline-containers==0.0.17 flake8-absolute-import==1.0 flake8-simplify==0.13.0 flake8-functions-names==0.0.5 +mypy-extensions==0.4.3 +