infiniyield/test/infiniyield_test.gleam
2025-08-09 18:40:17 +10:00

427 lines
9.6 KiB
Gleam

import gleam/int
import gleam/list
import gleeunit
import gleeunit/should
import infiniyield.{Next}
pub fn main() {
gleeunit.main()
}
pub fn step_test() {
let testcase = fn(subject) {
let step =
subject
|> infiniyield.cycle
|> infiniyield.step
let assert [h, ..t] = subject
let Next(h2, t2) = step
h
|> should.equal(h2)
t2
|> infiniyield.take(list.length(t))
|> should.equal(t)
}
testcase([1])
testcase([1, 2])
testcase([1, 2, 3])
}
// a |> cycle |> take(n) == a |> list.take(_, n)
pub fn take_test() {
let testcase = fn(n, subject) {
subject
|> infiniyield.cycle
|> infiniyield.take(n)
|> should.equal(list.take(subject, n))
}
testcase(0, [])
testcase(-1, [])
testcase(0, [0])
testcase(1, [0])
testcase(-1, [0])
testcase(0, [0, 1, 2, 3, 4])
testcase(1, [0, 1, 2, 3, 4])
testcase(2, [0, 1, 2, 3, 4])
}
pub fn transform_index_test() {
let f = fn(i, el) { Next(#(i, el), i + 1) }
["a", "b", "c", "d"]
|> infiniyield.cycle
|> infiniyield.transform(0, f)
|> infiniyield.take(4)
|> should.equal([#(0, "a"), #(1, "b"), #(2, "c"), #(3, "d")])
}
pub fn transform_scan_test() {
let f = fn(acc, el) {
let result = acc + el
Next(result, result)
}
[1, 2, 3, 4, 5]
|> infiniyield.cycle
|> infiniyield.transform(0, f)
|> infiniyield.take(5)
|> should.equal([1, 3, 6, 10, 15])
}
// a |> cycle |> map(f) == a |> list.map(_, f)
pub fn map_test() {
let testcase = fn(subject, f) {
subject
|> infiniyield.cycle
|> infiniyield.map(f)
|> infiniyield.take(list.length(subject))
|> should.equal(list.map(subject, f))
}
let f = fn(e) { e * 2 }
testcase([], f)
testcase([1], f)
testcase([1, 2, 3], f)
testcase([1, 2, 3, 4, 5, 6, 7, 8], f)
}
// map2(cycle(a), cycle(b), f) == list.map2(a, b, f)
pub fn map2_test() {
let testcase = fn(one, other, f) {
infiniyield.map2(infiniyield.cycle(one), infiniyield.cycle(other), f)
|> infiniyield.take(int.min(list.length(one), list.length(other)))
|> should.equal(list.map2(one, other, f))
}
let f = fn(a, b) { a / b }
testcase([], [], f)
testcase([], [2, 10, 3], f)
testcase([10], [2, 10, 3], f)
testcase([10, 20], [2, 10, 3], f)
testcase([10, 20, 30], [2, 10, 3], f)
testcase([10, 20, 30], [2, 10], f)
testcase([10, 20, 30], [2], f)
testcase([10, 20, 30], [], f)
}
pub fn map2_is_lazy_test() {
let one = infiniyield.cycle([])
let other = infiniyield.repeatedly(fn() { panic as "unreachable" })
infiniyield.map2(one, other, fn(x, y) { x + y })
|> infiniyield.take(0)
|> should.equal([])
}
// a |> cycle |> filter(f) == a |> list.filter(_, f)
pub fn filter_test() {
let testcase = fn(subject, f) {
let lst = list.filter(subject, f)
subject
|> infiniyield.cycle
|> infiniyield.filter(f)
|> infiniyield.take(list.length(lst))
|> should.equal(lst)
}
let even = fn(x) { x % 2 == 0 }
testcase([], even)
testcase([1], even)
testcase([1, 2], even)
testcase([1, 2, 3], even)
testcase([1, 2, 3, 4], even)
testcase([1, 2, 3, 4, 5], even)
testcase([1, 2, 3, 4, 5, 6], even)
}
pub fn filter_map_test() {
let testcase = fn(subject, f) {
let lst = list.filter_map(subject, f)
subject
|> infiniyield.cycle
|> infiniyield.filter_map(f)
|> infiniyield.take(list.length(lst))
|> should.equal(lst)
}
testcase([], int.parse)
testcase(["1"], int.parse)
testcase(["1", "2", "3"], int.parse)
testcase(["1", "a", "b"], int.parse)
testcase(["l", "2", "3", "a"], int.parse)
testcase(["1", "c", "3", "a", "b"], int.parse)
testcase(["1", "20", "ten", "4", "5", "69"], int.parse)
}
pub fn repeat_test() {
1
|> infiniyield.repeat
|> infiniyield.take(5)
|> should.equal([1, 1, 1, 1, 1])
}
pub fn cycle_test() {
[1, 2, 3]
|> infiniyield.cycle
|> infiniyield.take(9)
|> should.equal([1, 2, 3, 1, 2, 3, 1, 2, 3])
}
pub fn unfold_test() {
infiniyield.unfold(2, fn(acc) { infiniyield.Next(acc, acc * 2) })
|> infiniyield.take(5)
|> should.equal([2, 4, 8, 16, 32])
}
pub fn incrementing_test() {
let testcase = fn(a, expected) {
infiniyield.incrementing(from: a)
|> infiniyield.take(list.length(expected))
|> should.equal(expected)
}
testcase(0, [0])
testcase(1, [1])
testcase(-1, [-1])
testcase(0, [0, 1])
testcase(0, [0, 1, 2, 3, 4, 5])
testcase(1, [1, 2, 3, 4, 5])
}
pub fn deccrementing_test() {
let testcase = fn(a, expected) {
infiniyield.decrementing(from: a)
|> infiniyield.take(list.length(expected))
|> should.equal(expected)
}
testcase(0, [0])
testcase(1, [1])
testcase(-1, [-1])
testcase(0, [0, -1])
testcase(0, [0, -1, -2, -3, -4, -5])
testcase(1, [1, 0, -1, -2, -3, -4, -5])
}
pub fn drop_test() {
infiniyield.incrementing(from: 0)
|> infiniyield.drop(5)
|> infiniyield.take(6)
|> should.equal([5, 6, 7, 8, 9, 10])
}
type Cat {
Cat(id: Int)
}
pub fn find_test() {
infiniyield.incrementing(from: 0)
|> infiniyield.find(fn(e) { e == 5 })
|> should.equal(5)
infiniyield.incrementing(from: 0)
|> infiniyield.find(fn(e) { e > 10 })
|> should.equal(11)
infiniyield.unfold(Cat(id: 1), fn(cat: Cat) {
infiniyield.Next(cat, Cat(id: cat.id + 1))
})
|> infiniyield.find(fn(cat: Cat) { cat.id == 10 })
|> should.equal(Cat(id: 10))
}
pub fn find_map_test() {
infiniyield.incrementing(from: 0)
|> infiniyield.find_map(fn(e) {
case e == 5 {
True -> Ok(e)
False -> Error(Nil)
}
})
|> should.equal(5)
infiniyield.incrementing(from: 0)
|> infiniyield.find_map(fn(e) {
case e > 10 {
True -> Ok(e)
False -> Error(Nil)
}
})
|> should.equal(11)
infiniyield.unfold(Cat(id: 1), fn(cat: Cat) {
infiniyield.Next(cat, Cat(id: cat.id + 1))
})
|> infiniyield.find_map(fn(cat: Cat) {
case cat.id == 10 {
True -> Ok(cat)
False -> Error(Nil)
}
})
|> should.equal(Cat(id: 10))
}
pub fn index_test() {
infiniyield.cycle(["a", "b", "c"])
|> infiniyield.index
|> infiniyield.take(3)
|> should.equal([#("a", 0), #("b", 1), #("c", 2)])
}
pub fn iterate_test() {
fn(x) { x * 3 }
|> infiniyield.iterate(from: 1)
|> infiniyield.take(5)
|> should.equal([1, 3, 9, 27, 81])
}
pub fn take_while_test() {
infiniyield.cycle([1, 2, 3, 2, 4])
|> infiniyield.take_while(satisfying: fn(x) { x < 3 })
|> should.equal([1, 2])
}
pub fn drop_while_test() {
infiniyield.cycle([1, 2, 3, 4, 2, 5])
|> infiniyield.drop_while(satisfying: fn(x) { x < 4 })
|> infiniyield.take(3)
|> should.equal([4, 2, 5])
}
pub fn scan_test() {
infiniyield.cycle([1, 2, 3, 4, 5])
|> infiniyield.scan(from: 0, with: fn(acc, el) { acc + el })
|> infiniyield.take(5)
|> should.equal([1, 3, 6, 10, 15])
}
pub fn zip_test() {
infiniyield.cycle(["a", "b", "c"])
|> infiniyield.zip(infiniyield.incrementing(from: 20))
|> infiniyield.take(3)
|> should.equal([#("a", 20), #("b", 21), #("c", 22)])
}
pub fn chunk_test() {
infiniyield.cycle([1, 2, 2, 3, 4, 4, 6, 7, 7])
|> infiniyield.chunk(by: fn(n) { n % 2 })
|> infiniyield.take(5)
|> should.equal([[1], [2, 2], [3], [4, 4, 6], [7, 7, 1]])
}
pub fn sized_chunk_test() {
infiniyield.cycle([1, 2, 3, 4, 5, 6])
|> infiniyield.sized_chunk(into: 2)
|> infiniyield.take(3)
|> should.equal([[1, 2], [3, 4], [5, 6]])
infiniyield.cycle([1, 2, 3, 4, 5, 6, 7, 8])
|> infiniyield.sized_chunk(into: 3)
|> infiniyield.take(3)
|> should.equal([[1, 2, 3], [4, 5, 6], [7, 8, 1]])
}
pub fn intersperse_test() {
infiniyield.cycle([1])
|> infiniyield.intersperse(with: 0)
|> infiniyield.take(1)
|> should.equal([1])
infiniyield.cycle([1, 2, 3, 4, 5])
|> infiniyield.intersperse(with: 0)
|> infiniyield.take(9)
|> should.equal([1, 0, 2, 0, 3, 0, 4, 0, 5])
}
pub fn interleave_test() {
infiniyield.cycle([1, 2, 3, 4])
|> infiniyield.interleave(with: infiniyield.cycle([11, 12, 13, 14]))
|> infiniyield.take(8)
|> should.equal([1, 11, 2, 12, 3, 13, 4, 14])
infiniyield.cycle([1, 2, 3, 4])
|> infiniyield.interleave(with: infiniyield.cycle([100]))
|> infiniyield.take(8)
|> should.equal([1, 100, 2, 100, 3, 100, 4, 100])
}
// a |> cycle |> fold_until(acc, f) == a |> list.fold_until(acc, f)
pub fn fold_until_test() {
let testcase = fn(subject, acc, f) {
subject
|> infiniyield.cycle()
|> infiniyield.fold_until(acc, f)
|> should.equal(list.fold_until(subject, acc, f))
}
let f = fn(acc, e) {
case e {
_ if e < 6 -> list.Continue([e, ..acc])
_ -> list.Stop(acc)
}
}
testcase([1, 2, 3, 4, 5, 6, 7, 8], [], f)
[1, 2, 3, 4, 5, 6, 7, 8]
|> infiniyield.cycle()
|> infiniyield.fold_until([], f)
|> should.equal([5, 4, 3, 2, 1])
}
pub fn first_test() {
infiniyield.cycle([1, 2, 3])
|> infiniyield.first
|> should.equal(1)
}
pub fn at_test() {
infiniyield.cycle([1, 2, 3, 4])
|> infiniyield.at(2)
|> should.equal(3)
infiniyield.cycle([1, 2, 3, 4])
|> infiniyield.at(4)
|> should.equal(1)
}
pub fn each_test() {
use it <- infiniyield.each(infiniyield.cycle([1]))
it
|> should.equal(1)
}
pub fn yield_test() {
let items = {
use <- infiniyield.yield(1)
use <- infiniyield.yield(2)
use <- infiniyield.yield(3)
infiniyield.repeat(0)
}
items
|> infiniyield.take(6)
|> should.equal([1, 2, 3, 0, 0, 0])
}
pub fn yield_computes_only_necessary_values_test() {
let items = {
use <- infiniyield.yield(1)
use <- infiniyield.yield(2)
use <- infiniyield.yield(3)
panic as "yield computed more values than necessary"
}
items
|> infiniyield.take(3)
|> should.equal([1, 2, 3])
}
pub fn prepend_test() {
infiniyield.cycle([1, 2, 3])
|> infiniyield.prepend(0)
|> infiniyield.take(4)
|> should.equal([0, 1, 2, 3])
}