2022-04-11 13:45:45 +00:00
|
|
|
|
"""Tests for the Identity class
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import bip39
|
|
|
|
|
from ed25519 import SigningKey, create_keypair
|
|
|
|
|
import pytest
|
|
|
|
|
from pytest_mock.plugin import MockerFixture
|
|
|
|
|
|
|
|
|
|
from earthsnake.exc import ValidationError
|
|
|
|
|
from earthsnake.identity import Identity
|
|
|
|
|
|
2022-05-05 11:39:36 +00:00
|
|
|
|
from .helpers import DEFAULT_IDENTITY_SEED as TEST_SEED, random_name
|
2022-04-11 13:45:45 +00:00
|
|
|
|
|
|
|
|
|
TEST_MNEMONIC = bip39.encode_bytes(TEST_SEED)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
'name',
|
|
|
|
|
[
|
|
|
|
|
pytest.param('s', id='veryshort'),
|
|
|
|
|
pytest.param('sho', id='short'),
|
|
|
|
|
pytest.param('longy', id='long'),
|
|
|
|
|
pytest.param('verylong', id='verylong'),
|
|
|
|
|
pytest.param('0num', id='numberstart'),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
def test_init_bad_name(name: str) -> None:
|
|
|
|
|
"""Test if initialisation is not possible with an invalid name"""
|
|
|
|
|
|
|
|
|
|
sign, verify = create_keypair()
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValidationError) as ctx:
|
|
|
|
|
Identity(name, verify_key=verify, sign_key=sign)
|
|
|
|
|
|
|
|
|
|
assert 'Invalid name' in str(ctx.value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_init_key_mismatch() -> None:
|
|
|
|
|
"""Test if initialisation fails if the signing and verifying keys don’t match"""
|
|
|
|
|
|
|
|
|
|
sign1, _ = create_keypair()
|
|
|
|
|
_, verify2 = create_keypair()
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValidationError) as ctx:
|
|
|
|
|
Identity('name', verify_key=verify2, sign_key=sign1)
|
|
|
|
|
|
|
|
|
|
assert 'Signing and verifying keys don’t match' in str(ctx.value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_init_no_keys() -> None:
|
|
|
|
|
"""Test if initialisation is not possible without keys"""
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValidationError) as ctx:
|
|
|
|
|
Identity('name')
|
|
|
|
|
|
|
|
|
|
assert 'At least verify_key must be present' in str(ctx.value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.id_key_seed(TEST_SEED)
|
|
|
|
|
@pytest.mark.id_name('test')
|
|
|
|
|
def test_str(identity: Identity) -> None:
|
|
|
|
|
"""Test if the __str__ method returns the author address"""
|
|
|
|
|
|
2022-05-03 08:26:03 +00:00
|
|
|
|
assert str(identity) == '@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya'
|
2022-04-11 13:45:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.id_key_seed(TEST_SEED)
|
|
|
|
|
@pytest.mark.id_name('test')
|
|
|
|
|
def test_repr(identity: Identity) -> None:
|
2022-05-06 07:30:11 +00:00
|
|
|
|
"""Test if the __repr__ method returns the author address"""
|
|
|
|
|
|
|
|
|
|
assert (
|
|
|
|
|
repr(identity)
|
|
|
|
|
== '<Identity (signer) @test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya>'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_repr_nosign() -> None:
|
|
|
|
|
"""Test the __repr__ method marks the identity as a signer in the output"""
|
|
|
|
|
|
|
|
|
|
identity = Identity.from_address('@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya')
|
2022-04-11 13:45:45 +00:00
|
|
|
|
|
|
|
|
|
assert (
|
|
|
|
|
repr(identity) == '<Identity @test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya>'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_from_address() -> None:
|
|
|
|
|
"""Test loading an identity from an author address"""
|
|
|
|
|
|
|
|
|
|
skey = SigningKey(TEST_SEED)
|
|
|
|
|
vkey = skey.get_verifying_key()
|
2022-05-03 08:26:03 +00:00
|
|
|
|
identity = Identity.from_address('@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya')
|
2022-04-11 13:45:45 +00:00
|
|
|
|
|
|
|
|
|
assert identity.name == 'test'
|
|
|
|
|
assert identity.sign_key is None
|
|
|
|
|
assert identity.verify_key.to_bytes() == vkey.to_bytes()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_from_invalid_address() -> None:
|
|
|
|
|
"""Test loading an identity from an invalid address"""
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValidationError) as ctx:
|
|
|
|
|
Identity.from_address('@inva.lid')
|
|
|
|
|
|
|
|
|
|
assert 'Invalid address @inva.lid' in str(ctx.value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_generate(mocker: MockerFixture) -> None:
|
|
|
|
|
"""Test the generate property"""
|
|
|
|
|
|
|
|
|
|
skey = SigningKey(TEST_SEED)
|
|
|
|
|
vkey = skey.get_verifying_key()
|
|
|
|
|
|
|
|
|
|
mocker.patch('earthsnake.identity.create_keypair', return_value=(skey, vkey))
|
|
|
|
|
identity = Identity.generate('test')
|
|
|
|
|
|
2022-05-03 08:26:03 +00:00
|
|
|
|
assert str(identity) == '@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya'
|
2022-04-11 13:45:45 +00:00
|
|
|
|
assert identity.sign_key
|
|
|
|
|
assert identity.verify_key
|
|
|
|
|
assert identity.name == 'test'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.id_key_seed(TEST_SEED)
|
|
|
|
|
@pytest.mark.id_name('test')
|
|
|
|
|
def test_mnemonic(identity: Identity) -> None:
|
|
|
|
|
"""Test the mnemonic property"""
|
|
|
|
|
|
|
|
|
|
assert identity.mnemonic == f'test {TEST_MNEMONIC}'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_mnemonic_no_signing_key() -> None:
|
|
|
|
|
"""Test if the mnemonic property returns None if there is no signing key"""
|
|
|
|
|
|
2022-05-03 08:26:03 +00:00
|
|
|
|
identity = Identity.from_address('@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya')
|
2022-04-11 13:45:45 +00:00
|
|
|
|
|
|
|
|
|
assert identity.mnemonic is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_from_mnemonic() -> None:
|
|
|
|
|
"""Test if identities can be loaded from mnemonics"""
|
|
|
|
|
|
|
|
|
|
name = random_name()
|
|
|
|
|
identity = Identity.from_mnemonic(f'{name} {TEST_MNEMONIC}')
|
|
|
|
|
|
|
|
|
|
assert identity.name == name
|
|
|
|
|
assert identity.sign_key
|
|
|
|
|
assert identity.sign_key.to_seed() == TEST_SEED
|
2022-05-03 08:26:03 +00:00
|
|
|
|
assert str(identity) == f'@{name}.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya'
|
2022-04-11 13:45:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
'address',
|
|
|
|
|
[
|
2022-05-03 08:26:03 +00:00
|
|
|
|
pytest.param('noat.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya', id='no_at'),
|
2022-04-11 13:45:45 +00:00
|
|
|
|
pytest.param(
|
|
|
|
|
'@toolong.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya',
|
|
|
|
|
id='too_long',
|
|
|
|
|
),
|
|
|
|
|
pytest.param('@test.invalidkey', id='invalid_key'),
|
|
|
|
|
pytest.param(
|
|
|
|
|
'@test.cz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya',
|
|
|
|
|
id='nonprefixed_key',
|
|
|
|
|
),
|
|
|
|
|
pytest.param('@test.many.periods', id='many_periods'),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
def test_valid_address_invalid(address: str) -> None:
|
|
|
|
|
"""Test if valid_address fails for invalid addresses"""
|
|
|
|
|
|
|
|
|
|
assert Identity.valid_address(address) is False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_valid_address() -> None:
|
|
|
|
|
"""Test if valid_address passes on valid addresses"""
|
|
|
|
|
|
2022-05-03 08:26:03 +00:00
|
|
|
|
assert Identity.valid_address('@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya')
|
2022-05-04 11:52:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_eq_str() -> None:
|
|
|
|
|
"""Test if an Identity is considered equal to its string representation"""
|
|
|
|
|
|
|
|
|
|
identity_str = '@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya'
|
|
|
|
|
identity = Identity.from_address(identity_str)
|
|
|
|
|
|
|
|
|
|
assert identity == identity_str
|
|
|
|
|
assert identity != '@test.cz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreyb'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_eq_identity() -> None:
|
|
|
|
|
"""Test if two different identities are considered equal if their verifying key is equal"""
|
|
|
|
|
|
|
|
|
|
identity_str = '@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya'
|
|
|
|
|
identity1 = Identity.from_address(identity_str)
|
|
|
|
|
identity2 = Identity.from_address(identity_str)
|
|
|
|
|
identity3 = Identity.generate('some')
|
|
|
|
|
|
|
|
|
|
assert identity1 == identity2
|
|
|
|
|
assert identity1 != identity3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.id_key_seed(TEST_SEED)
|
|
|
|
|
@pytest.mark.id_name('test')
|
|
|
|
|
def test_eq_other(identity: Identity) -> None:
|
|
|
|
|
"""Test if Identity cannot be compared to something like an int"""
|
|
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
|
assert identity == 1
|
2022-05-04 12:30:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_sign_nokey() -> None:
|
|
|
|
|
"""Test if Identity.sign() fails if the identity doesn’t have a signing key available"""
|
|
|
|
|
|
|
|
|
|
identity_str = '@test.bcz76z52y5dlpohtkmpuj3jsdcvfmebzpcgfmtmhu4u7hlexzreya'
|
|
|
|
|
identity = Identity.from_address(identity_str)
|
|
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
|
identity.sign('test data')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.id_key_seed(TEST_SEED)
|
|
|
|
|
@pytest.mark.id_name('test')
|
|
|
|
|
def test_sign(identity: Identity) -> None:
|
|
|
|
|
"""Test if Identity.sign() works as expected"""
|
|
|
|
|
|
|
|
|
|
assert (
|
|
|
|
|
identity.sign('test data')
|
|
|
|
|
== 'b6gyis42cvdfhsp7xx3jb4773ebbqoq4zhdo4pyeitskefrfkkzxwdkwjkjpq2oyglpngx4tpzzezeedp7eb'
|
|
|
|
|
'x4i3vkpq7wj6odjinacy'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.id_key_seed(TEST_SEED)
|
|
|
|
|
@pytest.mark.id_name('test')
|
|
|
|
|
def test_verify(identity: Identity) -> None:
|
|
|
|
|
"""Test if Identity.verify works as expected"""
|
|
|
|
|
|
|
|
|
|
assert (
|
|
|
|
|
identity.verify(
|
|
|
|
|
'test data',
|
|
|
|
|
'b6gyis42cvdfhsp7xx3jb4773ebbqoq4zhdo4pyeitskefrfkkzxwdkwjkjpq2oyglpngx4tpzzezeedp7eb'
|
|
|
|
|
'x4i3vkpq7wj6odjinacy',
|
|
|
|
|
)
|
|
|
|
|
is True
|
|
|
|
|
)
|
|
|
|
|
assert (
|
|
|
|
|
identity.verify(
|
|
|
|
|
'test date',
|
|
|
|
|
'b6gyis42cvdfhsp7xx3jb4773ebbqoq4zhdo4pyeitskefrfkkzxwdkwjkjpq2oyglpngx4tpzzezeedp7eb'
|
|
|
|
|
'x4i3vkpq7wj6odjinacy',
|
|
|
|
|
)
|
|
|
|
|
is False
|
|
|
|
|
)
|
|
|
|
|
assert (
|
|
|
|
|
identity.verify(
|
|
|
|
|
'test data',
|
|
|
|
|
'b6gyis42cvdfhsp7xx3jb4773ebbqoq4zhdo4pyeitskefrfkkzxwdkwjkjpq2oyglpngx4tpzzezeedp7eb'
|
|
|
|
|
'x4i3vkpq7wj6odjinacq',
|
|
|
|
|
)
|
|
|
|
|
is False
|
|
|
|
|
)
|