diff --git a/iota/crypto/types.py b/iota/crypto/types.py index e0597db..c868940 100644 --- a/iota/crypto/types.py +++ b/iota/crypto/types.py @@ -112,6 +112,11 @@ class Seed(TryteString): - https://iota.stackexchange.com/q/249 """ + LEN = 81 + """ + Length of a Seed. + """ + def __init__(self, trytes=None): # type: (Optional[TrytesCompatible]) -> None if trytes and len(trytes) > Hash.LEN: diff --git a/iota/types.py b/iota/types.py index 5f5567c..9ce1d19 100644 --- a/iota/types.py +++ b/iota/types.py @@ -68,12 +68,12 @@ class TryteString(JsonSerializable): """ @classmethod - def random(cls, length): - # type: (int) -> TryteString + def random(cls, length=None): + # type: (Optional[int]) -> TryteString """ Generates a random sequence of trytes. - :param int length: + :param Optional[int] length: Number of trytes to generate. :return: @@ -81,6 +81,15 @@ def random(cls, length): """ alphabet = list(itervalues(AsciiTrytesCodec.alphabet)) generator = SystemRandom() + try: + if length is None: + length = cls.LEN + + if length <= 0: + raise TypeError("length parameter needs to be greater than zero") + except AttributeError: # class has no LEN attribute + if length is None: + raise TypeError("{class_name} does not define a length property".format(class_name=cls.__name__)) # :py:meth:`SystemRandom.choices` wasn't added until Python 3.6; # for compatibility, we will continue to use ``choice`` in a diff --git a/test/crypto/types_test.py b/test/crypto/types_test.py index 39164c3..55682f4 100644 --- a/test/crypto/types_test.py +++ b/test/crypto/types_test.py @@ -79,6 +79,12 @@ def test_init_error_too_short(self): with self.assertRaises(ValueError): Digest(b'9' * (2 * Hash.LEN - 1)) + def test_random(self): + """ + Generating a random Digest should fail. + """ + with self.assertRaises(TypeError): + random_digest = Digest.random() # noinspection SpellCheckingInspection class PrivateKeyTestCase(TestCase): @@ -152,3 +158,10 @@ def test_get_digest_multiple_fragments(self): # # Each fragment is processed independently, which is critical for # multisig to work correctly. + + def test_random(self): + """ + Generating a random PrivateKey should fail. + """ + with self.assertRaises(TypeError): + random_digest = PrivateKey.random() diff --git a/test/transaction/types_test.py b/test/transaction/types_test.py index 6cbf1bf..c39570b 100644 --- a/test/transaction/types_test.py +++ b/test/transaction/types_test.py @@ -6,7 +6,8 @@ from six import binary_type -from iota import TransactionHash +from iota import TransactionHash, BundleHash, Fragment, TransactionTrytes, \ + Nonce class TransactionHashTestCase(TestCase): @@ -39,3 +40,42 @@ def test_init_error_too_long(self): b'JVMTDGDPDFYHMZPMWEKKANBQSLSDTIIHAYQUMZOK' b'HXXXGJHJDQPOMDOMNRDKYCZRUFZROZDADTHZC99999' ) + + def test_random(self): + """ + Creating a random TransactionHash object. + """ + random_tx_hash = TransactionHash.random() + self.assertEqual(len(random_tx_hash), TransactionHash.LEN) + +class BundleHashTestCase(TestCase): + def test_random(self): + """ + Creating a random BundleHash object. + """ + random_bundle_hash = BundleHash.random() + self.assertEqual(len(random_bundle_hash), BundleHash.LEN) + +class FragmentTestCase(TestCase): + def test_random(self): + """ + Creating a random Fragment object. + """ + random_fragment = Fragment.random() + self.assertEqual(len(random_fragment), Fragment.LEN) + +class TransactionTrytesTestCase(TestCase): + def test_random(self): + """ + Creating a random TransactionTrytes object. + """ + random_tx_trytes = TransactionTrytes.random() + self.assertEqual(len(random_tx_trytes), TransactionTrytes.LEN) + +class NonceTestCase(TestCase): + def test_random(self): + """ + Creating a random Nonce object. + """ + random_nonce = Nonce.random() + self.assertEqual(len(random_nonce), Nonce.LEN) \ No newline at end of file diff --git a/test/types_test.py b/test/types_test.py index bdf4a10..2127d6c 100644 --- a/test/types_test.py +++ b/test/types_test.py @@ -754,6 +754,20 @@ def test_random(self): # generated. self.assertEqual(len(trytes), Hash.LEN) + def test_random_no_length(self): + """ + Trying to create a random TryteString without specifying length. + """ + with self.assertRaises(TypeError): + trytes = TryteString.random() + + def test_random_wrong_length(self): + """ + Generating random Trytestring with negative length. + """ + with self.assertRaises(TypeError): + trytes = TryteString.random(length=-5) + def test_from_bytes(self): """ Converting a sequence of bytes into a TryteString. @@ -883,6 +897,14 @@ def test_from_trits_wrong_length_padded(self): b'RBTC', ) +class HashTestCase(TestCase): + def test_random(self): + """ + Generating a random Hash. + """ + rand = Hash.random() + self.assertEqual(len(rand), Hash.LEN) + # noinspection SpellCheckingInspection class AddressTestCase(TestCase): @@ -1124,6 +1146,12 @@ def test_remove_checksum_second_time(self): self.assertFalse(addy.is_checksum_valid()) self.assertTrue(len(addy) == Address.LEN) + def test_random(self): + """ + Creating a random Address object. + """ + addy = Address.random() + self.assertEqual(len(addy), Address.LEN) # noinspection SpellCheckingInspection class AddressChecksumTestCase(TestCase): @@ -1149,6 +1177,13 @@ def test_init_error_too_long(self): # If it's an address checksum, it must be 9 trytes exactly. AddressChecksum(b'FOXM9MUBX9') + def test_random(self): + """ + Creating a random AddressChecksum object. + """ + checksum = AddressChecksum.random() + self.assertEqual(len(checksum), AddressChecksum.LEN) + # noinspection SpellCheckingInspection class TagTestCase(TestCase): @@ -1167,3 +1202,10 @@ def test_init_error_too_long(self): with self.assertRaises(ValueError): # 28 chars = no va. Tag(b'COLOREDCOINS9999999999999999') + + def test_random(self): + """ + Creating a random Tag object. + """ + tag = Tag.random() + self.assertEqual(len(tag), Tag.LEN) \ No newline at end of file