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

[Enhancement] Add test coverage reports #342

Merged
merged 3 commits into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[run]
branch = True

[report]
skip_empty = True
skip_covered = True

# Omit; need a different approach to test modules with hardware dependencies
omit =
*/__init__.py
*/tests/*
*/pyzbar/*
*/gui/*

# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

# Don't complain about missing debug-only code:
def __repr__
def __str__
if self\.debug

# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError

# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:

# Don't complain about abstract methods, they aren't run:
@(abc\.)?abstractmethod


[html]
directory = coverage_html_report
skip_empty = True
skip_covered = False
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ src/seedsigner.egg-info/
src/seedsigner/models/settings_definition.json
.idea
*.mo
.coverage
16 changes: 16 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,19 @@ Run a specific test:
```
pytest tests/test_this_file.py::test_this_specific_test
```

### Test Coverage
Run tests and generate test coverage
```
coverage run -m pytest
```

Show the resulting test coverage details:
```
coverage report
```

Generate the html overview:
```
coverage html
```
3 changes: 2 additions & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
coverage==7.2.1
mock==4.0.3
pytest==6.2.4
mock==4.0.3
46 changes: 46 additions & 0 deletions tests/test_mnemonic_generation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
import random

from embit import bip39
Expand Down Expand Up @@ -42,6 +43,35 @@ def test_calculate_checksum():
assert bip39.mnemonic_is_valid(" ".join(mnemonic))


def test_calculate_checksum_invalid_mnemonics():
"""
Should raise an Exception on a mnemonic that is invalid due to length or using invalid words.
"""
with pytest.raises(Exception) as e:
# Mnemonic is too short: 10 words instead of 11
partial_mnemonic = "abandon " * 9 + "about"
mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "), wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
assert "12- or 24-word" in str(e)

with pytest.raises(Exception) as e:
# Valid mnemonic but unsupported length
mnemonic = "devote myth base logic dust horse nut collect buddy element eyebrow visit empty dress jungle"
mnemonic_generation.calculate_checksum(mnemonic.split(" "), wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
assert "12- or 24-word" in str(e)

with pytest.raises(Exception) as e:
# Mnemonic is too short: 22 words instead of 23
partial_mnemonic = "abandon " * 21 + "about"
mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "), wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
assert "12- or 24-word" in str(e)

with pytest.raises(ValueError) as e:
# Invalid BIP-39 word
partial_mnemonic = "foobar " * 11 + "about"
mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "), wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
assert "not in the dictionary" in str(e)



def test_calculate_checksum_with_default_final_word():
""" 11-word and 23-word mnemonics use word `0000` as a temp final word to complete
Expand All @@ -62,6 +92,22 @@ def test_calculate_checksum_with_default_final_word():
assert mnemonic1 == mnemonic2


def test_generate_mnemonic_from_bytes():
"""
Should generate a valid BIP-39 mnemonic from entropy bytes
"""
# From iancoleman.io
entropy = "3350f6ac9eeb07d2c6209932808aa7f6"
expected_mnemonic = "crew marble private differ race truly blush basket crater affair prepare unique".split()
mnemonic = mnemonic_generation.generate_mnemonic_from_bytes(bytes.fromhex(entropy))
assert mnemonic == expected_mnemonic

entropy = "5bf41629fce815c3570955e8f45422abd7e2234141bd4d7ec63b741043b98cad"
expected_mnemonic = "fossil pass media what life ticket found click trophy pencil anger fish lawsuit balance agree dash estate wage mom trial aerobic system crawl review".split()
mnemonic = mnemonic_generation.generate_mnemonic_from_bytes(bytes.fromhex(entropy))
assert mnemonic == expected_mnemonic



def test_verify_against_coldcard_sample():
""" https://coldcard.com/docs/verifying-dice-roll-math """
Expand Down