/*
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

import { CIDRBlock } from "./cidrBlock";

test("192.168.0.0/16 is not modified", () => {
    const cidr = CIDRBlock.fromNumbers(192, 168, 0, 0, 16);
    expect(cidr.toString()).toEqual("192.168.0.0/16");
});

test("192.168.0.1/16 is sanitized", () => {
    const cidr = CIDRBlock.fromNumbers(192, 168, 0, 1, 16);
    expect(cidr.toString()).toEqual("192.168.0.0/16");
});

test("-5.4.5.6/12 is invalid", () => {
    expect(() => CIDRBlock.fromNumbers(-5, 4, 5, 6, 12)).toThrowError();
});

test("5.4.5.6/34 is invalid", () => {
    expect(() => CIDRBlock.fromNumbers(5, 4, 5, 6, 34)).toThrowError();
});

test("192.168.0.0/16 string is not modified", () => {
    const cidr = CIDRBlock.fromString("192.168.0.0/16");
    expect(cidr.toString()).toEqual("192.168.0.0/16");
});

test("192.168.0.1/16 string is sanitized", () => {
    const cidr = CIDRBlock.fromString("192.168.0.0/16");
    expect(cidr.toString()).toEqual("192.168.0.0/16");
});

test("-5.4.5.6/12 string is invalid", () => {
    expect(() => CIDRBlock.fromString("-5.4.5.6/12")).toThrowError();
});

test("5.4.5.6/34 is string invalid", () => {
    expect(() => CIDRBlock.fromString("5.4.5.6/34")).toThrowError();
});

test("'a.b.c.d' is rejected", () => {
    expect(() => CIDRBlock.fromString("a.b.c.d")).toThrowError();
});

test("'a.b.c.d/16' is rejected", () => {
    expect(() => CIDRBlock.fromString("a.b.c.d/16")).toThrowError('"a.b.c.d" is not a valid network address in CIDR "a.b.c.d/16"');
});

test("10.0.0.0/16 can be divided into 2", () => {
    const cidr = CIDRBlock.fromString("10.0.0.0/16");
    const newCidr = cidr.split(2);
    expect(newCidr.length).toEqual(2);
    expect(newCidr[0].toString()).toEqual("10.0.0.0/17");
    expect(newCidr[1].toString()).toEqual("10.0.128.0/17");
});

test("10.0.0.0/16 can be divided into 3", () => {
    const cidr = CIDRBlock.fromString("10.0.0.0/16");
    const newCidr = cidr.split(3);

    expect(newCidr.length).toEqual(4);
    expect(newCidr[0].toString()).toEqual("10.0.0.0/18");
    expect(newCidr[1].toString()).toEqual("10.0.64.0/18");
    expect(newCidr[2].toString()).toEqual("10.0.128.0/18");
    expect(newCidr[3].toString()).toEqual("10.0.192.0/18");
});

test("10.0.0.0/32 can't be divided into 2", () => {
    const cidr = CIDRBlock.fromString("10.0.0.0/32");
    expect(() => cidr.split(2)).toThrowError("Can't divide \"10.0.0.0/32\" into 2");
});

test("10.0.0.0/16 can't be divided into -1", () => {
    const cidr = CIDRBlock.fromString("10.0.0.0/16");
    expect(() => cidr.split(-1)).toThrowError("The required subnet amount must be positive");
});

test("Check that 10.0.0.0/16 broadcast address is 10.0.255.255", () => {
    const cidr = CIDRBlock.fromString("10.0.0.0/16");
    expect(cidr.broadcastAddress).toEqual("10.0.255.255");
});

test("192.168.0.0/30 has two ip address", () => {
    const cidr = CIDRBlock.fromString("192.168.0.0/30");
    const ips = cidr.ipAddress();
    expect(cidr.networkAddress).toEqual("192.168.0.0");
    expect(cidr.broadcastAddress).toEqual("192.168.0.3");
    expect(ips.next().value).toEqual("192.168.0.1");
    expect(ips.next().value).toEqual("192.168.0.2");
    expect(ips.next().done).toBe(true);
});

test("-1 is an invalid address index", () => {
    const cidr = CIDRBlock.fromString("192.168.0.0/30");
    expect(() => cidr.getAddress(-1)).toThrowError("-1 is not a valid address index for \"192.168.0.0/30\"");
});

test("getAddress(0) == networkAddress", () => {
    const cidr = CIDRBlock.fromString("192.168.0.0/30");
    expect(cidr.getAddress(0)).toEqual(cidr.networkAddress);
});

test("getAddress(maxAddressIndex) == broadcastAddress", () => {
    const cidr = CIDRBlock.fromString("192.168.0.0/30");
    expect(cidr.getAddress(cidr.maxAddressIndex)).toEqual(cidr.broadcastAddress);
});
