diff --git a/.github/workflows/github-actions-byob-test.yml b/.github/workflows/github-actions-byob-test.yml new file mode 100644 index 0000000..1ad0b29 --- /dev/null +++ b/.github/workflows/github-actions-byob-test.yml @@ -0,0 +1,85 @@ +# Adapted from: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: BYOB Test on Ubuntu +run-name: ${{ github.actor }} is testing out DDT on Ubuntu (latest) +on: #[push] + pull_request: + branches: [ "master3" ] + workflow_dispatch: + +jobs: + test-ubuntu: + defaults: + run: + shell: bash + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.7.1 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v4 + with: + path: ~/.cache + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + run: | + # set PATH=%PATH%;C:/Users/runneradmin/.local/bin/poetry + poetry --version + poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction + - run: | + source $VENV + pytest --version + + - name: Typecheck with mypy + id: mypy + continue-on-error: true + run: | + set +e + cd src + poetry run mypy --version + poetry run mypy unit_test_generator.py + MYPY_RESULT=$? + COLOR="blue" + echo "SELECTED_COLOR=green" >> "$GITHUB_OUTPUT" + echo "MYPY_RESULT=$MYPY_RESULT" >> "$GITHUB_OUTPUT" + echo "color=$COLOR" + echo "MYPY_RESULT=$MYPY_RESULT" + # echo "##[set-output name=data;]$($MYPY_RESULT)" + # echo "##[set-output name=color;]$(echo $COLOR)" + + if [ $MYPY_RESULT -ne 0 ]; then + echo "::notice::mypy found errors." && exit $MYPY_RESULT + fi + + - name: mypybadge + uses: RubbaBoy/BYOB@v1 + env: + SELECTED_COLOR: ${{ steps.mypy.outputs.SELECTED_COLOR }} + MYPY_RESULT: ${{ steps.mypy.outputs.MYPY_RESULT }} + with: + NAME: mypy + LABEL: 'mypy' + STATUS: ${{ steps.mypy.outputs.MYPY_RESULT }} # echo "$MYPY_RESULT" # ${{ steps.mypy.outputs.data }} + COLOR: ${{ steps.mypy.outputs.SELECTED_COLOR }} #echo "$SELECTED_COLOR" #${{ steps.mypy.outputs.color }} + GITHUB_TOKEN: ${{ secrets.DDT }} + REPOSITORY: ${{ github.actor }}/ddt + ACTOR: ${{ github.actor }} \ No newline at end of file diff --git a/.github/workflows/python-app-mypy-byob-test.yml b/.github/workflows/python-app-mypy-byob-test.yml new file mode 100644 index 0000000..03118e2 --- /dev/null +++ b/.github/workflows/python-app-mypy-byob-test.yml @@ -0,0 +1,85 @@ +# Adapted from: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: BYOB Test on Ubuntu +run-name: ${{ github.actor }} is testing out DDT on Ubuntu (latest) +on: #[push] + pull_request: + branches: [ "master" ] + workflow_dispatch: + +jobs: + test-ubuntu: + defaults: + run: + shell: bash + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.7.1 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v4 + with: + path: ~/.cache + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + run: | + # set PATH=%PATH%;C:/Users/runneradmin/.local/bin/poetry + poetry --version + poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction + - run: | + source $VENV + pytest --version + + - name: Typecheck with mypy + id: mypy + continue-on-error: true + run: | + set +e + cd src + poetry run mypy --version + poetry run mypy unit_test_generator.py + MYPY_RESULT=$? + COLOR="blue" + echo "SELECTED_COLOR=green" >> "$GITHUB_OUTPUT" + echo "MYPY_RESULT=$MYPY_RESULT" >> "$GITHUB_OUTPUT" + echo "color=$COLOR" + echo "MYPY_RESULT=$MYPY_RESULT" + # echo "##[set-output name=data;]$($MYPY_RESULT)" + # echo "##[set-output name=color;]$(echo $COLOR)" + + if [ $MYPY_RESULT -ne 0 ]; then + echo "::notice::mypy found errors." && exit $MYPY_RESULT + fi + + - name: mypybadge + uses: RubbaBoy/BYOB@v1 + env: + SELECTED_COLOR: ${{ steps.mypy.outputs.SELECTED_COLOR }} + MYPY_RESULT: ${{ steps.mypy.outputs.MYPY_RESULT }} + with: + NAME: mypy + LABEL: 'mypy' + STATUS: ${{ steps.mypy.outputs.MYPY_RESULT }} # echo "$MYPY_RESULT" # ${{ steps.mypy.outputs.data }} + COLOR: ${{ steps.mypy.outputs.SELECTED_COLOR }} #echo "$SELECTED_COLOR" #${{ steps.mypy.outputs.color }} + GITHUB_TOKEN: ${{ secrets.DDT }} + REPOSITORY: ${{ github.actor }}/ddt + ACTOR: ${{ github.actor }} \ No newline at end of file diff --git a/.github/workflows/python-app-ubuntu-car.yml b/.github/workflows/python-app-ubuntu-car.yml new file mode 100644 index 0000000..45b7a93 --- /dev/null +++ b/.github/workflows/python-app-ubuntu-car.yml @@ -0,0 +1,82 @@ +# Adapted from: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Lint and Test on Ubuntu +run-name: ${{ github.actor }} is testing out DDT on Ubuntu (latest) +on: #[push] + pull_request: + branches: [ "master" ] + workflow_dispatch: + +jobs: + test-ubuntu: + defaults: + run: + shell: bash + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.7.1 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v4 + with: + path: ~/.cache + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + run: | + # set PATH=%PATH%;C:/Users/runneradmin/.local/bin/poetry + #poetry --version + #poetry install --no-interaction --no-root + sudo apt install cloc + + - name: Install library + run: poetry install --no-interaction + - run: | + source $VENV + pytest --version + + - name: pytest oo_car + env: + PY_COLORS: "1" + # continue-on-error: true + run: | + cd tests/oo_car + # echo "car.py -d runtime:" + #poetry run python car.py -d + #echo "car.py runtime:" + poetry run python car.py + poetry run coverage run -m pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + - name: pytest coverage badge + env: + PY_COLORS: "1" + run: | + poetry add coverage-badge 2>&1 1>/dev/null + poetry run pip install genbadge[all] + poetry run coverage combine tests/fizzbuzz/.coverage tests/oo_car/.coverage tests/all_types/.coverage tests/pass_by_assignment/.coverage tests/procedural_division/.coverage src/.coverage + ls -lah + #poetry run coverage run -m pytest . + poetry run coverage report -m --omit="*/test_*" + poetry run coverage xml --omit="*/test_*" + poetry run coverage html + ls -lah + #echo "HTML?" + ls -lah htmlcov + poetry run coverage-badge -o coverage.svg + poetry run genbadge coverage -i coverage.xml + diff --git a/.github/workflows/python-app-ubuntu.yml b/.github/workflows/python-app-ubuntu.yml index 8eb8240..25eb0ed 100644 --- a/.github/workflows/python-app-ubuntu.yml +++ b/.github/workflows/python-app-ubuntu.yml @@ -40,8 +40,9 @@ jobs: - name: Install dependencies run: | # set PATH=%PATH%;C:/Users/runneradmin/.local/bin/poetry - poetry --version - poetry install --no-interaction --no-root + #poetry --version + #poetry install --no-interaction --no-root + sudo apt install cloc - name: Install library run: poetry install --no-interaction @@ -49,67 +50,162 @@ jobs: source $VENV pytest --version + # Count the number of lines of code (excluding comments and blank lines) using cloc + + - name: Count LoC + id: loc + run: | + lines_of_code=$(cloc src/unit_test_generator.py | tail -n 2 | head -n 1 | awk '{print $NF}') + echo "LOC=$lines_of_code" >> "$GITHUB_OUTPUT" - name: Lint with pylint + id: pylint continue-on-error: true run: | set +e # stop the build if there are Python syntax errors or undefined names - poetry run pylint src/unit_test_generator.py - PYLINT_RESULT=$? - if [ $PYLINT_RESULT -ne 0 ]; then - echo "::notice::Pylint recommends changes." && exit $PYLINT_RESULT + + chmod +x run_pylint.sh + ./run_pylint.sh src/unit_test_generator.py + #poetry run pylint src/unit_test_generator.py + DATA=$? + if [ $DATA -ne 0 ]; then + echo "::notice::Pylint recommends changes." && exit $DATA fi + #echo "DATA=$DATA" >> "$GITHUB_OUTPUT" + #echo "##[set-output name=data;]$($DATA)" + #COLOR#$(chmod +x color_picker.sh && ./color_picker.sh 0 100 $DATA)" + #echo "COLOR=green" >> "$GITHUB_OUTPUT" + + - name: pylint badge + uses: RubbaBoy/BYOB@v1 + with: + NAME: pylint + LABEL: 'pylint' + STATUS: ${{ steps.pylint.outputs.MSG }} + COLOR: ${{ steps.pylint.outputs.COLOR }} + GITHUB_TOKEN: ${{ secrets.DDT }} - name: Typecheck with mypy + id: mypy continue-on-error: true run: | set +e - cd src - poetry run mypy --version - poetry run mypy unit_test_generator.py - MYPY_RESULT=$? - if [ $MYPY_RESULT -ne 0 ]; then - echo "::notice::mypy found errors." && exit $MYPY_RESULT + chmod +x get_mypy_pct_errors.sh + python3 -m pip install pandas-stubs + ./get_mypy_pct_errors.sh src/unit_test_generator.py ${{ steps.loc.outputs.LOC }} + + if [ $? -ne 0 ]; then + echo "::notice::mypy found errors." && exit $DATA fi + - name: mypybadge + uses: RubbaBoy/BYOB@v1 + env: + COLOR: ${{ steps.mypy.outputs.COLOR }} + DATA: ${{ steps.mypy.outputs.DATA }} + with: + NAME: mypy + LABEL: 'mypy' + STATUS: ${{ steps.mypy.outputs.DATA }} # echo "$DATA" # ${{ steps.mypy.outputs.data }} + COLOR: ${{ steps.mypy.outputs.COLOR }} #echo "$COLOR" #${{ steps.mypy.outputs.color }} + GITHUB_TOKEN: ${{ secrets.DDT }} + REPOSITORY: ${{ github.actor }}/ddt + ACTOR: ${{ github.actor }} + + + - name: pytest procedural_division + env: + PY_COLORS: "1" # continue-on-error: true run: | cd tests/procedural_division - poetry run python divide_ints.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + echo "example_divide_ints.py -d runtime:" + time poetry run python example_divide_ints.py -d + echo "example_divide_ints.py runtime:" + time poetry run python example_divide_ints.py + #poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - name: pytest fizzbuzz + env: + PY_COLORS: "1" # continue-on-error: true run: | cd tests/fizzbuzz - poetry run python fizzbuzz.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + echo "example_fizzbuzz.py -d runtime:" + time poetry run python example_fizzbuzz.py -d + echo "example_fizzbuzz.py runtime:" + time poetry run python example_fizzbuzz.py + #poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - name: pytest all_types + env: + PY_COLORS: "1" # continue-on-error: true run: | cd tests/all_types - poetry run python all_types.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + echo "all_types.py -d runtime:" + time poetry run python all_types.py -d + echo "all_types.py runtime:" + time poetry run python all_types.py + #poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - name: pytest oo_car + env: + PY_COLORS: "1" # continue-on-error: true run: | cd tests/oo_car - poetry run python car.py + echo "example_car.py -d runtime:" + time poetry run python example_car.py -d + echo "example_car.py runtime:" + time poetry run python example_car.py + #sleep 1 poetry run coverage run -m pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - name: pytest pass_by_assignment + env: + PY_COLORS: "1" # continue-on-error: true run: | cd tests/pass_by_assignment - poetry run python pass_by_assignment.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + echo "example_pass_by_assignment.py -d runtime:" + time poetry run python example_pass_by_assignment.py + echo "example_pass_by_assignment.py runtime:" + poetry run python example_pass_by_assignment.py + #poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + + - name: pytest helper functions + env: + PY_COLORS: "1" + # continue-on-error: true + run: | + cd src + poetry run coverage run -m pytest --log-level=DEBUG -s -v . - name: pytest coverage badge + env: + PY_COLORS: "1" run: | - poetry add coverage-badge - poetry run coverage run -m pytest . + ls -lah + ls -lah tests/fizzbuzz + ls -lah tests/oo_car + ls -lah tests/all_types + ls -lah tests/procedural_division + ls -lah tests/pass_by_assignment + poetry add coverage-badge 2>&1 1>/dev/null + poetry run pip install genbadge[all] 2>&1 1>/dev/null + poetry run coverage combine tests/fizzbuzz/.coverage tests/oo_car/.coverage tests/all_types/.coverage tests/pass_by_assignment/.coverage tests/procedural_division/.coverage src/.coverage + ls -lah + #poetry run coverage run -m pytest . --omit="*/src" + poetry run coverage report -m --omit="*/test_*" + poetry run coverage xml --omit="*/test_*" + poetry run coverage html + ls -lah + echo "HTML?" + ls -lah htmlcov poetry run coverage-badge -o coverage.svg + poetry run genbadge coverage -i coverage.xml + diff --git a/.github/workflows/python-app-windows.yml b/.github/workflows/python-app-windows.yml index 0fcc453..871ec39 100644 --- a/.github/workflows/python-app-windows.yml +++ b/.github/workflows/python-app-windows.yml @@ -1,100 +1,107 @@ -# Adapted from: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python - -name: Test on Windows -run-name: ${{ github.actor }} is testing out DDT on Windows -on: # [push] - pull_request: - branches: [ "master" ] - workflow_dispatch: - -jobs: - lint-test-windows: - - defaults: - run: - shell: bash - runs-on: windows-2019 - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - version: 1.7.1 - virtualenvs-create: true - virtualenvs-in-project: true - - - name: Load cached venv - id: cached-pip-wheels - uses: actions/cache@v4 - with: - path: ~/.cache - key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} - - name: Install dependencies - - run: | - set PATH=%PATH%;C:\\Users\\runneradmin\\.local\\bin\\poetry - poetry --version - poetry install --no-interaction --no-root - - - name: Install library - run: poetry install --no-interaction - - run: | - source $VENV - pytest --version - - #- name: Lint with pylint - # continue-on-error: true - # run: | - # # stop the build if there are Python syntax errors or undefined names - # poetry run pylint src\\unit_test_generator.py - - #- name: Typecheck with mypy - # continue-on-error: true - # run: | - # cd src - # poetry run mypy --version - # poetry run mypy unit_test_generator.py - - - name: pytest procedural_division - # continue-on-error: true - run: | - cd tests\\procedural_division - poetry run python divide_ints.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - - - name: pytest fizzbuzz - # continue-on-error: true - run: | - cd tests\\fizzbuzz - poetry run python fizzbuzz.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - - - name: pytest all_types - # continue-on-error: true - run: | - cd tests\\all_types - poetry run python all_types.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - - - name: pytest oo_car - # continue-on-error: true - run: | - cd tests\\oo_car - poetry run python car.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - - - name: pytest pass_by_assignment - # continue-on-error: true - run: | - cd tests\\pass_by_assignment - poetry run python pass_by_assignment.py - poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - +# Adapted from: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Test on Windows +run-name: ${{ github.actor }} is testing out DDT on Windows +on: # [push] + pull_request: + branches: [ "master" ] + workflow_dispatch: + +jobs: + lint-test-windows: + + defaults: + run: + shell: bash + runs-on: windows-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.7.1 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-pip-wheels + uses: actions/cache@v4 + with: + path: ~/.cache + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + - name: Install dependencies + + run: | + set PATH=%PATH%;C:\\Users\\runneradmin\\.local\\bin\\poetry + poetry --version + poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction + - run: | + source $VENV + pytest --version + + #- name: Lint with pylint + # continue-on-error: true + # run: | + # # stop the build if there are Python syntax errors or undefined names + # poetry run pylint src\\unit_test_generator.py + + #- name: Typecheck with mypy + # continue-on-error: true + # run: | + # cd src + # poetry run mypy --version + # poetry run mypy unit_test_generator.py + + - name: pytest procedural_division + # continue-on-error: true + run: | + cd tests\\procedural_division + poetry run python divide_ints.py + poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + - name: pytest fizzbuzz + # continue-on-error: true + run: | + cd tests\\fizzbuzz + poetry run python fizzbuzz.py + poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + - name: pytest all_types + # continue-on-error: true + run: | + cd tests\\all_types + poetry run python all_types.py + poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + - name: pytest oo_car + # continue-on-error: true + run: | + cd tests\\oo_car + poetry run python example_car.py + poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + - name: pytest pass_by_assignment + # continue-on-error: true + run: | + cd tests\\pass_by_assignment + poetry run python pass_by_assignment.py + poetry run pytest -s -v . #--doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + + #- name: pytest helper functions + # # continue-on-error: true + # run: | + # cd src + # poetry run pytest --log-level=DEBUG -s -v . + + # TODO Get full coverage \ No newline at end of file diff --git a/.gitignore b/.gitignore index 52fcedb..ac1d39d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ settings.json #tests/*/*.json tests/*/.coverage feedback.pdf +.coverage # https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore diff --git a/README.md b/README.md index 1105edc..5a39c4a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ +![Coverage Status](./coverage-badge.svg?dummy=8484744) +![](https://byob.yarr.is/jahatfi/ddt/pylint) +![](https://byob.yarr.is/jahatfi/ddt/mypy) ![CI](https://github.com/jahatfi/ddt/actions/workflows/python-app-ubuntu.yml/badge.svg) -![CI](https://github.com/jahatfi/ddt/actions/workflows/python-app-ubuntu.yml/coverage.svg) ![CI](https://github.com/jahatfi/ddt/actions/workflows/python-app-windows.yml/badge.svg) - #### TODO: Update this file - it's quite out of date as of 14 Sept 2024 Notes: @@ -129,4 +130,4 @@ The test should assert the same exception is thrown. ## Paper TODO [ ] Add other examples to the repo -[ ] Last: Update section references, e.g. "In sectionV/% I'll discuss... \ No newline at end of file +[ ] Last: Update section references, e.g. "In sectionV/% I'll discuss... diff --git a/get_color.sh b/get_color.sh new file mode 100644 index 0000000..e604852 --- /dev/null +++ b/get_color.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# Chaptgpt + +# Check for the correct number of arguments +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Read input arguments +min_value=$1 +max_value=$2 +measured_value=$3 + +# Calculate the range +range=$(echo "$max_value - $min_value" | bc) + +# Calculate percentage of the measured value within the range +if [ $(echo "$range == 0" | bc) -eq 1 ]; then + echo "Error: The minimum and maximum values must be different." + exit 1 +fi + +percentage=$(echo "scale=4; ($measured_value - $min_value) / $range" | bc) + +# Determine the color based on the measured value +if (( $(echo "$percentage <= 0.5" | bc -l) )); then + echo "red" +elif (( $(echo "$percentage >= 1.0" | bc -l) )); then + echo "green" +else + # Calculate intervals + if (( $(echo "$percentage <= 0.6667" | bc -l) )); then + echo "orange" + elif (( $(echo "$percentage <= 0.8333" | bc -l) )); then + echo "yellow" + else + # light green + echo "90EE90" + fi +fi diff --git a/get_mypy_pct_errors.py b/get_mypy_pct_errors.py new file mode 100644 index 0000000..05e046b --- /dev/null +++ b/get_mypy_pct_errors.py @@ -0,0 +1,37 @@ +#!/bin/bash + +# Check if a filename is provided +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +FILE="$1" + +# Check if the file exists +if [ ! -f "$FILE" ]; then + echo "File not found: $FILE" + exit 1 +fi + +# Run mypy and capture the output +OUTPUT=$(mypy "$FILE" 2>&1) + +# Count the number of lines of code (excluding comments and blank lines) using cloc +lines_of_code=$(cloc "$FILE" --json | jq '.files[].nloc' | awk '{s+=$1} END {print s}') + +# Count the number of errors reported by mypy +error_count=$(echo "$OUTPUT" | grep -c 'error:') + +# Calculate the percentage of errors per line of code +if [ $lines_of_code -eq 0 ]; then + echo "No lines of code to analyze." + exit 1 +fi + +percentage=$(echo "scale=2; ($error_count / $lines_of_code) * 100" | bc) + +# Print the results +echo "Lines of code: $lines_of_code" +echo "Mypy errors: $error_count" +echo "Percentage of mypy errors: $percentage%" diff --git a/get_mypy_pct_errors.sh b/get_mypy_pct_errors.sh new file mode 100644 index 0000000..04de1fa --- /dev/null +++ b/get_mypy_pct_errors.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# Check if a filename is provided +if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +FILE="$1" +echo "FILE = $FILE" +lines_of_code="$2" +echo "loc = $lines_of_code" + +# Check if the file exists +if [ ! -f "$FILE" ]; then + echo "File not found: $FILE" + exit 1 +fi + +# Ensure valid loc value +if [ $lines_of_code -le 0 ]; then + echo "No lines of code to analyze." + exit 2 +fi + + +get_color() { + local percentage=$1 + + if (( $(echo "$percentage > 10" | bc -l) )); then + echo "red" + elif (( $(echo "$percentage > 5" | bc -l) )); then + echo "orange" + elif (( $(echo "$percentage > 2.5" | bc -l) )); then + echo "yellow" + elif (( $(echo "$percentage > 0" | bc -l) )); then + echo "90EE90" + else + echo "green" + fi +} + +# Run mypy and count the number of errors reported by mypy +mypy_output=$(poetry run mypy "$FILE" 2>&1) +echo $mypy_output +error_count=$(echo $mypy_output | grep -c 'error:') + +percentage=$(echo "scale=4; ($error_count / $lines_of_code) * 100" | bc) + +color=$(get_color $percentage) + +# Print the results +echo "Lines of code: $lines_of_code" +echo "Mypy errors: $error_count" +echo "Percentage of mypy errors: $percentage%" +echo "color=$color" + +echo "COLOR=$color" >> "$GITHUB_OUTPUT" +echo "DATA=$error_count error(s) ($percentage% by LoC)" >> "$GITHUB_OUTPUT" + +exit $error_count \ No newline at end of file diff --git a/paper/new.tex b/paper/new.tex index f00c52e..bae6ae1 100644 --- a/paper/new.tex +++ b/paper/new.tex @@ -69,11 +69,10 @@ \title{A Python Decorator for Programmatic and Deterministic Unit Test Code Generation\\} -\author{\IEEEauthorblockN{1\textsuperscript{st} Given Name Surname} -\IEEEauthorblockA{\textit{dept. name of organization (of Aff.)} \\ -\textit{name of organization (of Aff.)}\\ -City, Country \\ -email address or ORCID} +\author{\IEEEauthorblockN{James Hatfield} +\IEEEauthorblockA{ +Glen Burnie, MD, USA \\ +jahatfi@gmail.com} } \maketitle @@ -335,7 +334,7 @@ \subsection{Accessing the function and its arguments}\label{sec:approach-interna \lstinputlisting[language=Python,numbers=left, caption={decorator.py: A sample decorator that takes one argument.},label={lst:decorator},]{examples2/decorator.py} -Running the code in Listing~ref{lst:decorator-output} yields the output shown in +Running the code in Listing~\ref{lst:decorator} yields the output shown in Listing~\ref{lst:decorator-output}. Note the apparently erroneous math (line 1,6 of Listing~\ref{lst:decorator-output}), as the \textit{add\_ints} function is unaware that its first argument was modified by the \text{inner\_most\_decorator}. @@ -632,7 +631,7 @@ \subsubsection{Optimal Result by Solving the Minimum Set Cover Problem}\label{se The author did not implement the Minimum Set Cover problem or its weighted variants, but encourages the interested reader to do so. The author records the execution time of each -execution as the \lq cost \rq. This value could be applied in a weighted +execution as the \lq cost\rq. This value could be applied in a weighted variant of the Minimum Set Cover problem, i.e. select the "best" test cases such that coverage is maximized and run time is minimized. @@ -765,25 +764,29 @@ \subsection{Manually Created Tests}\label{sec:eval-1} are checked for correct values on lines 85-92. Note that not all test cases were retained due to the deduplication logic discussed in Section~\ref{sec:tuning-1}. -Executing the unit test is simple as shown in Listing~\ref{Running}\footnote{Due to the verbose way pytest prints the +Executing the unit test is simple as shown in Listing~\ref{Running Pytest}\footnote{Due to the verbose way pytest prints the all the parameters of parameterized tests such as these, the author removed them for the sake of simpler display. The reader is encouraged to run the code as shown on their own machine}. -\begin{lstlisting}[language=bash, numbers=left, caption={Running}] -pytest -s -v test_divide_ints.py -========== test session starts ========== -platform win32 -- Python 3.11.7, pytest-7.4.4, pluggy-1.4.0 -- <@\textcolor{orange}{PATH REDACTED}@>\.venv\Scripts\python.exe -cachedir: .pytest_cache -rootdir: <@\textcolor{orange}{PATH REDACTED}@>\tests\example_procedural_division -plugins: cov-5.0.0 -collected 4 items - -test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#1 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> -test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#2 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> -test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#3 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> -test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#4 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> -\end{lstlisting} + +\begin{lstlisting}[language=bash, numbers=left, caption={Running Pytest}, label={Running Pytest}] + pytest -s -v test_divide_ints.py + ========== test session starts ========== + platform win32 -- Python 3.11.7, pytest-7.4.4, pluggy-1.4.0 -- <@\textcolor{orange}{PATH REDACTED}@>\.venv\Scripts\python.exe + cachedir: .pytest_cache + rootdir: <@\textcolor{orange}{PATH REDACTED}@>\tests\example_procedural_division + plugins: cov-5.0.0 + collected 4 items + + test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#1 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> + test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#2 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> + test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#3 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> + test_divide_ints.py::test_divide_ints[<@\textcolor{orange}{Test \#4 arguments SNIPPED}@>] <@\textcolor{green}{PASSED}@> + \end{lstlisting} + + + The reader is encouraged to study the other examples in the repository. All examples can be executed via the @@ -904,7 +907,9 @@ \subsection{Related Work}\label{sec:related-work} In the current research this author did not discover a deterministic unit test generation paradigm that monitored other types of tests from which to create unit tests. - \section{Conclusion}\label{sec:conclusion} + +% +\section{Conclusion}\label{sec:conclusion} In this paper the author presented a Python decorator leveraging previously designed test(s) to directly create unit tests at minimal development cost. @@ -936,19 +941,18 @@ \subsection{Related Work}\label{sec:related-work} work for future research and application. The author hopes the concepts described herein will be applied in other languages with strong metaprogramming support -such as C\#, Go, Zig, etc. Further information on the code and documentation, please -find it online at +such as C\#, Go, Zig, etc. The full repo containing both the Python code and +LaTeX files for this report can be found in the "ddt" repo at: \begin{center} - \textbf{LINK REDACTED FOR DOUBLE BLIND REVIEW} + \textbf{https://github.com/jahatfi/ddt} \end{center} \section{Acknowledgements}\label{sec:acknowledgements} -Redacted for double-blind review; will populate if accepted. e.g. -The author wishes to thank Drs. \_\_\_\_\_ \_\_\_\_\_\_ and \_\_\_\_\_\_\_ \_\_\_\_\_\_\_\_ -for their assistance in technical writing, Mr. \_\_\_\_\_ \_\_\_\_\_\_ -for his input on the abstract, and Mr. \_\_\_\_\_ \_\_\_\_\_\_ for sharing his pytest +The author wishes to thank Drs. Dan and Mary Lou Midgett +for their assistance in technical writing, Lt Col Solomon Sonya +for his input on the abstract, and Mr. Brad Stinson for sharing his pytest expertise. diff --git a/pyproject.toml b/pyproject.toml index 889009f..79cf57d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,11 +25,6 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.pytest.ini_options] -ignore=[ -"src", -"decorator", -"paper", -] norecursedirs=[ "src", "decorator", diff --git a/run_pylint.sh b/run_pylint.sh new file mode 100644 index 0000000..628fac8 --- /dev/null +++ b/run_pylint.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# Check if a filename is provided +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +PYTHON_FILE=$1 + +# Run pylint and store the output +OUTPUT=$(poetry run pylint "$PYTHON_FILE" 2>&1) + +# Initialize counters +ERRORS=0 +WARNINGS=0 +CONVENTIONS=0 +REFS=0 +INFO=0 + +SCORE=0 + +echo "Examining each line:" +# Parse the pylint output +while IFS= read -r line; do + echo "$line" + if [[ $line == *": E"* ]]; then + ((ERRORS++)) + elif [[ $line == *": W"* ]]; then + ((WARNINGS++)) + elif [[ $line == *": C"* ]]; then + ((CONVENTIONS++)) + elif [[ $line == *": R"* ]]; then + ((REFS++)) + elif [[ $line == *": I"* ]]; then + ((INFO++)) + elif [[ $line == "Your code has been rated"* ]]; then + SCORE=$(echo "$line" | grep -oP '\d+\.\d+' | head -n 1 ) + fi +done <<< "$OUTPUT" + +# Output the counts +echo "Pylint Report for $PYTHON_FILE" +echo "Errors: $ERRORS" +echo "Warnings: $WARNINGS" +echo "Convention: $CONVENTIONS" +echo "Refactor: $REFS" +echo "Info: $INFO" +echo "Score: $SCORE" + +chmod +x ./get_color.sh +COLOR=$(./get_color.sh 0 10 $SCORE) + +echo "ERRORS=$ERRORS" >> "$GITHUB_OUTPUT" +echo "WARNINGS=$WARNINGS" >> "$GITHUB_OUTPUT" +echo "CONVENTIONS=$CONVENTIONS" >> "$GITHUB_OUTPUT" +echo "REFS=$REFS" >> "$GITHUB_OUTPUT" +echo "INFO=$INFO" >> "$GITHUB_OUTPUT" +echo "SCORE=$SCORE" >> "$GITHUB_OUTPUT" +echo "MSG=Score:$SCORE; #E:$ERRORS, #W:$WARNINGS, #C:$CONVENTIONS, #R:$REFS, #I:$INFO" >> "$GITHUB_OUTPUT" +echo "COLOR=$COLOR" >> "$GITHUB_OUTPUT" \ No newline at end of file diff --git a/src/test_auto_generate_tests copy.py b/src/test_auto_generate_tests copy.py deleted file mode 100644 index ea9cc21..0000000 --- a/src/test_auto_generate_tests copy.py +++ /dev/null @@ -1,666 +0,0 @@ -""" -Programmatically generated test function for auto_generate_tests() -""" - -import re -import pytest -from src import unit_test_generator -from _pytest.monkeypatch import MonkeyPatch - -# Now import modules specific to auto_generate_tests: -from _io import TextIOWrapper -from logging import PlaceHolder -from logging import StreamHandler -from src.unit_test_generator import FunctionMetaData -from logging import Manager -from src.unit_test_generator import CoverageInfo -from pprint import PrettyPrinter -from collections import OrderedDict -from collections import defaultdict -from logging import RootLogger -from logging import Logger -from pathlib import WindowsPath - -ALL_METADATA = defaultdict( - FunctionMetaData, - { - "update_global": FunctionMetaData( - name="update_global", - parameter_names=["obj", "this_global", "phase", "this_coverage_info"], - is_method=False, - lines=[ - 1599, - 1600, - 1601, - 1602, - 1603, - 1604, - 1605, - 1607, - 1615, - 1616, - 1617, - 1618, - 1619, - ], - non_code_lines={1606, 1608, 1609, 1610, 1611, 1612, 1613, 1614}, - global_vars_read_from={"logger"}, - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/src/unit_test_generator.py" - ), - coverage_io={ - "bc219f43158bcf9bd56390fd2488dcf6143970ff6002221e94e29f0d72d381d9": CoverageInfo( - args_before=[ - "0", - '"method_call_counter"', - '"Before"', - "CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - ], - args_after=OrderedDict( - [ - ( - "this_coverage_info", - "CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'method_call_counter': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - ) - ] - ), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'method_call_counter': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - expected_type="src.unit_test_generator.CoverageInfo", - coverage=[1599, 1602, 1607, 1615, 1616, 1619], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - ) - }, - coverage_percentage=46.15, - types_in_use={ - "logging.Manager", - "logging.StreamHandler", - "logging.Logger", - "logging.RootLogger", - "src.unit_test_generator.CoverageInfo", - "logging.PlaceHolder", - }, - unified_test_coverage={1602, 1607, 1615, 1616, 1619, 1599}, - needs_pytest=False, - callable_files={ - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - }, - ), - "update_metadata": FunctionMetaData( - name="update_metadata", - parameter_names=["f", "this_metadata"], - is_method=False, - lines=[ - 1423, - 1424, - 1425, - 1427, - 1428, - 1429, - 1430, - 1431, - 1432, - 1433, - 1435, - 1436, - 1437, - 1438, - 1439, - 1440, - 1441, - 1442, - 1443, - 1445, - 1447, - 1448, - 1449, - 1450, - 1451, - 1452, - 1453, - 1454, - 1452, - 1447, - 1455, - 1456, - 1457, - 1458, - 1459, - 1460, - 1461, - 1462, - 1461, - ], - non_code_lines={1426, 1444, 1446, 1434}, - global_vars_read_from={"logger"}, - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/src/unit_test_generator.py" - ), - coverage_io={ - "a957a0aed8423c01c38d1111e384806112a73d4876a082ea2ca1421a6a95602a": CoverageInfo( - args_before=[ - 'X', - "FunctionMetaData(name='Car.__init__', parameter_names=['self', 'color', 'speed', 'steer_angle'], is_method=True, lines=[], non_code_lines=set(), global_vars_read_from=set(), global_vars_written_to=set(), source_file=WindowsPath('C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py'), coverage_io={}, coverage_percentage=0.0, types_in_use=set(), unified_test_coverage=set(), needs_pytest=False, callable_files={})", - ], - args_after=OrderedDict( - [ - ( - "this_metadata", - "FunctionMetaData(name='Car.__init__', parameter_names=['self', 'color', 'speed', 'steer_angle'], is_method=True, lines=[41, 42, 43], non_code_lines=set(), global_vars_read_from=set(), global_vars_written_to=set(), source_file=WindowsPath('C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py'), coverage_io={}, coverage_percentage=0.0, types_in_use=set(), unified_test_coverage=set(), needs_pytest=False, callable_files={'__init__': 'C:\\\\Users\\\\James\\\\Documents\\\\CyberResources\\\\ddt\\\\tests\\\\oo_car\\\\car.py'})", - ) - ] - ), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="None", - expected_type="NoneType", - coverage=[ - 1423, - 1425, - 1427, - 1428, - 1429, - 1430, - 1431, - 1432, - 1433, - 1435, - 1437, - 1438, - 1439, - 1440, - 1441, - 1447, - 1455, - 1456, - 1457, - 1458, - 1459, - 1460, - ], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - ) - }, - coverage_percentage=56.41, - types_in_use={ - "logging.Manager", - "pathlib.WindowsPath", - "logging.Logger", - "logging.StreamHandler", - "src.unit_test_generator.FunctionMetaData", - "logging.RootLogger", - "car.Car", - "logging.PlaceHolder", - }, - unified_test_coverage={ - 1423, - 1425, - 1427, - 1428, - 1429, - 1430, - 1431, - 1432, - 1433, - 1435, - 1437, - 1438, - 1439, - 1440, - 1441, - 1447, - 1455, - 1456, - 1457, - 1458, - 1459, - 1460, - }, - needs_pytest=False, - callable_files={ - "update_metadata": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - }, - ), - "Car.__init__": FunctionMetaData( - name="Car.__init__", - parameter_names=["self", "color", "speed", "steer_angle"], - is_method=True, - lines=[41, 42, 43], - non_code_lines=set(), - global_vars_read_from=set(), - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py" - ), - coverage_io={ - "c878113de933bc35ec08d5024d0aae800d76ba42b32be7f1075b8a7586805a2c": CoverageInfo( - args_before=['"Red"', "10", "0"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="None", - expected_type="NoneType", - coverage=[41, 42, 43], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - ) - }, - coverage_percentage=100.0, - types_in_use=set(), - unified_test_coverage={41, 42, 43}, - needs_pytest=False, - callable_files={ - "__init__": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - }, - ), - "Car.gas": FunctionMetaData( - name="Car.gas", - parameter_names=["self", "rate", "duration"], - is_method=True, - lines=[66, 67, 68, 69, 70, 71], - non_code_lines=set(), - global_vars_read_from={"method_call_counter", "logger"}, - global_vars_written_to={"method_call_counter"}, - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py" - ), - coverage_io={ - "78e4f6e57c2f532c43747e020340acf548111ebba3a4dfbb9b7a12af2d0fa659": CoverageInfo( - args_before=["-1", "1"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={"method_call_counter": 0}, - globals_after={"method_call_counter": 1}, - expected_result="None", - expected_type="NoneType", - coverage=[66, 67, 68, 69], - exception_type="", - exception_message="Gas rate (m/s) must be positive.", - constructor='Car("Red", 10, 0)', - cost=0.0, - ), - "6489cc7d9835b1fc422a9e25a2d99a7374cf0a90d0450a9435df3167635e432a": CoverageInfo( - args_before=["2", "2"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={"method_call_counter": 1}, - globals_after={"method_call_counter": 2}, - expected_result="16", - expected_type="int", - coverage=[66, 67, 68, 70, 71], - exception_type="", - exception_message="", - constructor='Car("White", 12, -30)', - cost=0.0, - ), - }, - coverage_percentage=100.0, - types_in_use={ - "tests.oo_car.car.Car", - "logging.Manager", - "logging.StreamHandler", - "logging.Logger", - "logging.RootLogger", - "logging.PlaceHolder", - }, - unified_test_coverage={66, 67, 68, 69, 70, 71}, - needs_pytest=True, - callable_files={ - "gas": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - }, - ), - "Car.brake": FunctionMetaData( - name="Car.brake", - parameter_names=["self", "rate", "duration"], - is_method=True, - lines=[50, 51, 52, 53, 54, 55, 56], - non_code_lines=set(), - global_vars_read_from={"logger"}, - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py" - ), - coverage_io={ - "79d14ba2847338fe6989a7d3640887679f88b2cfadee250647df044fe4abc0b9": CoverageInfo( - args_before=["-1", "1"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="9", - expected_type="int", - coverage=[50, 51, 53, 55, 56], - exception_type="", - exception_message="", - constructor='Car("Red", 10, 0)', - cost=0.0, - ) - }, - coverage_percentage=71.43, - types_in_use={ - "tests.oo_car.car.Car", - "logging.Manager", - "logging.StreamHandler", - "logging.Logger", - "logging.RootLogger", - "logging.PlaceHolder", - }, - unified_test_coverage={50, 51, 53, 55, 56}, - needs_pytest=False, - callable_files={ - "brake": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - }, - ), - "Car.change_steer_angle": FunctionMetaData( - name="Car.change_steer_angle", - parameter_names=["self", "angle"], - is_method=True, - lines=[79, 80, 81, 83, 86, 87, 86, 88, 86, 90], - non_code_lines={89, 82, 84, 85}, - global_vars_read_from={"logger"}, - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py" - ), - coverage_io={ - "9e5729283fb4205cc004e81e18786a627d2eb0f21140111b0a77b56ac7ded037": CoverageInfo( - args_before=["30"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="30", - expected_type="int", - coverage=[79, 80, 83, 86, 90], - exception_type="", - exception_message="", - constructor='Car("Red", 9, 0)', - cost=0.0, - ), - "78fd5f6e8e8bd7118d1ec9602907dd07a7495e42f6814cd047a8057a96388cd7": CoverageInfo( - args_before=["90"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="60", - expected_type="int", - coverage=[79, 80, 83, 86, 90], - exception_type="", - exception_message="", - constructor='Car("White", 20, -30)', - cost=0.0, - ), - "4e6967deeb4e51bab447208d79037a8bca61cdf648fb62d21885290b177313f6": CoverageInfo( - args_before=["180"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="210", - expected_type="int", - coverage=[79, 80, 83, 86, 90], - exception_type="", - exception_message="", - constructor='Car("Blue", 0.0, 30)', - cost=0.0, - ), - "9da25bda4c0856a5b359c8df1d926a3ed762a3d8f6f58108d234a201cb75d875": CoverageInfo( - args_before=["-1080"], - args_after=OrderedDict(), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="None", - expected_type="NoneType", - coverage=[79, 80, 81], - exception_type="", - exception_message="angle=-1080 out of bounds!", - constructor='Car("Green", 48, 90)', - cost=0.0, - ), - }, - coverage_percentage=60.0, - types_in_use={ - "tests.oo_car.car.Car", - "logging.Manager", - "logging.StreamHandler", - "logging.Logger", - "logging.RootLogger", - "logging.PlaceHolder", - }, - unified_test_coverage={79, 80, 81, 83, 86, 90}, - needs_pytest=True, - callable_files={ - "change_steer_angle": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - }, - ), - "Car.is_going_faster_than": FunctionMetaData( - name="Car.is_going_faster_than", - parameter_names=["self", "other_car"], - is_method=True, - lines=[126], - non_code_lines=set(), - global_vars_read_from=set(), - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py" - ), - coverage_io={ - "797ee52405b6b24f04cee9d62d992fd2a5592ed30653401b854ee509666247fc": CoverageInfo( - args_before=['Car("White", 19, 0)'], - args_after=OrderedDict([("other_car", 'Car("White", 19, 0)')]), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="True", - expected_type="bool", - coverage=[126], - exception_type="", - exception_message="", - constructor='Car("Red", 20, 0)', - cost=0.0, - ) - }, - coverage_percentage=100.0, - types_in_use={"__main__.Car", "tests.oo_car.car.Car"}, - unified_test_coverage={126}, - needs_pytest=False, - callable_files={ - "is_going_faster_than": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - }, - ), - }, -) - - -# In sum, these tests covered 49.4% of auto_generate_tests's lines -# Line(s) not covered by ANY of the tests below: -# ['2048-2049', '2051-2052', '2054', '2056-2057', '2059-2061', '2063', '2068', '2070', '2074', '2086-2087', '2091-2094', '2096', '2098', '2104-2110', '2121', '2125', '2127-2128', '2130-2135', '2137', '2139-2140', '2142-2144', '2147', '2149', '2154', '2156', '2158-2159', '2163-2165', '2169-2180', '2190', '2194', '2209', '2219-2220', '2222', '2227-2228', '2230-2231', '2251-2253', '2271-2272', '2274-2279', '2285-2286', '2288-2293', '1899', '1918-1923', '1925-1926', '1928-1929', '1939-1942', '1944-1949', '1951-1953', '1963-1964', '1977-1978', '1980', '1998', '2002-2003', '2005-2006', '2012-2013', '2015-2016', '2018-2019', '2026', '2029-2030', '2037', '2041-2047'] -@pytest.mark.parametrize( - "function_metadata, state, function_name, source_file, tests_dir, outdir, indent_size, expected_result, args_after, globals_before", - [ - ( - FunctionMetaData( - name="update_global", - parameter_names=["obj", "this_global", "phase", "this_coverage_info"], - is_method=False, - lines=[ - 1599, - 1600, - 1601, - 1602, - 1603, - 1604, - 1605, - 1607, - 1615, - 1616, - 1617, - 1618, - 1619, - ], - non_code_lines={1606, 1608, 1609, 1610, 1611, 1612, 1613, 1614}, - global_vars_read_from={"logger"}, - global_vars_written_to=set(), - source_file=WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/src/unit_test_generator.py" - ), - coverage_io={ - "bc219f43158bcf9bd56390fd2488dcf6143970ff6002221e94e29f0d72d381d9": CoverageInfo( - args_before=[ - "0", - '"method_call_counter"', - '"Before"', - "CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - ], - args_after=OrderedDict( - [ - ( - "this_coverage_info", - "CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'method_call_counter': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - ) - ] - ), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'method_call_counter': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - expected_type="src.unit_test_generator.CoverageInfo", - coverage=[1599, 1602, 1607, 1615, 1616, 1619], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - ) - }, - coverage_percentage=46.15, - types_in_use={ - "logging.Manager", - "logging.RootLogger", - "logging.StreamHandler", - "logging.Logger", - "src.unit_test_generator.CoverageInfo", - "logging.PlaceHolder", - }, - unified_test_coverage={1602, 1607, 1615, 1616, 1619, 1599}, - needs_pytest=False, - callable_files={ - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - }, - ), - { - "bc219f43158bcf9bd56390fd2488dcf6143970ff6002221e94e29f0d72d381d9": CoverageInfo( - args_before=[ - "0", - '"method_call_counter"', - '"Before"', - "CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - ], - args_after=OrderedDict( - [ - ( - "this_coverage_info", - "CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'method_call_counter': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - ) - ] - ), - kwargs={}, - kwargs_after=OrderedDict(), - globals_before={}, - globals_after={}, - expected_result="CoverageInfo(args_before=['-1', '1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'method_call_counter': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0)", - expected_type="src.unit_test_generator.CoverageInfo", - coverage=[1599, 1602, 1607, 1615, 1616, 1619], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - ) - }, - "update_global", - WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/src/unit_test_generator.py" - ), - WindowsPath("."), - WindowsPath("."), - 2, - "252acc6c11e8af0020608482027ff01a094facec4dddd6c5b97a134d630b6692", - { - "function_metadata": "FunctionMetaData(name='update_global', parameter_names=['obj', 'this_global', 'phase', 'this_coverage_info'], is_method=False, lines=[1599, 1600, 1601, 1602, 1603, 1604, 1605, 1607, 1615, 1616, 1617, 1618, 1619], non_code_lines={1606, 1608, 1609, 1610, 1611, 1612, 1613, 1614}, global_vars_read_from={'logger'}, global_vars_written_to=set(), source_file=WindowsPath('C:/Users/James/Documents/CyberResources/ddt/src/unit_test_generator.py'), coverage_io={'bc219f43158bcf9bd56390fd2488dcf6143970ff6002221e94e29f0d72d381d9': CoverageInfo(args_before=['0', '\"method_call_counter\"', '\"Before\"', 'CoverageInfo(args_before=[\\'-1\\', \\'1\\'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result=\\'\\', expected_type=\\'\\', coverage=[], exception_type=\\'\\', exception_message=\\'\\', constructor=\\'Car(\"Red\", 10, 0)\\', cost=0.0)'], args_after=OrderedDict([('this_coverage_info', 'CoverageInfo(args_before=[\\'-1\\', \\'1\\'], args_after={}, kwargs={}, kwargs_after={}, globals_before={\\'method_call_counter\\': 0}, globals_after={}, expected_result=\\'\\', expected_type=\\'\\', coverage=[], exception_type=\\'\\', exception_message=\\'\\', constructor=\\'Car(\"Red\", 10, 0)\\', cost=0.0)')]), kwargs={}, kwargs_after=OrderedDict(), globals_before={}, globals_after={}, expected_result='CoverageInfo(args_before=[\\'-1\\', \\'1\\'], args_after={}, kwargs={}, kwargs_after={}, globals_before={\\'method_call_counter\\': 0}, globals_after={}, expected_result=\\'\\', expected_type=\\'\\', coverage=[], exception_type=\\'\\', exception_message=\\'\\', constructor=\\'Car(\"Red\", 10, 0)\\', cost=0.0)', expected_type='src.unit_test_generator.CoverageInfo', coverage=[1599, 1602, 1607, 1615, 1616, 1619], exception_type='', exception_message='', constructor='', cost=0.0)}, coverage_percentage=46.15, types_in_use={'logging.Manager', 'logging.RootLogger', 'logging.StreamHandler', 'logging.Logger', 'src.unit_test_generator.CoverageInfo', 'logging.PlaceHolder'}, unified_test_coverage={1602, 1607, 1615, 1616, 1619, 1599}, needs_pytest=False, callable_files={'update_global': 'C:\\\\Users\\\\James\\\\Documents\\\\CyberResources\\\\ddt\\\\src\\\\unit_test_generator.py'})", - "state": "{'bc219f43158bcf9bd56390fd2488dcf6143970ff6002221e94e29f0d72d381d9': CoverageInfo(args_before=['0', '\"method_call_counter\"', '\"Before\"', 'CoverageInfo(args_before=[\\'-1\\', \\'1\\'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result=\\'\\', expected_type=\\'\\', coverage=[], exception_type=\\'\\', exception_message=\\'\\', constructor=\\'Car(\"Red\", 10, 0)\\', cost=0.0)'], args_after={'this_coverage_info': 'CoverageInfo(args_before=[\\'-1\\', \\'1\\'], args_after={}, kwargs={}, kwargs_after={}, globals_before={\\'method_call_counter\\': 0}, globals_after={}, expected_result=\\'\\', expected_type=\\'\\', coverage=[], exception_type=\\'\\', exception_message=\\'\\', constructor=\\'Car(\"Red\", 10, 0)\\', cost=0.0)'}, kwargs={}, kwargs_after=OrderedDict(), globals_before={}, globals_after={}, expected_result='CoverageInfo(args_before=[\\'-1\\', \\'1\\'], args_after={}, kwargs={}, kwargs_after={}, globals_before={\\'method_call_counter\\': 0}, globals_after={}, expected_result=\\'\\', expected_type=\\'\\', coverage=[], exception_type=\\'\\', exception_message=\\'\\', constructor=\\'Car(\"Red\", 10, 0)\\', cost=0.0)', expected_type='src.unit_test_generator.CoverageInfo', coverage=[1599, 1602, 1607, 1615, 1616, 1619], exception_type='', exception_message='', constructor='', cost=0.0)}", - "source_file": "WindowsPath('C:/Users/James/Documents/CyberResources/ddt/src/unit_test_generator.py')", - "tests_dir": "WindowsPath('.')", - "outdir": "WindowsPath('.')", - }, - {}, - ), - ], -) -def test_auto_generate_tests( - function_metadata, - state, - function_name, - source_file, - tests_dir, - outdir, - indent_size, - expected_result, - args_after, - globals_before, -): - """ - Programmatically generated test function for auto_generate_tests() - """ - monkeypatch = MonkeyPatch() - monkeypatch.setattr(unit_test_generator, "all_metadata", ALL_METADATA) - result = unit_test_generator.auto_generate_tests( - function_metadata, - state, - function_name, - source_file, - tests_dir, - outdir, - indent_size, - ) - assert result == expected_result or result == eval(expected_result) - assert ( - function_metadata == eval(args_after["function_metadata"]) - or args_after["function_metadata"] == function_metadata - ) - assert state == eval(args_after["state"]) or args_after["state"] == state - assert ( - source_file == eval(args_after["source_file"]) - or args_after["source_file"] == source_file - ) - assert ( - tests_dir == eval(args_after["tests_dir"]) - or args_after["tests_dir"] == tests_dir - ) - assert outdir == eval(args_after["outdir"]) or args_after["outdir"] == outdir diff --git a/src/test_get_module_import_string.py b/src/test_get_module_import_string.py index d5fbef4..9d900eb 100644 --- a/src/test_get_module_import_string.py +++ b/src/test_get_module_import_string.py @@ -6,6 +6,7 @@ import pytest from collections import OrderedDict from src import unit_test_generator +#import pathlib # Now import modules specific to get_module_import_string: from logging import Manager @@ -13,7 +14,7 @@ from logging import StreamHandler from logging import RootLogger from logging import Logger -from pathlib import WindowsPath +from pathlib import Path # In sum, these tests covered 85.0% of get_module_import_string's lines @@ -23,12 +24,10 @@ "my_path, expected_result, args_after", [ ( - WindowsPath( - "C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py" - ), + Path("../tests/oo_car/car.py").resolve(), "tests.oo_car.car", { - "my_path": "WindowsPath('C:/Users/James/Documents/CyberResources/ddt/tests/oo_car/car.py')" + "my_path": "Path('../tests/oo_car/car.py').resolve()" }, ), ], diff --git a/src/unit_test_generator.py b/src/unit_test_generator.py index 7b3fad0..320d6b2 100644 --- a/src/unit_test_generator.py +++ b/src/unit_test_generator.py @@ -63,6 +63,10 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) +# FUNCTIONS is a set of all function names in this file, to be populated +# at the end of this file +FUNCTIONS = set() + recursion_depth_per_decoratee: dict[str, int] = defaultdict(int) def fullname(o:object)->str: @@ -168,10 +172,13 @@ def repr(self)->str: the object in Python. """ args_before_repr = [repr(x) for x in self.args_before] + # pylint: disable-next=C0200 for i in range(len(args_before_repr)): #if ")", r"'\1'", args_before_repr[i]) + args_before_repr[i] = re.sub(r"()", + r"'\1'", + args_before_repr[i]) result = ["CoverageInfo(args_before=["+','.join(args_before_repr)+"]"] #logger.critical(f"{result=}") result.append(" args_after="+repr(self.args_after)) @@ -186,7 +193,7 @@ def repr(self)->str: result.append(" exception_message="+repr(self.exception_message)) result.append(" constructor="+repr(self.constructor).replace('\"', "\"")) result.append(" cost="+repr(self.cost)) - result.append(" testable="+repr(self.cost)+')') + result.append(" testable="+repr(self.testable)+')') result_str:str = ','.join(result) #logger.debug("result=%s", result_str) @@ -220,7 +227,7 @@ def __str__(self) -> str: result.append(" exception_message="+repr(self.exception_message)) result.append(" constructor="+repr(self.constructor).replace('"', "\"")) result.append(" cost="+repr(self.cost)) - result.append(" testable="+repr(self.cost)+')') + result.append(" testable="+repr(self.testable)+')') result_str = ','.join(result) logger.debug("result=%s", result_str) @@ -333,7 +340,44 @@ def get_all_uncovered_line_str(self): return result def __str__(self)->str: - return f"{self.name}:\n{self.lines=}\n" + """ name:str, + parameter_names:List[str], + is_method:bool, + source_file:Path, + lines:Optional[List[int]] = None, + non_code_lines:Optional[Set[int]] = None, + global_vars_read_from:Optional[set] = None, + global_vars_written_to:Optional[set] = None, + coverage_io:Optional[dict[str, CoverageInfo]] = None, + coverage_percentage:float=0.0, + types_in_use:Optional[set] = None, + unified_test_coverage:Optional[set] = None, + needs_pytest:bool = False, + exceptions_raised:Optional[set] = None, + callable_files: Optional[dict[str, str]] = None + + Returns: + str: _description_ + """ + result = ["FunctionMetaData("] + result.append("name="+repr(self.name)) + result.append(" parameter_names="+repr(self.parameter_names)) + result.append(" is_method="+repr(self.is_method)) + result.append(" source_file="+repr(self.source_file)) + result.append(" lines="+repr(self.lines)) + result.append(" non_code_lines="+repr(self.non_code_lines)) + result.append(" global_vars_read_from="+repr(self.global_vars_read_from)) + result.append(" global_vars_written_to="+repr(self.global_vars_written_to)) + result.append(" coverage_io="+repr(self.coverage_io)) + result.append(" coverage_percentage="+repr(self.coverage_percentage)) + result.append(" types_in_use="+repr(self.types_in_use)) + result.append(" unified_test_coverage="+repr(self.unified_test_coverage)) + result.append(" needs_pytest="+repr(self.needs_pytest)) + result.append(" exceptions_raised="+repr(self.exceptions_raised)) + result.append(" callable_files="+repr(self.callable_files)) + result_str = ','.join(result) + logger.debug("result=%s", result_str) + return result_str def return_non_code_lines(self)->Set[int]: """ @@ -939,7 +983,7 @@ def args_iterator(self, args_dict = dict(zip(self.this_metadata.parameter_names, self.args)) elif which_args == "kwargs": - args_dict = self.kwargs + args_dict = copy.deepcopy(self.kwargs) else: logger.critical("Invalid option %s!", which_args) sys.exit(1) @@ -954,12 +998,13 @@ def iterator_helper(self, function_name = self.this_metadata.name for arg_i, (arg_name, arg) in enumerate(args_dict.items()): if mode == "After": - + if ((which_args == "args" and id(arg) != self.args_addresses[arg_name]) or \ - (which_args == "kwargs" and id(arg) != self.kwargs_addresses[arg_name])): - logger.info("Discarding param #%d: %s for 'after' comparison, address has changed", - arg_i, arg) - continue + (which_args == "kwargs" and id(arg) != self.kwargs_addresses[arg_name])): + # pylint: disable-next=line-too-long + logger.info("Discarding param #%d: %s for 'after' comparison, address has changed", + arg_i, arg) + continue if isinstance(arg, (int, str, float)): logger.info("After: Skip it!") continue @@ -994,12 +1039,14 @@ def iterator_helper(self, self.new_types_in_use.add(newest_import) continue + self.new_types_in_use |= get_all_types("1", arg, True, 0, function_name) if hasattr(arg, "__dict__"): logger.debug("Adding types for function %s for arg %s", function_name, arg) for v in arg.__dict__.values(): self.new_types_in_use |= get_all_types("1.1", v, False, 0, function_name) + #sys.exit(1) elif isinstance(arg, str): if which_args == "args": @@ -1074,7 +1121,7 @@ def iterator_helper(self, else: self.kwargs_copy[arg_name] = class_repr else: - logger.critical(f"arg_name=%s mode=%s", arg_name, mode) + logger.debug("arg_name=%s mode=%s", arg_name, mode) if which_args == "args": self.args_copy[arg_name] = repr(arg) else: @@ -1119,7 +1166,8 @@ def do_the_decorator_thing(func: Callable, function_name:str, per decorated function. """ # pylint: disable-next=global-variable-not-assigned - logger.critical(function_name) + logger.debug("function_name = %s", function_name) + global all_metadata, unique_inputs caught_exception = None kwargs = kwargs.get("kwargs", kwargs) @@ -1144,7 +1192,6 @@ def do_the_decorator_thing(func: Callable, function_name:str, this_coverage_info: CoverageInfo = CoverageInfo() #args_copy = [convert_to_serializable(x) for x in args] - logger.critical("function_name = %s", function_name) class_type = "" if this_metadata.is_method: if not function_name.endswith("__init__"): @@ -1193,6 +1240,7 @@ def do_the_decorator_thing(func: Callable, function_name:str, this_metadata.types_in_use |= these_types if kwargs: + logger.debug(f"{kwargs=}") this_coverage_info.kwargs = copy.deepcopy(kwargs) # TODO Add the function file and function name @@ -1246,6 +1294,7 @@ def do_the_decorator_thing(func: Callable, function_name:str, end_time = time.perf_counter() with Capturing() as stdout_lines: cov.json_report(outfile='-') + # result will not exist if the function threw an exception cov_report_ = json.loads(stdout_lines[0]) expected_type = str(type(result)) @@ -1372,10 +1421,10 @@ def do_the_decorator_thing(func: Callable, function_name:str, args_iterator_class.args_iterator("After") this_coverage_info.args_after = copy.deepcopy(args_iterator_class.args_copy) - logger.debug("args_iterator_class.kwargs_copy=%s", args_iterator_class.kwargs_copy) + logger.debug("args_iterator_class.args_copy=%s", args_iterator_class.args_copy) args_iterator_class.args_iterator("After", "kwargs") - this_coverage_info.kwargs_after = copy.deepcopy(args_iterator_class.kwargs_copy) + this_coverage_info.kwargs_after = copy.deepcopy(kwargs) logger.debug("args_iterator_class.kwargs_copy=%s", args_iterator_class.kwargs_copy) #this_coverage_info.args_after = args_iterator_class.args this_metadata.types_in_use |= args_iterator_class.new_types_in_use @@ -1479,7 +1528,7 @@ def update_metadata(f: Callable, this_metadata: FunctionMetaData)->None: dis_ = capture(dis) logger.debug("f=%s type(f)=%s", f.__name__, type(f)) disassembled_function = dis_(f) - print(f.__name__) + logger.debug("Updating metadata for %s", f.__name__) for line in disassembled_function.splitlines(): #print(line) if "faster" in f.__name__ or "gas" in f.__name__: @@ -1586,7 +1635,8 @@ def generate_all_tests_and_metadata_helper( local_all_metadata:defaultdict[str, # Replace unique keys with numbers sorted_unique_keys = sorted(test_suite.keys()) for sorted_unique_key_index, sorted_unique_key in enumerate(sorted_unique_keys): - test_suite[sorted_unique_key_index] = test_suite[sorted_unique_key] + # pylint: disable-next=line-too-long + test_suite[sorted_unique_key_index] = test_suite[sorted_unique_key] # type: ignore[index] del test_suite[sorted_unique_key] # The json file is optional and unused but makes for @@ -1606,8 +1656,14 @@ def generate_all_tests_and_metadata_helper( local_all_metadata:defaultdict[str, logger.debug("No test record for %s", function_name) continue - local_all_metadata[function_name].coverage_io = {k:v for k,v in local_all_metadata[function_name].coverage_io.items() if v.testable} - result_file_str = f"test_{function_name.lower()}".replace('.','_') + ".py" + for k,v in local_all_metadata[function_name].coverage_io.items(): + if v.testable: + local_all_metadata[function_name].coverage_io[k] = v + if function_name in FUNCTIONS: + tmp_str = f"test_{function_name.lower()}_{os.path.basename(os.getcwd())}" + result_file_str = tmp_str.replace('.','_') + ".py" + else: + result_file_str = f"test_{function_name.lower()}".replace('.','_') + ".py" result_file_str = re.sub("__init__", "constructor", result_file_str) result_file = tests_dir.joinpath(result_file_str) @@ -1681,7 +1737,7 @@ def update_global(obj, function skips it. """ if repr(obj).startswith("<"): - logger.critical("Skipping %s", obj) + logger.debug("Skipping %s", obj) return this_coverage_info if isinstance(obj, set): this_entry = sorted_set_repr(obj) @@ -1808,7 +1864,7 @@ def gen_coverage_list( function_metadata:FunctionMetaData, #percent_covered = 100*percent_covered coverage_str_list = [] start_list = [] - start_list.append(f"{tab}# Coverage: {percent_covered:.2f}% of function lines ") + start_list.append(f"{tab}# Coverage: {percent_covered:.2f}% of function lines") start_list.append(f"[{first_source_line_num}-{last_source_line_num}]\n") start_list.append(f"{tab}# Covered Lines: ") start = ''.join(start_list) @@ -1945,13 +2001,21 @@ def meta_program_function_call( this_state:CoverageInfo, #indent += tab line = f"{indent}assert result == expected_result or result == eval(expected_result)\n" list_of_lines.append(line) + try: + if isinstance(this_state, OrderedDict) and 'this_coverage_info' in this_state.args_after: + this_state.args_after['this_coverage_info']['args_after'] + except KeyError as e: + logger.warning(e) # TODO Why is this_state.args_after sometimes a tuple?? if isinstance(this_state.args_after, dict) and this_state.args_after.keys(): + list_of_lines.append(f"{indent}try:\n") for arg_after in this_state.args_after.keys(): - list_of_lines.append(f"{indent}assert {arg_after} == eval(args_after[\"{arg_after}\"]) or args_after[\"{arg_after}\"] == {arg_after}\n") + list_of_lines.append(f"{indent*2}assert {arg_after} == eval(args_after[\"{arg_after}\"]) or args_after[\"{arg_after}\"] == {arg_after}\n") + list_of_lines.append(f"{indent}except KeyError as e:\n") + list_of_lines.append(f"{indent*2}print(f\"Got Key Error in test, likely false positive: {{e=}}\")\n") if isinstance(this_state.kwargs_after, dict) and this_state.kwargs_after.keys(): for arg_after in this_state.kwargs_after.keys(): - list_of_lines.append(f"{indent}assert kwargs[\"{arg_after}\"] == eval(kwargs_after['{arg_after}']) or kwargs[\"{arg_after}\"] == kwargs_after['{arg_after}']\n") + list_of_lines.append(f"{indent}kwargs[\"{arg_after}\"] == kwargs_after['{arg_after}']\n") else: for name in parameter_names: @@ -1970,6 +2034,7 @@ def normalize_defaultdict_repr(repr_value:str)->str: class_name = class_name_matcher.groups()[0].split('.')[-1] logger.debug(class_name) + # pylint: disable-next=line-too-long result = re.sub(r"^(defaultdict\()([^']+)'>", r"\1\g",repr_value) #logger.debug(f"{repr_value=}") return result @@ -1988,16 +2053,24 @@ def auto_generate_tests(function_metadata:FunctionMetaData, This is the function that can automatically create a unit test file for each decorated function. The contents of the unit test file(s) are created by appending - to lists of strings, these lists of strings are evenutally + to lists of strings, these lists of strings are eventually written to a file, one per decorated function. """ + logger.debug("Dropping any untestable records") + state = {k:v for k,v in state.items() if v.testable} + if not state: + logger.warning("No testable inputs for %s, skipping it completely", function_name) + with open(result_file, "w", encoding="utf-8") as st: + st.write("\"\"\"\nNo testable inputs - see accompanying JSON file.\n\"\"\"") + return print(f"Auto-generating test for {function_name}...") outdir = outdir.absolute() tests_dir = tests_dir.absolute() imports = ["import re\n", + "import itertools\n", "import pytest\n", - "from collections import OrderedDict\n"] + "from collections import OrderedDict, defaultdict\n"] if function_name == "meta_program_function_call": imports.append("from collections import OrderedDict\n") @@ -2173,9 +2246,7 @@ def auto_generate_tests(function_metadata:FunctionMetaData, if args_after: these_aa :dict[str, typing.Any] = {} for arg_name, arg_value in state[unique_key].args_after.items(): - #if isinstance(arg_value, (int, str, float)): - # logger.info("In '%s' Skipping '%s': %s (type:%s)", function_name, arg_name, arg_value, type(arg_value)) - # continue + logger.debug("Keeping '%s':'%s", arg_name, arg_value) these_aa[arg_name] = arg_value state[unique_key].args_after = these_aa @@ -2183,9 +2254,7 @@ def auto_generate_tests(function_metadata:FunctionMetaData, if kwargs_after: these_kaa :dict[str, typing.Any] = {} for arg_name, arg_value in state[unique_key].kwargs_after.items(): - #if isinstance(arg_value, (int, str, float)): - # logger.info("In '%s' Skipping '%s': %s (type:%s)", function_name, arg_name, arg_value, type(arg_value)) - # continue + logger.debug("Keeping '%s':'%s", arg_name, arg_value) these_kaa[arg_name] = arg_value state[unique_key].kwargs_after = these_kaa @@ -2347,9 +2416,22 @@ def auto_generate_tests(function_metadata:FunctionMetaData, h.update(str(sorted(test_str_list_def_dict.items())).encode()) return h.digest().hex() - parameterization_list[-1] += "])\n" + + # Define and use counter function for the ids function in pytest, see + # https://docs.pytest.org/en/7.1.x/example/parametrize.html + + parameterization_list[-1] += "], ids=counter)\n" docstring = f'\"\"\"\nProgrammatically generated test function for {function_name}()\n\"\"\"' - print(f"Creating {result_file}...") + + header.extend( + [ + "def counter(start=0)->str:\n", + f"{tab}while True:\n", + f"{tab*2}yield f\"test#-{{start}}\"\n", + f"{tab*2}start += 1\n\n" + ] + ) + logger.critical("Creating %s ...", result_file) with open(result_file, "w", encoding="utf-8") as st: st.write(docstring+"\n") for item in [imports, header, parameterization_list]: @@ -2375,7 +2457,7 @@ def auto_generate_tests(function_metadata:FunctionMetaData, logger.error(e.stdout.decode()) logger.info("Re-formatted %s with black formatter", result_file) - ''' + try: subprocess.run( f"ruff {result_file} --fix".split(), check=True, @@ -2389,8 +2471,17 @@ def auto_generate_tests(function_metadata:FunctionMetaData, logger.error(e.stdout.decode()) logger.info("Linted %s with ruff", result_file) - ''' + # Return hash of resulting string here h = hashlib.new('sha256') h.update(str(sorted(test_str_list_def_dict.items())).encode()) return h.digest().hex() + +# REF: https://stackoverflow.com/questions/18451541 +copied_locals = dict(locals()) +for value in copied_locals.values(): + value = str(value) + if value.startswith("", - "exception_message": "index must be in range [0, 12], was -5", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "2": { - "args_before": [ - "(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)", - "50" - ], - "args_after": { - "iterable": "(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 29, - 31, - 32 - ], - "exception_type": "", - "exception_message": "index must be in range [0, 9], was 50", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "3": { - "args_before": [ - "[-1, -2, -3, -4]", - "0" - ], - "args_after": { - "iterable": "[-1, -2, -3, -4]" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "-1", - "expected_type": "int", - "coverage": [ - 29, - 31, - 33, - 36 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 85.71, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 29, - 31, - 32, - 33, - 34, - 36 - ], - "needs_pytest": true, - "exceptions_raised": [ - "" - ], - "callable_files": { - "get_item_at_index": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\all_types\\all_types.py" - } +{ + "name": "get_item_at_index", + "parameter_names": [ + "iterable", + "index" + ], + "is_method": false, + "source_file": null, + "lines": [ + 32, + 33, + 34, + 35, + 36, + 37, + 39 + ], + "non_code_lines": [ + 38 + ], + "coverage_io": { + "0": { + "args_before": [ + "\"The quick red fox jumped over the lazy brown dog\"", + "3" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": " ", + "expected_type": "str", + "coverage": [ + 32, + 34, + 36, + 39 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + }, + "1": { + "args_before": [ + "\"a test string\"", + "-5" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 32, + 34, + 36, + 37 + ], + "exception_type": "", + "exception_message": "index must be in range [0, 12], was -5", + "constructor": "", + "cost": 0.0, + "testable": true + }, + "2": { + "args_before": [ + "(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)", + "50" + ], + "args_after": { + "iterable": "(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 32, + 34, + 35 + ], + "exception_type": "", + "exception_message": "index must be in range [0, 9], was 50", + "constructor": "", + "cost": 0.0, + "testable": true + }, + "3": { + "args_before": [ + "[-1, -2, -3, -4]", + "0" + ], + "args_after": { + "iterable": "[-1, -2, -3, -4]" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "-1", + "expected_type": "int", + "coverage": [ + 32, + 34, + 36, + 39 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 85.71, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 32, + 34, + 35, + 36, + 37, + 39 + ], + "needs_pytest": true, + "exceptions_raised": [ + "" + ], + "callable_files": { + "get_item_at_index": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\all_types\\all_types.py" + } } \ No newline at end of file diff --git a/tests/all_types/test_coverage_str_helper.py b/tests/all_types/test_coverage_str_helper_all_types.py similarity index 51% rename from tests/all_types/test_coverage_str_helper.py rename to tests/all_types/test_coverage_str_helper_all_types.py index 0dca175..a77723c 100644 --- a/tests/all_types/test_coverage_str_helper.py +++ b/tests/all_types/test_coverage_str_helper_all_types.py @@ -1,40 +1,43 @@ -""" -Programmatically generated test function for coverage_str_helper() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - -# Now import modules specific to coverage_str_helper: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler - - -# In sum, these tests covered 37.5% of coverage_str_helper's lines -# Line(s) not covered by ANY of the tests below: -# ['1743', '1749-1757', '1759-1762', '1764-1766', '1768-1769'] -@pytest.mark.parametrize( - "this_list, non_code_lines, expected_result, args_after", - [ - ([30], {35}, "[30]", {"this_list": "[30]", "non_code_lines": "{35}"}), - ], -) -def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): - """ - Programmatically generated test function for coverage_str_helper() - """ - result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) - assert result == expected_result or result == eval(expected_result) - assert ( - this_list == eval(args_after["this_list"]) - or args_after["this_list"] == this_list - ) - assert ( - non_code_lines == eval(args_after["non_code_lines"]) - or args_after["non_code_lines"] == non_code_lines - ) +""" +Programmatically generated test function for coverage_str_helper() +""" + +import pytest +from src import unit_test_generator + +# Now import modules specific to coverage_str_helper: + + +# In sum, these tests covered 37.5% of coverage_str_helper's lines +# Line(s) not covered by ANY of the tests below: +# ['1799', '1805-1813', '1815-1818', '1820-1822', '1824-1825'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "this_list, non_code_lines, expected_result, args_after", + [ + ([33], {38}, "[33]", {"this_list": "[33]", "non_code_lines": "{38}"}), + ], + ids=counter, +) +def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): + """ + Programmatically generated test function for coverage_str_helper() + """ + result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_list == eval(args_after["this_list"]) + or args_after["this_list"] == this_list + ) + assert ( + non_code_lines == eval(args_after["non_code_lines"]) + or args_after["non_code_lines"] == non_code_lines + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/all_types/test_get_item_at_index.py b/tests/all_types/test_get_item_at_index.py index dd54451..2456493 100644 --- a/tests/all_types/test_get_item_at_index.py +++ b/tests/all_types/test_get_item_at_index.py @@ -1,48 +1,54 @@ -""" -Programmatically generated test function for get_item_at_index() -""" - -import re -import pytest -from collections import OrderedDict -from tests.all_types import all_types - - -# In sum, these tests covered 85.71% of get_item_at_index's lines -# Line(s) not covered by ANY of the tests below: -# [30] -@pytest.mark.parametrize( - "iterable, index, exception_type, exception_message, expected_result, args_after", - [ - ("The quick red fox jumped over the lazy brown dog", 3, "N/A", "N/A", " ", {}), - ( - "a test string", - -5, - ValueError, - "index must be in range [0, 12], was -5", - "None", - {}, - ), - ( - (5, 6, 7, 8, 9, 10, 11, 12, 13, 14), - 50, - ValueError, - "index must be in range [0, 9], was 50", - "None", - {"iterable": "(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)"}, - ), - ([-1, -2, -3, -4], 0, "N/A", "N/A", "-1", {"iterable": "[-1, -2, -3, -4]"}), - ], -) -def test_get_item_at_index( - iterable, index, exception_type, exception_message, expected_result, args_after -): - """ - Programmatically generated test function for get_item_at_index() - """ - if exception_type != "N/A": - with pytest.raises(exception_type, match=re.escape(exception_message)): - all_types.get_item_at_index(iterable, index) - else: - result = all_types.get_item_at_index(iterable, index) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for get_item_at_index() +""" + +import re +import pytest +import all_types + + +# In sum, these tests covered 85.71% of get_item_at_index's lines +# Line(s) not covered by ANY of the tests below: +# [33] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "iterable, index, exception_type, exception_message, expected_result, args_after", + [ + ("The quick red fox jumped over the lazy brown dog", 3, "N/A", "N/A", " ", {}), + ( + "a test string", + -5, + ValueError, + "index must be in range [0, 12], was -5", + "None", + {}, + ), + ( + (5, 6, 7, 8, 9, 10, 11, 12, 13, 14), + 50, + ValueError, + "index must be in range [0, 9], was 50", + "None", + {"iterable": "(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)"}, + ), + ([-1, -2, -3, -4], 0, "N/A", "N/A", "-1", {"iterable": "[-1, -2, -3, -4]"}), + ], + ids=counter, +) +def test_get_item_at_index( + iterable, index, exception_type, exception_message, expected_result, args_after +): + """ + Programmatically generated test function for get_item_at_index() + """ + if exception_type != "N/A": + with pytest.raises(exception_type, match=re.escape(exception_message)): + all_types.get_item_at_index(iterable, index) + else: + result = all_types.get_item_at_index(iterable, index) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/all_types/test_update_global.py b/tests/all_types/test_update_global.py deleted file mode 100644 index e1c5f58..0000000 --- a/tests/all_types/test_update_global.py +++ /dev/null @@ -1,2 +0,0 @@ -import warnings -warnings.warn("No testable samples!") \ No newline at end of file diff --git a/tests/all_types/test_update_global_all_types.py b/tests/all_types/test_update_global_all_types.py new file mode 100644 index 0000000..53dfbc4 --- /dev/null +++ b/tests/all_types/test_update_global_all_types.py @@ -0,0 +1,3 @@ +""" +No testable inputs - see accompanying JSON file. +""" \ No newline at end of file diff --git a/tests/all_types/update_global.json b/tests/all_types/update_global.json index 9bff7c9..0233bec 100644 --- a/tests/all_types/update_global.json +++ b/tests/all_types/update_global.json @@ -1,89 +1,89 @@ -{ - "name": "update_global", - "parameter_names": [ - "obj", - "this_global", - "phase", - "this_coverage_info" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1683, - 1684, - 1685, - 1686, - 1687, - 1688, - 1689, - 1691, - 1699, - 1700, - 1701, - 1702, - 1703 - ], - "non_code_lines": [ - 1690, - 1692, - 1693, - 1694, - 1695, - 1696, - 1697, - 1698 - ], - "coverage_io": { - "0": { - "args_before": [ - "", - "\"logger\"", - "\"Before\"", - "CoverageInfo(args_before=['[30]','{35}'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - ], - "args_after": { - "obj": "", - "this_coverage_info": "CoverageInfo(args_before=['[30]','{35}'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['[30]','{35}'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "expected_type": "src.unit_test_generator.CoverageInfo", - "coverage": [ - 1683, - 1684, - 1685 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": false - } - }, - "coverage_percentage": 23.08, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "src.unit_test_generator.CoverageInfo" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1683, - 1684, - 1685 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "update_global", + "parameter_names": [ + "obj", + "this_global", + "phase", + "this_coverage_info" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1739, + 1740, + 1741, + 1742, + 1743, + 1744, + 1745, + 1747, + 1755, + 1756, + 1757, + 1758, + 1759 + ], + "non_code_lines": [ + 1746, + 1748, + 1749, + 1750, + 1751, + 1752, + 1753, + 1754 + ], + "coverage_io": { + "0": { + "args_before": [ + "", + "\"logger\"", + "\"Before\"", + "CoverageInfo(args_before=['[33]','{38}'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + ], + "args_after": { + "obj": "", + "this_coverage_info": "CoverageInfo(args_before=['[33]','{38}'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['[33]','{38}'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "expected_type": "src.unit_test_generator.CoverageInfo", + "coverage": [ + 1739, + 1740, + 1741 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": false + } + }, + "coverage_percentage": 23.08, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "src.unit_test_generator.CoverageInfo" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1739, + 1740, + 1741 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/delete_test_files.bat b/tests/delete_test_files.bat index e7b8331..50e761a 100644 --- a/tests/delete_test_files.bat +++ b/tests/delete_test_files.bat @@ -1,24 +1,36 @@ -cd fizzbuzz -SET "keepfile=fizzbuzz.py" -FOR %%a IN (".\*") DO IF /i NOT "%%~nxa"=="%keepfile%" DEL "%%a" -cd .. - -cd all_types -SET "keepfile=all_types.py" -FOR %%a IN (".\*") DO IF /i NOT "%%~nxa"=="%keepfile%" DEL "%%a" -cd .. - -cd procedural_division -SET "keepfile=divide_ints.py" -FOR %%a IN (".\*") DO IF /i NOT "%%~nxa"=="%keepfile%" DEL "%%a" -cd .. - -cd oo_car -SET "keepfile=car.py" -FOR %%a IN (".\*") DO IF /i NOT "%%~nxa"=="%keepfile%" DEL "%%a" -cd .. - -cd pass_by_assignment -SET "keepfile=pass_by_assignment.py" -FOR %%a IN (".\*") DO IF /i NOT "%%~nxa"=="%keepfile%" DEL "%%a" +cd fizzbuzz +SET "keepfile=fizzbuzz.py" +SET "keepfile2=example_fizzbuzz.py" +FOR %%a IN (".\*") DO ( + IF /i NOT "%%~nxa"=="%keepfile%" IF /i NOT "%%~nxa"=="%keepfile2%" DEL "%%a" +) +cd .. + +cd all_types +SET "keepfile=all_types.py" +FOR %%a IN (".\*") DO IF /i NOT "%%~nxa"=="%keepfile%" DEL "%%a" +cd .. + +cd procedural_division +SET "keepfile=divide_ints.py" +SET "keepfile2=example_divide_ints.py" +FOR %%a IN (".\*") DO ( + IF /i NOT "%%~nxa"=="%keepfile%" IF /i NOT "%%~nxa"=="%keepfile2%" DEL "%%a" +) +cd .. + +cd oo_car +SET "keepfile=car.py" +SET "keepfile2=example_car.py" +FOR %%a IN (".\*") DO ( + IF /i NOT "%%~nxa"=="%keepfile%" IF /i NOT "%%~nxa"=="%keepfile2%" DEL "%%a" +) +cd .. + +cd pass_by_assignment +SET "keepfile=pass_by_assignment.py" +SET "keepfile2=example_pass_by_assignment.py" +FOR %%a IN (".\*") DO ( + IF /i NOT "%%~nxa"=="%keepfile%" IF /i NOT "%%~nxa"=="%keepfile2%" DEL "%%a" +) cd .. \ No newline at end of file diff --git a/tests/fizzbuzz/coverage_str_helper.json b/tests/fizzbuzz/coverage_str_helper.json index f42b8ed..9a17c6b 100644 --- a/tests/fizzbuzz/coverage_str_helper.json +++ b/tests/fizzbuzz/coverage_str_helper.json @@ -1,140 +1,140 @@ -{ - "name": "coverage_str_helper", - "parameter_names": [ - "this_list", - "non_code_lines" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1741, - 1742, - 1743, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1754, - 1755, - 1756, - 1757, - 1759, - 1760, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1768, - 1769, - 1771, - 1772, - 1773, - 1775, - 1777 - ], - "non_code_lines": [ - 1758, - 1767, - 1770, - 1774, - 1776 - ], - "coverage_io": { - "0": { - "args_before": [ - "[1701, 1702, 1684, 1685, 1687, 1688, 1689]", - "{1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}" - ], - "args_after": { - "this_list": "[1701, 1702, 1684, 1685, 1687, 1688, 1689]", - "non_code_lines": "{1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "['1701-1702', '1684-1685', '1687-1689']", - "expected_type": "list", - "coverage": [ - 1741, - 1742, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1755, - 1756, - 1757, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1771, - 1777 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 71.88, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1741, - 1742, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1755, - 1756, - 1757, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1771, - 1777 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "coverage_str_helper": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "coverage_str_helper", + "parameter_names": [ + "this_list", + "non_code_lines" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1797, + 1798, + 1799, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1810, + 1811, + 1812, + 1813, + 1815, + 1816, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1824, + 1825, + 1827, + 1828, + 1829, + 1831, + 1833 + ], + "non_code_lines": [ + 1814, + 1823, + 1826, + 1830, + 1832 + ], + "coverage_io": { + "0": { + "args_before": [ + "[1740, 1741, 1743, 1744, 1745, 1757, 1758]", + "{1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}" + ], + "args_after": { + "this_list": "[1740, 1741, 1743, 1744, 1745, 1757, 1758]", + "non_code_lines": "{1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "['1740-1741', '1743-1745', '1757-1758']", + "expected_type": "list", + "coverage": [ + 1797, + 1798, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1811, + 1812, + 1813, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1827, + 1833 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 71.88, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1797, + 1798, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1811, + 1812, + 1813, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1827, + 1833 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "coverage_str_helper": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/fizzbuzz/example_fizzbuzz.py b/tests/fizzbuzz/example_fizzbuzz.py new file mode 100644 index 0000000..f70911f --- /dev/null +++ b/tests/fizzbuzz/example_fizzbuzz.py @@ -0,0 +1,104 @@ +""" +Test case to demonstrate the DDT concept on a variant of the fizzbuzz problem. +Includes a global variable. +""" +import argparse +import logging +import os +import sys +from pathlib import Path +import coverage +import json + +from fizzbuzz import fizzbuzz, mode +from src import unit_test_generator +from src.unit_test_generator import ( + generate_all_tests_and_metadata, + unit_test_generator_decorator, + Capturing +) + +FMT_STR = '%(levelname)-8s|%(module)-16s|%(funcName)-20s:%(lineno)-4d:%(message)s' +logging.basicConfig(level=logging.INFO, format=FMT_STR) +logger = logging.getLogger(__name__) +unit_test_generator.logger.setLevel(logging.WARNING) + + +def main(): + """ + Begin ad hoc tests + """ + global mode # pylint: disable=global-statement + + print(fizzbuzz(6)) + print(fizzbuzz(30)) + mode = 'buzzfizz' + print(fizzbuzz(6)) + print(fizzbuzz(30)) + mode = "a_test" + print(fizzbuzz(6)) + + ''' + with Capturing() as stdout_lines: + cov.json_report(outfile='-') + # result will not exist if the function threw an exception + cov_report_ = json.loads(stdout_lines[0]) + logger.critical(cov_report_) + ''' + + # The generate_all_tests_and_metadata() function takes 2 Paths: + # 1. The output directory for the unit tests (.py) + # 2. The output directory for the .json files (I/O for each test) + + generate_all_tests_and_metadata(Path('.'), Path('.')) + +if __name__ == "__main__": + + log_levels = { + 'critical': logging.CRITICAL, + 'error': logging.ERROR, + 'warn': logging.WARNING, + 'warning': logging.WARNING, + 'info': logging.INFO, + 'debug': logging.DEBUG + } + + # Create the parser and add argument(s) + parser = argparse.ArgumentParser() + parser.add_argument('--log-level', + "-l", + help='log level', + type=str, + choices=log_levels.keys(), + default='info') + parser.add_argument("--disable-unit-test-generation", "-d", + action="store_true", + help="Set this flag to deactivate unit test generation for this code") + args = parser.parse_args() + print(f"{args=}") + + this_file = Path(__file__).absolute() + for file in this_file.parent.rglob("*"): + if file.name == "fizzbuzz.py": + continue + if file.suffix in (".py", ".json") and file.absolute() != this_file: + logger.debug("Deleting %s to ensure clean start", this_file) + os.remove(file) + + + if args.disable_unit_test_generation: + main() + sys.exit(0) + + # The code below applies the CLI arg above to selectively enable/disable + # automatic unit test generation (Could not use the syntactic sugar method + # of applying decorators as the user's input isn't parsed until now.) + # Alternatively, move the argument parsing to the very top of this file. + # NOTE: + # Decorating all functions programmatically is left as an exercise to the reader: + # Hint: https://stackoverflow.com/questions/3467526/ + #fizzbuzz = unit_test_generator_decorator(not args.disable_unit_test_generation)(fizzbuzz) + cov = coverage.Coverage() + with cov.collect(): + main() + cov.save() \ No newline at end of file diff --git a/tests/fizzbuzz/fizzbuzz.json b/tests/fizzbuzz/fizzbuzz.json index eec99a1..6d8a000 100644 --- a/tests/fizzbuzz/fizzbuzz.json +++ b/tests/fizzbuzz/fizzbuzz.json @@ -1,149 +1,84 @@ -{ - "name": "fizzbuzz", - "parameter_names": [ - "number" - ], - "is_method": false, - "source_file": null, - "lines": [ - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 56, - 57 - ], - "non_code_lines": [ - 55 - ], - "coverage_io": { - "0": { - "args_before": [ - "6" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "mode": "a_test" - }, - "globals_after": {}, - "expected_result": "Mode 'a_test' invalid for fizzbuzz()", - "expected_type": "str", - "coverage": [ - 40, - 41, - 48, - 56, - 57 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "1": { - "args_before": [ - "30" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "mode": "buzzfizz" - }, - "globals_after": {}, - "expected_result": "30 with mode='buzzfizz' yields 'buzzfizz'", - "expected_type": "str", - "coverage": [ - 40, - 41, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 57 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "2": { - "args_before": [ - "30" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "mode": "fizzbuzz" - }, - "globals_after": {}, - "expected_result": "30 with mode='fizzbuzz' yields 'fizzbuzz'", - "expected_type": "str", - "coverage": [ - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 57 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [], - "global_vars_read_from": [ - "mode" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 56, - 57 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "fizzbuzz": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\fizzbuzz\\fizzbuzz.py" - } +{ + "name": "fizzbuzz", + "parameter_names": [ + "number" + ], + "is_method": false, + "source_file": null, + "lines": [ + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 49, + 50 + ], + "non_code_lines": [ + 48 + ], + "coverage_io": { + "0": { + "args_before": [ + "30" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "mode": "fizzbuzz" + }, + "globals_after": {}, + "expected_result": "30 with mode='fizzbuzz' yields 'fizzbuzz'", + "expected_type": "str", + "coverage": [ + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 50 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 52.94, + "types_in_use": [], + "global_vars_read_from": [ + "mode" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 50 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "fizzbuzz": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\fizzbuzz\\fizzbuzz.py" + } } \ No newline at end of file diff --git a/tests/fizzbuzz/fizzbuzz.py b/tests/fizzbuzz/fizzbuzz.py index 8da3798..8c76771 100644 --- a/tests/fizzbuzz/fizzbuzz.py +++ b/tests/fizzbuzz/fizzbuzz.py @@ -2,24 +2,17 @@ Test case to demonstrate the DDT concept on a variant of the fizzbuzz problem. Includes a global variable. """ -import argparse -import logging -import os -from pathlib import Path from src import unit_test_generator from src.unit_test_generator import ( generate_all_tests_and_metadata, unit_test_generator_decorator, + Capturing ) -FMT_STR = '%(levelname)-8s|%(module)-16s|%(funcName)-20s:%(lineno)-4d:%(message)s' -logging.basicConfig(level=logging.INFO, format=FMT_STR) -logger = logging.getLogger(__name__) -unit_test_generator.logger.setLevel(logging.WARNING) - mode = 'fizzbuzz' # pylint: disable=invalid-name + @unit_test_generator_decorator(110,100) def fizzbuzz(number: int): """ @@ -55,63 +48,3 @@ def fizzbuzz(number: int): else: result = f"Mode '{mode}' invalid for fizzbuzz()" return result - -def main(): - """ - Begin ad hoc tests - """ - global mode # pylint: disable=global-statement - print(fizzbuzz(6)) - print(fizzbuzz(30)) - mode = 'buzzfizz' - print(fizzbuzz(6)) - print(fizzbuzz(30)) - mode = "a_test" - print(fizzbuzz(6)) - - # The generate_all_tests_and_metadata() function takes 2 Paths: - # 1. The output directory for the unit tests (.py) - # 2. The output directory for the .json files (I/O for each test) - - generate_all_tests_and_metadata(Path('.'), Path('.')) - -if __name__ == "__main__": - - log_levels = { - 'critical': logging.CRITICAL, - 'error': logging.ERROR, - 'warn': logging.WARNING, - 'warning': logging.WARNING, - 'info': logging.INFO, - 'debug': logging.DEBUG - } - - # Create the parser and add argument(s) - parser = argparse.ArgumentParser() - parser.add_argument('--log-level', - "-l", - help='log level', - type=str, - choices=log_levels.keys(), - default='info') - parser.add_argument("--disable-unit-test-generation", "-d", - action="store_true", - help="Set this flag to deactivate unit test generation for this code") - args = parser.parse_args() - print(f"{args=}") - - this_file = Path(__file__).absolute() - for file in this_file.parent.rglob("*"): - if file.suffix in (".py", ".json") and file.absolute() != this_file: - logger.debug("Deleting %s to ensure clean start", this_file) - os.remove(file) - # The code below applies the CLI arg above to selectively enable/disable - # automatic unit test generation (Could not use the syntactic sugar method - # of applying decorators as the user's input isn't parsed until now.) - # Alternatively, move the argument parsing to the very top of this file. - # NOTE: - # Decorating all functions programmatically is left as an exercise to the reader: - # Hint: https://stackoverflow.com/questions/3467526/ - #fizzbuzz = unit_test_generator_decorator(not args.disable_unit_test_generation)(fizzbuzz) - - main() diff --git a/tests/fizzbuzz/normalize_arg.json b/tests/fizzbuzz/normalize_arg.json index ea0f4a3..2f89fde 100644 --- a/tests/fizzbuzz/normalize_arg.json +++ b/tests/fizzbuzz/normalize_arg.json @@ -1,67 +1,67 @@ -{ - "name": "normalize_arg", - "parameter_names": [ - "arg" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1711, - 1712, - 1713, - 1714, - 1715, - 1716, - 1718, - 1719, - 1720, - 1721 - ], - "non_code_lines": [ - 1717 - ], - "coverage_io": { - "0": { - "args_before": [ - "\"CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)\"" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "expected_type": "str", - "coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 60.0, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "normalize_arg", + "parameter_names": [ + "arg" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1767, + 1768, + 1769, + 1770, + 1771, + 1772, + 1774, + 1775, + 1776, + 1777 + ], + "non_code_lines": [ + 1773 + ], + "coverage_io": { + "0": { + "args_before": [ + "\"CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)\"" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "expected_type": "str", + "coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 60.0, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/fizzbuzz/test_coverage_str_helper.py b/tests/fizzbuzz/test_coverage_str_helper.py deleted file mode 100644 index be3780e..0000000 --- a/tests/fizzbuzz/test_coverage_str_helper.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Programmatically generated test function for coverage_str_helper() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - -# Now import modules specific to coverage_str_helper: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler - - -# In sum, these tests covered 71.88% of coverage_str_helper's lines -# Line(s) not covered by ANY of the tests below: -# ['1743', '1754', '1759-1760', '1768-1769', '1772-1773'] -@pytest.mark.parametrize( - "this_list, non_code_lines, expected_result, args_after", - [ - ( - [1701, 1702, 1684, 1685, 1687, 1688, 1689], - {1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}, - "['1701-1702', '1684-1685', '1687-1689']", - { - "this_list": "[1701, 1702, 1684, 1685, 1687, 1688, 1689]", - "non_code_lines": "{1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}", - }, - ), - ], -) -def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): - """ - Programmatically generated test function for coverage_str_helper() - """ - result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) - assert result == expected_result or result == eval(expected_result) - assert ( - this_list == eval(args_after["this_list"]) - or args_after["this_list"] == this_list - ) - assert ( - non_code_lines == eval(args_after["non_code_lines"]) - or args_after["non_code_lines"] == non_code_lines - ) diff --git a/tests/fizzbuzz/test_coverage_str_helper_fizzbuzz.py b/tests/fizzbuzz/test_coverage_str_helper_fizzbuzz.py new file mode 100644 index 0000000..8606f4c --- /dev/null +++ b/tests/fizzbuzz/test_coverage_str_helper_fizzbuzz.py @@ -0,0 +1,51 @@ +""" +Programmatically generated test function for coverage_str_helper() +""" + +import pytest +from src import unit_test_generator + +# Now import modules specific to coverage_str_helper: + + +# In sum, these tests covered 71.88% of coverage_str_helper's lines +# Line(s) not covered by ANY of the tests below: +# ['1799', '1810', '1815-1816', '1824-1825', '1828-1829'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "this_list, non_code_lines, expected_result, args_after", + [ + ( + [1740, 1741, 1743, 1744, 1745, 1757, 1758], + {1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}, + "['1740-1741', '1743-1745', '1757-1758']", + { + "this_list": "[1740, 1741, 1743, 1744, 1745, 1757, 1758]", + "non_code_lines": "{1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}", + }, + ), + ], + ids=counter, +) +def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): + """ + Programmatically generated test function for coverage_str_helper() + """ + result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_list == eval(args_after["this_list"]) + or args_after["this_list"] == this_list + ) + assert ( + non_code_lines == eval(args_after["non_code_lines"]) + or args_after["non_code_lines"] == non_code_lines + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/fizzbuzz/test_fizzbuzz.py b/tests/fizzbuzz/test_fizzbuzz.py index ed398a1..4673445 100644 --- a/tests/fizzbuzz/test_fizzbuzz.py +++ b/tests/fizzbuzz/test_fizzbuzz.py @@ -1,29 +1,35 @@ -""" -Programmatically generated test function for fizzbuzz() -""" - -import re -import pytest -from collections import OrderedDict -from tests.fizzbuzz import fizzbuzz -from _pytest.monkeypatch import MonkeyPatch - - -# In sum, these tests covered 100.0% of fizzbuzz's lines -@pytest.mark.parametrize( - "number, expected_result, globals_before", - [ - (6, "Mode 'a_test' invalid for fizzbuzz()", {"mode": "a_test"}), - (30, "30 with mode='buzzfizz' yields 'buzzfizz'", {"mode": "buzzfizz"}), - (30, "30 with mode='fizzbuzz' yields 'fizzbuzz'", {"mode": "fizzbuzz"}), - ], -) -def test_fizzbuzz(number, expected_result, globals_before): - """ - Programmatically generated test function for fizzbuzz() - """ - monkeypatch = MonkeyPatch() - for k, v in globals_before.items(): - monkeypatch.setattr(fizzbuzz, k, v) - result = fizzbuzz.fizzbuzz(number) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for fizzbuzz() +""" + +import pytest +from tests.fizzbuzz import fizzbuzz +from _pytest.monkeypatch import MonkeyPatch + +MODE = "fizzbuzz" + + +# In sum, these tests covered 52.94% of fizzbuzz's lines +# Line(s) not covered by ANY of the tests below: +# ['41-47'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "number, expected_result", + [ + (30, "30 with mode='fizzbuzz' yields 'fizzbuzz'"), + ], + ids=counter, +) +def test_fizzbuzz(number, expected_result): + """ + Programmatically generated test function for fizzbuzz() + """ + monkeypatch = MonkeyPatch() + monkeypatch.setattr(fizzbuzz, "mode", MODE) + result = fizzbuzz.fizzbuzz(number) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/fizzbuzz/test_normalize_arg.py b/tests/fizzbuzz/test_normalize_arg_fizzbuzz.py similarity index 82% rename from tests/fizzbuzz/test_normalize_arg.py rename to tests/fizzbuzz/test_normalize_arg_fizzbuzz.py index 20ea583..1cbf21f 100644 --- a/tests/fizzbuzz/test_normalize_arg.py +++ b/tests/fizzbuzz/test_normalize_arg_fizzbuzz.py @@ -1,28 +1,33 @@ -""" -Programmatically generated test function for normalize_arg() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - - -# In sum, these tests covered 60.0% of normalize_arg's lines -# Line(s) not covered by ANY of the tests below: -# ['1714', '1716', '1719-1720'] -@pytest.mark.parametrize( - "arg, expected_result", - [ - ( - "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - ), - ], -) -def test_normalize_arg(arg, expected_result): - """ - Programmatically generated test function for normalize_arg() - """ - result = unit_test_generator.normalize_arg(arg) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for normalize_arg() +""" + +import pytest +from src import unit_test_generator + + +# In sum, these tests covered 60.0% of normalize_arg's lines +# Line(s) not covered by ANY of the tests below: +# ['1770', '1772', '1775-1776'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "arg, expected_result", + [ + ( + "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + ), + ], + ids=counter, +) +def test_normalize_arg(arg, expected_result): + """ + Programmatically generated test function for normalize_arg() + """ + result = unit_test_generator.normalize_arg(arg) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/fizzbuzz/test_update_global.py b/tests/fizzbuzz/test_update_global_fizzbuzz.py similarity index 76% rename from tests/fizzbuzz/test_update_global.py rename to tests/fizzbuzz/test_update_global_fizzbuzz.py index c794660..4aebff7 100644 --- a/tests/fizzbuzz/test_update_global.py +++ b/tests/fizzbuzz/test_update_global_fizzbuzz.py @@ -1,65 +1,68 @@ -""" -Programmatically generated test function for update_global() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - -# Now import modules specific to update_global: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler -from src.unit_test_generator import CoverageInfo - - -# In sum, these tests covered 46.15% of update_global's lines -# Line(s) not covered by ANY of the tests below: -# ['1701-1702', '1684-1685', '1687-1689'] -@pytest.mark.parametrize( - "obj, this_global, phase, this_coverage_info, expected_result, args_after", - [ - ( - "fizzbuzz", - "mode", - "Before", - CoverageInfo( - args_before=["6"], - args_after={}, - kwargs={}, - kwargs_after={}, - globals_before={}, - globals_after={}, - expected_result="", - expected_type="", - coverage=[], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - testable=0.0, - ), - "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - { - "this_coverage_info": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - }, - ), - ], -) -def test_update_global( - obj, this_global, phase, this_coverage_info, expected_result, args_after -): - """ - Programmatically generated test function for update_global() - """ - result = unit_test_generator.update_global( - obj, this_global, phase, this_coverage_info - ) - assert result == expected_result or result == eval(expected_result) - assert ( - this_coverage_info == eval(args_after["this_coverage_info"]) - or args_after["this_coverage_info"] == this_coverage_info - ) +""" +Programmatically generated test function for update_global() +""" + +import pytest +from src import unit_test_generator + +# Now import modules specific to update_global: +from src.unit_test_generator import CoverageInfo + + +# In sum, these tests covered 46.15% of update_global's lines +# Line(s) not covered by ANY of the tests below: +# ['1740-1741', '1743-1745', '1757-1758'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "obj, this_global, phase, this_coverage_info, expected_result, args_after", + [ + ( + "fizzbuzz", + "mode", + "Before", + CoverageInfo( + args_before=["6"], + args_after={}, + kwargs={}, + kwargs_after={}, + globals_before={}, + globals_after={}, + expected_result="", + expected_type="", + coverage=[], + exception_type="", + exception_message="", + constructor="", + cost=0.0, + testable=True, + ), + "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + { + "this_coverage_info": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + }, + ), + ], + ids=counter, +) +def test_update_global( + obj, this_global, phase, this_coverage_info, expected_result, args_after +): + """ + Programmatically generated test function for update_global() + """ + result = unit_test_generator.update_global( + obj, this_global, phase, this_coverage_info + ) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_coverage_info == eval(args_after["this_coverage_info"]) + or args_after["this_coverage_info"] == this_coverage_info + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/fizzbuzz/update_global.json b/tests/fizzbuzz/update_global.json index 767007e..7744ae6 100644 --- a/tests/fizzbuzz/update_global.json +++ b/tests/fizzbuzz/update_global.json @@ -1,94 +1,94 @@ -{ - "name": "update_global", - "parameter_names": [ - "obj", - "this_global", - "phase", - "this_coverage_info" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1683, - 1684, - 1685, - 1686, - 1687, - 1688, - 1689, - 1691, - 1699, - 1700, - 1701, - 1702, - 1703 - ], - "non_code_lines": [ - 1690, - 1692, - 1693, - 1694, - 1695, - 1696, - 1697, - 1698 - ], - "coverage_io": { - "0": { - "args_before": [ - "\"fizzbuzz\"", - "\"mode\"", - "\"Before\"", - "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - ], - "args_after": { - "this_coverage_info": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "expected_type": "src.unit_test_generator.CoverageInfo", - "coverage": [ - 1683, - 1686, - 1691, - 1699, - 1700, - 1703 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 46.15, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "src.unit_test_generator.CoverageInfo" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1683, - 1686, - 1691, - 1699, - 1700, - 1703 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "update_global", + "parameter_names": [ + "obj", + "this_global", + "phase", + "this_coverage_info" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1739, + 1740, + 1741, + 1742, + 1743, + 1744, + 1745, + 1747, + 1755, + 1756, + 1757, + 1758, + 1759 + ], + "non_code_lines": [ + 1746, + 1748, + 1749, + 1750, + 1751, + 1752, + 1753, + 1754 + ], + "coverage_io": { + "0": { + "args_before": [ + "\"fizzbuzz\"", + "\"mode\"", + "\"Before\"", + "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + ], + "args_after": { + "this_coverage_info": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'mode': 'fizzbuzz'}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "expected_type": "src.unit_test_generator.CoverageInfo", + "coverage": [ + 1739, + 1742, + 1747, + 1755, + 1756, + 1759 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 46.15, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "src.unit_test_generator.CoverageInfo" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1739, + 1742, + 1747, + 1755, + 1756, + 1759 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/oo_car/Car.brake.json b/tests/oo_car/Car.brake.json index 869ed14..19869b0 100644 --- a/tests/oo_car/Car.brake.json +++ b/tests/oo_car/Car.brake.json @@ -1,72 +1,72 @@ -{ - "name": "Car.brake", - "parameter_names": [ - "self", - "rate", - "duration" - ], - "is_method": true, - "source_file": null, - "lines": [ - 50, - 51, - 52, - 53, - 54, - 55, - 56 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "-1", - "1" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "9", - "expected_type": "int", - "coverage": [ - 50, - 51, - 53, - 55, - 56 - ], - "exception_type": "", - "exception_message": "", - "constructor": "Car(\"Red\", 10, 0)", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 71.43, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "tests.oo_car.car.Car" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 50, - 51, - 53, - 55, - 56 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "brake": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - } +{ + "name": "Car.brake", + "parameter_names": [ + "self", + "rate", + "duration" + ], + "is_method": true, + "source_file": null, + "lines": [ + 53, + 54, + 55, + 56, + 57, + 58, + 59 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "-1", + "1" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "9", + "expected_type": "int", + "coverage": [ + 53, + 54, + 56, + 58, + 59 + ], + "exception_type": "", + "exception_message": "", + "constructor": "Car(\"Red\", 10, 0)", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 71.43, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "tests.oo_car.car.Car" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 53, + 54, + 56, + 58, + 59 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "brake": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" + } } \ No newline at end of file diff --git a/tests/oo_car/Car.change_steer_angle.json b/tests/oo_car/Car.change_steer_angle.json index 773a66e..a2e4a2a 100644 --- a/tests/oo_car/Car.change_steer_angle.json +++ b/tests/oo_car/Car.change_steer_angle.json @@ -1,151 +1,151 @@ -{ - "name": "Car.change_steer_angle", - "parameter_names": [ - "self", - "angle" - ], - "is_method": true, - "source_file": null, - "lines": [ - 79, - 80, - 81, - 83, - 86, - 87, - 86, - 88, - 86, - 90 - ], - "non_code_lines": [ - 82, - 84, - 85, - 89 - ], - "coverage_io": { - "0": { - "args_before": [ - "-1080" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 79, - 80, - 81 - ], - "exception_type": "", - "exception_message": "angle=-1080 out of bounds!", - "constructor": "Car(\"Green\", 48, 90)", - "cost": 0.0, - "testable": true - }, - "1": { - "args_before": [ - "180" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "210", - "expected_type": "int", - "coverage": [ - 79, - 80, - 83, - 86, - 90 - ], - "exception_type": "", - "exception_message": "", - "constructor": "Car(\"Blue\", 0.0, 30)", - "cost": 0.0, - "testable": true - }, - "2": { - "args_before": [ - "30" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "30", - "expected_type": "int", - "coverage": [ - 79, - 80, - 83, - 86, - 90 - ], - "exception_type": "", - "exception_message": "", - "constructor": "Car(\"Red\", 9, 0)", - "cost": 0.0, - "testable": true - }, - "3": { - "args_before": [ - "90" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "60", - "expected_type": "int", - "coverage": [ - 79, - 80, - 83, - 86, - 90 - ], - "exception_type": "", - "exception_message": "", - "constructor": "Car(\"White\", 20, -30)", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 60.0, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "tests.oo_car.car.Car" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 79, - 80, - 81, - 83, - 86, - 90 - ], - "needs_pytest": true, - "exceptions_raised": [ - "" - ], - "callable_files": { - "change_steer_angle": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - } +{ + "name": "Car.change_steer_angle", + "parameter_names": [ + "self", + "angle" + ], + "is_method": true, + "source_file": null, + "lines": [ + 82, + 83, + 84, + 86, + 89, + 90, + 89, + 91, + 89, + 93 + ], + "non_code_lines": [ + 85, + 87, + 88, + 92 + ], + "coverage_io": { + "0": { + "args_before": [ + "-1080" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 82, + 83, + 84 + ], + "exception_type": "", + "exception_message": "angle=-1080 out of bounds!", + "constructor": "Car(\"Green\", 48, 90)", + "cost": 0.0, + "testable": true + }, + "1": { + "args_before": [ + "180" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "210", + "expected_type": "int", + "coverage": [ + 82, + 83, + 86, + 89, + 93 + ], + "exception_type": "", + "exception_message": "", + "constructor": "Car(\"Blue\", 0.0, 30)", + "cost": 0.0, + "testable": true + }, + "2": { + "args_before": [ + "30" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "30", + "expected_type": "int", + "coverage": [ + 82, + 83, + 86, + 89, + 93 + ], + "exception_type": "", + "exception_message": "", + "constructor": "Car(\"Red\", 9, 0)", + "cost": 0.0, + "testable": true + }, + "3": { + "args_before": [ + "90" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "60", + "expected_type": "int", + "coverage": [ + 82, + 83, + 86, + 89, + 93 + ], + "exception_type": "", + "exception_message": "", + "constructor": "Car(\"White\", 20, -30)", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 60.0, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "tests.oo_car.car.Car" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 82, + 83, + 84, + 86, + 89, + 93 + ], + "needs_pytest": true, + "exceptions_raised": [ + "" + ], + "callable_files": { + "change_steer_angle": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" + } } \ No newline at end of file diff --git a/tests/oo_car/Car.constructor.json b/tests/oo_car/Car.constructor.json index 84a1002..3bc69cf 100644 --- a/tests/oo_car/Car.constructor.json +++ b/tests/oo_car/Car.constructor.json @@ -1,57 +1,57 @@ -{ - "name": "Car.__init__", - "parameter_names": [ - "self", - "color", - "speed", - "steer_angle" - ], - "is_method": true, - "source_file": null, - "lines": [ - 41, - 42, - 43 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "\"Red\"", - "10", - "0" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 41, - 42, - 43 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 41, - 42, - 43 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "__init__": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - } +{ + "name": "Car.__init__", + "parameter_names": [ + "self", + "color", + "speed", + "steer_angle" + ], + "is_method": true, + "source_file": null, + "lines": [ + 44, + 45, + 46 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "\"Red\"", + "10", + "0" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 44, + 45, + 46 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 100.0, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 44, + 45, + 46 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "__init__": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" + } } \ No newline at end of file diff --git a/tests/oo_car/Car.gas.json b/tests/oo_car/Car.gas.json index b8c24ac..96948d3 100644 --- a/tests/oo_car/Car.gas.json +++ b/tests/oo_car/Car.gas.json @@ -1,109 +1,109 @@ -{ - "name": "Car.gas", - "parameter_names": [ - "self", - "rate", - "duration" - ], - "is_method": true, - "source_file": null, - "lines": [ - 66, - 67, - 68, - 69, - 70, - 71 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "-1", - "1" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "method_call_counter": 0 - }, - "globals_after": { - "method_call_counter": 1 - }, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 66, - 67, - 68, - 69 - ], - "exception_type": "", - "exception_message": "Gas rate (m/s) must be positive.", - "constructor": "Car(\"Red\", 10, 0)", - "cost": 0.0, - "testable": true - }, - "1": { - "args_before": [ - "2", - "2" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "method_call_counter": 1 - }, - "globals_after": { - "method_call_counter": 2 - }, - "expected_result": "16", - "expected_type": "int", - "coverage": [ - 66, - 67, - 68, - 70, - 71 - ], - "exception_type": "", - "exception_message": "", - "constructor": "Car(\"White\", 12, -30)", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "tests.oo_car.car.Car" - ], - "global_vars_read_from": [ - "logger", - "method_call_counter" - ], - "global_vars_written_to": [ - "method_call_counter" - ], - "unified_test_coverage": [ - 66, - 67, - 68, - 69, - 70, - 71 - ], - "needs_pytest": true, - "exceptions_raised": [ - "" - ], - "callable_files": { - "gas": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - } +{ + "name": "Car.gas", + "parameter_names": [ + "self", + "rate", + "duration" + ], + "is_method": true, + "source_file": null, + "lines": [ + 69, + 70, + 71, + 72, + 73, + 74 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "-1", + "1" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "method_call_counter": 0 + }, + "globals_after": { + "method_call_counter": 1 + }, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 69, + 70, + 71, + 72 + ], + "exception_type": "", + "exception_message": "Gas rate (m/s) must be positive.", + "constructor": "Car(\"Red\", 10, 0)", + "cost": 0.0, + "testable": true + }, + "1": { + "args_before": [ + "2", + "2" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "method_call_counter": 1 + }, + "globals_after": { + "method_call_counter": 2 + }, + "expected_result": "16", + "expected_type": "int", + "coverage": [ + 69, + 70, + 71, + 73, + 74 + ], + "exception_type": "", + "exception_message": "", + "constructor": "Car(\"White\", 12, -30)", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 100.0, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "tests.oo_car.car.Car" + ], + "global_vars_read_from": [ + "logger", + "method_call_counter" + ], + "global_vars_written_to": [ + "method_call_counter" + ], + "unified_test_coverage": [ + 69, + 70, + 71, + 72, + 73, + 74 + ], + "needs_pytest": true, + "exceptions_raised": [ + "" + ], + "callable_files": { + "gas": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" + } } \ No newline at end of file diff --git a/tests/oo_car/Car.is_going_faster_than.json b/tests/oo_car/Car.is_going_faster_than.json index 3a66e48..7d729c7 100644 --- a/tests/oo_car/Car.is_going_faster_than.json +++ b/tests/oo_car/Car.is_going_faster_than.json @@ -1,52 +1,52 @@ -{ - "name": "Car.is_going_faster_than", - "parameter_names": [ - "self", - "other_car" - ], - "is_method": true, - "source_file": null, - "lines": [ - 126 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "Car(\"White\", 19, 0)" - ], - "args_after": { - "other_car": "Car(\"White\", 19, 0)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "True", - "expected_type": "bool", - "coverage": [ - 126 - ], - "exception_type": "", - "exception_message": "", - "constructor": "Car(\"Red\", 20, 0)", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [ - "__main__.Car", - "tests.oo_car.car.Car" - ], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 126 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "is_going_faster_than": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" - } +{ + "name": "Car.is_going_faster_than", + "parameter_names": [ + "self", + "other_car" + ], + "is_method": true, + "source_file": null, + "lines": [ + 129 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "Car(\"White\", 19, 0)" + ], + "args_after": { + "other_car": "Car(\"White\", 19, 0)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "True", + "expected_type": "bool", + "coverage": [ + 129 + ], + "exception_type": "", + "exception_message": "", + "constructor": "Car(\"Red\", 20, 0)", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 100.0, + "types_in_use": [ + "car.Car", + "tests.oo_car.car.Car" + ], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 129 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "is_going_faster_than": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\oo_car\\car.py" + } } \ No newline at end of file diff --git a/tests/oo_car/car.py b/tests/oo_car/car.py index 05ce47c..2f4250b 100644 --- a/tests/oo_car/car.py +++ b/tests/oo_car/car.py @@ -6,6 +6,9 @@ import logging import os from pathlib import Path +import coverage +import sys +import time from src import unit_test_generator from src.unit_test_generator import ( @@ -137,124 +140,3 @@ def __eq__(self, other_car:object) -> bool: if self.steer_angle != other_car.steer_angle: return False return True -def first_test(): - """ - Create a bunch of cars to test all the Car class methods - except for is_going_faster_than() - """ - # Create a bunch of cars in a loop for testing: - colors = ["Red", "White", "Blue", "Green"] - init_speeds = [10,12,14,16] - init_angles = [0, -30, 30, 90 ] - change_angles = [30, 90, 180, -1080] - change_speed = [-1, 2, 3, 4] - durations = [1,2,-3,4] - lists = [ - colors, - init_speeds, - init_angles, - change_angles, - change_speed, - durations - ] - for i, (color, speed, angle, c_angle, c_speed, duration) in enumerate(zip(*lists)): - logger.info(f"Car #{i}".center(80, '-')) - this_car = Car(color, speed, angle) - if this_car is None or not this_car: - raise ValueError("this_car is None!") - - logger.info(this_car) - logger.info("Driving %s", {this_car.repr()}) - # Note the intentional bug here for the - # sake of demonstrating the ValueError: - try: - this_car.gas(c_speed, duration) - except ValueError as e: - logger.error("gas(%.2f,%d) raised %s", c_speed, duration, type(e)) - # Instead of a try/except we should do: - if c_speed >= 0: - this_car.gas(c_speed, duration) - else: - this_car.brake(c_speed, duration) - - #car.change_steer_angle(c_angle) - try: - this_car.change_steer_angle(c_angle) - except AssertionError as e: - logger.error("change_steer_angle(%s) raised %s", c_angle, type(e)) - - logger.info(this_car) - -def second_test(): - """ - Create two cars and determine which one is going faster - by using the is_going_faster_than() Car method - """ - logger.info("Test 2.1".center(80, '-')) - car_1 = Car("Red", 20, 0) - car_2 = Car("White", 19, 0) - - if car_1.is_going_faster_than(car_2): - logger.info("%s is going faster than %s", car_1, car_2) - else: - logger.info("%s's speed is less than or equal to %s's speed", car_1, car_2) - - logger.info("Test 2.2".center(80, '-')) - # The invocation below will also work, - # demonstrating that the unit_test_generator_decorator works on both - Car.is_going_faster_than(car_1, car_2) - -def main(): - """ - Call test functions for Car class, then generate test files for each - method. - """ - first_test() - second_test() - generate_all_tests_and_metadata(Path('.'), Path('.')) - -if __name__ == "__main__": - - log_levels = { - 'critical': logging.CRITICAL, - 'error': logging.ERROR, - 'warn': logging.WARNING, - 'warning': logging.WARNING, - 'info': logging.INFO, - 'debug': logging.DEBUG - } - - # Create the parser and add argument(s) - parser = argparse.ArgumentParser() - parser.add_argument('--log-level', - "-l", - help='log level', - type=str, - choices=log_levels.keys(), - default='info') - parser.add_argument("--disable-unit-test-generation", "-d", - action="store_true", - help="Set this flag to deactivate unit test generation for this code") - args = parser.parse_args() - logger.info("args=%s", args) - - this_file = Path(__file__).absolute() - for file in this_file.parent.rglob("*"): - if file.suffix in (".py", ".json") and file.absolute() != this_file: - logger.debug("%s != %s", file.absolute().name, this_file.name) - logger.debug("Deleting %s to ensure clean start", file.name) - os.remove(file) - - # The code below applies the CLI arg above to selectively enable/disable - # automatic unit test generation (Could not use the syntactic sugar method - # of applying decorators as the user's input isn't parsed until now.) - # Alternatively, move the argument parsing to the very top of this file. - # NOTE: - # Decorating all functions programmatically is left as an exercise to the reader: - # Hint: https://stackoverflow.com/questions/3467526/ - Car.brake = unit_test_generator_decorator(110, 100)(Car.brake) - Car.gas = unit_test_generator_decorator(110, 100)(Car.gas) - Car.change_steer_angle = unit_test_generator_decorator(110, 100, True)(Car.change_steer_angle) - Car.is_going_faster_than = unit_test_generator_decorator(110, 110)(Car.is_going_faster_than) - Car.__init__ = unit_test_generator_decorator(110, 110)(Car.__init__) - main() diff --git a/tests/oo_car/coverage_str_helper.json b/tests/oo_car/coverage_str_helper.json index f599449..eeb2339 100644 --- a/tests/oo_car/coverage_str_helper.json +++ b/tests/oo_car/coverage_str_helper.json @@ -1,128 +1,128 @@ -{ - "name": "coverage_str_helper", - "parameter_names": [ - "this_list", - "non_code_lines" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1741, - 1742, - 1743, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1754, - 1755, - 1756, - 1757, - 1759, - 1760, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1768, - 1769, - 1771, - 1772, - 1773, - 1775, - 1777 - ], - "non_code_lines": [ - 1758, - 1767, - 1770, - 1774, - 1776 - ], - "coverage_io": { - "0": { - "args_before": [ - "[52, 54]", - "set()" - ], - "args_after": { - "this_list": "[52, 54]", - "non_code_lines": "set()" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "['52']", - "expected_type": "list", - "coverage": [ - 1741, - 1742, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1753, - 1755, - 1759, - 1760, - 1761, - 1762, - 1763, - 1771, - 1777 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 53.12, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1741, - 1742, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1753, - 1755, - 1759, - 1760, - 1761, - 1762, - 1763, - 1771, - 1777 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "coverage_str_helper": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "coverage_str_helper", + "parameter_names": [ + "this_list", + "non_code_lines" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1797, + 1798, + 1799, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1810, + 1811, + 1812, + 1813, + 1815, + 1816, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1824, + 1825, + 1827, + 1828, + 1829, + 1831, + 1833 + ], + "non_code_lines": [ + 1814, + 1823, + 1826, + 1830, + 1832 + ], + "coverage_io": { + "0": { + "args_before": [ + "[55, 57]", + "set()" + ], + "args_after": { + "this_list": "[55, 57]", + "non_code_lines": "set()" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "['55']", + "expected_type": "list", + "coverage": [ + 1797, + 1798, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1809, + 1811, + 1815, + 1816, + 1817, + 1818, + 1819, + 1827, + 1833 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 53.12, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1797, + 1798, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1809, + 1811, + 1815, + 1816, + 1817, + 1818, + 1819, + 1827, + 1833 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "coverage_str_helper": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/oo_car/example_car.py b/tests/oo_car/example_car.py new file mode 100644 index 0000000..b64c6e3 --- /dev/null +++ b/tests/oo_car/example_car.py @@ -0,0 +1,161 @@ +""" +Object-oriented test sample +""" + +import argparse +import logging +import os +from pathlib import Path +import coverage +import sys +import time + +from car import Car +from src import unit_test_generator +from src.unit_test_generator import ( + generate_all_tests_and_metadata, + unit_test_generator_decorator, +) + +FMT_STR = '%(levelname)-8s|%(module)-16s|%(funcName)-25s:%(lineno)-4d:%(message)s' +logging.basicConfig(level=logging.INFO, format=FMT_STR) +logger = logging.getLogger(__name__) +unit_test_generator.logger.setLevel(logging.CRITICAL) + +# The global below is simply so the update_global() function in +# unit_test_generator.py will be executed, without which that +# unit test will be empty and will raise an exception. +method_call_counter = 0 # pylint: disable=invalid-name + +def first_test(): + """ + Create a bunch of cars to test all the Car class methods + except for is_going_faster_than() + """ + # Create a bunch of cars in a loop for testing: + colors = ["Red", "White", "Blue", "Green"] + init_speeds = [10,12,14,16] + init_angles = [0, -30, 30, 90 ] + change_angles = [30, 90, 180, -1080] + change_speed = [-1, 2, 3, 4] + durations = [1,2,-3,4] + lists = [ + colors, + init_speeds, + init_angles, + change_angles, + change_speed, + durations + ] + for i, (color, speed, angle, c_angle, c_speed, duration) in enumerate(zip(*lists)): + logger.info(f"Car #{i}".center(80, '-')) + this_car = Car(color, speed, angle) + if this_car is None or not this_car: + raise ValueError("this_car is None!") + + logger.info(this_car) + logger.info("Driving %s", {this_car.repr()}) + # Note the intentional bug here for the + # sake of demonstrating the ValueError: + try: + this_car.gas(c_speed, duration) + except ValueError as e: + logger.error("gas(%.2f,%d) raised %s", c_speed, duration, type(e)) + # Instead of a try/except we should do: + if c_speed >= 0: + this_car.gas(c_speed, duration) + else: + this_car.brake(c_speed, duration) + + #car.change_steer_angle(c_angle) + try: + this_car.change_steer_angle(c_angle) + except AssertionError as e: + logger.error("change_steer_angle(%s) raised %s", c_angle, type(e)) + + logger.info(this_car) + +def second_test(): + """ + Create two cars and determine which one is going faster + by using the is_going_faster_than() Car method + """ + logger.info("Test 2.1".center(80, '-')) + car_1 = Car("Red", 20, 0) + car_2 = Car("White", 19, 0) + + if car_1.is_going_faster_than(car_2): + logger.info("%s is going faster than %s", car_1, car_2) + else: + logger.info("%s's speed is less than or equal to %s's speed", car_1, car_2) + + logger.info("Test 2.2".center(80, '-')) + # The invocation below will also work, + # demonstrating that the unit_test_generator_decorator works on both + Car.is_going_faster_than(car_1, car_2) + +def main(): + """ + Call test functions for Car class, then generate test files for each + method. + """ + + first_test() + second_test() + generate_all_tests_and_metadata(Path('.'), Path('.')) + +if __name__ == "__main__": + + log_levels = { + 'critical': logging.CRITICAL, + 'error': logging.ERROR, + 'warn': logging.WARNING, + 'warning': logging.WARNING, + 'info': logging.INFO, + 'debug': logging.DEBUG + } + + # Create the parser and add argument(s) + parser = argparse.ArgumentParser() + parser.add_argument('--log-level', + "-l", + help='log level', + type=str, + choices=log_levels.keys(), + default='info') + parser.add_argument("--disable-unit-test-generation", "-d", + action="store_true", + help="Set this flag to deactivate unit test generation for this code") + args = parser.parse_args() + logger.info("args=%s", args) + + this_file = Path(__file__).absolute() + for file in this_file.parent.rglob("*"): + if file.name == "car.py": + continue + if file.suffix in (".py", ".json") and file.absolute() != this_file: + logger.debug("%s != %s", file.absolute().name, this_file.name) + logger.debug("Deleting %s to ensure clean start", file.name) + logger.warning("Removing file: %s", file) + os.remove(file) + + if args.disable_unit_test_generation: + main() + sys.exit(0) + # The code below applies the CLI arg above to selectively enable/disable + # automatic unit test generation (Could not use the syntactic sugar method + # of applying decorators as the user's input isn't parsed until now.) + # Alternatively, move the argument parsing to the very top of this file. + # NOTE: + # Decorating all functions programmatically is left as an exercise to the reader: + # Hint: https://stackoverflow.com/questions/3467526/ + Car.brake = unit_test_generator_decorator(110, 100)(Car.brake) + Car.gas = unit_test_generator_decorator(110, 100)(Car.gas) + Car.change_steer_angle = unit_test_generator_decorator(110, 100, True)(Car.change_steer_angle) + Car.is_going_faster_than = unit_test_generator_decorator(110, 110)(Car.is_going_faster_than) + Car.__init__ = unit_test_generator_decorator(110, 110)(Car.__init__) + + cov = coverage.Coverage() + with cov.collect(): + main() + cov.save() diff --git a/tests/oo_car/normalize_arg.json b/tests/oo_car/normalize_arg.json index 75351c8..6b3d1f2 100644 --- a/tests/oo_car/normalize_arg.json +++ b/tests/oo_car/normalize_arg.json @@ -1,67 +1,67 @@ -{ - "name": "normalize_arg", - "parameter_names": [ - "arg" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1711, - 1712, - 1713, - 1714, - 1715, - 1716, - 1718, - 1719, - 1720, - 1721 - ], - "non_code_lines": [ - 1717 - ], - "coverage_io": { - "0": { - "args_before": [ - "\"None\"" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "str", - "coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 60.0, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "normalize_arg", + "parameter_names": [ + "arg" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1767, + 1768, + 1769, + 1770, + 1771, + 1772, + 1774, + 1775, + 1776, + 1777 + ], + "non_code_lines": [ + 1773 + ], + "coverage_io": { + "0": { + "args_before": [ + "\"None\"" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "str", + "coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 60.0, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/oo_car/test_car_brake.py b/tests/oo_car/test_car_brake.py index b7b4277..7f9aa24 100644 --- a/tests/oo_car/test_car_brake.py +++ b/tests/oo_car/test_car_brake.py @@ -1,33 +1,32 @@ -""" -Programmatically generated test function for Car.brake() -""" - -import re -import pytest -from collections import OrderedDict -from tests.oo_car import car - -# Now import modules specific to Car.brake: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler -from tests.oo_car.car import Car - - -# In sum, these tests covered 71.43% of Car.brake's lines -# Line(s) not covered by ANY of the tests below: -# ['52'] -@pytest.mark.parametrize( - "test_class_instance, rate, duration, expected_result", - [ - (Car("Red", 10, 0), -1, 1, "9"), - ], -) -def test_car_brake(test_class_instance, rate, duration, expected_result): - """ - Programmatically generated test function for Car.brake() - """ - result = test_class_instance.brake(rate, duration) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for Car.brake() +""" + +import pytest + +# Now import modules specific to Car.brake: +from tests.oo_car.car import Car + + +# In sum, these tests covered 71.43% of Car.brake's lines +# Line(s) not covered by ANY of the tests below: +# ['55'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "test_class_instance, rate, duration, expected_result", + [ + (Car("Red", 10, 0), -1, 1, "9"), + ], + ids=counter, +) +def test_car_brake(test_class_instance, rate, duration, expected_result): + """ + Programmatically generated test function for Car.brake() + """ + result = test_class_instance.brake(rate, duration) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/oo_car/test_car_change_steer_angle.py b/tests/oo_car/test_car_change_steer_angle.py index dba587c..d3f064d 100644 --- a/tests/oo_car/test_car_change_steer_angle.py +++ b/tests/oo_car/test_car_change_steer_angle.py @@ -1,48 +1,48 @@ -""" -Programmatically generated test function for Car.change_steer_angle() -""" - -import re -import pytest -from collections import OrderedDict -from tests.oo_car import car - -# Now import modules specific to Car.change_steer_angle: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler -from tests.oo_car.car import Car - - -# In sum, these tests covered 60.0% of Car.change_steer_angle's lines -# Line(s) not covered by ANY of the tests below: -# ['87-88'] -@pytest.mark.parametrize( - "test_class_instance, angle, exception_type, exception_message, expected_result", - [ - ( - Car("Green", 48, 90), - -1080, - AssertionError, - "angle=-1080 out of bounds!", - "None", - ), - (Car("Blue", 0.0, 30), 180, "N/A", "N/A", "210"), - (Car("Red", 9, 0), 30, "N/A", "N/A", "30"), - (Car("White", 20, -30), 90, "N/A", "N/A", "60"), - ], -) -def test_car_change_steer_angle( - test_class_instance, angle, exception_type, exception_message, expected_result -): - """ - Programmatically generated test function for Car.change_steer_angle() - """ - if exception_type != "N/A": - with pytest.raises(exception_type, match=re.escape(exception_message)): - test_class_instance.change_steer_angle(angle) - else: - result = test_class_instance.change_steer_angle(angle) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for Car.change_steer_angle() +""" + +import re +import pytest + +# Now import modules specific to Car.change_steer_angle: +from tests.oo_car.car import Car + + +# In sum, these tests covered 60.0% of Car.change_steer_angle's lines +# Line(s) not covered by ANY of the tests below: +# ['90-91'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "test_class_instance, angle, exception_type, exception_message, expected_result", + [ + ( + Car("Green", 48, 90), + -1080, + AssertionError, + "angle=-1080 out of bounds!", + "None", + ), + (Car("Blue", 0.0, 30), 180, "N/A", "N/A", "210"), + (Car("Red", 9, 0), 30, "N/A", "N/A", "30"), + (Car("White", 20, -30), 90, "N/A", "N/A", "60"), + ], + ids=counter, +) +def test_car_change_steer_angle( + test_class_instance, angle, exception_type, exception_message, expected_result +): + """ + Programmatically generated test function for Car.change_steer_angle() + """ + if exception_type != "N/A": + with pytest.raises(exception_type, match=re.escape(exception_message)): + test_class_instance.change_steer_angle(angle) + else: + result = test_class_instance.change_steer_angle(angle) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/oo_car/test_car_constructor.py b/tests/oo_car/test_car_constructor.py index 2da3280..499eee7 100644 --- a/tests/oo_car/test_car_constructor.py +++ b/tests/oo_car/test_car_constructor.py @@ -1,26 +1,31 @@ -""" -Programmatically generated test function for Car.__init__() -""" - -import re -import pytest -from collections import OrderedDict -from tests.oo_car import car - - -# In sum, these tests covered 100.0% of Car.__init__'s lines -@pytest.mark.parametrize( - "color, speed, steer_angle, expected_result", - [ - ("Red", 10, 0, "None"), - ], -) -def test_car___init__(color, speed, steer_angle, expected_result): - """ - Programmatically generated test function for Car.__init__() - """ - result = car.Car(color, speed, steer_angle) - assert isinstance(result, car.Car) - assert result.color == color - assert result.speed == speed - assert result.steer_angle == steer_angle +""" +Programmatically generated test function for Car.__init__() +""" + +import pytest +from tests.oo_car import car + + +# In sum, these tests covered 100.0% of Car.__init__'s lines +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "color, speed, steer_angle, expected_result", + [ + ("Red", 10, 0, "None"), + ], + ids=counter, +) +def test_car___init__(color, speed, steer_angle, expected_result): + """ + Programmatically generated test function for Car.__init__() + """ + result = car.Car(color, speed, steer_angle) + assert isinstance(result, car.Car) + assert result.color == color + assert result.speed == speed + assert result.steer_angle == steer_angle diff --git a/tests/oo_car/test_car_gas.py b/tests/oo_car/test_car_gas.py index 53c0570..1ce4cf1 100644 --- a/tests/oo_car/test_car_gas.py +++ b/tests/oo_car/test_car_gas.py @@ -1,75 +1,76 @@ -""" -Programmatically generated test function for Car.gas() -""" - -import re -import pytest -from collections import OrderedDict -from tests.oo_car import car -from _pytest.monkeypatch import MonkeyPatch - -# Now import modules specific to Car.gas: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler -from tests.oo_car.car import Car - - -# In sum, these tests covered 100.0% of Car.gas's lines -@pytest.mark.parametrize( - "test_class_instance, rate, duration, exception_type, exception_message, expected_result, globals_before, globals_after", - [ - ( - Car("Red", 10, 0), - -1, - 1, - ValueError, - "Gas rate (m/s) must be positive.", - "None", - {"method_call_counter": 0}, - {"method_call_counter": 1}, - ), - ( - Car("White", 12, -30), - 2, - 2, - "N/A", - "N/A", - "16", - {"method_call_counter": 1}, - {"method_call_counter": 2}, - ), - ], -) -def test_car_gas( - test_class_instance, - rate, - duration, - exception_type, - exception_message, - expected_result, - globals_before, - globals_after, -): - """ - Programmatically generated test function for Car.gas() - """ - monkeypatch = MonkeyPatch() - for k, v in globals_before.items(): - monkeypatch.setattr(car, k, v) - if exception_type != "N/A": - with pytest.raises(exception_type, match=re.escape(exception_message)): - test_class_instance.gas(rate, duration) - else: - result = test_class_instance.gas(rate, duration) - assert result == expected_result or result == eval(expected_result) - for global_var_written_to in ["method_call_counter"]: - if global_var_written_to in ["None", "[]", "{}"]: - assert not car.__dict__.get(global_var_written_to) - else: - assert ( - car.__dict__.get(global_var_written_to) - == globals_after[global_var_written_to] - ) +""" +Programmatically generated test function for Car.gas() +""" + +import re +import pytest +from tests.oo_car import car +from _pytest.monkeypatch import MonkeyPatch + +# Now import modules specific to Car.gas: +from tests.oo_car.car import Car + + +# In sum, these tests covered 100.0% of Car.gas's lines +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "test_class_instance, rate, duration, exception_type, exception_message, expected_result, globals_before, globals_after", + [ + ( + Car("Red", 10, 0), + -1, + 1, + ValueError, + "Gas rate (m/s) must be positive.", + "None", + {"method_call_counter": 0}, + {"method_call_counter": 1}, + ), + ( + Car("White", 12, -30), + 2, + 2, + "N/A", + "N/A", + "16", + {"method_call_counter": 1}, + {"method_call_counter": 2}, + ), + ], + ids=counter, +) +def test_car_gas( + test_class_instance, + rate, + duration, + exception_type, + exception_message, + expected_result, + globals_before, + globals_after, +): + """ + Programmatically generated test function for Car.gas() + """ + monkeypatch = MonkeyPatch() + for k, v in globals_before.items(): + monkeypatch.setattr(car, k, v) + if exception_type != "N/A": + with pytest.raises(exception_type, match=re.escape(exception_message)): + test_class_instance.gas(rate, duration) + else: + result = test_class_instance.gas(rate, duration) + assert result == expected_result or result == eval(expected_result) + for global_var_written_to in ["method_call_counter"]: + if global_var_written_to in ["None", "[]", "{}"]: + assert not car.__dict__.get(global_var_written_to) + else: + assert ( + car.__dict__.get(global_var_written_to) + == globals_after[global_var_written_to] + ) diff --git a/tests/oo_car/test_car_is_going_faster_than.py b/tests/oo_car/test_car_is_going_faster_than.py index 8c97803..68d36ee 100644 --- a/tests/oo_car/test_car_is_going_faster_than.py +++ b/tests/oo_car/test_car_is_going_faster_than.py @@ -1,38 +1,44 @@ -""" -Programmatically generated test function for Car.is_going_faster_than() -""" - -import re -import pytest -from collections import OrderedDict -from tests.oo_car import car - -# Now import modules specific to Car.is_going_faster_than: -from car import Car -from tests.oo_car.car import Car - - -# In sum, these tests covered 100.0% of Car.is_going_faster_than's lines -@pytest.mark.parametrize( - "test_class_instance, other_car, expected_result, args_after", - [ - ( - Car("Red", 20, 0), - Car("White", 19, 0), - "True", - {"other_car": 'Car("White", 19, 0)'}, - ), - ], -) -def test_car_is_going_faster_than( - test_class_instance, other_car, expected_result, args_after -): - """ - Programmatically generated test function for Car.is_going_faster_than() - """ - result = test_class_instance.is_going_faster_than(other_car) - assert result == expected_result or result == eval(expected_result) - assert ( - other_car == eval(args_after["other_car"]) - or args_after["other_car"] == other_car - ) +""" +Programmatically generated test function for Car.is_going_faster_than() +""" + +import pytest + +# Now import modules specific to Car.is_going_faster_than: +from tests.oo_car.car import Car + + +# In sum, these tests covered 100.0% of Car.is_going_faster_than's lines +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "test_class_instance, other_car, expected_result, args_after", + [ + ( + Car("Red", 20, 0), + Car("White", 19, 0), + "True", + {"other_car": 'Car("White", 19, 0)'}, + ), + ], + ids=counter, +) +def test_car_is_going_faster_than( + test_class_instance, other_car, expected_result, args_after +): + """ + Programmatically generated test function for Car.is_going_faster_than() + """ + result = test_class_instance.is_going_faster_than(other_car) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + other_car == eval(args_after["other_car"]) + or args_after["other_car"] == other_car + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/oo_car/test_coverage_str_helper.py b/tests/oo_car/test_coverage_str_helper_oo_car.py similarity index 50% rename from tests/oo_car/test_coverage_str_helper.py rename to tests/oo_car/test_coverage_str_helper_oo_car.py index d9df5fd..6a08687 100644 --- a/tests/oo_car/test_coverage_str_helper.py +++ b/tests/oo_car/test_coverage_str_helper_oo_car.py @@ -1,45 +1,48 @@ -""" -Programmatically generated test function for coverage_str_helper() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - -# Now import modules specific to coverage_str_helper: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler - - -# In sum, these tests covered 53.12% of coverage_str_helper's lines -# Line(s) not covered by ANY of the tests below: -# ['1743', '1750-1752', '1754', '1756-1757', '1764-1766', '1768-1769', '1772-1773'] -@pytest.mark.parametrize( - "this_list, non_code_lines, expected_result, args_after", - [ - ( - [52, 54], - set(), - "['52']", - {"this_list": "[52, 54]", "non_code_lines": "set()"}, - ), - ], -) -def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): - """ - Programmatically generated test function for coverage_str_helper() - """ - result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) - assert result == expected_result or result == eval(expected_result) - assert ( - this_list == eval(args_after["this_list"]) - or args_after["this_list"] == this_list - ) - assert ( - non_code_lines == eval(args_after["non_code_lines"]) - or args_after["non_code_lines"] == non_code_lines - ) +""" +Programmatically generated test function for coverage_str_helper() +""" + +import pytest +from src import unit_test_generator + +# Now import modules specific to coverage_str_helper: + + +# In sum, these tests covered 53.12% of coverage_str_helper's lines +# Line(s) not covered by ANY of the tests below: +# ['1799', '1806-1808', '1810', '1812-1813', '1820-1822', '1824-1825', '1828-1829'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "this_list, non_code_lines, expected_result, args_after", + [ + ( + [55, 57], + set(), + "['55']", + {"this_list": "[55, 57]", "non_code_lines": "set()"}, + ), + ], + ids=counter, +) +def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): + """ + Programmatically generated test function for coverage_str_helper() + """ + result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_list == eval(args_after["this_list"]) + or args_after["this_list"] == this_list + ) + assert ( + non_code_lines == eval(args_after["non_code_lines"]) + or args_after["non_code_lines"] == non_code_lines + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/pass_by_assignment/test_normalize_arg.py b/tests/oo_car/test_normalize_arg_oo_car.py similarity index 76% rename from tests/pass_by_assignment/test_normalize_arg.py rename to tests/oo_car/test_normalize_arg_oo_car.py index b44b129..a1f7ffa 100644 --- a/tests/pass_by_assignment/test_normalize_arg.py +++ b/tests/oo_car/test_normalize_arg_oo_car.py @@ -1,25 +1,30 @@ -""" -Programmatically generated test function for normalize_arg() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - - -# In sum, these tests covered 60.0% of normalize_arg's lines -# Line(s) not covered by ANY of the tests below: -# ['1714', '1716', '1719-1720'] -@pytest.mark.parametrize( - "arg, expected_result", - [ - ("None", "None"), - ], -) -def test_normalize_arg(arg, expected_result): - """ - Programmatically generated test function for normalize_arg() - """ - result = unit_test_generator.normalize_arg(arg) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for normalize_arg() +""" + +import pytest +from src import unit_test_generator + + +# In sum, these tests covered 60.0% of normalize_arg's lines +# Line(s) not covered by ANY of the tests below: +# ['1770', '1772', '1775-1776'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "arg, expected_result", + [ + ("None", "None"), + ], + ids=counter, +) +def test_normalize_arg(arg, expected_result): + """ + Programmatically generated test function for normalize_arg() + """ + result = unit_test_generator.normalize_arg(arg) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/oo_car/test_update_global.py b/tests/oo_car/test_update_global.py deleted file mode 100644 index e1c5f58..0000000 --- a/tests/oo_car/test_update_global.py +++ /dev/null @@ -1,2 +0,0 @@ -import warnings -warnings.warn("No testable samples!") \ No newline at end of file diff --git a/tests/oo_car/test_update_global_oo_car.py b/tests/oo_car/test_update_global_oo_car.py new file mode 100644 index 0000000..53dfbc4 --- /dev/null +++ b/tests/oo_car/test_update_global_oo_car.py @@ -0,0 +1,3 @@ +""" +No testable inputs - see accompanying JSON file. +""" \ No newline at end of file diff --git a/tests/oo_car/update_global.json b/tests/oo_car/update_global.json index 4de68d2..f63e091 100644 --- a/tests/oo_car/update_global.json +++ b/tests/oo_car/update_global.json @@ -1,89 +1,89 @@ -{ - "name": "update_global", - "parameter_names": [ - "obj", - "this_global", - "phase", - "this_coverage_info" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1683, - 1684, - 1685, - 1686, - 1687, - 1688, - 1689, - 1691, - 1699, - 1700, - 1701, - 1702, - 1703 - ], - "non_code_lines": [ - 1690, - 1692, - 1693, - 1694, - 1695, - 1696, - 1697, - 1698 - ], - "coverage_io": { - "0": { - "args_before": [ - "", - "\"logger\"", - "\"Before\"", - "CoverageInfo(args_before=['-1','1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0, testable=0.0)" - ], - "args_after": { - "obj": "", - "this_coverage_info": "CoverageInfo(args_before=['-1','1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0, testable=0.0)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['-1','1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0, testable=0.0)", - "expected_type": "src.unit_test_generator.CoverageInfo", - "coverage": [ - 1683, - 1684, - 1685 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": false - } - }, - "coverage_percentage": 23.08, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "src.unit_test_generator.CoverageInfo" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1683, - 1684, - 1685 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "update_global", + "parameter_names": [ + "obj", + "this_global", + "phase", + "this_coverage_info" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1739, + 1740, + 1741, + 1742, + 1743, + 1744, + 1745, + 1747, + 1755, + 1756, + 1757, + 1758, + 1759 + ], + "non_code_lines": [ + 1746, + 1748, + 1749, + 1750, + 1751, + 1752, + 1753, + 1754 + ], + "coverage_io": { + "0": { + "args_before": [ + "", + "\"logger\"", + "\"Before\"", + "CoverageInfo(args_before=['-1','1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0, testable=True)" + ], + "args_after": { + "obj": "", + "this_coverage_info": "CoverageInfo(args_before=['-1','1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0, testable=True)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['-1','1'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='Car(\"Red\", 10, 0)', cost=0.0, testable=True)", + "expected_type": "src.unit_test_generator.CoverageInfo", + "coverage": [ + 1739, + 1740, + 1741 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": false + } + }, + "coverage_percentage": 23.08, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "src.unit_test_generator.CoverageInfo" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1739, + 1740, + 1741 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/pass_by_assignment/add_to_my_set_kwargs.json b/tests/pass_by_assignment/add_to_my_set_kwargs.json index e4b6554..30bbd54 100644 --- a/tests/pass_by_assignment/add_to_my_set_kwargs.json +++ b/tests/pass_by_assignment/add_to_my_set_kwargs.json @@ -1,54 +1,59 @@ -{ - "name": "add_to_my_set_kwargs", - "parameter_names": [], - "is_method": false, - "source_file": null, - "lines": [ - 70, - 71, - 70 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [], - "args_after": {}, - "kwargs": { - "my_set": [ - 0, - 2, - 3 - ] - }, - "kwargs_after": { - "my_set": "{0, 1, 2, 3}" - }, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 70, - 71 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 66.67, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 70, - 71 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "add_to_my_set_kwargs": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" - } +{ + "name": "add_to_my_set_kwargs", + "parameter_names": [], + "is_method": false, + "source_file": null, + "lines": [ + 53, + 54, + 53 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [], + "args_after": {}, + "kwargs": { + "my_set": [ + 0, + 2, + 3 + ] + }, + "kwargs_after": { + "my_set": [ + 0, + 1, + 2, + 3 + ] + }, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 53, + 54 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 66.67, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 53, + 54 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "add_to_my_set_kwargs": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" + } } \ No newline at end of file diff --git a/tests/pass_by_assignment/append_list.json b/tests/pass_by_assignment/append_list.json index f3e848a..a39e137 100644 --- a/tests/pass_by_assignment/append_list.json +++ b/tests/pass_by_assignment/append_list.json @@ -1,61 +1,61 @@ -{ - "name": "append_list", - "parameter_names": [ - "this_list", - "item" - ], - "is_method": false, - "source_file": null, - "lines": [ - 41, - 42 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "[1, 2, 3, 4]", - "6" - ], - "args_after": { - "this_list": "[1, 2, 3, 4, 6]" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 41, - 42 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 41, - 42 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "append_list": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" - } +{ + "name": "append_list", + "parameter_names": [ + "this_list", + "item" + ], + "is_method": false, + "source_file": null, + "lines": [ + 26, + 27 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "[1, 2, 3, 4]", + "6" + ], + "args_after": { + "this_list": "[1, 2, 3, 4, 6]" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 26, + 27 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 100.0, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 26, + 27 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "append_list": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" + } } \ No newline at end of file diff --git a/tests/pass_by_assignment/example_pass_by_assignment.py b/tests/pass_by_assignment/example_pass_by_assignment.py new file mode 100644 index 0000000..e47a411 --- /dev/null +++ b/tests/pass_by_assignment/example_pass_by_assignment.py @@ -0,0 +1,115 @@ +""" +Test case to demonstrate tests for pass by assignment. +""" + +import argparse +import logging +import os +import sys +from pathlib import Path +from typing import TypeVar + +import coverage +from pass_by_assignment import ( + append_list, + overwrite_list, + increment_my_list_kwargs, + add_to_my_set_kwargs +) +from src import unit_test_generator +from src.unit_test_generator import ( + generate_all_tests_and_metadata, + unit_test_generator_decorator, +) + +T = TypeVar('T') + +FMT_STR = "%(levelname)-8s|%(module)-16s|%(funcName)-20s:%(lineno)-4d:%(message)s" +logging.basicConfig(level=logging.INFO, format=FMT_STR) +logger = logging.getLogger(__name__) +unit_test_generator.logger.setLevel(logging.CRITICAL) + +def main(): + """ + Execute the functions above. + """ + # Begin ad hoc tests + # Test append_list + + my_list = [1,2,3,4] + append_list(my_list, 6) + overwrite_list(my_list[::-1]) + + kwargs = {"my_list":[0,3]} + print(f"my_list Before increment_my_list_kwargs(): {kwargs=}") + increment_my_list_kwargs(**kwargs) + print(f"After: {kwargs=}") + + + kwargs = {} + kwargs["my_set"] = set([0,2,3]) + print(f"my_set Before: add_to_my_set_kwargs(): {kwargs=}") + + add_to_my_set_kwargs(**kwargs) + print(f"After: {kwargs=}") + + generate_all_tests_and_metadata(Path("."), Path(".")) + +if __name__ == "__main__": + log_levels = { + "critical": logging.CRITICAL, + "error": logging.ERROR, + "warn": logging.WARNING, + "warning": logging.WARNING, + "info": logging.INFO, + "debug": logging.DEBUG, + } + # Create the parser and add argument(s) + parser = argparse.ArgumentParser() + parser.add_argument( + "--log-level", + "-l", + help="log level", + type=str, + choices=log_levels.keys(), + default="info", + ) + parser.add_argument( + "--disable-unit-test-generation", + "-d", + action="store_true", + help="Set this flag to deactivate unit test generation for this code", + ) + args = parser.parse_args() + logger.setLevel(log_levels[args.log_level]) + logger.info("args=%s", args) + + this_file = Path(__file__).absolute() + for file in this_file.parent.rglob("*"): + if file.name == "pass_by_assignment.py": + continue + if file.suffix in (".py", ".json") and file.absolute() != this_file: + logger.debug("Deleting %s to ensure clean start", this_file) + os.remove(file) + + logger.info("%s", __file__) + + + if args.disable_unit_test_generation: + main() + sys.exit(0) + + # The code below applies the CLI arg above to selectively enable/disable + # automatic unit test generation (Could not use the syntactic sugar method + # of applying decorators as the user's input isn't parsed until now.) + # Alternatively, move the argument parsing to the very top of this file. + # NOTE: + # Decorating all functions programmatically is left as an exercise to the reader: + # Hint: https://stackoverflow.com/questions/3467526/ + # get_key_to_set_with_highest_value = unit_test_generator_decorator(not args.disable_unit_test_generation)(get_key_to_set_with_highest_value) # pylint: disable=line-too-long + # get_item_at_index = unit_test_generator_decorator(not args.disable_unit_test_generation)(get_item_at_index) # pylint: disable=line-too-long + + cov = coverage.Coverage() + with cov.collect(): + main() + cov.save() \ No newline at end of file diff --git a/tests/pass_by_assignment/increment_my_list_kwargs.json b/tests/pass_by_assignment/increment_my_list_kwargs.json index b6bafe0..d0df873 100644 --- a/tests/pass_by_assignment/increment_my_list_kwargs.json +++ b/tests/pass_by_assignment/increment_my_list_kwargs.json @@ -1,58 +1,57 @@ -{ - "name": "increment_my_list_kwargs", - "parameter_names": [], - "is_method": false, - "source_file": null, - "lines": [ - 60, - 61, - 62, - 60 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [], - "args_after": {}, - "kwargs": { - "my_list": [ - 0, - 3 - ] - }, - "kwargs_after": { - "my_list": "[0, 3, 1, ClassForTesting('test')]" - }, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 60, - 61, - 62 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 75.0, - "types_in_use": [ - "__main__.ClassForTesting" - ], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 60, - 61, - 62 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "increment_my_list_kwargs": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" - } +{ + "name": "increment_my_list_kwargs", + "parameter_names": [], + "is_method": false, + "source_file": null, + "lines": [ + 44, + 45, + 44 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [], + "args_after": {}, + "kwargs": { + "my_list": [ + 0, + 3 + ] + }, + "kwargs_after": { + "my_list": [ + 0, + 3, + 1 + ] + }, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 44, + 45 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 66.67, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 44, + 45 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "increment_my_list_kwargs": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" + } } \ No newline at end of file diff --git a/tests/pass_by_assignment/normalize_arg.json b/tests/pass_by_assignment/normalize_arg.json index 75351c8..6b3d1f2 100644 --- a/tests/pass_by_assignment/normalize_arg.json +++ b/tests/pass_by_assignment/normalize_arg.json @@ -1,67 +1,67 @@ -{ - "name": "normalize_arg", - "parameter_names": [ - "arg" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1711, - 1712, - 1713, - 1714, - 1715, - 1716, - 1718, - 1719, - 1720, - 1721 - ], - "non_code_lines": [ - 1717 - ], - "coverage_io": { - "0": { - "args_before": [ - "\"None\"" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "str", - "coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 60.0, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "normalize_arg", + "parameter_names": [ + "arg" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1767, + 1768, + 1769, + 1770, + 1771, + 1772, + 1774, + 1775, + 1776, + 1777 + ], + "non_code_lines": [ + 1773 + ], + "coverage_io": { + "0": { + "args_before": [ + "\"None\"" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "str", + "coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 60.0, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/pass_by_assignment/overwrite_list.json b/tests/pass_by_assignment/overwrite_list.json index 66a0b05..fae6bff 100644 --- a/tests/pass_by_assignment/overwrite_list.json +++ b/tests/pass_by_assignment/overwrite_list.json @@ -1,51 +1,51 @@ -{ - "name": "overwrite_list", - "parameter_names": [ - "this_list" - ], - "is_method": false, - "source_file": null, - "lines": [ - 51, - 52 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "[6, 4, 3, 2, 1]" - ], - "args_after": { - "this_list": "[6, 4, 3, 2, 1]" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 51, - 52 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 51, - 52 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "overwrite_list": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" - } +{ + "name": "overwrite_list", + "parameter_names": [ + "this_list" + ], + "is_method": false, + "source_file": null, + "lines": [ + 35, + 36 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "[6, 4, 3, 2, 1]" + ], + "args_after": { + "this_list": "[6, 4, 3, 2, 1]" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 35, + 36 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 100.0, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 35, + 36 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "overwrite_list": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\pass_by_assignment\\pass_by_assignment.py" + } } \ No newline at end of file diff --git a/tests/pass_by_assignment/pass_by_assignment.py b/tests/pass_by_assignment/pass_by_assignment.py index 47b9552..4cd78a9 100644 --- a/tests/pass_by_assignment/pass_by_assignment.py +++ b/tests/pass_by_assignment/pass_by_assignment.py @@ -2,31 +2,16 @@ Test case to demonstrate tests for pass by assignment. """ -import argparse import logging -import os -from pathlib import Path from typing import Any, List, TypeVar from src import unit_test_generator from src.unit_test_generator import ( - generate_all_tests_and_metadata, unit_test_generator_decorator, ) T = TypeVar('T') - -class ClassForTesting(): - def __init__(self, name): - self.name = name - - def __repr__(self): - return f"ClassForTesting('{self.name}')" - - def __eq__(self, __value: Any) -> bool: - return self.name == __value.name - FMT_STR = "%(levelname)-8s|%(module)-16s|%(funcName)-20s:%(lineno)-4d:%(message)s" logging.basicConfig(level=logging.INFO, format=FMT_STR) logger = logging.getLogger(__name__) @@ -40,13 +25,12 @@ def append_list(this_list:List[Any], item:Any)->None: """ logger.info("APPEND %s to %s", item, this_list) this_list.append(item) - + @unit_test_generator_decorator(sample_count=6, keep_subsets=True, percent_coverage=0) def overwrite_list(this_list:List[Any])->None: """ - Given a list of items of the same type T and a separate item, - delete the local copy. + Given a list of items; overwrite the local copy. """ this_list = [0] print(this_list) @@ -59,7 +43,6 @@ def increment_my_list_kwargs(**kwargs): """ if "my_list" in kwargs and isinstance(kwargs["my_list"], list): kwargs["my_list"].append(1) - kwargs["my_list"].append(ClassForTesting("test")) @unit_test_generator_decorator(sample_count=6, keep_subsets=True, percent_coverage=0) def add_to_my_set_kwargs(**kwargs): @@ -68,77 +51,4 @@ def add_to_my_set_kwargs(**kwargs): append a 1 to it. """ if "my_set" in kwargs and isinstance(kwargs["my_set"], set): - kwargs["my_set"].add(1) - - -def main(): - """ - Execute the functions above. - """ - # Begin ad hoc tests - # Test append_list - - my_list = [1,2,3,4] - append_list(my_list, 6) - overwrite_list(my_list[::-1]) - - kwargs = {"my_list":[0,3]} - print(f"Before: {kwargs=}") - increment_my_list_kwargs(**kwargs) - print(f"After: {kwargs=}") - - - kwargs = {} - kwargs["my_set"] = set([0,2,3]) - add_to_my_set_kwargs(**kwargs) - print(f"After: {kwargs=}") - - generate_all_tests_and_metadata(Path("."), Path(".")) - -if __name__ == "__main__": - log_levels = { - "critical": logging.CRITICAL, - "error": logging.ERROR, - "warn": logging.WARNING, - "warning": logging.WARNING, - "info": logging.INFO, - "debug": logging.DEBUG, - } - # Create the parser and add argument(s) - parser = argparse.ArgumentParser() - parser.add_argument( - "--log-level", - "-l", - help="log level", - type=str, - choices=log_levels.keys(), - default="info", - ) - parser.add_argument( - "--disable-unit-test-generation", - "-d", - action="store_true", - help="Set this flag to deactivate unit test generation for this code", - ) - args = parser.parse_args() - logger.setLevel(log_levels[args.log_level]) - logger.info("args=%s", args) - - this_file = Path(__file__).absolute() - for file in this_file.parent.rglob("*"): - if file.suffix in (".py", ".json") and file.absolute() != this_file: - logger.debug("Deleting %s to ensure clean start", this_file) - os.remove(file) - - logger.info("%s", __file__) - # The code below applies the CLI arg above to selectively enable/disable - # automatic unit test generation (Could not use the syntactic sugar method - # of applying decorators as the user's input isn't parsed until now.) - # Alternatively, move the argument parsing to the very top of this file. - # NOTE: - # Decorating all functions programmatically is left as an exercise to the reader: - # Hint: https://stackoverflow.com/questions/3467526/ - # get_key_to_set_with_highest_value = unit_test_generator_decorator(not args.disable_unit_test_generation)(get_key_to_set_with_highest_value) # pylint: disable=line-too-long - # get_item_at_index = unit_test_generator_decorator(not args.disable_unit_test_generation)(get_item_at_index) # pylint: disable=line-too-long - - main() + kwargs["my_set"].add(1) \ No newline at end of file diff --git a/tests/pass_by_assignment/test_add_to_my_set_kwargs.py b/tests/pass_by_assignment/test_add_to_my_set_kwargs.py index 3f30dd1..39b7bb7 100644 --- a/tests/pass_by_assignment/test_add_to_my_set_kwargs.py +++ b/tests/pass_by_assignment/test_add_to_my_set_kwargs.py @@ -1,29 +1,31 @@ -""" -Programmatically generated test function for add_to_my_set_kwargs() -""" - -import re -import pytest -from collections import OrderedDict -import pass_by_assignment - - -# In sum, these tests covered 66.67% of add_to_my_set_kwargs's lines -# Line(s) not covered by ANY of the tests below: -# set() -@pytest.mark.parametrize( - "kwargs, expected_result, kwargs_after", - [ - ({"my_set": {0, 2, 3}}, "None", {"my_set": "{0, 1, 2, 3}"}), - ], -) -def test_add_to_my_set_kwargs(kwargs, expected_result, kwargs_after): - """ - Programmatically generated test function for add_to_my_set_kwargs() - """ - result = pass_by_assignment.add_to_my_set_kwargs(**kwargs) - assert result == expected_result or result == eval(expected_result) - assert ( - kwargs["my_set"] == eval(kwargs_after["my_set"]) - or kwargs["my_set"] == kwargs_after["my_set"] - ) +""" +Programmatically generated test function for add_to_my_set_kwargs() +""" + +import pytest +from tests.pass_by_assignment import pass_by_assignment + + +# In sum, these tests covered 66.67% of add_to_my_set_kwargs's lines +# Line(s) not covered by ANY of the tests below: +# set() +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "kwargs, expected_result, kwargs_after", + [ + ({"my_set": {0, 2, 3}}, "None", {"my_set": {0, 1, 2, 3}}), + ], + ids=counter, +) +def test_add_to_my_set_kwargs(kwargs, expected_result, kwargs_after): + """ + Programmatically generated test function for add_to_my_set_kwargs() + """ + result = pass_by_assignment.add_to_my_set_kwargs(**kwargs) + assert result == expected_result or result == eval(expected_result) + kwargs["my_set"] == kwargs_after["my_set"] diff --git a/tests/pass_by_assignment/test_append_list.py b/tests/pass_by_assignment/test_append_list.py index 79fa4af..381bade 100644 --- a/tests/pass_by_assignment/test_append_list.py +++ b/tests/pass_by_assignment/test_append_list.py @@ -1,34 +1,37 @@ -""" -Programmatically generated test function for append_list() -""" - -import re -import pytest -from collections import OrderedDict -import pass_by_assignment - -# Now import modules specific to append_list: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler - - -# In sum, these tests covered 100.0% of append_list's lines -@pytest.mark.parametrize( - "this_list, item, expected_result, args_after", - [ - ([1, 2, 3, 4], 6, "None", {"this_list": "[1, 2, 3, 4, 6]"}), - ], -) -def test_append_list(this_list, item, expected_result, args_after): - """ - Programmatically generated test function for append_list() - """ - result = pass_by_assignment.append_list(this_list, item) - assert result == expected_result or result == eval(expected_result) - assert ( - this_list == eval(args_after["this_list"]) - or args_after["this_list"] == this_list - ) +""" +Programmatically generated test function for append_list() +""" + +import pytest +from tests.pass_by_assignment import pass_by_assignment + +# Now import modules specific to append_list: + + +# In sum, these tests covered 100.0% of append_list's lines +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "this_list, item, expected_result, args_after", + [ + ([1, 2, 3, 4], 6, "None", {"this_list": "[1, 2, 3, 4, 6]"}), + ], + ids=counter, +) +def test_append_list(this_list, item, expected_result, args_after): + """ + Programmatically generated test function for append_list() + """ + result = pass_by_assignment.append_list(this_list, item) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_list == eval(args_after["this_list"]) + or args_after["this_list"] == this_list + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/pass_by_assignment/test_increment_my_list_kwargs.py b/tests/pass_by_assignment/test_increment_my_list_kwargs.py index 57671a7..0767ce7 100644 --- a/tests/pass_by_assignment/test_increment_my_list_kwargs.py +++ b/tests/pass_by_assignment/test_increment_my_list_kwargs.py @@ -1,36 +1,31 @@ -""" -Programmatically generated test function for increment_my_list_kwargs() -""" - -import re -import pytest -from collections import OrderedDict -import pass_by_assignment - -# Now import modules specific to increment_my_list_kwargs: -from pass_by_assignment import ClassForTesting - - -# In sum, these tests covered 75.0% of increment_my_list_kwargs's lines -# Line(s) not covered by ANY of the tests below: -# set() -@pytest.mark.parametrize( - "kwargs, expected_result, kwargs_after", - [ - ( - {"my_list": [0, 3]}, - "None", - {"my_list": "[0, 3, 1, ClassForTesting('test')]"}, - ), - ], -) -def test_increment_my_list_kwargs(kwargs, expected_result, kwargs_after): - """ - Programmatically generated test function for increment_my_list_kwargs() - """ - result = pass_by_assignment.increment_my_list_kwargs(**kwargs) - assert result == expected_result or result == eval(expected_result) - assert ( - kwargs["my_list"] == eval(kwargs_after["my_list"]) - or kwargs["my_list"] == kwargs_after["my_list"] - ) +""" +Programmatically generated test function for increment_my_list_kwargs() +""" + +import pytest +from tests.pass_by_assignment import pass_by_assignment + + +# In sum, these tests covered 66.67% of increment_my_list_kwargs's lines +# Line(s) not covered by ANY of the tests below: +# set() +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "kwargs, expected_result, kwargs_after", + [ + ({"my_list": [0, 3]}, "None", {"my_list": [0, 3, 1]}), + ], + ids=counter, +) +def test_increment_my_list_kwargs(kwargs, expected_result, kwargs_after): + """ + Programmatically generated test function for increment_my_list_kwargs() + """ + result = pass_by_assignment.increment_my_list_kwargs(**kwargs) + assert result == expected_result or result == eval(expected_result) + kwargs["my_list"] == kwargs_after["my_list"] diff --git a/tests/oo_car/test_normalize_arg.py b/tests/pass_by_assignment/test_normalize_arg_pass_by_assignment.py similarity index 76% rename from tests/oo_car/test_normalize_arg.py rename to tests/pass_by_assignment/test_normalize_arg_pass_by_assignment.py index b44b129..a1f7ffa 100644 --- a/tests/oo_car/test_normalize_arg.py +++ b/tests/pass_by_assignment/test_normalize_arg_pass_by_assignment.py @@ -1,25 +1,30 @@ -""" -Programmatically generated test function for normalize_arg() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - - -# In sum, these tests covered 60.0% of normalize_arg's lines -# Line(s) not covered by ANY of the tests below: -# ['1714', '1716', '1719-1720'] -@pytest.mark.parametrize( - "arg, expected_result", - [ - ("None", "None"), - ], -) -def test_normalize_arg(arg, expected_result): - """ - Programmatically generated test function for normalize_arg() - """ - result = unit_test_generator.normalize_arg(arg) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for normalize_arg() +""" + +import pytest +from src import unit_test_generator + + +# In sum, these tests covered 60.0% of normalize_arg's lines +# Line(s) not covered by ANY of the tests below: +# ['1770', '1772', '1775-1776'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "arg, expected_result", + [ + ("None", "None"), + ], + ids=counter, +) +def test_normalize_arg(arg, expected_result): + """ + Programmatically generated test function for normalize_arg() + """ + result = unit_test_generator.normalize_arg(arg) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/pass_by_assignment/test_overwrite_list.py b/tests/pass_by_assignment/test_overwrite_list.py index 2a9dd90..1d54981 100644 --- a/tests/pass_by_assignment/test_overwrite_list.py +++ b/tests/pass_by_assignment/test_overwrite_list.py @@ -1,27 +1,35 @@ -""" -Programmatically generated test function for overwrite_list() -""" - -import re -import pytest -from collections import OrderedDict -import pass_by_assignment - - -# In sum, these tests covered 100.0% of overwrite_list's lines -@pytest.mark.parametrize( - "this_list, expected_result, args_after", - [ - ([6, 4, 3, 2, 1], "None", {"this_list": "[6, 4, 3, 2, 1]"}), - ], -) -def test_overwrite_list(this_list, expected_result, args_after): - """ - Programmatically generated test function for overwrite_list() - """ - result = pass_by_assignment.overwrite_list(this_list) - assert result == expected_result or result == eval(expected_result) - assert ( - this_list == eval(args_after["this_list"]) - or args_after["this_list"] == this_list - ) +""" +Programmatically generated test function for overwrite_list() +""" + +import pytest +from tests.pass_by_assignment import pass_by_assignment + + +# In sum, these tests covered 100.0% of overwrite_list's lines +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "this_list, expected_result, args_after", + [ + ([6, 4, 3, 2, 1], "None", {"this_list": "[6, 4, 3, 2, 1]"}), + ], + ids=counter, +) +def test_overwrite_list(this_list, expected_result, args_after): + """ + Programmatically generated test function for overwrite_list() + """ + result = pass_by_assignment.overwrite_list(this_list) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_list == eval(args_after["this_list"]) + or args_after["this_list"] == this_list + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/pass_by_assignment/test_update_global.py b/tests/pass_by_assignment/test_update_global.py deleted file mode 100644 index e1c5f58..0000000 --- a/tests/pass_by_assignment/test_update_global.py +++ /dev/null @@ -1,2 +0,0 @@ -import warnings -warnings.warn("No testable samples!") \ No newline at end of file diff --git a/tests/pass_by_assignment/test_update_global_pass_by_assignment.py b/tests/pass_by_assignment/test_update_global_pass_by_assignment.py new file mode 100644 index 0000000..53dfbc4 --- /dev/null +++ b/tests/pass_by_assignment/test_update_global_pass_by_assignment.py @@ -0,0 +1,3 @@ +""" +No testable inputs - see accompanying JSON file. +""" \ No newline at end of file diff --git a/tests/pass_by_assignment/update_global.json b/tests/pass_by_assignment/update_global.json index d16fe3f..30d1400 100644 --- a/tests/pass_by_assignment/update_global.json +++ b/tests/pass_by_assignment/update_global.json @@ -1,89 +1,89 @@ -{ - "name": "update_global", - "parameter_names": [ - "obj", - "this_global", - "phase", - "this_coverage_info" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1683, - 1684, - 1685, - 1686, - 1687, - 1688, - 1689, - 1691, - 1699, - 1700, - 1701, - 1702, - 1703 - ], - "non_code_lines": [ - 1690, - 1692, - 1693, - 1694, - 1695, - 1696, - 1697, - 1698 - ], - "coverage_io": { - "0": { - "args_before": [ - "", - "\"logger\"", - "\"Before\"", - "CoverageInfo(args_before=['[1, 2, 3, 4]','6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - ], - "args_after": { - "obj": "", - "this_coverage_info": "CoverageInfo(args_before=['[1, 2, 3, 4]','6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['[1, 2, 3, 4]','6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "expected_type": "src.unit_test_generator.CoverageInfo", - "coverage": [ - 1683, - 1684, - 1685 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": false - } - }, - "coverage_percentage": 23.08, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "src.unit_test_generator.CoverageInfo" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1683, - 1684, - 1685 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "update_global", + "parameter_names": [ + "obj", + "this_global", + "phase", + "this_coverage_info" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1739, + 1740, + 1741, + 1742, + 1743, + 1744, + 1745, + 1747, + 1755, + 1756, + 1757, + 1758, + 1759 + ], + "non_code_lines": [ + 1746, + 1748, + 1749, + 1750, + 1751, + 1752, + 1753, + 1754 + ], + "coverage_io": { + "0": { + "args_before": [ + "", + "\"logger\"", + "\"Before\"", + "CoverageInfo(args_before=['[1, 2, 3, 4]','6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + ], + "args_after": { + "obj": "", + "this_coverage_info": "CoverageInfo(args_before=['[1, 2, 3, 4]','6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['[1, 2, 3, 4]','6'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "expected_type": "src.unit_test_generator.CoverageInfo", + "coverage": [ + 1739, + 1740, + 1741 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": false + } + }, + "coverage_percentage": 23.08, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "src.unit_test_generator.CoverageInfo" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1739, + 1740, + 1741 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/procedural_division/coverage_str_helper.json b/tests/procedural_division/coverage_str_helper.json index f42b8ed..9a17c6b 100644 --- a/tests/procedural_division/coverage_str_helper.json +++ b/tests/procedural_division/coverage_str_helper.json @@ -1,140 +1,140 @@ -{ - "name": "coverage_str_helper", - "parameter_names": [ - "this_list", - "non_code_lines" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1741, - 1742, - 1743, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1754, - 1755, - 1756, - 1757, - 1759, - 1760, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1768, - 1769, - 1771, - 1772, - 1773, - 1775, - 1777 - ], - "non_code_lines": [ - 1758, - 1767, - 1770, - 1774, - 1776 - ], - "coverage_io": { - "0": { - "args_before": [ - "[1701, 1702, 1684, 1685, 1687, 1688, 1689]", - "{1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}" - ], - "args_after": { - "this_list": "[1701, 1702, 1684, 1685, 1687, 1688, 1689]", - "non_code_lines": "{1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "['1701-1702', '1684-1685', '1687-1689']", - "expected_type": "list", - "coverage": [ - 1741, - 1742, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1755, - 1756, - 1757, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1771, - 1777 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 71.88, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1741, - 1742, - 1744, - 1745, - 1746, - 1747, - 1748, - 1749, - 1750, - 1751, - 1752, - 1753, - 1755, - 1756, - 1757, - 1761, - 1762, - 1763, - 1764, - 1765, - 1766, - 1771, - 1777 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "coverage_str_helper": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "coverage_str_helper", + "parameter_names": [ + "this_list", + "non_code_lines" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1797, + 1798, + 1799, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1810, + 1811, + 1812, + 1813, + 1815, + 1816, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1824, + 1825, + 1827, + 1828, + 1829, + 1831, + 1833 + ], + "non_code_lines": [ + 1814, + 1823, + 1826, + 1830, + 1832 + ], + "coverage_io": { + "0": { + "args_before": [ + "[1740, 1741, 1743, 1744, 1745, 1757, 1758]", + "{1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}" + ], + "args_after": { + "this_list": "[1740, 1741, 1743, 1744, 1745, 1757, 1758]", + "non_code_lines": "{1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "['1740-1741', '1743-1745', '1757-1758']", + "expected_type": "list", + "coverage": [ + 1797, + 1798, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1811, + 1812, + 1813, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1827, + 1833 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 71.88, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1797, + 1798, + 1800, + 1801, + 1802, + 1803, + 1804, + 1805, + 1806, + 1807, + 1808, + 1809, + 1811, + 1812, + 1813, + 1817, + 1818, + 1819, + 1820, + 1821, + 1822, + 1827, + 1833 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "coverage_str_helper": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/procedural_division/divide_ints.json b/tests/procedural_division/divide_ints.json index e47ebbf..69a3319 100644 --- a/tests/procedural_division/divide_ints.json +++ b/tests/procedural_division/divide_ints.json @@ -1,179 +1,179 @@ -{ - "name": "divide_ints", - "parameter_names": [ - "a", - "b" - ], - "is_method": false, - "source_file": null, - "lines": [ - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42 - ], - "non_code_lines": [], - "coverage_io": { - "0": { - "args_before": [ - "\"10\"", - "2" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "error_code": 0 - }, - "globals_after": { - "error_code": -1 - }, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 32, - 33, - 34, - 35 - ], - "exception_type": "", - "exception_message": "TypeError: Variable a='10' is not an int!", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "1": { - "args_before": [ - "3", - "0" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "error_code": 0 - }, - "globals_after": { - "error_code": -3 - }, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 32, - 33, - 36, - 39, - 40, - 41 - ], - "exception_type": "", - "exception_message": "ValueError: Cannot divide by zero!", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "2": { - "args_before": [ - "6", - "2" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "error_code": 0 - }, - "globals_after": { - "error_code": 0 - }, - "expected_result": "6/2=3.0", - "expected_type": "str", - "coverage": [ - 32, - 33, - 36, - 39, - 42 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - }, - "3": { - "args_before": [ - "8", - "[]" - ], - "args_after": { - "b": "[]" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": { - "error_code": 0 - }, - "globals_after": { - "error_code": -2 - }, - "expected_result": "None", - "expected_type": "NoneType", - "coverage": [ - 32, - 33, - 36, - 37, - 38 - ], - "exception_type": "", - "exception_message": "TypeError: Variable b=[] is not an int!", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 100.0, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler" - ], - "global_vars_read_from": [ - "error_code", - "logger" - ], - "global_vars_written_to": [ - "error_code" - ], - "unified_test_coverage": [ - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42 - ], - "needs_pytest": true, - "exceptions_raised": [ - "", - "" - ], - "callable_files": { - "divide_ints": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\procedural_division\\divide_ints.py" - } +{ + "name": "divide_ints", + "parameter_names": [ + "a", + "b" + ], + "is_method": false, + "source_file": null, + "lines": [ + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45 + ], + "non_code_lines": [], + "coverage_io": { + "0": { + "args_before": [ + "8", + "[]" + ], + "args_after": { + "b": "[]" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "error_code": -1 + }, + "globals_after": { + "error_code": -2 + }, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 35, + 36, + 39, + 40, + 41 + ], + "exception_type": "", + "exception_message": "TypeError: Variable b=[] is not an int!", + "constructor": "", + "cost": 0.0, + "testable": true + }, + "1": { + "args_before": [ + "\"10\"", + "2" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "error_code": -3 + }, + "globals_after": { + "error_code": -1 + }, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 35, + 36, + 37, + 38 + ], + "exception_type": "", + "exception_message": "TypeError: Variable a='10' is not an int!", + "constructor": "", + "cost": 0.0, + "testable": true + }, + "2": { + "args_before": [ + "3", + "0" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "error_code": 0 + }, + "globals_after": { + "error_code": -3 + }, + "expected_result": "None", + "expected_type": "NoneType", + "coverage": [ + 35, + 36, + 39, + 42, + 43, + 44 + ], + "exception_type": "", + "exception_message": "ValueError: Cannot divide by zero!", + "constructor": "", + "cost": 0.0, + "testable": true + }, + "3": { + "args_before": [ + "6", + "2" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": { + "error_code": 0 + }, + "globals_after": { + "error_code": 0 + }, + "expected_result": "6/2=3.0", + "expected_type": "str", + "coverage": [ + 35, + 36, + 39, + 42, + 45 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 100.0, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler" + ], + "global_vars_read_from": [ + "error_code", + "logger" + ], + "global_vars_written_to": [ + "error_code" + ], + "unified_test_coverage": [ + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45 + ], + "needs_pytest": true, + "exceptions_raised": [ + "", + "" + ], + "callable_files": { + "divide_ints": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\tests\\procedural_division\\divide_ints.py" + } } \ No newline at end of file diff --git a/tests/procedural_division/divide_ints.py b/tests/procedural_division/divide_ints.py index 570e7d0..df41959 100644 --- a/tests/procedural_division/divide_ints.py +++ b/tests/procedural_division/divide_ints.py @@ -5,9 +5,12 @@ import argparse import logging import os +import sys import time from pathlib import Path +import coverage + from src import unit_test_generator from src.unit_test_generator import ( generate_all_tests_and_metadata, @@ -40,69 +43,3 @@ def divide_ints(a: int, b: int)->str: error_code = -3 raise ValueError("ValueError: Cannot divide by zero!") return f"{a}/{b}={a/b}" - -def main(): - """ - Call division function - """ - start = time.perf_counter() - a_list = [6, 3,"10", 8, [], {}, 4] - b_list = [2, 0, 2, [], 2, 3, set()] - global error_code # pylint: disable=global-statement - for a, b in zip(a_list, b_list): - try: - logger.info("-"*80) - error_code = 0 - try: - logger.info("Trying divide_ints(%s, %s)", repr(a), repr(b)) - except TypeError as e: - logger.info(e) - print(f"divide_ints({a}, {b})={divide_ints(a, b)}") - except (ValueError, TypeError) as e: - logger.error("%s: %s", type(e),str(e)) - logger.info("error_code=%d", error_code) - - generate_all_tests_and_metadata(Path('.'), Path('.')) - print(f"Took {time.perf_counter()-start} seconds") - -if __name__ == "__main__": - - log_levels = { - 'critical': logging.CRITICAL, - 'error': logging.ERROR, - 'warn': logging.WARNING, - 'warning': logging.WARNING, - 'info': logging.INFO, - 'debug': logging.DEBUG - } - - # Create the parser and add argument(s) - parser = argparse.ArgumentParser() - parser.add_argument('--log-level', - "-l", - help='log level', - type=str, - choices=log_levels.keys(), - default='info') - parser.add_argument("--disable-unit-test-generation", "-d", - action="store_true", - help="Set this flag to deactivate unit test generation for this code") - args = parser.parse_args() - print(f"{args=}") - - this_file = Path(__file__).absolute() - for file in this_file.parent.rglob("*"): - if file.suffix in (".py", ".json") and file.absolute() != this_file: - logger.debug("Deleting %s to ensure clean start", this_file) - os.remove(file) - - # The code below applies the CLI arg above to selectively enable/disable - # automatic unit test generation (Could not use the syntactic sugar method - # of applying decorators as the user's input isn't parsed until now.) - # Alternatively, move the argument parsing to the very top of this file. - # NOTE: - # Decorating all functions programmatically is left as an exercise to the reader: - # Hint: https://stackoverflow.com/questions/3467526/ - divide_ints = unit_test_generator_decorator(percent_coverage=110)(divide_ints) - - main() diff --git a/tests/procedural_division/example_divide_ints.py b/tests/procedural_division/example_divide_ints.py new file mode 100644 index 0000000..d2ca5e4 --- /dev/null +++ b/tests/procedural_division/example_divide_ints.py @@ -0,0 +1,99 @@ +""" +Trivial example to demonstrate DDT concept +""" + +import argparse +import logging +import os +import sys +import time +from pathlib import Path + +import coverage +from divide_ints import divide_ints, error_code +from src import unit_test_generator +from src.unit_test_generator import ( + generate_all_tests_and_metadata, + unit_test_generator_decorator, +) + +FMT_STR = '%(levelname)-8s|%(module)-16s|%(funcName)-20s:%(lineno)-4d:%(message)s' +logging.basicConfig(level=logging.INFO, format=FMT_STR) +logger = logging.getLogger(__name__) +unit_test_generator.logger.setLevel(logging.CRITICAL) + +def main(): + """ + Call division function + """ + start = time.perf_counter() + a_list = [6, 3,"10", 8, [], {}, 4] + b_list = [2, 0, 2, [], 2, 3, set()] + for a, b in zip(a_list, b_list): + try: + logger.info("-"*80) + error_code = 0 + try: + logger.info("Trying divide_ints(%s, %s)", repr(a), repr(b)) + except TypeError as e: + logger.info(e) + print(f"divide_ints({a}, {b})={divide_ints(a, b)}") + except (ValueError, TypeError) as e: + logger.error("%s: %s", type(e),str(e)) + logger.info("error_code=%d", error_code) + + generate_all_tests_and_metadata(Path('.'), Path('.')) + print(f"Took {time.perf_counter()-start} seconds") + +if __name__ == "__main__": + + log_levels = { + 'critical': logging.CRITICAL, + 'error': logging.ERROR, + 'warn': logging.WARNING, + 'warning': logging.WARNING, + 'info': logging.INFO, + 'debug': logging.DEBUG + } + + # Create the parser and add argument(s) + parser = argparse.ArgumentParser() + parser.add_argument('--log-level', + "-l", + help='log level', + type=str, + choices=log_levels.keys(), + default='info') + parser.add_argument("--disable-unit-test-generation", "-d", + action="store_true", + help="Set this flag to deactivate unit test generation for this code") + args = parser.parse_args() + print(f"{args=}") + + this_file = Path(__file__).absolute() + for file in this_file.parent.rglob("*"): + if file.name == "divide_ints.py": + continue + if file.suffix in (".py", ".json") and file.absolute() != this_file: + logger.debug("Deleting %s to ensure clean start", this_file) + os.remove(file) + + + if args.disable_unit_test_generation: + main() + sys.exit(0) + + + # The code below applies the CLI arg above to selectively enable/disable + # automatic unit test generation (Could not use the syntactic sugar method + # of applying decorators as the user's input isn't parsed until now.) + # Alternatively, move the argument parsing to the very top of this file. + # NOTE: + # Decorating all functions programmatically is left as an exercise to the reader: + # Hint: https://stackoverflow.com/questions/3467526/ + divide_ints = unit_test_generator_decorator(percent_coverage=110)(divide_ints) + + cov = coverage.Coverage() + with cov.collect(): + main() + cov.save() \ No newline at end of file diff --git a/tests/procedural_division/normalize_arg.json b/tests/procedural_division/normalize_arg.json index 09e108d..fa68ef3 100644 --- a/tests/procedural_division/normalize_arg.json +++ b/tests/procedural_division/normalize_arg.json @@ -1,67 +1,67 @@ -{ - "name": "normalize_arg", - "parameter_names": [ - "arg" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1711, - 1712, - 1713, - 1714, - 1715, - 1716, - 1718, - 1719, - 1720, - 1721 - ], - "non_code_lines": [ - 1717 - ], - "coverage_io": { - "0": { - "args_before": [ - "\"CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)\"" - ], - "args_after": {}, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "expected_type": "str", - "coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 60.0, - "types_in_use": [], - "global_vars_read_from": [], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1711, - 1712, - 1713, - 1715, - 1718, - 1721 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "normalize_arg", + "parameter_names": [ + "arg" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1767, + 1768, + 1769, + 1770, + 1771, + 1772, + 1774, + 1775, + 1776, + 1777 + ], + "non_code_lines": [ + 1773 + ], + "coverage_io": { + "0": { + "args_before": [ + "\"CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)\"" + ], + "args_after": {}, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "expected_type": "str", + "coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 60.0, + "types_in_use": [], + "global_vars_read_from": [], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1767, + 1768, + 1769, + 1771, + 1774, + 1777 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "normalize_arg": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/procedural_division/test_coverage_str_helper.py b/tests/procedural_division/test_coverage_str_helper.py deleted file mode 100644 index be3780e..0000000 --- a/tests/procedural_division/test_coverage_str_helper.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Programmatically generated test function for coverage_str_helper() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - -# Now import modules specific to coverage_str_helper: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler - - -# In sum, these tests covered 71.88% of coverage_str_helper's lines -# Line(s) not covered by ANY of the tests below: -# ['1743', '1754', '1759-1760', '1768-1769', '1772-1773'] -@pytest.mark.parametrize( - "this_list, non_code_lines, expected_result, args_after", - [ - ( - [1701, 1702, 1684, 1685, 1687, 1688, 1689], - {1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}, - "['1701-1702', '1684-1685', '1687-1689']", - { - "this_list": "[1701, 1702, 1684, 1685, 1687, 1688, 1689]", - "non_code_lines": "{1696, 1697, 1698, 1690, 1692, 1693, 1694, 1695}", - }, - ), - ], -) -def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): - """ - Programmatically generated test function for coverage_str_helper() - """ - result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) - assert result == expected_result or result == eval(expected_result) - assert ( - this_list == eval(args_after["this_list"]) - or args_after["this_list"] == this_list - ) - assert ( - non_code_lines == eval(args_after["non_code_lines"]) - or args_after["non_code_lines"] == non_code_lines - ) diff --git a/tests/procedural_division/test_coverage_str_helper_procedural_division.py b/tests/procedural_division/test_coverage_str_helper_procedural_division.py new file mode 100644 index 0000000..8606f4c --- /dev/null +++ b/tests/procedural_division/test_coverage_str_helper_procedural_division.py @@ -0,0 +1,51 @@ +""" +Programmatically generated test function for coverage_str_helper() +""" + +import pytest +from src import unit_test_generator + +# Now import modules specific to coverage_str_helper: + + +# In sum, these tests covered 71.88% of coverage_str_helper's lines +# Line(s) not covered by ANY of the tests below: +# ['1799', '1810', '1815-1816', '1824-1825', '1828-1829'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "this_list, non_code_lines, expected_result, args_after", + [ + ( + [1740, 1741, 1743, 1744, 1745, 1757, 1758], + {1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}, + "['1740-1741', '1743-1745', '1757-1758']", + { + "this_list": "[1740, 1741, 1743, 1744, 1745, 1757, 1758]", + "non_code_lines": "{1746, 1748, 1749, 1750, 1751, 1752, 1753, 1754}", + }, + ), + ], + ids=counter, +) +def test_coverage_str_helper(this_list, non_code_lines, expected_result, args_after): + """ + Programmatically generated test function for coverage_str_helper() + """ + result = unit_test_generator.coverage_str_helper(this_list, non_code_lines) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_list == eval(args_after["this_list"]) + or args_after["this_list"] == this_list + ) + assert ( + non_code_lines == eval(args_after["non_code_lines"]) + or args_after["non_code_lines"] == non_code_lines + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/procedural_division/test_divide_ints.py b/tests/procedural_division/test_divide_ints.py index a897475..37cc45c 100644 --- a/tests/procedural_division/test_divide_ints.py +++ b/tests/procedural_division/test_divide_ints.py @@ -1,86 +1,90 @@ -""" -Programmatically generated test function for divide_ints() -""" - -import re -import pytest -from collections import OrderedDict -import divide_ints -from _pytest.monkeypatch import MonkeyPatch - -# Now import modules specific to divide_ints: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler - -ERROR_CODE = 0 - - -# In sum, these tests covered 100.0% of divide_ints's lines -@pytest.mark.parametrize( - "a, b, exception_type, exception_message, expected_result, args_after, globals_before, globals_after", - [ - ( - "10", - 2, - TypeError, - "TypeError: Variable a='10' is not an int!", - "None", - {}, - {}, - {"error_code": -1}, - ), - ( - 3, - 0, - ValueError, - "ValueError: Cannot divide by zero!", - "None", - {}, - {}, - {"error_code": -3}, - ), - (6, 2, "N/A", "N/A", "6/2=3.0", {}, {}, {"error_code": 0}), - ( - 8, - [], - TypeError, - "TypeError: Variable b=[] is not an int!", - "None", - {"b": "[]"}, - {}, - {"error_code": -2}, - ), - ], -) -def test_divide_ints( - a, - b, - exception_type, - exception_message, - expected_result, - args_after, - globals_before, - globals_after, -): - """ - Programmatically generated test function for divide_ints() - """ - monkeypatch = MonkeyPatch() - monkeypatch.setattr(divide_ints, "error_code", ERROR_CODE) - if exception_type != "N/A": - with pytest.raises(exception_type, match=re.escape(exception_message)): - divide_ints.divide_ints(a, b) - else: - result = divide_ints.divide_ints(a, b) - assert result == expected_result or result == eval(expected_result) - for global_var_written_to in ["error_code"]: - if global_var_written_to in ["None", "[]", "{}"]: - assert not divide_ints.__dict__.get(global_var_written_to) - else: - assert ( - divide_ints.__dict__.get(global_var_written_to) - == globals_after[global_var_written_to] - ) +""" +Programmatically generated test function for divide_ints() +""" + +import re +import pytest +import divide_ints +from _pytest.monkeypatch import MonkeyPatch + +# Now import modules specific to divide_ints: + + +# In sum, these tests covered 100.0% of divide_ints's lines +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "a, b, exception_type, exception_message, expected_result, args_after, globals_before, globals_after", + [ + ( + 8, + [], + TypeError, + "TypeError: Variable b=[] is not an int!", + "None", + {"b": "[]"}, + {"error_code": -1}, + {"error_code": -2}, + ), + ( + "10", + 2, + TypeError, + "TypeError: Variable a='10' is not an int!", + "None", + {}, + {"error_code": -3}, + {"error_code": -1}, + ), + ( + 3, + 0, + ValueError, + "ValueError: Cannot divide by zero!", + "None", + {}, + {"error_code": 0}, + {"error_code": -3}, + ), + (6, 2, "N/A", "N/A", "6/2=3.0", {}, {"error_code": 0}, {"error_code": 0}), + ], + ids=counter, +) +def test_divide_ints( + a, + b, + exception_type, + exception_message, + expected_result, + args_after, + globals_before, + globals_after, +): + """ + Programmatically generated test function for divide_ints() + """ + monkeypatch = MonkeyPatch() + for k, v in globals_before.items(): + monkeypatch.setattr(divide_ints, k, v) + if exception_type != "N/A": + with pytest.raises(exception_type, match=re.escape(exception_message)): + divide_ints.divide_ints(a, b) + else: + result = divide_ints.divide_ints(a, b) + assert result == expected_result or result == eval(expected_result) + try: + assert b == eval(args_after["b"]) or args_after["b"] == b + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") + for global_var_written_to in ["error_code"]: + if global_var_written_to in ["None", "[]", "{}"]: + assert not divide_ints.__dict__.get(global_var_written_to) + else: + assert ( + divide_ints.__dict__.get(global_var_written_to) + == globals_after[global_var_written_to] + ) diff --git a/tests/procedural_division/test_normalize_arg.py b/tests/procedural_division/test_normalize_arg_procedural_division.py similarity index 82% rename from tests/procedural_division/test_normalize_arg.py rename to tests/procedural_division/test_normalize_arg_procedural_division.py index 3cde486..cf0afee 100644 --- a/tests/procedural_division/test_normalize_arg.py +++ b/tests/procedural_division/test_normalize_arg_procedural_division.py @@ -1,28 +1,33 @@ -""" -Programmatically generated test function for normalize_arg() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - - -# In sum, these tests covered 60.0% of normalize_arg's lines -# Line(s) not covered by ANY of the tests below: -# ['1714', '1716', '1719-1720'] -@pytest.mark.parametrize( - "arg, expected_result", - [ - ( - "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - ), - ], -) -def test_normalize_arg(arg, expected_result): - """ - Programmatically generated test function for normalize_arg() - """ - result = unit_test_generator.normalize_arg(arg) - assert result == expected_result or result == eval(expected_result) +""" +Programmatically generated test function for normalize_arg() +""" + +import pytest +from src import unit_test_generator + + +# In sum, these tests covered 60.0% of normalize_arg's lines +# Line(s) not covered by ANY of the tests below: +# ['1770', '1772', '1775-1776'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "arg, expected_result", + [ + ( + "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + ), + ], + ids=counter, +) +def test_normalize_arg(arg, expected_result): + """ + Programmatically generated test function for normalize_arg() + """ + result = unit_test_generator.normalize_arg(arg) + assert result == expected_result or result == eval(expected_result) diff --git a/tests/procedural_division/test_update_global.py b/tests/procedural_division/test_update_global_procedural_division.py similarity index 76% rename from tests/procedural_division/test_update_global.py rename to tests/procedural_division/test_update_global_procedural_division.py index 0efec2f..01f5baa 100644 --- a/tests/procedural_division/test_update_global.py +++ b/tests/procedural_division/test_update_global_procedural_division.py @@ -1,65 +1,68 @@ -""" -Programmatically generated test function for update_global() -""" - -import re -import pytest -from collections import OrderedDict -from src import unit_test_generator - -# Now import modules specific to update_global: -from logging import Logger -from logging import Manager -from logging import PlaceHolder -from logging import RootLogger -from logging import StreamHandler -from src.unit_test_generator import CoverageInfo - - -# In sum, these tests covered 46.15% of update_global's lines -# Line(s) not covered by ANY of the tests below: -# ['1701-1702', '1684-1685', '1687-1689'] -@pytest.mark.parametrize( - "obj, this_global, phase, this_coverage_info, expected_result, args_after", - [ - ( - 0, - "error_code", - "Before", - CoverageInfo( - args_before=["6", "2"], - args_after={}, - kwargs={}, - kwargs_after={}, - globals_before={}, - globals_after={}, - expected_result="", - expected_type="", - coverage=[], - exception_type="", - exception_message="", - constructor="", - cost=0.0, - testable=0.0, - ), - "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - { - "this_coverage_info": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - }, - ), - ], -) -def test_update_global( - obj, this_global, phase, this_coverage_info, expected_result, args_after -): - """ - Programmatically generated test function for update_global() - """ - result = unit_test_generator.update_global( - obj, this_global, phase, this_coverage_info - ) - assert result == expected_result or result == eval(expected_result) - assert ( - this_coverage_info == eval(args_after["this_coverage_info"]) - or args_after["this_coverage_info"] == this_coverage_info - ) +""" +Programmatically generated test function for update_global() +""" + +import pytest +from src import unit_test_generator + +# Now import modules specific to update_global: +from src.unit_test_generator import CoverageInfo + + +# In sum, these tests covered 46.15% of update_global's lines +# Line(s) not covered by ANY of the tests below: +# ['1740-1741', '1743-1745', '1757-1758'] +def counter(start=0) -> str: + while True: + yield f"test#-{start}" + start += 1 + + +@pytest.mark.parametrize( + "obj, this_global, phase, this_coverage_info, expected_result, args_after", + [ + ( + 0, + "error_code", + "Before", + CoverageInfo( + args_before=["6", "2"], + args_after={}, + kwargs={}, + kwargs_after={}, + globals_before={}, + globals_after={}, + expected_result="", + expected_type="", + coverage=[], + exception_type="", + exception_message="", + constructor="", + cost=0.0, + testable=True, + ), + "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + { + "this_coverage_info": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + }, + ), + ], + ids=counter, +) +def test_update_global( + obj, this_global, phase, this_coverage_info, expected_result, args_after +): + """ + Programmatically generated test function for update_global() + """ + result = unit_test_generator.update_global( + obj, this_global, phase, this_coverage_info + ) + assert result == expected_result or result == eval(expected_result) + try: + assert ( + this_coverage_info == eval(args_after["this_coverage_info"]) + or args_after["this_coverage_info"] == this_coverage_info + ) + except KeyError as e: + print(f"Got Key Error in test, likely false positive: {e=}") diff --git a/tests/procedural_division/update_global.json b/tests/procedural_division/update_global.json index 4646446..8bf2e87 100644 --- a/tests/procedural_division/update_global.json +++ b/tests/procedural_division/update_global.json @@ -1,94 +1,94 @@ -{ - "name": "update_global", - "parameter_names": [ - "obj", - "this_global", - "phase", - "this_coverage_info" - ], - "is_method": false, - "source_file": null, - "lines": [ - 1683, - 1684, - 1685, - 1686, - 1687, - 1688, - 1689, - 1691, - 1699, - 1700, - 1701, - 1702, - 1703 - ], - "non_code_lines": [ - 1690, - 1692, - 1693, - 1694, - 1695, - 1696, - 1697, - 1698 - ], - "coverage_io": { - "0": { - "args_before": [ - "0", - "\"error_code\"", - "\"Before\"", - "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - ], - "args_after": { - "this_coverage_info": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)" - }, - "kwargs": {}, - "kwargs_after": {}, - "globals_before": {}, - "globals_after": {}, - "expected_result": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=0.0)", - "expected_type": "src.unit_test_generator.CoverageInfo", - "coverage": [ - 1683, - 1686, - 1691, - 1699, - 1700, - 1703 - ], - "exception_type": "", - "exception_message": "", - "constructor": "", - "cost": 0.0, - "testable": true - } - }, - "coverage_percentage": 46.15, - "types_in_use": [ - "logging.Logger", - "logging.Manager", - "logging.PlaceHolder", - "logging.RootLogger", - "logging.StreamHandler", - "src.unit_test_generator.CoverageInfo" - ], - "global_vars_read_from": [ - "logger" - ], - "global_vars_written_to": [], - "unified_test_coverage": [ - 1683, - 1686, - 1691, - 1699, - 1700, - 1703 - ], - "needs_pytest": false, - "exceptions_raised": [], - "callable_files": { - "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" - } +{ + "name": "update_global", + "parameter_names": [ + "obj", + "this_global", + "phase", + "this_coverage_info" + ], + "is_method": false, + "source_file": null, + "lines": [ + 1739, + 1740, + 1741, + 1742, + 1743, + 1744, + 1745, + 1747, + 1755, + 1756, + 1757, + 1758, + 1759 + ], + "non_code_lines": [ + 1746, + 1748, + 1749, + 1750, + 1751, + 1752, + 1753, + 1754 + ], + "coverage_io": { + "0": { + "args_before": [ + "0", + "\"error_code\"", + "\"Before\"", + "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + ], + "args_after": { + "this_coverage_info": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)" + }, + "kwargs": {}, + "kwargs_after": {}, + "globals_before": {}, + "globals_after": {}, + "expected_result": "CoverageInfo(args_before=['6','2'], args_after={}, kwargs={}, kwargs_after={}, globals_before={'error_code': 0}, globals_after={}, expected_result='', expected_type='', coverage=[], exception_type='', exception_message='', constructor='', cost=0.0, testable=True)", + "expected_type": "src.unit_test_generator.CoverageInfo", + "coverage": [ + 1739, + 1742, + 1747, + 1755, + 1756, + 1759 + ], + "exception_type": "", + "exception_message": "", + "constructor": "", + "cost": 0.0, + "testable": true + } + }, + "coverage_percentage": 46.15, + "types_in_use": [ + "logging.Logger", + "logging.Manager", + "logging.PlaceHolder", + "logging.RootLogger", + "logging.StreamHandler", + "src.unit_test_generator.CoverageInfo" + ], + "global_vars_read_from": [ + "logger" + ], + "global_vars_written_to": [], + "unified_test_coverage": [ + 1739, + 1742, + 1747, + 1755, + 1756, + 1759 + ], + "needs_pytest": false, + "exceptions_raised": [], + "callable_files": { + "update_global": "C:\\Users\\James\\Documents\\CyberResources\\ddt\\src\\unit_test_generator.py" + } } \ No newline at end of file diff --git a/tests/test_all.py b/tests/test_all.py deleted file mode 100644 index a2069e6..0000000 --- a/tests/test_all.py +++ /dev/null @@ -1,11 +0,0 @@ -import pytest -import logging -from .example_all_types.all_types import main as at_main - -fmt_str = '%(levelname)-8s|%(module)-16s|%(funcName)-20s:%(lineno)-4d:%(message)s' -logging.basicConfig(level=logging.INFO, format=fmt_str) -logger = logging.getLogger(__name__) - -def test_all(): - print("Punch it") - at_main() diff --git a/tests/test_all_keep_files.bat b/tests/test_all_keep_files.bat index 0d6e330..92e1026 100644 --- a/tests/test_all_keep_files.bat +++ b/tests/test_all_keep_files.bat @@ -1,24 +1,24 @@ -cd fizzbuzz -python fizzbuzz.py >NUL 2>NUL -pytest -s -vv . -cd .. - -cd all_types -python all_types.py >NUL 2>NUL -pytest -s -vv . -cd .. - -cd procedural_division -python divide_ints.py >NUL 2>NUL -pytest -s -vv . -cd .. - -cd oo_car -python car.py >NUL 2>NUL -pytest -s -vv . -cd .. - -cd pass_by_assignment -python pass_by_assignment.py >NUL 2>NUL -pytest -s -vv . +cd fizzbuzz +python example_fizzbuzz.py >NUL 2>NUL +pytest -s -vv . +cd .. + +cd all_types +python all_types.py >NUL 2>NUL +pytest -s -vv . +cd .. + +cd procedural_division +python example_divide_ints.py >NUL 2>NUL +pytest -s -vv . +cd .. + +cd oo_car +python example_car.py >NUL 2>NUL +pytest -s -vv . +cd .. + +cd pass_by_assignment +python example_pass_by_assignment.py >NUL 2>NUL +pytest -s -vv . cd .. \ No newline at end of file diff --git a/tests/test_all_keep_files_keep_output.bat b/tests/test_all_keep_files_keep_output.bat index 14f2051..4210ea7 100644 --- a/tests/test_all_keep_files_keep_output.bat +++ b/tests/test_all_keep_files_keep_output.bat @@ -1,24 +1,40 @@ cd fizzbuzz -python fizzbuzz.py -pytest -s -vv . +python example_fizzbuzz.py +coverage run -m pytest +::pytest -s -vv . +timeout 1 cd .. cd all_types python all_types.py -pytest -s -vv . +coverage run -m pytest +::pytest -s -vv . cd .. cd procedural_division -python divide_ints.py -pytest -s -vv . +python example_divide_ints.py +coverage run -m pytest +::pytest -s -vv . cd .. cd oo_car -python car.py -pytest -s -vv . +python example_car.py +coverage run -m pytest +::pytest -s -vv . cd .. cd pass_by_assignment -python pass_by_assignment.py -pytest -s -vv . -cd .. \ No newline at end of file +python example_pass_by_assignment.py +coverage run -m pytest +cd .. + +cd ..\src +:: pytest . +coverage run -m pytest +cd .. + +: Give time for .coverage files to hit disk + +coverage combine --keep tests\fizzbuzz\.coverage tests\oo_car\.coverage tests\all_types\.coverage tests\pass_by_assignment\.coverage tests\procedural_division\.coverage src\.coverage +coverage report -m +coverage html \ No newline at end of file