#!/usr/bin/ruby

var r = range(101, -Inf, -2)

assert(!r.contains(30))
assert(!r.contains(2))

r = range(100, -Inf, -2)

assert(r.contains(30))
assert(r.contains(2))

r = range(20, -Inf, -2)

assert(!r.contains(30))
assert(!r.contains(5))
assert(r.contains(2))

r = range(100, -Inf, 2)

assert(!r.contains(30))
assert(!r.contains(2))

r = range(-3, Inf, 2)

assert(!r.contains(30))
assert(!r.contains(2))

r = range(-100, Inf, 2)

assert(r.contains(30))
assert(r.contains(2))
assert(r.contains(132438))

r = range(-3, Inf, 2)

assert(!r.contains(30))
assert(!r.contains(2))
assert(r.contains(5))
assert(r.contains(-3))
assert(!r.contains(-9))

r = range(100, -Inf, -3)

assert(!r.contains(103))
assert(r.contains(73))
assert(r.contains(-531341))
assert(!r.contains(-100))
assert(r.contains(100))

r = (1..100 -> by(0.5))

assert(r.contains(45))
assert(!r.contains(101))
assert(r.contains(100))
assert(!r.contains(0))
assert(r.contains(1))
assert(r.contains(1.5))
assert(!r.contains(1.05))
assert(r.contains(45.5))
assert(!r.contains(45.6))
assert(!r.contains(45.51))
assert(r.contains(2))
assert(r.contains(99.5))
assert(!r.contains(99.9999))

assert_eq('a'..'z' -> first, 'a')
assert_eq('a'..'z' -> first(3), ['a', 'b', 'c'])
assert_eq('p'..'d' -> first(5), [])

assert_eq(1..5   -> first(57), [1,2,3,4,5])
assert_eq(3..10  -> first, 3)
assert_eq(7..3   -> first(10), [])
assert_eq(1..5   -> first(0), [])
assert_eq(1..13  -> first(1), [1])
assert_eq(1..1e9 -> first(-3), [])
assert_eq(1..10  -> reverse.first(2), [10, 9])
assert_eq(1..10  -> by(2).first(3), [1, 3, 5])
assert_eq(-5..10 -> first(8), [-5, -4, -3, -2, -1, 0, 1, 2])

assert_eq(1..10  -> last(3), [8, 9, 10])
assert_eq(-1e9..1e9 -> last(3), [1e9 - 2, 1e9-1, 1e9])
assert_eq('a'..'z' -> last(3), ['x', 'y', 'z'])
assert_eq(1..5 -> last(100), [1,2,3,4,5])
assert_eq(1..5 -> last(-1), [])
assert_eq(1..3 -> last(0), [])
assert_eq(1..17 -> last(1), [17])
assert_eq(1..23 -> last, 23)

assert_eq(-2**63 .. (-2**63 + 10) -> map { _ }, %n(
    -9223372036854775808
    -9223372036854775807
    -9223372036854775806
    -9223372036854775805
    -9223372036854775804
    -9223372036854775803
    -9223372036854775802
    -9223372036854775801
    -9223372036854775800
    -9223372036854775799
    -9223372036854775798
))

assert_eq(-9223372036854775813, Number('-9223372036854775813'))
assert_eq("#{-9223372036854775813}", "-9223372036854775813")

assert_eq(-(2**63) - 5 .. (-(2**63) + 10) -> map { _ }, %n(
    -9223372036854775813
    -9223372036854775812
    -9223372036854775811
    -9223372036854775810
    -9223372036854775809
    -9223372036854775808
    -9223372036854775807
    -9223372036854775806
    -9223372036854775805
    -9223372036854775804
    -9223372036854775803
    -9223372036854775802
    -9223372036854775801
    -9223372036854775800
    -9223372036854775799
    -9223372036854775798
))

assert_eq((2**2048 - 3) .. 2**2048 -> map { _ }, [2**2048 - 3, 2**2048 - 2, 2**2048 - 1, 2**2048])

assert_eq(1 .. 2**2048 -> first(5), [1,2,3,4,5])
assert_eq(-3 .. 2**2048 -> first(7), [-3,-2,-1,0,1,2,3])

assert_eq(2**2048 .. 2**4096 -> first(3), [2**2048, 2**2048 + 1, 2**2048 + 2])

assert_eq(1 .. 100 `by`  Inf -> map { _ }, [1])
assert_eq(100 .. 1 `by` -Inf -> map { _ }, [100])

assert_eq(100 .. 1 `by` NaN -> map { _ }, [])
assert_eq(1 .. 100 `by` NaN -> map { _ }, [])

assert_eq( Inf ..  Inf -> first(3), [ Inf,  Inf,  Inf])
assert_eq(-Inf ..  Inf -> first(3), [-Inf, -Inf, -Inf])
assert_eq(-Inf .. -Inf -> first(3), [-Inf, -Inf, -Inf])

assert_eq( Inf .. Inf `by` Inf -> first(3), [ Inf,  Inf,  Inf])
assert_eq(-Inf .. Inf `by` Inf -> first(3), [-Inf])                # counter-intuitive?

assert_eq(1 .. 100 `by` -Inf -> first(3), [])
assert_eq(100 .. 1 `by`  Inf -> first(3), [])

assert_eq(1 .. Inf `by` -Inf -> first(3), [])
assert_eq(Inf .. 1 `by`  Inf -> first(3), [])

assert_eq(-Inf ..  Inf `by` -Inf -> first(3), [])
assert_eq( Inf .. -Inf `by`  Inf -> first(3), [])

assert_eq(1 .. Inf `by`  Inf -> first(3), [1, Inf, Inf])
assert_eq(Inf .. 1 `by` -Inf -> first(3), [Inf])                   # counter-intutive?

assert_eq( Inf ..  Inf `by` Inf -> first(3), [Inf, Inf, Inf])
assert_eq( Inf .. -Inf `by` Inf -> first(3), [])
assert_eq(-Inf ..  Inf `by` Inf -> first(3), [-Inf])               # counter-intuitive?

assert_eq( NaN ..  NaN -> first(3), [])
assert_eq( NaN ..  Inf -> first(3), [])
assert_eq( NaN .. -Inf -> first(3), [])
assert_eq( Inf ..  NaN -> first(3), [])
assert_eq(-Inf ..  NaN -> first(3), [])

assert_eq(NaN ..   10 -> first(3), [])
assert_eq( 10 ..  NaN -> first(3), [])
assert_eq( 10 .. -Inf -> first(3), [])

assert_eq(   1 .. Inf `by` NaN -> first(3), [])
assert_eq( Inf .. Inf `by` NaN -> first(3), [])
assert_eq(-Inf .. Inf `by` NaN -> first(3), [])

assert_eq( Inf .. 3 -> first(3), [])
assert_eq( Inf .. 3 `by` NaN -> first(3), [])
assert_eq( Inf .. 3 `by` -1 -> first(3), [Inf, Inf, Inf])
assert_eq(-Inf .. 3 `by` -1 -> first(3), [])
assert_eq(-Inf .. 3 `by` NaN -> first(3), [])
assert_eq(-Inf .. 3 `by` 100 -> first(3), [-Inf, -Inf, -Inf])

do {
    var sum = 0
    for (9223372036854775798 .. 9223372036854775818) {
        sum += _
    }
    assert_eq(sum, 193690812773950291968)
    assert_eq(9223372036854775798 .. 9223372036854775818 -> to_a.len, 21)
    assert_eq(9223372036854775798 .. 9223372036854775818 -> sum, sum)
}

do {
    var sum = 0
    for (18446744073709551606 .. 18446744073709551626) {
        sum += _
    }
    assert_eq(sum, 387381625547900583936)
    assert_eq(18446744073709551606 .. 18446744073709551626 -> to_a.len, 21)
    assert_eq(18446744073709551606 .. 18446744073709551626 -> sum, sum)
}

assert_eq(
    gather { (1 .. 2*18446744073709551626 `by` 18446744073709551606) -> each {|n| take(n)} },
    %n[1, 18446744073709551607, 36893488147419103213]
)

assert_eq(
    gather { (1 .. 3*18446744073709551626 `by` 18446744073709551626) -> each {|n| take(n)} },
    %n[1, 18446744073709551627, 36893488147419103253]
)

assert_eq(
    gather { (-20 .. 3*18446744073709551626 `by` 18446744073709551626) -> each {|n| take(n)} },
    %n[-20, 18446744073709551606, 36893488147419103232, 55340232221128654858]
)

assert_eq(
    gather { (-20 .. 3*9223372036854775818 `by` 9223372036854775818) -> each {|n| take(n)} },
    %n[-20, 9223372036854775798, 18446744073709551616, 27670116110564327434]
)

assert_eq(
    gather { (-20 .. 3*9223372036854775798 `by` 9223372036854775798) -> each {|n| take(n)} },
    %n[-20, 9223372036854775778, 18446744073709551576, 27670116110564327374]
)

say "** Test passed!"