import {clone} from "../../../source/util/clone.mjs";
import {expect} from "chai"

describe('Clone', function () {

    class A {
        constructor(b) {
            this.b = b
        }

        a() {

        }
    }
    
    class B {
        constructor(b) {
            this.b = b
        }

        a() {

        }
        
        getClone() {
            return "DONE"
        }
        
    }

    describe('.clone(B) with getClone', function () {
        it('.clone(B) should object', function () {
            let b = new B({
                x: {
                    y: 1, d: new A(1), z: () => {
                    }
                }
            });
            let r = clone(b);
            expect(b).to.be.instanceOf(B)
            expect(r).not.equal(b);
            expect(JSON.stringify(r)).equal(JSON.stringify('DONE'));

        });
    })
    
    describe('.clone(A)', function () {
        it('.clone(A) should object', function () {
            let a = new A({
                x: {
                    y: 1, d: new A(1), z: () => {
                    }
                }
            });
            let b = clone(a);
            expect(a).to.be.instanceOf(A)
            expect(b).to.be.instanceOf(A)
            expect(b).not.equal(a);
            expect(JSON.stringify(a)).equal(JSON.stringify(b));

        });
    })

    // nodejs does not have a DOM
    if (typeof DocumentFragment === "object") {
        describe('.clone(DocumentFragment)', function () {
            it('.clone(DocumentFragment) should same DocumentFragment', function () {
                let a = document.createDocumentFragment();
                let b = clone(a);
                expect(b).equal(a);
            });
        })
    }

    describe('.clone(null)', function () {
        // typeof null results in 'object'.  https://2ality.com/2013/10/typeof-null.html
        it('.clone(null) should  null', function () {
            let a = null
            let b = clone(a);
            expect(b).equal(a);
            expect(b).to.be.null;
            expect(a).to.be.null;
        });
    })

    describe('.clone(undefined)', function () {
        it('.clone(undefined) should  undefined', function () {
            let a = undefined
            let b = clone(a);
            expect(a === b).to.be.true
            expect(typeof b === 'undefined').to.be.true
            expect(a === undefined).to.be.true
            expect(b === undefined).to.be.true
        });
    })

    describe('.clone(object)', function () {

        it('.clone({}) should  object', function () {
            let a = {}
            let b = clone(a);
            expect(typeof b === 'object').to.be.true
        });

        it('.clone({x:1}) should  object', function () {
            let a = {x: 1}
            let b = clone(a);
            expect(a.x).is.equal(b.x)
        });
    })
    describe('.clone(function)', function () {

        it('.clone(function) should  function', function () {
            let a = () => {
            }
            let b = clone(a);
            expect(typeof b === 'function').to.be.true
        });

    })

    describe('.clone(Map)', function () {
        it('.clone(Map) should preserve entries', function () {
            let a = new Map([
                ['x', 1],
                ['y', {z: 2}],
            ]);
            let b = clone(a);
            expect(b).to.be.instanceOf(Map);
            expect(b).not.equal(a);
            expect(b.get('x')).to.equal(1);
            expect(JSON.stringify(b.get('y'))).to.equal(JSON.stringify({z: 2}));
        });
    })

    describe('.clone(Set)', function () {
        it('.clone(Set) should preserve values', function () {
            let a = new Set([1, 2, 3]);
            let b = clone(a);
            expect(b).to.be.instanceOf(Set);
            expect(b).not.equal(a);
            expect([...b]).to.deep.equal([1, 2, 3]);
        });
    })

    describe('.clone(RegExp)', function () {
        it('.clone(RegExp) should preserve pattern and flags', function () {
            let a = /test/gi;
            let b = clone(a);
            expect(b).to.be.instanceOf(RegExp);
            expect(b).not.equal(a);
            expect(b.source).to.equal(a.source);
            expect(b.flags).to.equal(a.flags);
        });
    })

    describe('.clone()', function () {

        [
            ['test1', 'string'],
            [undefined, 'undefined'],
            [null, 'object'], // typeof null results in 'object'.  https://2ality.com/2013/10/typeof-null.html
            [() => {
            }, 'function'],
            [2, 'number'],
            [false, 'boolean'],
            [true, 'boolean'],
            [4.5, 'number'],
            [{}, 'object'],
            [[1, 2, 3], 'object'], // array ist auch type object
            [Symbol("foo"), 'symbol'],
        ].forEach(function (data) {

            let a = data.shift()
            let b = data.shift()


            it('.clone(' + JSON.stringify(a) + ') should  ' + b + ' ', function () {
                let c = clone(a);
                expect(typeof c).is.equal(b);
            });


        });


    });

});
