Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False positive partial branch when capturing the match-case wildcard statement #1860

Closed
moritz89 opened this issue Sep 25, 2024 · 2 comments
Closed
Labels
bug Something isn't working fixed

Comments

@moritz89
Copy link

Describe the bug
Two equivalent function using the match/case construct with two different ways to use wildcard pattern are reported differently, with the "capture in default / wildcard" case marked as missing branch.

To Reproduce
Here is a minimal reproducible example, note testing is done pairwise to verify the functions as equivalent.

import os

import pytest


def wildcard_alone() -> str:

    match os.getenv("SOME_VAR", "default"):
        case "dev":
            return "development value"
        case "test" | "prod":
            return "production value"
        case _:
            return "default value"


def wildcard_or() -> str:

    match os.getenv("SOME_VAR", "default"):
        case "dev":
            return "development value"
        case "test" | "prod":
            return "production value"
        case _ as value:  # marked as partial branch
            return "default value"


@pytest.mark.parametrize("f", [wildcard_or, wildcard_alone])
def test_match_env_dev(f, monkeypatch):
    monkeypatch.setenv("SOME_VAR", "dev")
    assert f() == "development value"


@pytest.mark.parametrize("f", [wildcard_or, wildcard_alone])
def test_match_env_test(f, monkeypatch):
    monkeypatch.setenv("SOME_VAR", "test")
    assert f() == "production value"


@pytest.mark.parametrize("f", [wildcard_or, wildcard_alone])
def test_match_env_prod(f, monkeypatch):
    monkeypatch.setenv("SOME_VAR", "prod")
    assert f() == "production value"


@pytest.mark.parametrize("f", [wildcard_or, wildcard_alone])
def test_match_env_unset(f, monkeypatch):
    monkeypatch.delenv("SOME_VAR", raising=False)
    assert f() == "default value"

@pytest.mark.parametrize("f", [wildcard_or, wildcard_alone])
def test_match_env_other(f, monkeypatch):
    monkeypatch.setenv("SOME_VAR", "unmatched")
    assert f() == "default value"

Here is the coverage.

============================= test session starts ==============================
platform linux -- Python 3.10.12, pytest-8.3.3, pluggy-1.5.0
rootdir: /home/moritz/Sandbox/testing
collected 10 items                                                             

coverage_test.py ..........                                              [100%]

============================== 10 passed in 0.03s ==============================
Name               Stmts   Miss Branch BrPart  Cover   Missing
--------------------------------------------------------------
coverage_test.py      38      0     10      1    98%   24->exit
--------------------------------------------------------------
TOTAL                 38      0     10      1    98%

And finally, the output of coverage debug sys.

-- sys -------------------------------------------------------
               coverage_version: 7.6.1
                coverage_module: /home/moritz/.virtualenvs/testing-qQMgLcoQ/lib/python3.10/site-packages/coverage/__init__.py
                           core: -none-
                        CTracer: available
           plugins.file_tracers: -none-
            plugins.configurers: -none-
      plugins.context_switchers: -none-
              configs_attempted: /home/moritz/Sandbox/testing/.coveragerc
                                 /home/moritz/Sandbox/testing/setup.cfg
                                 /home/moritz/Sandbox/testing/tox.ini
                                 /home/moritz/Sandbox/testing/pyproject.toml
                   configs_read: -none-
                    config_file: None
                config_contents: -none-
                      data_file: -none-
                         python: 3.10.12 (main, Sep 11 2024, 15:47:36) [GCC 11.4.0]
                       platform: Linux-6.8.0-40-generic-x86_64-with-glibc2.35
                 implementation: CPython
                    gil_enabled: True
                     executable: /home/moritz/.virtualenvs/testing-qQMgLcoQ/bin/python
                   def_encoding: utf-8
                    fs_encoding: utf-8
                            pid: 2149091
                            cwd: /home/moritz/Sandbox/testing
                           path: /home/moritz/.virtualenvs/testing-qQMgLcoQ/bin
                                 /usr/lib/python310.zip
                                 /usr/lib/python3.10
                                 /usr/lib/python3.10/lib-dynload
                                 /home/moritz/.virtualenvs/testing-qQMgLcoQ/lib/python3.10/site-packages
                    environment: HOME = /home/moritz
                                 PIP_PYTHON_PATH = /home/moritz/.virtualenvs/testing-qQMgLcoQ/bin/python
                                 PYTHONDONTWRITEBYTECODE = 1
                   command_line: /home/moritz/.virtualenvs/testing-qQMgLcoQ/bin/coverage debug sys
         sqlite3_sqlite_version: 3.37.2
             sqlite3_temp_store: 0
        sqlite3_compile_options: ATOMIC_INTRINSICS=1, COMPILER=gcc-11.4.0, DEFAULT_AUTOVACUUM,
                                 DEFAULT_CACHE_SIZE=-2000, DEFAULT_FILE_FORMAT=4,
                                 DEFAULT_JOURNAL_SIZE_LIMIT=-1, DEFAULT_MMAP_SIZE=0, DEFAULT_PAGE_SIZE=4096,
                                 DEFAULT_PCACHE_INITSZ=20, DEFAULT_RECURSIVE_TRIGGERS,
                                 DEFAULT_SECTOR_SIZE=4096, DEFAULT_SYNCHRONOUS=2,
                                 DEFAULT_WAL_AUTOCHECKPOINT=1000, DEFAULT_WAL_SYNCHRONOUS=2,
                                 DEFAULT_WORKER_THREADS=0, ENABLE_COLUMN_METADATA, ENABLE_DBSTAT_VTAB,
                                 ENABLE_FTS3, ENABLE_FTS3_PARENTHESIS, ENABLE_FTS3_TOKENIZER, ENABLE_FTS4,
                                 ENABLE_FTS5, ENABLE_JSON1, ENABLE_LOAD_EXTENSION, ENABLE_MATH_FUNCTIONS,
                                 ENABLE_PREUPDATE_HOOK, ENABLE_RTREE, ENABLE_SESSION, ENABLE_STMTVTAB,
                                 ENABLE_UNLOCK_NOTIFY, ENABLE_UPDATE_DELETE_LIMIT, HAVE_ISNAN,
                                 LIKE_DOESNT_MATCH_BLOBS, MALLOC_SOFT_LIMIT=1024, MAX_ATTACHED=10,
                                 MAX_COLUMN=2000, MAX_COMPOUND_SELECT=500, MAX_DEFAULT_PAGE_SIZE=32768,
                                 MAX_EXPR_DEPTH=1000, MAX_FUNCTION_ARG=127, MAX_LENGTH=1000000000,
                                 MAX_LIKE_PATTERN_LENGTH=50000, MAX_MMAP_SIZE=0x7fff0000,
                                 MAX_PAGE_COUNT=1073741823, MAX_PAGE_SIZE=65536, MAX_SCHEMA_RETRY=25,
                                 MAX_SQL_LENGTH=1000000000, MAX_TRIGGER_DEPTH=1000,
                                 MAX_VARIABLE_NUMBER=250000, MAX_VDBE_OP=250000000, MAX_WORKER_THREADS=8,
                                 MUTEX_PTHREADS, OMIT_LOOKASIDE, SECURE_DELETE, SOUNDEX, SYSTEM_MALLOC,
                                 TEMP_STORE=1, THREADSAFE=1, USE_URI

Expected behavior
All branches are covered and both function should be at 100% coverage.

Additional context
This bug is very similar to #1421 from which the example was taken and simply updated to highlight the bug.

@moritz89 moritz89 added the bug Something isn't working label Sep 25, 2024
@nedbat
Copy link
Owner

nedbat commented Sep 25, 2024

Thanks. Fixed in commit 71f0f4c

@nedbat nedbat closed this as completed Sep 25, 2024
@nedbat nedbat added the fixed label Sep 25, 2024
@nedbat
Copy link
Owner

nedbat commented Oct 9, 2024

This is now released as part of coverage 7.6.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed
Projects
None yet
Development

No branches or pull requests

2 participants