<commit_before>import {jsonMember, jsonObject, TypedJSON} from '../src';

TypedJSON.setGlobalConfig({
    errorHandler: e => {
        throw e;
    },
});

describe('mapped types', () => {
    class CustomType {
        value: any;

        constructor(value: any) {
            this.value = value;
        }

        hasSucceeded(): boolean {
            return this.value != null;
        }
    }

    @jsonObject
    class MappedTypesSpec {

        @jsonMember
        one: CustomType;

        @jsonMember
        two: CustomType;
    }

    const testData = {
        one: 1,
        two: 2,
    };

    describe('global', () => {
        TypedJSON.mapType(CustomType, {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        });

        it('deserializes', () => {
            const result = TypedJSON.parse(testData, MappedTypesSpec);

            expect(result.one).toBeInstanceOf(CustomType);
            expect(result.one.hasSucceeded()).toBeTrue();
            expect(result.two).toBeInstanceOf(CustomType);
            expect(result.two.hasSucceeded()).toBeTrue();
        });

        it('serializes', () => {
            const test = new MappedTypesSpec();
            test.one = new CustomType(1);
            test.two = new CustomType(2);
            const result = TypedJSON.toPlainJson(test, MappedTypesSpec);

            expect(result).toEqual(testData);
        });
    });

    describe('instance', () => {
        const typedJson = new TypedJSON(MappedTypesSpec);
        typedJson.mapType(CustomType, {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        });

        it('deserializes', () => {
            const result = typedJson.parse(testData);

            expect(result.one).toBeInstanceOf(CustomType);
            expect(result.one.hasSucceeded()).toBeTrue();
            expect(result.two).toBeInstanceOf(CustomType);
            expect(result.two.hasSucceeded()).toBeTrue();
        });

        it('serializes', () => {
            const test = new MappedTypesSpec();
            test.one = new CustomType(1);
            test.two = new CustomType(2);
            const result = typedJson.toPlainJson(test);

            expect(result).toEqual(testData);
        });
    });

    describe('works with constructor,', () => {
        @jsonObject
        class MappedTypeWithConstructor {

            @jsonMember({constructor: CustomType})
            nullable: any;
        }

        const typedJson = new TypedJSON(MappedTypeWithConstructor);
        const CustomTypeMap = {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        };
        typedJson.mapType(CustomType, CustomTypeMap);

        it('deserializes', () => {
            spyOn(CustomTypeMap, 'deserializer').and.callThrough();
            const result = typedJson.parse({nullable: 5});
            expect(result.nullable?.hasSucceeded()).toBeTrue();
            expect(result.nullable?.value).toBe(5);
            expect(CustomTypeMap.deserializer).toHaveBeenCalled();
        });

        it('serializes', () => {
            spyOn(CustomTypeMap, 'serializer').and.callThrough();
            const object = new MappedTypeWithConstructor();
            object.nullable = new CustomType(5);
            const result = typedJson.toPlainJson(object);
            expect(CustomTypeMap.serializer).toHaveBeenCalled();
            expect(result).toEqual({nullable: 5});
        });
    });
});<commit_msg>Test overwriting transformers of mapped types<commit_after>import {jsonMember, jsonObject, TypedJSON} from '../src';

TypedJSON.setGlobalConfig({
    errorHandler: e => {
        throw e;
    },
});

describe('mapped types', () => {
    class CustomType {
        value: any;

        constructor(value: any) {
            this.value = value;
        }

        hasSucceeded(): boolean {
            return this.value != null;
        }
    }

    @jsonObject
    class MappedTypesSpec {

        @jsonMember
        one: CustomType;

        @jsonMember
        two: CustomType;
    }

    const testData = {
        one: 1,
        two: 2,
    };

    describe('global', () => {
        TypedJSON.mapType(CustomType, {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        });

        it('deserializes', () => {
            const result = TypedJSON.parse(testData, MappedTypesSpec);

            expect(result.one).toBeInstanceOf(CustomType);
            expect(result.one.hasSucceeded()).toBeTrue();
            expect(result.two).toBeInstanceOf(CustomType);
            expect(result.two.hasSucceeded()).toBeTrue();
        });

        it('serializes', () => {
            const test = new MappedTypesSpec();
            test.one = new CustomType(1);
            test.two = new CustomType(2);
            const result = TypedJSON.toPlainJson(test, MappedTypesSpec);

            expect(result).toEqual(testData);
        });
    });

    describe('instance', () => {
        const typedJson = new TypedJSON(MappedTypesSpec);
        typedJson.mapType(CustomType, {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        });

        it('deserializes', () => {
            const result = typedJson.parse(testData);

            expect(result.one).toBeInstanceOf(CustomType);
            expect(result.one.hasSucceeded()).toBeTrue();
            expect(result.two).toBeInstanceOf(CustomType);
            expect(result.two.hasSucceeded()).toBeTrue();
        });

        it('serializes', () => {
            const test = new MappedTypesSpec();
            test.one = new CustomType(1);
            test.two = new CustomType(2);
            const result = typedJson.toPlainJson(test);

            expect(result).toEqual(testData);
        });
    });

    describe('works with constructor,', () => {
        @jsonObject
        class MappedTypeWithConstructor {

            @jsonMember({constructor: CustomType})
            nullable: any;
        }

        const typedJson = new TypedJSON(MappedTypeWithConstructor);
        const CustomTypeMap = {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        };
        typedJson.mapType(CustomType, CustomTypeMap);

        it('deserializes', () => {
            spyOn(CustomTypeMap, 'deserializer').and.callThrough();
            const result = typedJson.parse({nullable: 5});
            expect(result.nullable?.hasSucceeded()).toBeTrue();
            expect(result.nullable?.value).toBe(5);
            expect(CustomTypeMap.deserializer).toHaveBeenCalled();
        });

        it('serializes', () => {
            spyOn(CustomTypeMap, 'serializer').and.callThrough();
            const object = new MappedTypeWithConstructor();
            object.nullable = new CustomType(5);
            const result = typedJson.toPlainJson(object);
            expect(CustomTypeMap.serializer).toHaveBeenCalled();
            expect(result).toEqual({nullable: 5});
        });
    });

    it('can be overwritten with deserializer/serializer prop', () => {
        const jsonMemberOptions = {
            deserializer: json => new CustomType(0),
            serializer: value => 1,
        };

        const CustomTypeMap = {
            deserializer: json => new CustomType(json),
            serializer: value => value.value,
        };

        spyOn(CustomTypeMap, 'serializer').and.callThrough();
        spyOn(jsonMemberOptions, 'serializer').and.callThrough();
        spyOn(CustomTypeMap, 'deserializer').and.callThrough();
        spyOn(jsonMemberOptions, 'deserializer').and.callThrough();

        @jsonObject
        class OverriddenSerializer {
            @jsonMember(jsonMemberOptions)
            overwritten: CustomType;

            @jsonMember
            simple: CustomType;
        }

        const typedJson = new TypedJSON(OverriddenSerializer);
        typedJson.mapType(CustomType, CustomTypeMap);

        const parsed = typedJson.parse({data: 5, simple: 5});
        expect(CustomTypeMap.deserializer).toHaveBeenCalledTimes(1);
        expect(jsonMemberOptions.deserializer).toHaveBeenCalledTimes(1);
        expect(parsed.overwritten.value).toBe(0);
        expect(parsed.simple.value).toBe(5);

        const plain: any = typedJson.toPlainJson(parsed);
        expect(CustomTypeMap.serializer).toHaveBeenCalledTimes(1);
        expect(jsonMemberOptions.serializer).toHaveBeenCalledTimes(1);
        expect(plain.overwritten).toBe(1);
        expect(plain.simple).toBe(5);
    });
});
{'fraction_non_alphanumeric': 0.1295742232451093, 'fraction_numerical': 0.003682393555811277, 'mean_word_length': 2.1477725461789205, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5292912', 'n_tokens_mistral': 2404, 'n_tokens_neox': 2362, 'n_words': 394}