diff --git a/src/uas_standards/ansi_cta_2063_a.py b/src/uas_standards/ansi_cta_2063_a.py index 0fee7d6..abd3d3b 100644 --- a/src/uas_standards/ansi_cta_2063_a.py +++ b/src/uas_standards/ansi_cta_2063_a.py @@ -1,5 +1,6 @@ from __future__ import annotations import random +from typing import Optional class SerialNumber(str): @@ -35,18 +36,23 @@ def valid(self) -> bool: return False return True - def make_invalid_by_changing_payload_length(self) -> SerialNumber: + def make_invalid_by_changing_payload_length(self, r: Optional[random.Random] = None) -> SerialNumber: """Generates an invalid serial number similar to this serial number.""" + if r is None: + r = random my_length = self.length_code lengths_except_mine = [ c for c in SerialNumber.length_code_points if c != my_length ] - new_length_code = random.choice(lengths_except_mine) + new_length_code = r.choice(lengths_except_mine) k = SerialNumber.length_code_points.index(new_length_code) + 1 - random_serial_number = "".join(random.choices(SerialNumber.code_points, k=k)) - return SerialNumber( - self.manufacturer_code + self.length_code + random_serial_number - ) + while True: + random_serial_number = "".join(r.choices(SerialNumber.code_points, k=k)) + result = SerialNumber( + self.manufacturer_code + self.length_code + random_serial_number + ) + if not result.valid: + return result @staticmethod def from_components( @@ -61,9 +67,11 @@ def from_components( ) @staticmethod - def generate_valid() -> SerialNumber: + def generate_valid(r: Optional[random.Random] = None) -> SerialNumber: """Generates a valid and random UAV serial number per ANSI/CTA-2063-A.""" - manufacturer_code = "".join(random.choices(SerialNumber.code_points, k=4)) - k = random.randrange(0, len(SerialNumber.length_code_points)) + 1 - random_serial_number = "".join(random.choices(SerialNumber.code_points, k=k)) + if r is None: + r = random + manufacturer_code = "".join(r.choices(SerialNumber.code_points, k=4)) + k = r.randrange(0, len(SerialNumber.length_code_points)) + 1 + random_serial_number = "".join(r.choices(SerialNumber.code_points, k=k)) return SerialNumber.from_components(manufacturer_code, random_serial_number) diff --git a/src/uas_standards/en4709_02.py b/src/uas_standards/en4709_02.py index 38ecbd6..111e610 100644 --- a/src/uas_standards/en4709_02.py +++ b/src/uas_standards/en4709_02.py @@ -1,6 +1,7 @@ from __future__ import annotations import random import string +from typing import Optional class OperatorRegistrationNumber(str): @@ -65,16 +66,21 @@ def valid(self) -> bool: return self.checksum == checksum def make_invalid_by_changing_final_control_string( - self, + self, r: Optional[random.Random] = None ) -> OperatorRegistrationNumber: """A method to generate an invalid Operator Registration number by replacing the control string""" - new_random_string = "".join( - random.choice(string.ascii_lowercase) - for _ in range(OperatorRegistrationNumber.final_random_string_length) - ) - return OperatorRegistrationNumber( - self.checksum_control + "-" + new_random_string - ) + if r is None: + r = random + while True: + new_random_string = "".join( + r.choice(string.ascii_lowercase) + for _ in range(OperatorRegistrationNumber.final_random_string_length) + ) + result = OperatorRegistrationNumber( + self.checksum_control + "-" + new_random_string + ) + if not result.valid: + return result @staticmethod def validate_prefix(prefix: str) -> None: @@ -142,14 +148,16 @@ def generate_checksum(base_id: str, final_random_string: str) -> str: ] @staticmethod - def generate_valid(prefix: str) -> OperatorRegistrationNumber: + def generate_valid(prefix: str, r: Optional[random.Random] = None) -> OperatorRegistrationNumber: """Generate a random operator registration number with the specified prefix""" + if r is None: + r = random final_random_string = "".join( - random.choice(string.ascii_lowercase) + r.choice(string.ascii_lowercase) for _ in range(OperatorRegistrationNumber.final_random_string_length) ) base_id = "".join( - random.choice(string.ascii_lowercase + string.digits) + r.choice(string.ascii_lowercase + string.digits) for _ in range(OperatorRegistrationNumber.base_id_length) ) return OperatorRegistrationNumber.from_components( diff --git a/tests/test_ansi_cta_2063_a.py b/tests/test_ansi_cta_2063_a.py index 28deb66..b03ab99 100644 --- a/tests/test_ansi_cta_2063_a.py +++ b/tests/test_ansi_cta_2063_a.py @@ -1,10 +1,13 @@ import json +import random from uas_standards.ansi_cta_2063_a import SerialNumber def test_basic_usage(): - sn = SerialNumber.generate_valid() + r = random.Random(12345) + + sn = SerialNumber.generate_valid(r) assert sn.valid sn2 = SerialNumber.from_components(sn.manufacturer_code, sn.manufacturer_serial_number) @@ -16,6 +19,6 @@ def test_basic_usage(): assert sn3.valid assert sn3 == sn - sn_invalid = sn.make_invalid_by_changing_payload_length() + sn_invalid = sn.make_invalid_by_changing_payload_length(r) assert sn.valid assert not sn_invalid.valid diff --git a/tests/test_en4709_02.py b/tests/test_en4709_02.py index 6098ab5..13f2fd1 100644 --- a/tests/test_en4709_02.py +++ b/tests/test_en4709_02.py @@ -1,11 +1,14 @@ import json +import random import pytest from uas_standards.en4709_02 import OperatorRegistrationNumber def test_basic_usage(): - rn = OperatorRegistrationNumber.generate_valid('EXM') + r = random.Random(12345) + + rn = OperatorRegistrationNumber.generate_valid('EXM', r) assert rn.valid OperatorRegistrationNumber.validate_prefix(rn.prefix) OperatorRegistrationNumber.validate_base_id(rn.base_id) @@ -20,7 +23,7 @@ def test_basic_usage(): assert rn3.valid assert rn3 == rn - rn_invalid = rn.make_invalid_by_changing_final_control_string() + rn_invalid = rn.make_invalid_by_changing_final_control_string(r) assert rn.valid assert not rn_invalid.valid OperatorRegistrationNumber.validate_prefix(rn_invalid.prefix)