test_natural_sort.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. """Storage locations sort naturally, not lexicographically (issue: "Drybox 2"
  2. belongs before "Drybox 10")."""
  3. from backend.app.utils.natural_sort import natural_sort_key
  4. def test_orders_embedded_numbers_by_value_not_by_character():
  5. names = ["Drybox 10", "Drybox 2", "Drybox 1"]
  6. assert sorted(names, key=natural_sort_key) == ["Drybox 1", "Drybox 2", "Drybox 10"]
  7. def test_matches_plain_alphabetical_order_when_there_are_no_digits():
  8. names = ["Shelf B", "Shelf A", "Shelf C"]
  9. assert sorted(names, key=natural_sort_key) == ["Shelf A", "Shelf B", "Shelf C"]
  10. def test_is_case_insensitive():
  11. names = ["shelf", "Drybox", "SHELF A"]
  12. assert sorted(names, key=natural_sort_key) == ["Drybox", "shelf", "SHELF A"]
  13. def test_names_with_no_digits_sort_before_the_same_prefix_with_a_number():
  14. # "Drybox" (len-1 key) is a prefix of "Drybox 1" (len-3 key); Python
  15. # tuple comparison puts the shorter, exhausted tuple first.
  16. names = ["Drybox 1", "Drybox"]
  17. assert sorted(names, key=natural_sort_key) == ["Drybox", "Drybox 1"]
  18. def test_handles_multiple_number_runs_in_one_name():
  19. names = ["Row 10 Bin 2", "Row 2 Bin 10", "Row 2 Bin 2"]
  20. assert sorted(names, key=natural_sort_key) == ["Row 2 Bin 2", "Row 2 Bin 10", "Row 10 Bin 2"]
  21. def test_does_not_raise_when_a_str_and_int_position_would_otherwise_collide():
  22. # A regression guard for the tuple-comparison hazard described in the
  23. # module docstring: mixing names where a digit run appears at different
  24. # positions must not raise "'<' not supported between instances of 'int'
  25. # and 'str'" — every key's even indices are always str and odd indices
  26. # are always int, so this must simply sort without error.
  27. names = ["A1", "1A", "AA", "11"]
  28. result = sorted(names, key=natural_sort_key)
  29. assert set(result) == set(names)