Skip to content

Commit

Permalink
Merge pull request #35 from hyperskill/master
Browse files Browse the repository at this point in the history
Release supporting unit tests
  • Loading branch information
inuur authored Oct 18, 2022
2 parents 692e2c0 + a67d341 commit 3f266b1
Show file tree
Hide file tree
Showing 404 changed files with 3,334 additions and 5,615 deletions.
23 changes: 23 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[flake8]
count = True
max-line-length = 100
max-doc-length = 100
exclude =
.git,
__pycache__,
build,
dist,
node_modules,
venv,
.mypy_cache,
tests/projects,
tests/outcomes/**/main*.py,
tests/outcomes/**/cleaning.py,
tests/outcomes/**/pandas_*.py,
tests/outcomes/**/matplotlib_*.py,
tests/outcomes/**/seaborn_*.py
ignore =
# visually indented line with same indent as next logical line
E129,
# W504 line break after binary operator line break after binary operator
W504
6 changes: 6 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Task: [#HSPC-](https://vyahhi.myjetbrains.com/youtrack/issue/HSPC-)

**Reviewers**
- [ ] @

**Description**
93 changes: 93 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Python package

on: [ push ]

jobs:
Lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.6
uses: actions/setup-python@v4
with:
python-version: "3.6"
- name: Python version
run: python --version
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
npm install
- name: python version
run: python --version
- name: Lint
run: flake8
test-ubuntu:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10" ]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Python version
run: python --version
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
npm install
- name: Run unittests
run: python tests/testing.py
test-windows:
runs-on: windows-latest
env:
PYTHONIOENCODING: 'utf-8'
strategy:
fail-fast: false
matrix:
python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10" ]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Python version
run: python --version
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
npm install
- name: Run unittests
run: python tests/testing.py
test-macos:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10" ]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Python version
run: python --version
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
npm install
- name: Run unittests
run: python tests/testing.py
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
**__pycache__**
.idea
venv*
build/
/hs_test_python.egg-info/
node_modules
package-lock.json
18 changes: 14 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
FROM python:3.8.2-alpine3.11
FROM python:3.6-alpine3.15

RUN apk add --no-cache \
bash \
g++ \
gcc \
linux-headers

RUN pip install --no-cache-dir \
matplotlib \
seaborn \
pandas \
numpy

COPY . hs-test-python
RUN pip3 install --no-cache-dir ./hs-test-python

RUN apk add bash

WORKDIR /hs-test-python
ENV PYTHONPATH=.

CMD ["bin/bash"]
CMD ["bash"]
14 changes: 4 additions & 10 deletions hstest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'DjangoTest',
'FlaskTest',
'PlottingTest',
'SQLTest',

'TestCase',
'SimpleTestCase',
Expand All @@ -19,16 +20,9 @@
]

from hstest.dynamic.dynamic_test import dynamic_test
from hstest.exception.outcomes import TestPassed
from hstest.exception.outcomes import WrongAnswer
from hstest.stage import DjangoTest
from hstest.stage import FlaskTest
from hstest.stage import StageTest
from hstest.test_case import CheckResult
from hstest.test_case import SimpleTestCase
from hstest.test_case import TestCase
from hstest.test_case import correct
from hstest.test_case import wrong
from hstest.exception.outcomes import TestPassed, WrongAnswer
from hstest.stage import DjangoTest, FlaskTest, SQLTest, StageTest
from hstest.test_case import CheckResult, correct, SimpleTestCase, TestCase, wrong
from hstest.testing.tested_program import TestedProgram

try:
Expand Down
2 changes: 1 addition & 1 deletion hstest/check_result.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# deprecated, but old tests use "from hstest.check_result import CheckResult"
# new way to import is "from hstest import CheckResult"
from hstest.test_case import CheckResult, correct, wrong
from hstest.test_case import CheckResult, correct, wrong # noqa: F401
26 changes: 17 additions & 9 deletions hstest/common/reflection_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,23 @@
def is_tests(stage):
package = inspect.getmodule(stage).__package__
file = inspect.getmodule(stage).__file__
return package and package.startswith('tests.outcomes.') or \
package and package.startswith('tests.projects.') or \
file and f'{os.sep}hs-test-python{os.sep}tests{os.sep}outcomes{os.sep}' in file or \
file and f'{os.sep}hs-test-python{os.sep}tests{os.sep}projects{os.sep}' in file
return (
package and package.startswith('tests.outcomes.') or
package and package.startswith('tests.projects.') or
file and f'{os.sep}hs-test-python{os.sep}tests{os.sep}outcomes{os.sep}' in file or
file and f'{os.sep}hs-test-python{os.sep}tests{os.sep}projects{os.sep}' in file or
file and f'{os.sep}hs-test-python{os.sep}tests{os.sep}sql{os.sep}' in file
)


def setup_cwd(stage):
test_file = inspect.getmodule(stage).__file__
test_folder = os.path.dirname(test_file)
os.chdir(test_folder)
if stage.is_tests:
test_file = inspect.getmodule(stage).__file__
test_folder = os.path.dirname(test_file)
os.chdir(test_folder)

if os.path.basename(os.getcwd()) == 'test':
os.chdir(os.path.dirname(os.getcwd()))


def get_stacktrace(ex: BaseException, hide_internals=False) -> str:
Expand Down Expand Up @@ -100,7 +107,7 @@ def str_to_stacktrace(str_trace: str) -> str:
exec(compile(contents+"\n", file, 'exec'), glob, loc)
Which will appear when testing locally inside PyCharm.
'''
''' # noqa: W291, W505, E501
if f'{os.sep}JetBrains{os.sep}' in trace:
continue

Expand All @@ -118,7 +125,8 @@ def str_to_stacktrace(str_trace: str) -> str:
return clean_stacktrace([before] + user_traceback + [after], user_traceback)


def clean_stacktrace(full_traceback: List[str], user_traceback: List[str], user_dir: str = '') -> str:
def clean_stacktrace(full_traceback: List[str],
user_traceback: List[str], user_dir: str = '') -> str:
dir_names = []
for tr in user_traceback:
try:
Expand Down
16 changes: 9 additions & 7 deletions hstest/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
success_msg = '#educational_plugin test OK'


def failed(message: str):
def failed(message: str, is_unittest: bool):
""" Reports failure """
lines = message.splitlines()
print('\n' + failed_msg_start + lines[0])
for line in lines[1:]:
print(failed_msg_continue + line)
if not is_unittest:
lines = message.splitlines()
print('\n' + failed_msg_start + lines[0])
for line in lines[1:]:
print(failed_msg_continue + line)
return -1, message


def passed():
def passed(is_unittest: bool):
""" Reports success """
print('\n' + success_msg)
if not is_unittest:
print('\n' + success_msg)
return 0, 'test OK'


Expand Down
11 changes: 7 additions & 4 deletions hstest/dynamic/input/dynamic_input_func.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from typing import Callable, Optional, Union
from typing import Callable, Optional, TYPE_CHECKING, Union

InputFunction = Callable[[str], Union[str, 'CheckResult']]
DynamicTestFunction = Callable[[], Optional[str]]
if TYPE_CHECKING:
from hstest import CheckResult

InputFunction = Callable[[str], Union[str, CheckResult]]
DynamicTestFunction = Callable[[], Optional[str]]


class DynamicInputFunction:
def __init__(self, trigger_count: int, func: InputFunction):
def __init__(self, trigger_count: int, func: 'InputFunction'):
self.trigger_count = trigger_count
self.input_function = func

Expand Down
8 changes: 5 additions & 3 deletions hstest/dynamic/input/dynamic_input_handler.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from typing import Optional, List
from typing import List, Optional, TYPE_CHECKING

from hstest.common.utils import clean_text
from hstest.dynamic.input.dynamic_input_func import DynamicTestFunction
from hstest.dynamic.output.infinite_loop_detector import loop_detector
from hstest.dynamic.output.output_handler import OutputHandler

if TYPE_CHECKING:
from hstest.dynamic.input.dynamic_input_func import DynamicTestFunction


class DynamicInputHandler:
def __init__(self, func: DynamicTestFunction):
def __init__(self, func: 'DynamicTestFunction'):
self._dynamic_input_function: DynamicTestFunction = func
self._input_lines: List[str] = []

Expand Down
27 changes: 15 additions & 12 deletions hstest/dynamic/input/dynamic_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
from hstest.exception.outcomes import TestPassed, UnexpectedError, WrongAnswer
from hstest.testing.tested_program import TestedProgram

DynamicTesting = Callable[[], Optional['CheckResult']]
DynamicTestingWithoutParams = Callable[['StageTest', Any], Optional['CheckResult']]

if typing.TYPE_CHECKING:
from hstest import StageTest, TestCase
from hstest import CheckResult, StageTest, TestCase
from hstest.dynamic.input.dynamic_input_func import DynamicInputFunction

DynamicTesting = Callable[[], Optional[CheckResult]]
DynamicTestingWithoutParams = Callable[[StageTest, Any], Optional[CheckResult]]


class DynamicTestElement:
def __init__(self,
test: DynamicTestingWithoutParams,
test: 'DynamicTestingWithoutParams',
name: str,
order: Tuple[int, int],
repeat: int,
Expand Down Expand Up @@ -68,13 +68,17 @@ def check_errors(self):

for k, v in self.files.items():
if type(k) != str:
raise UnexpectedError(f"All keys in 'files' parameter in dynamic test should be "
f"of type \"str\", found {type(k)}.")
raise UnexpectedError(
f"All keys in 'files' parameter in dynamic test should be "
f"of type \"str\", found {type(k)}."
)
if type(v) != str:
raise UnexpectedError(f"All values in 'files' parameter in dynamic test should be "
f"of type \"str\", found {type(v)}.")
raise UnexpectedError(
f"All values in 'files' parameter in dynamic test should be "
f"of type \"str\", found {type(v)}."
)

def get_tests(self, obj) -> List[DynamicTesting]:
def get_tests(self, obj) -> List['DynamicTesting']:
tests = []
for i in range(self.repeat):
for args in self.args_list:
Expand All @@ -83,8 +87,7 @@ def get_tests(self, obj) -> List[DynamicTesting]:


def to_dynamic_testing(source: str, args: List[str],
input_funcs: List['DynamicInputFunction']) -> DynamicTesting:

input_funcs: List['DynamicInputFunction']) -> 'DynamicTesting':
from hstest.dynamic.input.dynamic_input_func import DynamicInputFunction
from hstest.test_case.check_result import CheckResult

Expand Down
11 changes: 7 additions & 4 deletions hstest/dynamic/input/input_handler.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import io
import sys
from typing import Any
from typing import Any, TYPE_CHECKING

from hstest.dynamic.input.dynamic_input_func import DynamicTestFunction
from hstest.dynamic.input.input_mock import Condition, InputMock
from hstest.dynamic.input.input_mock import InputMock

if TYPE_CHECKING:
from hstest.dynamic.input.dynamic_input_func import DynamicTestFunction
from hstest.dynamic.input.input_mock import Condition


class InputHandler:
Expand All @@ -19,7 +22,7 @@ def revert_input():
sys.stdin = InputHandler.real_in

@staticmethod
def install_input_handler(obj: Any, condition: Condition, input_func: DynamicTestFunction):
def install_input_handler(obj: Any, condition: 'Condition', input_func: 'DynamicTestFunction'):
InputHandler.mock_in.install_input_handler(obj, condition, input_func)

@staticmethod
Expand Down
Loading

0 comments on commit 3f266b1

Please sign in to comment.