diff --git a/CHANGELOG.md b/CHANGELOG.md index a2f1340f6..d5fb986b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. ## [Unreleased] ### Added +- Added unit test for 'endpoint.py' to increase coverage. - Automated assignment guard for `advanced` issues; requires completion of at least one `good first issue` and one `intermediate` issue before assignment (exempts maintainers, committers, and triage members). (#1142) - Added Hbar object support for TransferTransaction HBAR transfers: - Methods now accept `Union[int, Hbar]` for amount parameters with immediate normalization to tinybars diff --git a/tests/unit/endpoint_test.py b/tests/unit/endpoint_test.py new file mode 100644 index 000000000..35f7c62d0 --- /dev/null +++ b/tests/unit/endpoint_test.py @@ -0,0 +1,119 @@ +import pytest +from unittest.mock import MagicMock +from src.hiero_sdk_python.address_book.endpoint import Endpoint + +pytestmark = pytest.mark.unit + + +def test_getter_setter(): # type: ignore + + """Test for Endpoint constructor, getters, and setters with fluent interface.""" + + endpoint = Endpoint(address=None, port=None, domain_name=None) + + # Test fluent interface (method chaining) + result = endpoint.set_address(b'127.0.1.1') + assert result is endpoint, "set_address should return self for method chaining" + + result = endpoint.set_port(77777) + assert result is endpoint, "set_port should return self for method chaining" + + result = endpoint.set_domain_name("redpanda.com") + assert result is endpoint, "set_domain_name should return self for method chaining" + + # Protect against breaking changes - verify attributes exist + assert hasattr(endpoint, 'get_address'), "Missing get_address method" + assert hasattr(endpoint, 'get_port'), "Missing get_port method" + assert hasattr(endpoint, 'get_domain_name'), "Missing get_domain_name method" + + assert endpoint.get_address() == b'127.0.1.1' + assert endpoint.get_port() == 77777 + assert endpoint.get_domain_name() == "redpanda.com" + + +def test_constructor_with_values(): + """Test Endpoint constructor with actual values.""" + endpoint = Endpoint(address=b'192.168.1.1', port=8080, domain_name="example.com") + + assert endpoint.get_address() == b'192.168.1.1' + assert endpoint.get_port() == 8080 + assert endpoint.get_domain_name() == "example.com" + +@pytest.mark.parametrize("input_port, expected_port", [ + (0, 50211), # Default port mapping when port is 0 + (50111, 50211), # Legacy port 50111 maps to new port 50211 + (80, 80) # Standard ports pass through unchanged +]) + +def test_from_proto_port_mapping(input_port, expected_port): + """Tests the logic that converts a Protobuf ServiceEndpoint into an Endpoint object.""" + + mock_proto = MagicMock() + mock_proto.port = input_port + mock_proto.ipAddressV4 = b"127.0.1.1" + mock_proto.domain_name = "redpanda.com" + + endpoint = Endpoint._from_proto(mock_proto) + + # Verify port mapping + assert endpoint.get_port() == expected_port + + # Verify all fields are mapped correctly + assert endpoint.get_address() == b"127.0.1.1", "Address should be mapped from proto" + assert endpoint.get_domain_name() == "redpanda.com", "Domain name should be mapped from proto" + + # Protect against breaking changes - verify return type + assert isinstance(endpoint, Endpoint), "Should return Endpoint instance" + +def test_to_proto(): + + '''Verifies that an Endpoint instance can be correctly serialized back into + a Protobuf ServiceEndpoint object with all fields intact.''' + + endpoint = Endpoint(address=b'127.0.1.1', port=77777, domain_name="redpanda.com") + proto = endpoint._to_proto() + assert proto.ipAddressV4 == b'127.0.1.1' + assert proto.port == 77777 + assert proto.domain_name == "redpanda.com" + +def test_str(): + + """Tests the human-readable string representation of the Endpoint.""" + + endpoint = Endpoint(address=b'127.0.1.1', port=77777, domain_name="redpanda.com") + result = str(endpoint) + + # Verify return type + assert isinstance(result, str), "String representation should return a string" + assert result == '127.0.1.1:77777' + + +def test_str_with_none_values(): + """Test string representation when address or port is None.""" + endpoint = Endpoint(address=b"", port=None, domain_name="example.com") + result = str(endpoint) + + assert isinstance(result, str), "Should return string even with None values" + # Verify it doesn't raise an exception and returns something meaningful + assert result is not None and len(result) > 0, "Should produce non-empty string representation" + +def test_from_dict_error(): + + '''Validates 'Guard Clause' error handling''' + + invalid_data = {"port": 77777} + with pytest.raises(ValueError, match="JSON data must contain"): + Endpoint.from_dict(invalid_data) + +def test_from_dict_success(): + ''' Tests successful creation of an Endpoint from a dictionary (JSON format) ''' + data = { + "ip_address_v4": "127.0.0.1", + "port": 77777, + "domain_name": "redpanda.com" + } + endpoint = Endpoint.from_dict(data) + + assert endpoint.get_address() == b"127.0.0.1" + assert endpoint.get_port() == 77777 + assert endpoint.get_domain_name() == "redpanda.com" \ No newline at end of file