File size: 4,709 Bytes
d90101d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/// Resolves and validates line ranges, ensuring they are always valid
/// and within the specified maximum size.
///
/// # Arguments
/// * `start_line` - Optional starting line position (defaults to 1)
/// * `end_line` - Optional ending line position
/// * `max_size` - The maximum allowed range size
///
/// # Returns
/// A tuple of (start_line, end_line) that is guaranteed to be valid
///
/// # Behavior
/// - If start_line is None, defaults to 1
/// - If end_line is None, defaults to start_line + max_size
/// - If end_line < start_line, swaps them to ensure valid range
/// - If range exceeds max_size, adjusts end_line to stay within limits
/// - Always ensures start_line >= 1
pub fn resolve_range(start_line: Option<u64>, end_line: Option<u64>, max_size: u64) -> (u64, u64) {
    // Handle edge case: if max_size is 0, return minimal valid range
    if max_size == 0 {
        return (1, 1);
    }

    // 1. Normalise incoming values
    let s0 = start_line.unwrap_or(1).max(1);
    let e0 = end_line.unwrap_or(s0.saturating_add(max_size.saturating_sub(1)));

    // 2. Sort them (min → start, max → end) and force start ≥ 1
    let start = s0.min(e0).max(1);
    let mut end = s0.max(e0);

    // 3. Clamp the range length to `max_size`
    end = end.min(start.saturating_add(max_size.saturating_sub(1)));

    (start, end)
}

#[cfg(test)]
mod tests {
    use pretty_assertions::assert_eq;

    use super::*;

    #[test]
    fn test_resolve_range_with_defaults() {
        let fixture = (None, None, 100);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 100);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_start_only() {
        let fixture = (Some(5), None, 50);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (5, 54);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_both_start_and_end() {
        let fixture = (Some(10), Some(20), 100);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (10, 20);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_swapped_start_end() {
        let fixture = (Some(20), Some(10), 100);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (10, 20);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_exceeding_max_size() {
        let fixture = (Some(1), Some(200), 50);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 50);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_zero_start() {
        let fixture = (Some(0), Some(10), 20);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 10);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_zero_end_swapped() {
        let fixture = (Some(5), Some(0), 20);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 5);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_exact_max_size() {
        let fixture = (Some(1), Some(10), 10);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 10);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_max_size_boundary() {
        let fixture = (Some(5), Some(16), 10);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (5, 14);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_large_numbers() {
        let fixture = (Some(1000), Some(2000), 500);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1000, 1499);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_single_line() {
        let fixture = (Some(42), Some(42), 100);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (42, 42);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_end_only() {
        let fixture = (None, Some(50), 100);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 50);
        assert_eq!(actual, expected);
    }

    #[test]
    fn test_resolve_range_with_zero_max_size() {
        let fixture = (None, None, 0);
        let actual = resolve_range(fixture.0, fixture.1, fixture.2);
        let expected = (1, 1);
        assert_eq!(actual, expected);
    }
}