#!/usr/bin/ruby

# Tests for Bag()

assert_eq(Bag(1, 2)       ∩ Bag(2, 3)         , Bag(2))
assert_eq(Bag(1, 1, 1, 3) ∩ Bag(1, 1, 2)      , Bag(1, 1))
assert_eq(Bag(1, 1, 2, 4) ∩ Bag(1, 1, 1, 2, 3), Bag(1, 1, 2))

assert_eq(Bag(1, 2) ∪ Bag(1)         , Bag(1, 2))
assert_eq(Bag(1, 2) ∪ Bag(1, 1)      , Bag(1, 1, 2))
assert_eq(Bag(1, 1) ∪ Bag(1, 1, 1, 2), Bag(1, 1, 1, 2))

assert_eq(Bag(1)          | Bag(1, 2)        , Bag(1, 2))
assert_eq(Bag(1, 1)       | Bag(1, 2)        , Bag(1, 1, 2))
assert_eq(Bag(1, 1, 1, 2) | Bag(1, 1)        , Bag(1, 1, 1, 2))

assert_eq(Bag(1, 2, 3)     ^ Bag(2)            , Bag(1, 3))
assert_eq(Bag(1, 2, 3)     ^ Bag(3, 4)         , Bag(1, 2, 4))
assert_eq(Bag(1, 1, 2)     ^ Bag(1, 4, 4)      , Bag(1, 2, 4, 4))
assert_eq(Bag(7, 8, 9, 10) ^ Bag(9, 10, 11, 12), Bag(7, 8, 11, 12))

assert_eq(Bag(3, 4, 4, 5, 4) - Bag(3, 4, 4, 9), Bag(4, 5))
assert_eq(Bag(3, 4, 4, 5, 4) - Bag(3, 4, 4, 9, 4), Bag(5))
assert_eq(Bag(3, 4, 4, 5, 4, 9) - Bag(9, 4), Bag(3, 4, 4, 5))

do {
    var a = Bag(3,4,4,4,9,5,3)

    assert_eq(a.len, 7)         # count total elements
    assert_eq(a.elems, 4)       # count unique elements
}

assert_eq(Bag(3).to_s, "Bag(3)")
assert_eq(Bag(3, 4, 4, 4, 5), Bag(4, 3, 4, 5, 4))

assert_eq(Bag(1, 1, 2, 3) ^ Bag(1, 1, 1, 1, 2, 3), Bag(1, 1))
assert_eq(Bag(1, 1, 1, 1, 2, 3) ^ Bag(1, 1, 2, 3), Bag(1, 1))

do {
    var a = Bag(2, 2, 4)
    var b = Bag(2, 3, 3, 4)

    assert(!(a <= b), "a is not a subset of b")
    assert_eq(a ^ b, Bag(3, 3, 2))
    assert_eq(a + b, Bag(2, 2, 2, 4, 4, 3, 3))
    assert_eq(a | b, Bag(2, 2, 4, 3, 3))
    assert_eq(b | a, Bag(2, 2, 4, 3, 3))
}

assert_eq(Bag(2, 2, 2, 2, 2, 3, 4) | Bag(2, 2, 2, 3, 3, 3, 4), Bag(2, 2, 2, 2, 2, 3, 3, 3, 4))
assert_eq(Bag(2, 2, 2, 3, 3, 3, 4) | Bag(2, 2, 2, 2, 2, 3, 4), Bag(2, 2, 2, 2, 2, 3, 3, 3, 4))

assert(Bag(2, 2, 3, 4) <= Bag(2, 2, 2, 3, 3, 3, 4))
assert(Bag(2, 2, 3, 4) <= Bag(3, 2, 4, 2))

assert(Bag(2, 2, 2, 3, 3, 3, 4) >= Bag(2, 2, 3, 4))
assert(Bag(3, 2, 4, 2) >= Bag(2, 2, 3, 4))

assert(!(Bag(2, 2, 3, 4, 2) <= Bag(3, 2, 4, 2)))
assert(!(Bag(2, 2, 3, 4) >= Bag(3, 2, 4, 2, 2)))

do {
    var a = Bag(2, 2, 2, 4, 4, 5, 6)
    var t = []

    for k,v in a {
        t << [k,v]
    }

    assert_eq(t.sort, [[2, 3], [4, 2], [5, 1], [6, 1]])
}

do {
    var a = Bag(2, 2, 2, 4, 4, 5, 6)
    var t = []

    a.each_kv {|k,v|
        t << [k,v]
    }

    assert_eq(t.sort, [[2, 3], [4, 2], [5, 1], [6, 1]])
}

do {
    var a = Bag(2, 2, 2, 4, 4, 5, 6)
    var t = []

    a.each {|elem|
        t << elem
    }

    assert_eq(t.sort, [2,2,2,4,4,5,6])
    assert_eq(a.uniq, Bag(2, 4, 5, 6))
    assert_eq(a.keys.sort, [2, 4, 5, 6])
    assert_eq(a.expand.sort, [2, 2, 2, 4, 4, 5, 6])

    assert_eq(a.count(2), 3)
    assert_eq(a.count(4), 2)
    assert_eq(a.count(42), 0)

    a.append_pair(2, 10)
    assert_eq(a.count(2), 13)

    a.add_pair(3, 5)
    assert_eq(a.count(3), 5)

    a.replace_pair(2, 4)
    assert_eq(a.count(2), 4)

    a.append_pairs(2, 1, 3, 6)
    assert_eq(a.count(2), 5)
    assert_eq(a.count(3), 11)

    a.replace_pairs(2, 1, 3, 7)

    assert_eq(a.count(2), 1)
    assert_eq(a.count(3), 7)
}

do {
    var a = Bag(-2, -2, -4, 2, 4)

    assert_eq(a.map { _*_ }, Bag(4, 4, 4, 16, 16))
    assert_eq(a.grep { _ > 0 }, Bag(2, 4))
    assert_eq(a.grep { _ < 0 }, Bag(-2, -2, -4))
}

do {
    var a = Bag(1, 2)

    a.push(1)
    a.push(1)
    assert_eq(a, Bag(1, 1, 1, 2))
    a.push(42, 99)
    assert_eq(a, Bag(1, 1, 1, 2, 42, 99))
    a.push(42, 42, 5)
    assert_eq(a, Bag(1, 1, 1, 2, 5, 42, 42, 42, 99))
    assert_eq(a.to_set, Set(1, 2, 5, 42, 99))
    assert_eq(a.clone, a)
    assert_eq(a.dclone, a)
}

do {
    var a = %w(spam eggs spam spam bacon spam).to_bag

    assert_eq(a.len, 6)
    assert_eq(a.keys_len, 3)
    assert_eq(a.keys.sort, ["bacon", "eggs", "spam"])

    assert_eq(Bag("abracadabra".chars...).top(1), [["a", 5]])
    assert_eq(Bag("abracadabra".chars...).top(3).sort, [["a", 5], ["b", 2], ["r", 2]])
}

func createSubstrings(String word) -> Array {
  gather {
    combinations(word.len+1, 2, {|i,j|
        take(word.substr(i, j-i))
    })
  }
}

func findLongestCommon(String first, String second) -> String {
    Bag(createSubstrings(first)...) & Bag(createSubstrings(second)...) -> max_by { .len }
}

assert_eq(findLongestCommon("thisisatest", "testing123testing"), "test")

say "** Test passed!"