252 lines
6.4 KiB
Python
252 lines
6.4 KiB
Python
import pytest
|
|
|
|
from myutils.ProxyObject import ProxyObject
|
|
|
|
|
|
# Test fixtures
|
|
class Person:
|
|
def __init__(self, name, age):
|
|
self.name = name
|
|
self.age = age
|
|
|
|
|
|
class City:
|
|
def __init__(self, name, zip_code):
|
|
self.name = name
|
|
self.zip_code = zip_code
|
|
|
|
|
|
class Address:
|
|
def __init__(self, city, country):
|
|
self.city = city
|
|
self.country = country
|
|
|
|
|
|
class Employee:
|
|
def __init__(self, name, age, address):
|
|
self.name = name
|
|
self.age = age
|
|
self.address = address
|
|
|
|
|
|
@pytest.fixture
|
|
def person():
|
|
return Person("John", 30)
|
|
|
|
|
|
@pytest.fixture
|
|
def employee():
|
|
address = Address("Paris", "France")
|
|
return Employee("Alice", 25, address)
|
|
|
|
|
|
# ============================================================================
|
|
# Basic tests
|
|
# ============================================================================
|
|
|
|
def test_i_can_create_proxy_object_with_simple_mapping(person):
|
|
"""
|
|
ProxyObject should be created successfully with a simple mapping.
|
|
"""
|
|
mappings = {"display_name": "name"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
assert isinstance(proxy, ProxyObject)
|
|
|
|
|
|
def test_i_can_access_mapped_property(person):
|
|
"""
|
|
Accessing a mapped property should return the value from the source object.
|
|
"""
|
|
mappings = {"display_name": "name"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
assert proxy.display_name == "John"
|
|
|
|
|
|
def test_i_can_map_nested_properties(employee):
|
|
"""
|
|
Nested properties using dot notation should be mapped correctly.
|
|
"""
|
|
mappings = {"city_name": "address.city"}
|
|
proxy = ProxyObject(employee, mappings)
|
|
|
|
assert proxy.city_name == "Paris"
|
|
|
|
|
|
def test_i_can_map_nested_nested_properties():
|
|
address = Address(City("Paris", "75001"), "France")
|
|
employee2 = Employee("Alice", 25, address)
|
|
mappings = {"city_zip_code": "address.city.zip_code"}
|
|
proxy = ProxyObject(employee2, mappings)
|
|
|
|
assert proxy.city_zip_code == "75001"
|
|
|
|
|
|
def test_i_can_map_multiple_properties(employee):
|
|
"""
|
|
Multiple mappings should work simultaneously.
|
|
"""
|
|
mappings = {
|
|
"full_name": "name",
|
|
"years": "age",
|
|
"city_name": "address.city"
|
|
}
|
|
proxy = ProxyObject(employee, mappings)
|
|
|
|
assert proxy.full_name == "Alice"
|
|
assert proxy.years == 25
|
|
assert proxy.city_name == "Paris"
|
|
|
|
|
|
def test_i_can_manage_wild_card(employee):
|
|
mappings = {"*": ""}
|
|
proxy = ProxyObject(employee, mappings)
|
|
|
|
assert proxy.name == employee.name
|
|
assert proxy.age == employee.age
|
|
assert proxy.address == employee.address
|
|
|
|
|
|
def test_i_can_manage_wild_card_2(employee):
|
|
mappings = {"*": "*"}
|
|
proxy = ProxyObject(employee, mappings)
|
|
|
|
assert proxy.name == employee.name
|
|
assert proxy.age == employee.age
|
|
assert proxy.city == employee.address.city
|
|
assert proxy.country == employee.address.country
|
|
|
|
|
|
def test_i_can_manage_wild_card_on_nested_properties():
|
|
address = Address(City("Paris", "75001"), "France")
|
|
employee2 = Employee("Alice", 25, address)
|
|
|
|
mappings = {"name": "name", "*": "address"}
|
|
proxy = ProxyObject(employee2, mappings)
|
|
|
|
assert proxy.name == employee2.name
|
|
assert proxy.city == employee2.address.city
|
|
assert proxy.country == employee2.address.country
|
|
|
|
|
|
def test_i_can_manage_wild_card_on_multiple_properties():
|
|
address = Address(City("Paris", "75001"), "France")
|
|
employee2 = Employee("Alice", 25, address)
|
|
|
|
mappings = {"*": "address.*"}
|
|
proxy = ProxyObject(employee2, mappings)
|
|
|
|
assert proxy.name == employee2.address.city.name
|
|
assert proxy.zip_code == employee2.address.city.zip_code
|
|
assert proxy.country == employee2.address.country
|
|
|
|
|
|
# ============================================================================
|
|
# Edge case tests
|
|
# ============================================================================
|
|
|
|
def test_i_cannot_access_unmapped_property(person):
|
|
"""
|
|
Accessing an unmapped property should raise AttributeError.
|
|
"""
|
|
mappings = {"display_name": "name"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
with pytest.raises(AttributeError):
|
|
_ = proxy.unknown_property
|
|
|
|
|
|
def test_i_can_handle_missing_source_property(person):
|
|
"""
|
|
When the source property doesn't exist, the proxy should handle it gracefully.
|
|
The current implementation breaks the loop and assigns the last valid value.
|
|
"""
|
|
mappings = {"missing": "non_existent_attr"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
# The property exists in _props (because of break behavior)
|
|
# but contains the original object
|
|
assert proxy.missing == person
|
|
|
|
|
|
def test_i_can_handle_none_values():
|
|
"""
|
|
None values should be handled correctly.
|
|
"""
|
|
person = Person(None, 30)
|
|
mappings = {"display_name": "name"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
assert proxy.display_name is None
|
|
|
|
|
|
# ============================================================================
|
|
# Special methods tests
|
|
# ============================================================================
|
|
|
|
def test_proxy_objects_with_same_props_are_equal(person):
|
|
"""
|
|
Two ProxyObject instances with the same _props should be equal.
|
|
"""
|
|
mappings = {"display_name": "name", "years": "age"}
|
|
proxy1 = ProxyObject(person, mappings)
|
|
proxy2 = ProxyObject(person, mappings)
|
|
|
|
assert proxy1 == proxy2
|
|
|
|
|
|
def test_proxy_objects_with_different_props_are_not_equal(person):
|
|
"""
|
|
Two ProxyObject instances with different _props should not be equal.
|
|
"""
|
|
mappings1 = {"display_name": "name"}
|
|
mappings2 = {"years": "age"}
|
|
proxy1 = ProxyObject(person, mappings1)
|
|
proxy2 = ProxyObject(person, mappings2)
|
|
|
|
assert proxy1 != proxy2
|
|
|
|
|
|
def test_i_can_hash_proxy_object(person):
|
|
"""
|
|
ProxyObject should be hashable and usable in sets/dicts.
|
|
"""
|
|
mappings = {"display_name": "name", "years": "age"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
# Should not raise an exception
|
|
proxy_hash = hash(proxy)
|
|
assert isinstance(proxy_hash, int)
|
|
|
|
# Should be usable in a set
|
|
proxy_set = {proxy}
|
|
assert proxy in proxy_set
|
|
|
|
|
|
def test_repr_shows_key_when_present():
|
|
"""
|
|
When 'key' is present in _props, __repr__ should show it.
|
|
"""
|
|
person = Person("key_value", 30)
|
|
mappings = {"key": "name"}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
repr_str = repr(proxy)
|
|
assert "key=key_value" in repr_str
|
|
|
|
|
|
def test_repr_truncates_long_content(person):
|
|
"""
|
|
When _props content is longer than 50 chars, __repr__ should truncate it.
|
|
"""
|
|
mappings = {
|
|
"very_long_property_name_1": "name",
|
|
"very_long_property_name_2": "age"
|
|
}
|
|
proxy = ProxyObject(person, mappings)
|
|
|
|
repr_str = repr(proxy)
|
|
assert "..." in repr_str
|
|
assert len(repr_str) < 100 # Should be truncated
|