#!/usr/bin/ruby

#
## Tests for Array set operations
#

var errors = 0

func test(op, a, b, c) {
    try {
        assert_eq(a.shuffle.(op)(b.shuffle).sort, c.sort)
    }
    catch {
        say "a: #{a.sort}";
        say "b: #{b.sort}";
        say "#{a.(op)(b)} != #{c.sort}\n"
        ++errors;
    }
}

struct T {
    a,
    b,
    diff,
    xor,
}

class Example(name, value) {
    method <=>(other) {
        self.value <=> other.value
    }
    method to_s {
        "(#{name}, #{value})";
    }
}

var a = Example("a", 1);
var b = Example("b", 2);
var c = Example("c", 3);        #| this two
var d = Example("d", 3);        #| are equal
var e = Example("e", 4);

var tests = [
    T(
        a: [6,1, 2, 3, 5, 1, 3, 4],
        b: [3,2],
        diff: [1, 1, 3, 4, 5, 6],
        xor: [1, 1, 3, 4, 5, 6],
    ),
    T(
        a: [6,1, 2, 3, 5, 1, 3, 4],
        b: [3,2,1],
        diff: [1, 3, 4, 5, 6],
        xor: [1, 3, 4, 5, 6],
    ),
    T(
        a: [6,1, 2, 3, 5, 1, 3, 4],
        b: [3,2,1,4],
        diff: [1, 3, 5, 6],
        xor: [1, 3, 5, 6],
    ),
    T(
        a: [6,1, 2, 3, 5, 1, 3, 4],
        b: [3,2,4],
        diff: [1, 1, 3, 5, 6],
        xor: [1, 1, 3, 5, 6],
    ),
    T(
        a: [3,12,2,4,5,7],
        b: [6,1, 2, 3, 5, 1, 3, 4,20],
        diff: [7, 12],
        xor: [1, 1, 3, 6, 7, 12, 20],
    ),
    T(
        a: [ 1, 1, 2, 2, 3, 3, 4, 5 ],
        b: [ 1, 2, 4, 6],
        diff: [1, 2, 3, 3, 5],
        xor: [1, 2, 3, 3, 5, 6],
    ),
    T(
        a: [1, 2, 3, 4],
        b: [4, 2],
        diff: [1, 3],
        xor: [1, 3],
    ),
    T(
        a: [1, 2, 3, 4, 5],
        b: [1, 2, 4, 6],
        diff: [3, 5],
        xor: [3, 5, 6],
    ),
    T(
        a: [1, 2, 4, 6],
        b: [1, 2, 3, 4, 5],
        diff: [6],
        xor: [5, 3, 6],
    ),
    T(
        a: <kim bob sue joe jim>,
        b: <kim bob sue>,
        diff: <joe jim>,
        xor: <joe jim>,
    ),
    T(
        a: ["John", "Serena", "Bob", "Mary", "Serena"],
        b: ["Jim", "Mary", "John", "Jim", "Bob"],
        diff: ["Serena", "Serena"],
        xor: ["Jim", "Jim", "Serena", "Serena"],
    ),
    T(
        a: ["Jim", "Mary", "John", "Jim", "Bob"],
        b: ["John", "Serena", "Bob", "Mary", "Serena"],
        diff: ["Jim", "Jim"],
        xor: ["Jim", "Jim", "Serena", "Serena"],
    ),
    T(
        a: [a,b,c,a,d,e,a,a],
        b: [c,c,a],
        diff: [a, a, a, b, e],
        xor: [a, a, a, b, e],
    ),
    T(
        a: [a, b, c, a],
        b: [d, e],
        diff: [a, a, b],
        xor: [a, a, b, e],
    ),
    T(
        a: [d, e],
        b: [e, c, d, a],
        diff: [],
        xor: [a, c],
    ),
    T(
        a: [e],
        b: [c, a, b, c],
        diff: [e],
        xor: [c, c, e, a, b],
    ),
]

tests.each { |t|
    test('-', t.a, t.b, t.diff)
    test('^', t.a, t.b, t.xor)
}

assert_eq(errors, 0);

say "** Test passed!";