import "jest";
import { Range, walk } from "../ranges";

describe(walk.name, () => {
  function walkAsArray<T extends Range>(ranges: T[]) {
    const result: Array<Readonly<Range> & { active: ReadonlyArray<T> }> = [];
    walk(ranges, (range, active) => {
      result.push({ ...range, active });
    });
    return result;
  }

  it("0 ranges", () => {
    expect(walkAsArray([])).toMatchObject([]);
  });

  describe("1 range", () => {
    it("empty", () => {
      const rangeFoo = { id: "foo", from: 0, to: 0 };
      expect(walkAsArray([rangeFoo])).toMatchObject([{ from: 0, to: 0, active: [rangeFoo] }]);
    });

    it("wide", () => {
      const rangeFoo = { id: "foo", from: 0, to: 10 };
      expect(walkAsArray([rangeFoo])).toMatchObject([{ from: 0, to: 10, active: [rangeFoo] }]);
    });
  });

  describe("2 ranges", () => {
    it("empty overlapping", () => {
      const rangeFoo = { id: "foo", from: 0, to: 0 };
      const rangeBar = { id: "bar", from: 0, to: 0 };
      expect(walkAsArray([rangeFoo, rangeBar])).toMatchObject([{ from: 0, to: 0, active: [rangeFoo, rangeBar] }]);
    });

    it("empty adjacent", () => {
      const rangeFoo = { id: "foo", from: 0, to: 0 };
      const rangeBar = { id: "bar", from: 10, to: 10 };
      expect(walkAsArray([rangeFoo, rangeBar])).toMatchObject([
        { from: 0, to: 0, active: [rangeFoo] },
        { from: 10, to: 10, active: [rangeBar] }
      ]);
    });

    it("a encompass b", () => {
      const rangeFoo = { id: "foo", from: 0, to: 10 };
      const rangeBar = { id: "bar", from: 5, to: 6 };
      expect(walkAsArray([rangeFoo, rangeBar])).toMatchObject([
        { from: 0, to: 5, active: [rangeFoo] },
        { from: 5, to: 6, active: [rangeFoo, rangeBar] },
        { from: 6, to: 10, active: [rangeFoo] }
      ]);
    });

    it("a overlap b", () => {
      const rangeFoo = { id: "foo", from: 0, to: 10 };
      const rangeBar = { id: "bar", from: 5, to: 15 };
      expect(walkAsArray([rangeFoo, rangeBar])).toMatchObject([
        { from: 0, to: 5, active: [rangeFoo] },
        { from: 5, to: 10, active: [rangeFoo, rangeBar] },
        { from: 10, to: 15, active: [rangeBar] }
      ]);
    });

    it("a adjacent b", () => {
      const rangeFoo = { id: "foo", from: 0, to: 5 };
      const rangeBar = { id: "bar", from: 10, to: 15 };
      expect(walkAsArray([rangeFoo, rangeBar])).toMatchObject([
        { from: 0, to: 5, active: [rangeFoo] },
        { from: 10, to: 15, active: [rangeBar] }
      ]);
    });
  });
});
