Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-27 08:41:18

0001 import time
0002 
0003 import pytest
0004 
0005 from pyrobird.edm4eic import parse_entry_numbers
0006 from pyrobird.entries import (parse_entry_ranges, count_entries, format_ranges, out_of_range_parts,
0007                               clamp_ranges, select_entries, shorten, EntrySelectionError)
0008 
0009 
0010 @pytest.mark.parametrize("value, expected", [
0011     ('3', [(3, 3)]),
0012     ('1-5', [(1, 5)]),
0013     ('1,2,3', [(1, 1), (2, 2), (3, 3)]),
0014     ('1,2-5,8', [(1, 1), (2, 5), (8, 8)]),
0015     (' 1 - 3 ', [(1, 3)]),
0016 ])
0017 def test_parse_entry_ranges(value, expected):
0018     assert parse_entry_ranges(value) == expected
0019 
0020 
0021 @pytest.mark.parametrize("value", ['5-1', 'abc', '1,a,3', '', '1,,2', '-1', '1-2-3'])
0022 def test_parse_entry_ranges_invalid(value):
0023     with pytest.raises(ValueError, match="Invalid entry format"):
0024         parse_entry_ranges(value)
0025 
0026 
0027 @pytest.mark.parametrize("value", ['3', '1-5', '1,2,3', '1,2-5,8', '0', '7-7', '0,0'])
0028 def test_parse_entry_numbers_matches_ranges(value):
0029     """parse_entry_numbers is the expansion of parse_entry_ranges: one grammar."""
0030     expanded = []
0031     for start, end in parse_entry_ranges(value):
0032         expanded.extend(range(start, end + 1))
0033     assert parse_entry_numbers(value) == expanded
0034 
0035 
0036 def test_huge_range_is_not_expanded():
0037     started = time.perf_counter()
0038     ranges = parse_entry_ranges('0-1000000000000')
0039     assert count_entries(ranges) == 1000000000001
0040     assert out_of_range_parts(ranges, 10) == [(10, 1000000000000)]
0041     with pytest.raises(EntrySelectionError, match="1000000000001 entries; at most 1000"):
0042         select_entries(ranges, 10, max_count=1000)
0043     assert time.perf_counter() - started < 1.0
0044 
0045 
0046 def test_select_entries_in_range():
0047     assert select_entries(parse_entry_ranges('0,2-3'), 5) == ([0, 2, 3], None)
0048 
0049 
0050 def test_select_entries_clamps_to_the_file_with_one_warning():
0051     """Entries outside the file are dropped and summarized once, as the browser converter does."""
0052     selection = select_entries(parse_entry_ranges('0-5'), 2)
0053     assert selection.entries == [0, 1]
0054     assert selection.warning == "Event 2-5 is out of range: the file holds 2 events (0..1); converting 0-1"
0055 
0056 
0057 def test_select_entries_clamps_huge_range_without_expanding_it():
0058     started = time.perf_counter()
0059     selection = select_entries(parse_entry_ranges('3-1000000000000'), 5)
0060     assert selection.entries == [3, 4]
0061     assert "Event 5-1000000000000 is out of range" in selection.warning
0062     assert time.perf_counter() - started < 1.0
0063 
0064 
0065 def test_select_entries_keeps_requested_order_and_repeats():
0066     selection = select_entries(parse_entry_ranges('4,9,1-2,1'), 5)
0067     assert selection.entries == [4, 1, 2, 1]
0068     assert selection.warning == "Event 9 is out of range: the file holds 5 events (0..4); converting 4, 1-2, 1"
0069 
0070 
0071 def test_select_entries_with_no_entry_in_the_file_is_an_error():
0072     with pytest.raises(EntrySelectionError) as info:
0073         select_entries(parse_entry_ranges('50-60'), 10)
0074     assert str(info.value) == "Event 50-60 is out of range: the file holds 10 events (0..9)"
0075 
0076 
0077 def test_select_entries_empty_file():
0078     with pytest.raises(EntrySelectionError, match="the file holds no events"):
0079         select_entries(parse_entry_ranges('0'), 0)
0080 
0081 
0082 def test_size_limit_counts_the_request_before_the_clamp():
0083     """The cap guards the request itself: '0-1999' on a 10-entry file stays rejected."""
0084     with pytest.raises(EntrySelectionError, match="2000 entries; at most 1000"):
0085         select_entries(parse_entry_ranges('0-1999'), 10, max_count=1000)
0086 
0087 
0088 def test_select_entries_of_an_empty_selection_is_empty():
0089     assert select_entries([], 5) == ([], None)
0090 
0091 
0092 def test_clamp_ranges():
0093     assert clamp_ranges([(-2, 1), (3, 9), (7, 8)], 5) == [(0, 1), (3, 4)]
0094     assert clamp_ranges([(5, 9)], 5) == []
0095 
0096 
0097 def test_out_of_range_parts_negative_and_high():
0098     assert out_of_range_parts([(-2, 10)], 5) == [(-2, -1), (5, 10)]
0099     assert out_of_range_parts([(1, 3)], 5) == []
0100 
0101 
0102 def test_error_listing_is_truncated():
0103     ranges = parse_entry_ranges('10,12,14,16,18,20,22,24')
0104     with pytest.raises(EntrySelectionError) as info:
0105         select_entries(ranges, 5)
0106     assert "Event 10, 12, 14, 16, 18 (and 3 more) is out of range" in str(info.value)
0107 
0108 
0109 def test_warning_listing_is_truncated():
0110     selection = select_entries(parse_entry_ranges('0,10,12,14,16,18,20,22,24'), 5)
0111     assert selection.entries == [0]
0112     assert selection.warning.startswith("Event 10, 12, 14, 16, 18 (and 3 more) is out of range")
0113 
0114 
0115 def test_format_ranges():
0116     assert format_ranges([(1, 1), (3, 5)]) == "1, 3-5"
0117 
0118 
0119 def test_shorten():
0120     assert shorten('abc', 5) == 'abc'
0121     assert shorten('a' * 10, 5) == 'aaaaa...'