nedbat / coveragepy

The code coverage tool for Python
https://coverage.readthedocs.io
Apache License 2.0
2.98k stars 429 forks source link

or clauses in conditions should be considered branches #1120

Closed thedrow closed 3 years ago

thedrow commented 3 years ago

Describe the bug

The following statement is considered covered if one of the conditions is True:

a = True
b = False

def foo():
  pass

if a or b:
  foo()

However, coverage will correctly detect not branches are covered when the following code is used instead:

a = True
b = False

def foo():
  pass

if a:
  foo()
elif b:
  foo()

To Reproduce How can we reproduce the problem? Please be specific. Don't just link to a failing CI job. Answer the questions below:

  1. What version of Python are you using? 3.9.0

  2. What version of coverage.py are you using? The output of coverage debug sys is helpful. coverage debug sys -- sys ------------------------------------------------------- version: 5.3 coverage: /home/thedrow/.virtualenvs/celery/lib/python3.9/site-packages/coverage/init.py tracer: -none- CTracer: available plugins.file_tracers: -none- plugins.configurers: -none- plugins.context_switchers: -none- configs_attempted: .coveragerc configs_read: /home/thedrow/Documents/Projects/celery/.coveragerc config_file: /home/thedrow/Documents/Projects/celery/.coveragerc config_contents: b'[run]\nbranch = 1\ncover_pylib = 0\ninclude=celery/\nomit = celery.tests.\n\n[report]\nomit =\n /python?.?/\n /site-packages/\n /pypy/\n /celery/bin/graph.py\n celery/bin/logtool.py\n celery/task/base.py\n celery/contrib/sphinx.py\n celery/concurrency/asynpool.py\n celery/utils/debug.py\n celery/contrib/testing/\n celery/contrib/pytest.py\n' data_file: -none- python: 3.9.0 (default, Oct 12 2020, 10:53:02) [GCC 5.5.0] platform: Linux-5.8.0-43-generic-x86_64-with-glibc2.32 implementation: CPython executable: /home/thedrow/.virtualenvs/celery/bin/python def_encoding: utf-8 fs_encoding: utf-8 pid: 240986 cwd: /home/thedrow/Documents/Projects/celery path: /home/thedrow/.virtualenvs/celery/bin /home/thedrow/.pyenv/versions/3.9.0/lib/python39.zip /home/thedrow/.pyenv/versions/3.9.0/lib/python3.9 /home/thedrow/.pyenv/versions/3.9.0/lib/python3.9/lib-dynload /home/thedrow/.virtualenvs/celery/lib/python3.9/site-packages /home/thedrow/Documents/Projects/celery environment: PYENV_SHELL = bash PYENV_VIRTUALENVWRAPPER_PYENV_VERSION = 3.9.0 VIRTUALENVWRAPPER_PYTHON = /home/thedrow/.pyenv/versions/3.9.0/bin/python command_line: /home/thedrow/.virtualenvs/celery/bin/coverage debug sys sqlite3_version: 2.6.0 sqlite3_sqlite_version: 3.34.0 sqlite3_temp_store: 0 sqlite3_compile_options: COMPILER=gcc-5.4.0 20160609 ENABLE_COLUMN_METADATA ENABLE_FTS3 ENABLE_FTS3_PARENTHESIS ENABLE_FTS4 ENABLE_FTS5 ENABLE_GEOPOLY ENABLE_JSON1 ENABLE_PREUPDATE_HOOK ENABLE_RTREE ENABLE_SESSION MAX_VARIABLE_NUMBER=250000 THREADSAFE=1

  3. What versions of what packages do you have installed? The output of pip freeze is helpful. alabaster==0.7.12 amqp==5.0.1 appdirs==1.4.4 attrs==20.2.0 autopep8==1.5.4 aws-xray-sdk==0.95 azure-common==1.1.5 azure-nspkg==3.0.2 azure-storage==0.36.0 azure-storage-common==1.1.0 azure-storage-nspkg==3.1.0 Babel==2.8.0 backcall==0.2.0 billiard==3.6.3.0 bleach==3.2.1 boto==2.49.0 boto3==1.16.9 botocore==1.19.9 bump2version==1.0.1 bumpversion==0.6.0 case==1.5.3 cassandra-driver==3.20.2 -e git+git@github.com:celery/celery.git@fe4b21ffa12c1f5645818323e45fb1e1b7dc3b3a#egg=celery certifi==2020.12.5 cffi==1.14.4 cfgv==3.2.0 chardet==3.0.4 click==7.1.2 click-didyoumean==0.0.3 click-plugins==1.1.1 click-repl==0.1.6 codecov==2.1.10 colorama==0.4.4 coverage==5.3 cryptography==3.2.1 DateTime==4.3 decorator==4.4.2 distlib==0.3.1 dnspython==1.16.0 docker==4.3.1 docutils==0.16 ecdsa==0.16.0 elasticsearch==7.9.1 ephem==3.7.7.1 eventlet==0.29.1 filelock==3.0.12 flower==0.9.5 future==0.18.2 gevent==20.9.0 greenlet==0.4.17 humanize==3.1.0 identify==1.5.6 idna==2.10 imagesize==1.2.0 importlib-metadata==2.0.0 iniconfig==1.1.1 ipython==7.19.0 ipython-genutils==0.2.0 isort==5.7.0 jedi==0.17.2 jeepney==0.6.0 Jinja2==2.11.2 jmespath==0.10.0 jsondiff==1.1.1 jsonpickle==1.4.1 keyring==21.5.0 kombu==5.0.2 linecache2==1.0.0 MarkupSafe==1.1.1 mock==4.0.2 moto==1.3.7 msgpack==1.0.0 nodeenv==1.5.0 nose==1.3.7 packaging==20.7 parso==0.7.1 pbr==5.5.1 pexpect==4.8.0 pickleshare==0.7.5 pkginfo==1.6.1 pluggy==0.13.1 pre-commit==2.8.2 prometheus-client==0.8.0 prompt-toolkit==3.0.8 ptyprocess==0.6.0 py==1.9.0 pyaml==20.4.0 pyArango==1.3.4 pycodestyle==2.6.0 pycouchdb==1.14.1 pycparser==2.20 pycryptodome==3.9.8 pycurl==7.43.0.5 pydocumentdb==2.3.2 Pygments==2.7.3 pylibmc==1.6.1 pymongo==3.11.0 pyparsing==2.4.7 pytest==6.1.2 pytest-celery==0.0.0a1 pytest-cov==2.10.1 pytest-rerunfailures==9.1.1 pytest-subtests==0.3.2 pytest-timeout==1.4.2 pytest-travis-fold==1.3.0 python-consul==1.1.0 python-dateutil==2.8.1 python-jose==2.0.2 python-memcached==1.59 pytz==2020.1 PyYAML==5.3.1 readme-renderer==28.0 redis==3.5.3 requests==2.25.0 requests-toolbelt==0.9.1 responses==0.12.0 rfc3986==1.4.0 s3transfer==0.3.3 SecretStorage==3.3.0 simplejson==3.17.2 six==1.15.0 snowballstemmer==2.0.0 softlayer-messaging==1.0.3 Sphinx==3.3.0 sphinx-celery==2.0.0 sphinx-click==2.5.0 sphinx-testing==0.7.2 sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==1.0.3 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.4 SQLAlchemy==1.3.20 tblib==1.7.0 toml==0.10.2 tornado==6.1 tqdm==4.54.1 traceback2==1.4.0 traitlets==5.0.5 twine==3.2.0 unittest2==1.1.0 urllib3==1.26.2 vine==5.0.0 virtualenv==20.1.0 wcwidth==0.2.5 webencodings==0.5.1 websocket-client==0.57.0 Werkzeug==1.0.1 wrapt==1.12.1 xmltodict==0.12.0 zipp==3.4.0 zope.event==4.5.0 zope.interface==5.1.2

  4. What code are you running? Give us a specific commit of a specific repo that we can check out. https://github.com/celery/celery/pull/6600

  5. What commands did you run? pytest t/unit/utils/test_platforms.py --cov-report html --cov celery

Expected behavior I expect coverage to correctly detect the or clause as four branches:

  1. a is True
  2. b is True
  3. Both a and b are True
  4. Both a and b are False

Additional context None

nedbat commented 3 years ago

This is a long-standing limitation of the line-oriented tracing that coverage.py builds on. Other cases are discussed in #509.