import { deepClone, deepEqual } from "./object-helper";

describe("object-cloning-helper.js", () => {
    describe("deepClone", () => {
        it("Should return null if no object is passed in", async () => {
            // Arrange
            const expected = null;

            // Act
            const result = deepClone(null);

            // Assert
            expect(result).toEqual(expected);
        });

        it("Should return a deep copy of the object", async () => {
            // Arrange

            const object = {
                addressQuestions: {
                    streetAddress: "555 Some St",
                    apartmentNumberOrBusinessName: "Apt 1",
                    city: "Funkytown",
                    state: "OH",
                    zipCode: "55555",
                },
                isVehicleProtected: true,
                serviceZipCode: "55555",
            };

            const expected = {
                addressQuestions: {
                    streetAddress: "555 Some St",
                    apartmentNumberOrBusinessName: "Apt 1",
                    city: "Funkytown",
                    state: "OH",
                    zipCode: "55555",
                },
                isVehicleProtected: true,
                serviceZipCode: "55555",
            };

            // Act
            const result = deepClone(object);

            // Assert
            expect(result).toStrictEqual(expected);
        });

        it("Should return a copy of the array", async () => {
            // Arrange

            const array = [9, 8, 7, 6, 5, 4, 3, 2, 1];

            const expected = [9, 8, 7, 6, 5, 4, 3, 2, 1];

            // Act
            const result = deepClone(array);

            // Assert
            expect(result).toStrictEqual(expected);
        });
    });

    describe("deepEqual", () => {
        it("Should return false if the items being compared are not the same type", async () => {
            // Arrange
            const obj1 = ""; // String
            const obj2 = 3; // Number
            const expected = false;

            // Act
            const result = deepEqual(obj1, obj2);

            // Assert
            expect(result).toEqual(expected);
        });

        it("Should return false if one the items being compared is null", async () => {
            // Arrange
            const obj1 = {}; // Object
            const obj2 = null; // Array
            const expected = false;

            // Act
            const result = deepEqual(obj1, obj2);

            // Assert
            expect(result).toEqual(expected);
        });

        describe("Both items being compared are arrays", () => {
            it("Should return true if the two arrays have the same elements in the same order", async () => {
                // Arrange
                const obj1 = [1, 2, 3]; // Array
                const obj2 = [1, 2, 3]; // Array
                const expected = true;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return true if the two arrays have the same elements in a different order", async () => {
                // Arrange
                const obj1 = [1, 2, 3]; // Array
                const obj2 = [3, 1, 2]; // Array
                const expected = true;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return false if the two arrays are not the same length", async () => {
                // Arrange
                const obj1 = [1, 2, 3]; // Array
                const obj2 = [1, 2]; // Array
                const expected = false;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return false if they have the same elements but their the array elements are different", async () => {
                // Arrange
                const obj1 = [1, 2, 3]; // Array
                const obj2 = [4, 5, 6]; // Array
                const expected = false;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });
        });

        describe("Both items being compared are objects", () => {
            it("Should return false if the two objects *do not* have the same number of keys", async () => {
                // Arrange
                const obj1 = {
                    prop1: {},
                }; // Object

                const obj2 = {
                    prop1: {},
                    prop2: {},
                }; // Object
                const expected = false;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return true if the two objects have the same keys in the same order", async () => {
                // Arrange
                const obj1 = {
                    prop1: {},
                    prop2: {},
                }; // Object

                const obj2 = {
                    prop1: {},
                    prop2: {},
                }; // Object

                const expected = true;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return true if the two objects have the same keys in a different order", async () => {
                // Arrange
                const obj1 = {
                    prop1: {},
                    prop2: {},
                }; // Object

                const obj2 = {
                    prop2: {},
                    prop1: {},
                }; // Object

                const expected = true;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return false if the two objects have the same keys but in a nested object comparison one of the two values is null", async () => {
                // Arrange
                const obj1 = {
                    prop1: {
                        subProp1: {
                            foo: "",
                            bar: null,
                        },
                    },
                    prop2: {
                        subProp1: [1, 2, 3],
                    },
                }; // Object

                const obj2 = {
                    prop1: {},
                    prop2: {},
                }; // Object

                const expected = false;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });

            it("Should return false if the two objects have the same elements but a nested object comparison is of two different types", async () => {
                // Arrange
                const obj1 = {
                    prop1: {
                        subProp1: {
                            foo: "",
                            bar: "",
                        },
                    },
                    prop2: {
                        subProp1: [1, 2, 3],
                    },
                }; // Object

                const obj2 = {
                    prop1: {
                        subProp1: {
                            foo: "",
                            bar: "",
                        },
                    },
                    prop2: {
                        subProp1: {
                            foo1: "",
                            bar1: "",
                        },
                    },
                }; // Object

                const expected = false;

                // Acts
                const result = deepEqual(obj1, obj2);

                // Assert
                expect(result).toEqual(expected);
            });
        });
    });
});
