103 lines
3.1 KiB
Python
103 lines
3.1 KiB
Python
""" test copying PGP objects
|
|
"""
|
|
from __future__ import print_function
|
|
import pytest
|
|
|
|
import copy
|
|
import glob
|
|
import inspect
|
|
import os.path
|
|
import six
|
|
|
|
import pgpy
|
|
|
|
from pgpy import PGPSignature, PGPUID, PGPMessage, PGPKey
|
|
|
|
|
|
_keys = glob.glob('tests/testdata/keys/*.1.pub.asc') + glob.glob('tests/testdata/keys/*.1.sec.asc')
|
|
_msgs = [ 'tests/testdata/messages/message.{}.asc'.format(f) for f in ['signed', 'rsa.cast5.no-mdc', 'rsa.dsa.pass.aes']]
|
|
|
|
|
|
def sig():
|
|
return PGPSignature.from_file('tests/testdata/blocks/rsasignature.asc')
|
|
|
|
|
|
def uid():
|
|
return PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='abraham.lincoln@whitehouse.gov')
|
|
|
|
|
|
def key(fn):
|
|
key, _ = PGPKey.from_file(fn)
|
|
return key
|
|
|
|
|
|
def walk_obj(obj, prefix=""):
|
|
from enum import Enum
|
|
|
|
for name, val in inspect.getmembers(obj):
|
|
if hasattr(obj.__class__, name):
|
|
continue
|
|
|
|
yield '{}{}'.format(prefix, name), val
|
|
|
|
if not isinstance(val, Enum):
|
|
for n, v in walk_obj(val, prefix="{}{}.".format(prefix, name)):
|
|
yield n, v
|
|
|
|
|
|
def check_id(obj):
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
# do some type checking to determine if we should check the identity of an object member
|
|
# these types are singletons
|
|
if isinstance(obj, (Enum, bool, type(None))):
|
|
return False
|
|
|
|
# these types are immutable
|
|
if isinstance(obj, (six.string_types, datetime)):
|
|
return False
|
|
|
|
# integers are kind of a special case.
|
|
# ints that do not exceed sys.maxsize are singletons, and in either case are immutable
|
|
# this shouldn't apply to MPIs, though, which are subclasses of int
|
|
if isinstance(obj, int) and not isinstance(obj, pgpy.packet.types.MPI):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def ksort(key):
|
|
# return a tuple of key, key.count('.') so we get a descending alphabetical, ascending depth ordering
|
|
return key, key.count('.')
|
|
|
|
|
|
objs = [sig(), uid(),] + [PGPMessage.from_file(m) for m in _msgs] + [key(f) for f in _keys]
|
|
cids = ['sig', 'uid',] + [os.path.basename(m) for m in _msgs] + [os.path.basename(f) for f in _keys]
|
|
|
|
|
|
@pytest.mark.parametrize('obj', objs, ids=cids)
|
|
def test_copy_obj(request, obj):
|
|
obj2 = copy.copy(obj)
|
|
|
|
objflat = {name: val for name, val in walk_obj(obj, '{}.'.format(request.node.callspec.id))}
|
|
obj2flat = {name: val for name, val in walk_obj(obj2, '{}.'.format(request.node.callspec.id))}
|
|
|
|
for k in sorted(objflat, key=ksort):
|
|
print("checking attribute: {} ".format(k), end="")
|
|
if isinstance(objflat[k], pgpy.types.SorteDeque):
|
|
print("[SorteDeque] ", end="")
|
|
assert len(objflat[k]) == len(obj2flat[k])
|
|
|
|
if not isinstance(objflat[k], (pgpy.types.PGPObject, pgpy.types.SorteDeque)):
|
|
print("[{} ]".format(type(objflat[k])), end="")
|
|
assert objflat[k] == objflat[k], k
|
|
|
|
# check identity, but only types that should definitely be copied
|
|
if check_id(objflat[k]):
|
|
print("[id] {}".format(type(objflat[k])))
|
|
assert objflat[k] is not obj2flat[k], "{}: {}".format(type(objflat[k]), k)
|
|
|
|
else:
|
|
print()
|