extend("test")
extend("array")
extend("string")

describe("array:pluck", () => {
  objs = [ [a:1, b:2], [a:3], [b:4], [a:5, b:6] ]
  it("retrieves a property from each object", () => {
    expect_equal(array:pluck("a", objs), [1,3,_,5])
  })
  it("partial: key first", () => {
    pluckA = array:pluck("a")
    expect_equal(pluckA(objs), [1,3,_,5])
  })
  it("placeholder: array first", () => {
    p = array:pluck(_, objs)
    expect_equal(p("b"), [2,_,4,6])
  })
})

describe("array:group_by", () => {
  arr = [ [type:"cat", name:"Milo"], [type:"dog", name:"Rex"], [type:"cat", name:"Kit"] ]
  it("groups by a key property", () => {
    grouped = array:group_by(obj => array:prop("type", obj), arr)
    expect_equal(grouped["cat"], [ [type:"cat", name:"Milo"], [type:"cat", name:"Kit"] ])
    expect_equal(grouped["dog"], [ [type:"dog", name:"Rex"] ])
  })
  it("partial: function first", () => {
    gb = array:group_by(obj => array:prop("type", obj))
    res = gb(arr)
    expect_equal(res["cat"][1]["name"], "Kit")
  })
  it("placeholder: array first", () => {
    gbp = array:group_by(_, arr)
    expect_equal(type(gbp(obj => array:prop("type", obj))), "keyed_array")
  })
})

describe("array:chunk", () => {
  arr = [1,2,3,4,5]
  it("splits into chunks", () => {
    expect_equal(array:chunk(2, arr), [[1,2],[3,4],[5]])
  })
  it("partial: chunk size first", () => {
    c2 = array:chunk(2)
    expect_equal(c2(arr), [[1,2],[3,4],[5]])
  })
  it("placeholder: array first", () => {
    part = array:chunk(_, arr)
    expect_equal(part(3), [[1,2,3],[4,5]])
  })
})

describe("array:drop", () => {
  arr = [10,20,30,40]
  it("drops the first N", () => {
    expect_equal(array:drop(2, arr), [30,40])
  })
  it("partial: drop count first", () => {
    drop2 = array:drop(2)
    expect_equal(drop2(arr), [30,40])
  })
  it("placeholder: array first", () => {
    p = array:drop(_, arr)
    expect_equal(p(3), [40])
  })
})

describe("array:drop_while", () => {
  arr = [1,2,3,4,1,2,3]
  it("drops while predicate true", () => {
    expect_equal(array:drop_while(x => x < 3, arr), [3,4,1,2,3])
  })
  it("partial: function first", () => {
    dw = array:drop_while(x => x < 4)
    expect_equal(dw(arr), [4,1,2,3])
  })
  it("placeholder: array first", () => {
    p = array:drop_while(_, arr)
    expect_equal(p(x => x != 3), [3,4,1,2,3])
  })
})

describe("array:take", () => {
  arr = [5,6,7,8,9]
  it("takes N elements", () => {
    expect_equal(array:take(3, arr), [5,6,7])
  })
  it("partial: count first", () => {
    take2 = array:take(2)
    expect_equal(take2(arr), [5,6])
  })
  it("placeholder: array first", () => {
    p = array:take(_, arr)
    expect_equal(p(4), [5,6,7,8])
  })
})

describe("array:take_while", () => {
  arr = [2,4,6,7,8]
  it("takes while predicate is true", () => {
    expect_equal(array:take_while(x => x % 2 == 0, arr), [2,4,6])
  })
  it("partial: function first", () => {
    tw = array:take_while(x => x < 7)
    expect_equal(tw(arr), [2,4,6])
  })
  it("placeholder: array first", () => {
    p = array:take_while(_, arr)
    expect_equal(p(x => x < 8), [2,4,6,7])
  })
})

describe("array:fill", () => {
  it("fills with value", () => {
    expect_equal(array:fill("x", 3), ["x","x","x"])
  })
  it("partial: value first", () => {
    fillA = array:fill("A")
    expect_equal(fillA(2), ["A","A"])
  })
  it("placeholder: count first", () => {
    p = array:fill(_, 4)
    expect_equal(p("y"), ["y","y","y","y"])
  })
})

describe("array:repeat", () => {
  it("is alias for fill", () => {
    expect_equal(array:repeat("x", 2), ["x","x"])
  })
})

describe("array:init", () => {
  arr = [10,20,30]
  it("returns all but last", () => {
    expect_equal(array:init(arr), [10,20])
  })
  it("empty if len=1", () => {
    expect_equal(array:init([123]), [])
  })
})

describe("array:slice", () => {
  arr = [10,20,30,40,50]
  it("gets subarray [start:end]", () => {
    expect_equal(array:slice(1, 3, arr), [20,30])
  })
  it("negative indices", () => {
    expect_equal(array:slice(-3, -1, arr), [30,40])
  })
  it("partial: start known", () => {
    s1 = array:slice(2)
    expect_equal(s1(4, arr), [30,40])
  })
  it("partial: start, end known", () => {
    s2 = array:slice(1,3)
    expect_equal(s2(arr), [20,30])
  })
  it("placeholder: array known", () => {
    p = array:slice(_, _, arr)
    expect_equal(p(2,5), [30,40,50])
  })
})
