linsel 0.1.0-alpha.1

A small program to print out selected lines of a file
Documentation
// SPDX-FileCopyrightText: 2026 David Zaslavsky <diazona@ellipsix.net>
//
// SPDX-License-Identifier: GPL-3.0-or-later

use linsel::{CreateRangeError, ParseRangeError, Range, RangeElement};

// Range creation tests

/// "Canary" test that the constructor works in normal situations.
#[test]
fn create_simple_range() {
    let _ = Range::new(1, 1, 1);
}

/// Test that the correct error is returned when `start > end`.
#[test]
fn inverted_bounds_error() {
    let result = Range::new(2, 1, 1);
    assert_eq!(result, Err(CreateRangeError::InvertedBounds(2, 1)));
}

/// Test that the correct error is returned when `step == 0`.
#[test]
fn zero_step_error() {
    let result = Range::new(1, 1, 0);
    assert_eq!(result, Err(CreateRangeError::NonPositiveStep(0)));
}

// Range API tests

/// Test that `contains()` returns `true` for the value inside a range of one
/// element.
#[test]
fn length_one_range_contains_value() {
    let result = Range::new(1, 1, 1).unwrap();
    assert!(result.contains(1));
}

/// Test that `contains()` returns `true` for the start point of a length-two
/// range.
#[test]
fn length_two_range_contains_start() {
    let result = Range::new(1, 2, 1).unwrap();
    assert!(result.contains(1));
}

/// Test that `contains()` returns `true` for the end point of a length-two
/// range.
#[test]
fn length_two_range_contains_end() {
    let result = Range::new(1, 2, 1).unwrap();
    assert!(result.contains(2));
}

/// Test that `contains()` returns `true` for the start point of an arbitrary
/// length range.
#[test]
fn range_contains_start() {
    let result = Range::new(1, 10, 1).unwrap();
    assert!(result.contains(1));
}

/// Test that `contains()` returns `true` for the end point of an arbitrary
/// length range.
#[test]
fn range_contains_end() {
    let result = Range::new(1, 10, 1).unwrap();
    assert!(result.contains(10));
}

/// Test that `contains()` returns `true` for a value that is neither the start
/// nor end of the range.
#[test]
fn range_contains_interior_value() {
    let result = Range::new(1, 10, 1).unwrap();
    assert!(result.contains(5));
}

/// Test that `contains()` returns `false` for a value before the range start.
#[test]
fn range_does_not_contain_value_before_start() {
    let result = Range::new(2, 10, 1).unwrap();
    assert!(!result.contains(1));
}

/// Test that `contains()` returns `false` for a value after the range end.
#[test]
fn range_does_not_contain_value_before_end() {
    let result = Range::new(2, 10, 1).unwrap();
    assert!(!result.contains(11));
}

// Non-unit step

/// Test that `contains()` returns `true` for the value inside a range of one
/// element with a larger step size.
#[test]
fn length_one_range_with_non_unit_step_contains_value() {
    // The step may be normalized to 1 inside the constructor, but that's not
    // part of the API so we test as though it doesn't happen.
    let result = Range::new(1, 1, 2).unwrap();
    assert!(result.contains(1));
}

/// Test that `contains()` returns `true` for the start point of a length-two
/// range with a non-unit step.
#[test]
fn length_two_range_with_non_unit_step_contains_start() {
    let result = Range::new(1, 2, 2).unwrap();
    assert!(result.contains(1));
}

/// Test that `contains()` returns `false` for the end point of a length-two
/// range with a non-unit step.
#[test]
fn length_two_range_with_non_unit_step_contains_end() {
    let result = Range::new(1, 2, 2).unwrap();
    assert!(!result.contains(2));
}

/// Test that `contains()` returns `true` for the start point of an arbitrary
/// length range with a non-unit step.
#[test]
fn range_with_non_unit_step_contains_start() {
    let result = Range::new(1, 9, 2).unwrap();
    assert!(result.contains(1));
}

/// Test that `contains()` returns `true` for the end point of an arbitrary
/// length range with a non-unit step.
#[test]
fn range_with_non_unit_step_contains_end() {
    let result = Range::new(1, 9, 2).unwrap();
    assert!(result.contains(9));
}

// Range parsing tests

#[test]
fn one() {
    let result = "1".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(1, 1, 1).unwrap());
}

#[test]
fn u32max() {
    let result = "4294967296".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(4294967296, 4294967296, 1).unwrap());
}

#[test]
fn i32max() {
    let result = "2147483648".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(2147483648, 2147483648, 1).unwrap());
}

#[test]
fn zero() {
    let result = "0".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(0, 0, 1).unwrap());
}

#[test]
fn empty_input() {
    let result = "".parse::<Range>();
    assert_eq!(result, Err(ParseRangeError::EmptyString))
}

#[test]
fn simple_range() {
    let result = "1-10".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(1, 10, 1).unwrap());
}

#[test]
fn range_without_start() {
    let result = "-10".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(RangeElement::MIN, 10, 1).unwrap());
}

#[test]
fn range_without_end() {
    let result = "1-".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(1, RangeElement::MAX, 1).unwrap());
}

#[test]
fn large_range() {
    let result = "1-2147483648".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(1, 2147483648, 1).unwrap());
}

#[test]
fn range_with_step() {
    let result = "1-100/10".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(1, 100, 10).unwrap());
}

#[test]
fn range_without_start_with_step() {
    let result = "-10/2".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(RangeElement::MIN, 10, 2).unwrap());
}

#[test]
fn range_without_end_with_step() {
    let result = "1-/2".parse::<Range>().unwrap();
    assert_eq!(result, Range::new(1, RangeElement::MAX, 2).unwrap());
}