from src.core.utils import FilterConf, SortConf, sort_by from src.core.Expando import Expando def test_i_can_sort_by_ascending_strings(): """Test sorting strings in ascending order.""" items = [ Expando({"name": "charlie"}), Expando({"name": "alice"}), Expando({"name": "bob"}) ] sort_conf = SortConf(property="name", ascending=True) result = sort_by(items, sort_conf) assert len(result) == 3 assert result[0].name == "alice" assert result[1].name == "bob" assert result[2].name == "charlie" def test_i_can_sort_by_descending_strings(): """Test sorting strings in descending order.""" items = [ Expando({"name": "alice"}), Expando({"name": "charlie"}), Expando({"name": "bob"}) ] sort_conf = SortConf(property="name", ascending=False) result = sort_by(items, sort_conf) assert len(result) == 3 assert result[0].name == "charlie" assert result[1].name == "bob" assert result[2].name == "alice" def test_i_can_handle_none_sort_conf(): """Test that None sort configuration returns items unchanged.""" items = [ Expando({"name": "charlie"}), Expando({"name": "alice"}) ] result = sort_by(items, None) assert result == items assert result[0].name == "charlie" assert result[1].name == "alice" def test_i_can_handle_empty_list(): """Test that empty list returns empty list.""" items = [] sort_conf = SortConf(property="name") result = sort_by(items, sort_conf) assert result == [] def test_i_can_sort_with_missing_properties(): """Test sorting when some objects don't have the property.""" items = [ Expando({"name": "bob"}), Expando({"age": 25}), # no name property Expando({"name": "alice"}) ] sort_conf = SortConf(property="name", ascending=True) result = sort_by(items, sort_conf) assert len(result) == 3 # Items without the property should get empty string and sort first assert result[0].geti("name", "") == "" # the one with missing property assert result[1].name == "alice" assert result[2].name == "bob" def test_i_can_sort_with_none_values(): """Test sorting when properties have None values.""" items = [ Expando({"name": "bob"}), Expando({"name": None}), Expando({"name": "alice"}) ] sort_conf = SortConf(property="name", ascending=True) result = sort_by(items, sort_conf) assert len(result) == 3 # None values should be treated as empty strings and sort first assert result[0].name is None assert result[1].name == "alice" assert result[2].name == "bob" def test_i_can_sort_with_case_insensitive_property_names(): """Test sorting using case-insensitive property names.""" items = [ Expando({"Name": "charlie"}), # uppercase N Expando({"Name": "alice"}), Expando({"Name": "bob"}) ] sort_conf = SortConf(property="name", ascending=True) # lowercase n result = sort_by(items, sort_conf) assert len(result) == 3 assert result[0].Name == "alice" assert result[1].Name == "bob" assert result[2].Name == "charlie" def test_i_can_sort_mixed_types(): """Test sorting with mixed types (numbers, strings, None).""" items = [ Expando({"value": "zebra"}), Expando({"value": 10}), Expando({"value": None}), Expando({"value": "apple"}) ] sort_conf = SortConf(property="value", ascending=True) result = sort_by(items, sort_conf) assert len(result) == 4 # Mixed types will be converted to strings for comparison # None -> "", numbers -> str(number), strings stay strings assert result[0].value is None # None becomes "" and sorts first assert result[1].value == 10 # "10" sorts before "apple" assert result[2].value == "apple" # "apple" sorts before "zebra" assert result[3].value == "zebra" def test_i_can_sort_with_whitespace_in_property_name(): """Test that property names are stripped of whitespace.""" items = [ Expando({"name": "charlie"}), Expando({"name": "alice"}), Expando({"name": "bob"}) ] sort_conf = SortConf(property=" name ", ascending=True) # whitespace around property result = sort_by(items, sort_conf) assert len(result) == 3 assert result[0].name == "alice" assert result[1].name == "bob" assert result[2].name == "charlie"