cs50 / problems

Checks for check50
145 stars 238 forks source link

CS50P Problem Set 4 - game - check50 only checks for edge case when testing for non-negative numbers in user guess. #272

Open kguryanov opened 3 months ago

kguryanov commented 3 months ago

Preconditions

  1. Have a game.py, which allows negative guesses from user:
    
    import random
    from typing import Sequence

CONST_USER_PROMPT_LEVEL = "Level: " CONST_USER_PROMPT_GUESS = "Guess: " CONST_GUESS_TOO_SMALL = "Too small! " CONST_GUESS_TOO_LARGE = "Too large! " CONST_GUESS_RIGHT = "Just right! "

def main(argv: Sequence | None = None) -> int: while True: try: level = int(input(CONST_USER_PROMPT_LEVEL)) if level > 0: break except ValueError: continue

target = random.randint(1, level)
try:
    while True:
        try:
            guess = int(input(CONST_USER_PROMPT_GUESS))
        except ValueError:
            continue

        if guess and target == guess:
            print(CONST_GUESS_RIGHT)
            break
        elif guess and target > guess:
            print(CONST_GUESS_TOO_SMALL)
            continue
        elif guess and target < guess:
            print(CONST_GUESS_TOO_LARGE)
            continue
except EOFError:
    return 0

if name == "main": exit(main())

2. Have a `test_game.py`:
```python
from io import StringIO
import random

import pytest
from game import main, CONST_GUESS_TOO_SMALL, CONST_GUESS_RIGHT, CONST_USER_PROMPT_GUESS, CONST_USER_PROMPT_LEVEL  # noqa, E501

@pytest.mark.parametrize(
    "input,expected",
    [
        ("\n".join(("10", "1", "7")), f"{CONST_USER_PROMPT_LEVEL}{CONST_USER_PROMPT_GUESS}{CONST_GUESS_TOO_SMALL}\n{CONST_USER_PROMPT_GUESS}{CONST_GUESS_RIGHT}\n"),  # noqa, E501
        ("\n".join(("10", "0", "7")), f"{CONST_USER_PROMPT_LEVEL}{CONST_USER_PROMPT_GUESS}{CONST_USER_PROMPT_GUESS}{CONST_GUESS_RIGHT}\n"),  # noqa, E501
        ("\n".join(("10", "-1", "7")), f"{CONST_USER_PROMPT_LEVEL}{CONST_USER_PROMPT_GUESS}{CONST_USER_PROMPT_GUESS}{CONST_GUESS_RIGHT}\n"),  # noqa, E501
    ],
)
def test_main_strdin(input, expected, monkeypatch, capsys):
    random.seed(0)
    with monkeypatch.context() as m:
        m.setattr("sys.stdin", StringIO(input))
        main()
        out, err = capsys.readouterr()
        assert out == expected

Steps to reproduce

1, Run check50 cs50/problems/2022/python/game

Actual result

  1. check50 only test for edge case of user guess of 0 and passes.

    Expected result

    1, As stated in the problem statement:

    Prompts the user to guess that integer. If the guess is not a positive integer, the program should prompt the user again.

  2. check50 should check for actual negative values in user guess input, as the code mistake can be quite common and accept an incorrect acceptance of user guesses:

    (.venv) [09:06:18] ~/.../week4/game (main)$ python game.py 
    Level: 1
    Guess: -1
    Too small! 
    Guess: -10
    Too small! 
    Guess: 0
    Guess: 1
    Just right! 

    image

    Proposed solution

  3. Add another test to https://github.com/cs50/problems/blob/2022/python/game/__init__.py:

    @check50.check(test_valid_level)
    def test_negative_guess():
    """game.py rejects negative guess"""
    check50.run("python3 game.py").stdin("4", prompt=True).stdin("-1", prompt=True).reject()          # another edge case
    check50.run("python3 game.py").stdin("4", prompt=True).stdin("-10", prompt=True).reject()         # base case