diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000..86499e3 --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,28 @@ +name: lab-coverage + +on: [push] + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.11.6' + - name: Run image + uses: abatilo/actions-poetry@v2 + with: + poetry-version: '1.7.1' + - name: Install dependencies + run: poetry install; poetry add pytest; poetry add pytest-mock; poetry add pytest-cov + - name: Run pytest-cov + run: poetry run pytest tests/ --cov=app --cov-branch --cov-report json:coverage.json + - name: Check coverage threshold + run: | + coverage=$(jq -r '.totals.percent_covered' coverage.json) + if [ $(echo "$coverage >= 85" | bc -l) -eq 1 ]; then + echo "coverage $coverage% is ok" + else + exit 1 + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index 68bc17f..a9126ee 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,4 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +/.idea/ diff --git a/README.md b/README.md index 364803d..0d8cd31 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Python console app hangman game based on the [code](https://github.com/markpatte > _Your answer. For example (5):_ > -> **Q1** (__) +> **Q1** (4) ## Create test cases (3pt) @@ -47,12 +47,12 @@ Python console app hangman game based on the [code](https://github.com/markpatte * What is the line coverage of your test suite for the `hangman.py`? > _Your answer in %. For example (86):_ > -> **Q2** (__) +> **Q2** (89) * What is the current branch coverage of your test suite for the `hangman.py`? > _Your answer in %. For example (86):_ > -> **Q3** (__) +> **Q3** (90) ## Add CI (1pt) diff --git a/cov.json b/cov.json new file mode 100644 index 0000000..06bb10a --- /dev/null +++ b/cov.json @@ -0,0 +1,13 @@ +{"meta": + { + "format": 2, "version": "7.4.3", "timestamp": "2024-03-03T21:30:46.186905", "branch_coverage": true, "show_contexts": false + }, + "files": + {"app/__init__.py": + {"executed_lines": [], "summary": + {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "num_branches": 0, "num_partial_branches": 0, "covered_branches": 0, "missing_branches": 0 + }, + "missing_lines": [], "excluded_lines": [], "executed_branches": [], "missing_branches": []}, "app/hangman.py": + {"executed_lines": [5, 6, 9, 14, 98, 100, 102, 106, 120, 122, 124, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 141, 142, 143, 146, 147, 148, 151, 152, 153, 155, 156, 158, 160, 163, 166, 168, 169, 170, 173, 176, 177, 178, 180, 182, 183, 184, 188], + "summary": { + "covered_lines": 49, "num_statements": 55, "percent_covered": 90.41095890410959, "percent_covered_display": "90", "missing_lines": 6, "excluded_lines": 0, "num_branches": 18, "num_partial_branches": 1, "covered_branches": 17, "missing_branches": 1}, "missing_lines": [104, 108, 116, 117, 189, 190], "excluded_lines": [], "executed_branches": [[141, 142], [141, 146], [146, 147], [146, 151], [153, 155], [153, 160], [155, 156], [155, 158], [166, 168], [166, 173], [168, 132], [168, 169], [169, 168], [169, 170], [177, 124], [177, 178], [188, -5]], "missing_branches": [[188, 189]]}}, "totals": {"covered_lines": 49, "num_statements": 55, "percent_covered": 90.41095890410959, "percent_covered_display": "90", "missing_lines": 6, "excluded_lines": 0, "num_branches": 18, "num_partial_branches": 1, "covered_branches": 17, "missing_branches": 1}} \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index fc34378..65c2701 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,6 +11,70 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.4.3" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, + {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, + {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, + {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, + {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, + {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, + {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, + {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, + {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, + {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, + {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, + {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, + {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, + {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, + {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, + {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, + {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, + {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, + {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, + {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, + {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, + {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, +] + +[package.extras] +toml = ["tomli"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -68,7 +132,25 @@ pluggy = ">=1.3.0,<2.0" [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "b439de7b0c1dcc9846389b7d06c9d856f9f0b7eedcfdf44f2c335d4b4aed0ed1" +content-hash = "db187dfd28c4026f23474af0361bedddda1aa56a3e159fd1f1de7cb3c22fe7fc" diff --git a/pyproject.toml b/pyproject.toml index 2713c46..224b167 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.11" pytest = "^8.0.0" +pytest-cov = "^4.1.0" [build-system] diff --git a/tests/test_hangman.py b/tests/test_hangman.py index 4180a76..c319dcb 100644 --- a/tests/test_hangman.py +++ b/tests/test_hangman.py @@ -1,7 +1,57 @@ -# add your tests in the test_hangman -# you may use parametrization if needed - +from app.hangman import hangman import pytest -def test_hangman(): - assert True \ No newline at end of file +def choice(): + return 'python' + + +def test_win(mocker, capsys): + mocker.patch('app.hangman.get_random_word', choice) + mocker.patch('builtins.input', side_effect=["p", "y", "t", "h", "o", "n", "n"]) + hangman() + captured = capsys.readouterr() + assert "You win!" in captured.out + + +def test_loose(mocker, capsys): + mocker.patch('app.hangman.get_random_word', choice) + mocker.patch('builtins.input', side_effect=["a", "b", "c", "d", "e", "f", "g", "n"]) + hangman() + captured = capsys.readouterr() + assert "You lose!" in captured.out + + +def test_play_again(mocker, capsys): + mocker.patch('app.hangman.get_random_word', choice) + #Здесь я сначала угадал python, потом нажал y для начала новой игры, снова угадал python, и не стал играть дальше + mocker.patch('builtins.input', side_effect=["p", "y", "t", "h", "o", "n", "y", "p", "y", "t", "h", "o", "n", "n"]) + hangman() + captured = capsys.readouterr() + assert "Goodbye!" in captured.out + + +def test_invalid(mocker, capsys): + mocker.patch('app.hangman.get_random_word', choice) + #Invalid guess - число 1 + mocker.patch('builtins.input', side_effect=["1", "p", "y", "t", "h", "o", "n", "n"]) + hangman() + captured = capsys.readouterr() + assert "Invalid guess. Please enter a single letter." in captured.out + + +def test_already_guessedd(mocker, capsys): + mocker.patch('app.hangman.get_random_word', choice) + #alreday guessed - y + mocker.patch('builtins.input', side_effect=["p", "y", "y", "t", "h", "o", "n", "n"]) + hangman() + captured = capsys.readouterr() + assert "You have already guessed that letter." in captured.out + + +def test_keyboard_interupt(mocker, capsys): + mocker.patch('app.hangman.get_random_word', choice) + mocker.patch('builtins.input', side_effect=KeyboardInterrupt) + with pytest.raises(SystemExit): + hangman() + captured = capsys.readouterr() + assert "Goodbye!" in captured.out \ No newline at end of file