use koto_runtime::KValue;
use koto_test_utils::*;
mod iterator {
use super::*;
mod next {
use super::*;
#[test]
fn null_in_output() {
let script = "
x = (1, null, 'x').iter()
x.next().get() # 1
x.next().get() # null
";
check_script_output(script, KValue::Null);
}
}
mod next_back {
use super::*;
#[test]
fn null_in_output() {
let script = "
x = (1, null, 'x').iter()
x.next_back().get() # 'x'
x.next_back().get() # null
";
check_script_output(script, KValue::Null);
}
}
mod chain {
use super::*;
#[test]
fn make_copy_in_first_iter() {
let script = "
x = (10..12).chain 12..15
x.next().get() # 10
y = copy x
x.next().get() # 11
x.next().get() # 12
y.next().get()
";
check_script_output(script, 11);
}
#[test]
fn make_copy_in_second_iter() {
let script = "
x = (0..2).chain 2..5
x.next().get() # 0
x.next().get() # 1
x.next().get() # 2
y = copy x
x.next().get() # 3
x.next().get() # 4
y.next().get()
";
check_script_output(script, 3);
}
}
mod chunks {
use super::*;
#[test]
fn with_generator() {
let script = "
generator = ||
for i in 1..=4
yield i
generator()
.chunks 2
.skip 1
.flatten()
.to_tuple()
";
check_script_output(script, number_tuple(&[3, 4]));
}
#[test]
fn with_peekable() {
let script = "
(1..=5)
.peekable()
.chunks 2
.each |w| w.to_tuple()
.to_tuple()
";
check_script_output(
script,
tuple(&[
number_tuple(&[1, 2]),
number_tuple(&[3, 4]),
number_tuple(&[5]),
]),
);
}
}
mod cycle {
use super::*;
#[test]
fn empty_input() {
let script = "
[].cycle().next()
";
check_script_output(script, KValue::Null);
}
#[test]
fn make_copy() {
let script = "
x = (1..=3).cycle()
x.next().get() # 1
y = copy x
x.next().get() # 2
x.next().get() # 3
y.next().get()
";
check_script_output(script, 2);
}
#[test]
fn with_peekable() {
let script = "
(1..=3)
.peekable()
.cycle()
.take 7
.to_tuple()
";
check_script_output(script, number_tuple(&[1, 2, 3, 1, 2, 3, 1]));
}
}
mod each {
use super::*;
#[test]
fn make_copy() {
let script = "
x = (3, 4, 5, 6).each |x| x * x
x.next().get() # 9
y = copy x
x.next().get() # 16
x.next().get() # 25
y.next().get()
";
check_script_output(script, 16);
}
#[test]
fn each_reversed() {
let script = "
x = (2, 4, 6)
.each |x| x * x
.reversed()
x.next().get()
";
check_script_output(script, 36);
}
#[test]
fn each_with_native_function() {
let script = "
(2.5, 4.6, 6.1)
.each number.round
.to_tuple()
";
check_script_output(script, number_tuple(&[3, 5, 6]));
}
}
mod enumerate {
use super::*;
#[test]
fn as_standalone_function() {
let script = "
x = iterator.enumerate 'abc'
x.next().get()
";
check_script_output(script, tuple(&[0.into(), "a".into()]));
}
#[test]
fn make_copy() {
let script = "
x = (10..20).enumerate()
x.next().get() # 0, 10
y = copy x
x.next().get() # 1, 11
x.next().get() # 2, 12
y.next().get()
";
check_script_output(script, tuple(&[1.into(), 11.into()]));
}
}
mod intersperse {
use super::*;
#[test]
fn intersperse_by_value_make_copy() {
let script = "
x = (1, 2, 3).intersperse 0
x.next().get() # 1
x.next().get() # 0
y = copy x
x.next().get() # 2
x.next().get() # 0
y.next().get()
";
check_script_output(script, 2);
}
#[test]
fn intersperse_with_function_make_copy() {
let script = "
x = (10, 20, 30).intersperse || 42
x.next().get() # 10
x.next().get() # 42
y = copy x
x.next().get() # 20
x.next().get() # 42
y.next().get()
";
check_script_output(script, 20);
}
}
mod generate {
use super::*;
#[test]
fn with_inline_function() {
let script = "
add = |a, b| a + b
iterator.generate(|| add(2, 3), 5).to_tuple()
";
check_script_output(script, number_tuple(&[5, 5, 5, 5, 5]));
}
}
mod keep {
use super::*;
#[test]
fn make_copy() {
let script = "
x = 'abcdef'.chars().keep |c| 'bef'.contains c
x.next().get() # 'b'
y = copy x
x.next().get() # 'e'
y.next().get()
";
check_script_output(script, "e");
}
}
mod peekable {
use super::*;
use KValue::Null;
#[test]
fn peek() {
let script = "
i = (1, 2, 3).peekable()
result = []
result.push i.peek().get() # 1
result.push i.next().get() # 1
result.push i.next().get() # 2
result.push i.peek().get() # 3
result.push i.next().get() # 3
result.push i.peek() # null
result.push i.next() # null
result
";
check_script_output(
script,
list(&[1.into(), 1.into(), 2.into(), 3.into(), 3.into(), Null, Null]),
);
}
#[test]
fn peek_back_forwards() {
let script = "
i = (1, 2, 3).peekable()
result = []
result.push i.peek().get() # 1
result.push i.peek_back().get() # 3
result.push i.peek_back().get() # 3
result.push i.next().get() # 1
result.push i.next().get() # 2
result.push i.peek().get() # 3
result.push i.next().get() # 3
result.push i.next() # null
result.push i.next_back() # null
result.push i.peek_back() # null
result
";
check_script_output(
script,
list(&[
1.into(),
3.into(),
3.into(),
1.into(),
2.into(),
3.into(),
3.into(),
Null,
Null,
Null,
]),
);
}
#[test]
fn peek_back_backwards() {
let script = "
i = (1, 2, 3).peekable()
result = []
result.push i.peek().get() # 1
result.push i.peek_back().get() # 3
result.push i.peek_back().get() # 3
result.push i.next_back().get() # 3
result.push i.next_back().get() # 2
result.push i.peek_back().get() # 1
result.push i.next_back().get() # 1
result.push i.peek_back() # null
result.push i.next_back() # null
result.push i.next() # null
result
";
check_script_output(
script,
list(&[
1.into(),
3.into(),
3.into(),
3.into(),
2.into(),
1.into(),
1.into(),
Null,
Null,
Null,
]),
);
}
}
mod repeat {
use super::*;
#[test]
fn repeat_used_as_imported_function() {
let script = "
from iterator import repeat
repeat(1, 4).to_tuple()
repeat(2, 3).to_tuple()
repeat(3, 2).to_tuple()
";
check_script_output(script, number_tuple(&[3, 3]));
}
}
mod skip {
use super::*;
#[test]
fn skip_past_end_then_collect_shouldnt_panic() {
let script = "
[].skip(1).to_tuple()
";
check_script_output(script, tuple(&[]));
}
}
mod take {
use super::*;
#[test]
fn make_copy() {
let script = "
x = 'abcdef'.chars().take 4
x.next().get() # 'a'
x.next().get() # 'b'
y = copy x
x.next().get() # 'c'
y.next().get()
";
check_script_output(script, "c");
}
}
mod windows {
use super::*;
#[test]
fn with_a_generator() {
let script = "
generator = ||
for i in 1..=4
yield i
generator()
.windows 2
.flatten()
.to_tuple()
";
check_script_output(script, number_tuple(&[1, 2, 2, 3, 3, 4]));
}
#[test]
fn in_for_loop() {
let script = "
result = []
for a, b in (1..=5).windows(2)
result.push a
result.push b
result
";
check_script_output(script, number_list(&[1, 2, 2, 3, 3, 4, 4, 5]));
}
#[test]
fn with_peekable() {
let script = "
(1..=5)
.peekable()
.windows 3
.each |w| w.to_tuple()
.to_tuple()
";
check_script_output(
script,
tuple(&[
number_tuple(&[1, 2, 3]),
number_tuple(&[2, 3, 4]),
number_tuple(&[3, 4, 5]),
]),
);
}
}
mod zip {
use super::*;
#[test]
fn make_copy() {
let script = "
x = (1..5).zip 11..15
x.next().get() # (1, 11)
x.next().get() # (2, 12)
y = copy x
x.next().get() # (3, 13)
y.next().get()
";
check_script_output(script, number_tuple(&[3, 13]));
}
#[test]
fn for_loop_over_many_zipped_values() {
let script = "
r = 1..=128
for a, b in r.zip r
() # no-op
b
";
check_script_output(script, 128);
}
}
}
mod map {
use super::*;
mod keys {
use super::*;
#[test]
fn make_copy() {
let script = "
x = {foo: 42, bar: 99, baz: -1}.keys()
x.next().get() # foo
y = copy x
x.next().get() # bar
y.next().get()
";
check_script_output(script, "bar");
}
}
mod values {
use super::*;
#[test]
fn make_copy() {
let script = "
x = {foo: 42, bar: 99, baz: -1}.values()
x.next().get() # 42
y = copy x
x.next().get() # 99
y.next().get()
";
check_script_output(script, 99);
}
}
}
mod string {
use super::*;
mod graphemes {
use super::*;
#[test]
fn next_back() {
let script = "
'abc'.next_back().get()
";
check_script_output(script, "c");
}
}
mod bytes {
use super::*;
#[test]
fn make_copy() {
let script = "
x = 'abc'.bytes()
x.next().get() # 97
y = copy x
x.next().get() # 98
y.next().get()
";
check_script_output(script, 98);
}
}
mod char_indices {
use super::*;
#[test]
fn text() {
let script = "
'xßîहिं'.char_indices().to_tuple()
";
check_script_output(
script,
tuple(&[range(0..1), range(1..3), range(3..5), range(5..14)]),
);
}
#[test]
fn emojis() {
let script = "
'👍🫶🏽🫱🏼🫲🏾'.char_indices().to_tuple()
";
check_script_output(script, tuple(&[range(0..4), range(4..12), range(12..31)]));
}
}
mod lines {
use super::*;
#[test]
fn make_copy() {
let script = "
x = 'abc\ndef\nxyz'.lines()
x.next().get() # abc
y = copy x
x.next().get() # def
y.next().get()
";
check_script_output(script, "def");
}
#[test]
fn crlf_line_endings() {
let script = "
'abc\r\ndef\r\nxyz\r\n\r\n'.lines().to_tuple()
";
check_script_output(
script,
tuple(&["abc".into(), "def".into(), "xyz".into(), "".into()]),
);
}
}
mod split {
use super::*;
#[test]
fn make_copy_pattern() {
let script = "
x = '1-2-3'.split '-'
x.next().get() # 1
y = copy x
x.next().get() # 2
y.next().get()
";
check_script_output(script, "2");
}
#[test]
fn make_copy_predicate() {
let script = "
x = '1-2_3'.split |c| '-_'.contains c
x.next().get() # 1
y = copy x
x.next().get() # 2
y.next().get()
";
check_script_output(script, "2");
}
}
}