<commit_before>import should from 'should';
import u from 'updeep';
import moment from 'moment';

import diffOperations from '../server/lib/diff-operations';
import { UNKNOWN_OPERATION_TYPE } from '../shared/helpers';

let A = {
    title: "Toto",
    raw: "Toto",
    amount: 10,
    date: new Date(),
    type: 'type.transfer'
};

let copyA = { ...A };

let B = {
    title: "Savings",
    raw: "Savings",
    amount: 15,
    date: moment(new Date()).add(10, 'day').toDate(),
    type: 'type.card'
};

let copyB = { ...B };

let C = {
    title: "Bury me with my money",
    raw: "Bury me with my money",
    amount: 35,
    date: moment(new Date()).add(20, 'day').toDate(),
    type: 'type.card'
};

let copyC = { ...C };

describe("diffing operations when there's only one operation", function() {
    it('should return an exact match for the same operation', () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [copyA]);
        perfectMatches.length.should.equal(1);

        let match = perfectMatches[0];
        match[0].should.equal(A);
        match[1].should.equal(copyA);

        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);
        duplicateCandidates.length.should.equal(0);
    });

    it("should insert a single provider's operation", () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([], [A]);

        perfectMatches.length.should.equal(0);

        providerOrphans.length.should.equal(1);
        providerOrphans[0].should.equal(A);

        knownOrphans.length.should.equal(0);
        duplicateCandidates.length.should.equal(0);
    });

    it("should mark a known single operation as orphan", () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], []);

        perfectMatches.length.should.equal(0);
        providerOrphans.length.should.equal(0);

        knownOrphans.length.should.equal(1);
        knownOrphans[0].should.equal(A);

        duplicateCandidates.length.should.equal(0);
    });

    it("should merge a single operation when the dates are separated by 1 day", () => {
        let changedA = u({
            date: moment(A.date).add(1, 'day').toDate()
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [changedA]);

        perfectMatches.length.should.equal(0);
        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(1);
        let pair = duplicateCandidates[0];
        pair[0].should.equal(A);
        pair[1].should.equal(changedA);
    });

    it("should select the operation with the closest date as duplicate, and detect the other as orphan", () => {
        let changedA = u({
            date: moment(A.date).add(1, 'day').toDate()
        }, A);

        let youngerA = u({
            date: moment(A.date).add(2, 'day').toDate()
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [changedA, youngerA]);

        perfectMatches.length.should.equal(0);
        providerOrphans.length.should.equal(1);
        providerOrphans[0].should.equal(youngerA);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(1);
        let pair = duplicateCandidates[0];
        pair[0].should.equal(A);
        pair[1].should.equal(changedA);
    });

    it("should merge an operation if the provided operation has an unknown type.", () => {
        let changedA = u({
            type: UNKNOWN_OPERATION_TYPE
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [changedA]);

        perfectMatches.length.should.equal(1);
        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(0);
    });
});

describe("diffing operation when there are several operations", function() {
    it("should find perfect matches in any order", () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A, B, C], [copyB, copyC, copyA]);

        perfectMatches.length.should.equal(3);

        let match = perfectMatches[0];<commit_msg>Add unit test of operations diff when known op has unknown type<commit_after>import should from 'should';
import u from 'updeep';
import moment from 'moment';

import diffOperations from '../server/lib/diff-operations';
import { UNKNOWN_OPERATION_TYPE } from '../shared/helpers';

let A = {
    title: "Toto",
    raw: "Toto",
    amount: 10,
    date: new Date(),
    type: 'type.transfer'
};

let copyA = { ...A };

let B = {
    title: "Savings",
    raw: "Savings",
    amount: 15,
    date: moment(new Date()).add(10, 'day').toDate(),
    type: 'type.card'
};

let copyB = { ...B };

let C = {
    title: "Bury me with my money",
    raw: "Bury me with my money",
    amount: 35,
    date: moment(new Date()).add(20, 'day').toDate(),
    type: 'type.card'
};

let copyC = { ...C };

describe("diffing operations when there's only one operation", function() {
    it('should return an exact match for the same operation', () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [copyA]);
        perfectMatches.length.should.equal(1);

        let match = perfectMatches[0];
        match[0].should.equal(A);
        match[1].should.equal(copyA);

        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);
        duplicateCandidates.length.should.equal(0);
    });

    it("should insert a single provider's operation", () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([], [A]);

        perfectMatches.length.should.equal(0);

        providerOrphans.length.should.equal(1);
        providerOrphans[0].should.equal(A);

        knownOrphans.length.should.equal(0);
        duplicateCandidates.length.should.equal(0);
    });

    it("should mark a known single operation as orphan", () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], []);

        perfectMatches.length.should.equal(0);
        providerOrphans.length.should.equal(0);

        knownOrphans.length.should.equal(1);
        knownOrphans[0].should.equal(A);

        duplicateCandidates.length.should.equal(0);
    });

    it("should merge a single operation when the dates are separated by 1 day", () => {
        let changedA = u({
            date: moment(A.date).add(1, 'day').toDate()
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [changedA]);

        perfectMatches.length.should.equal(0);
        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(1);
        let pair = duplicateCandidates[0];
        pair[0].should.equal(A);
        pair[1].should.equal(changedA);
    });

    it("should select the operation with the closest date as duplicate, and detect the other as orphan", () => {
        let changedA = u({
            date: moment(A.date).add(1, 'day').toDate()
        }, A);

        let youngerA = u({
            date: moment(A.date).add(2, 'day').toDate()
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [changedA, youngerA]);

        perfectMatches.length.should.equal(0);
        providerOrphans.length.should.equal(1);
        providerOrphans[0].should.equal(youngerA);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(1);
        let pair = duplicateCandidates[0];
        pair[0].should.equal(A);
        pair[1].should.equal(changedA);
    });

    it("should merge an operation if the provided operation has an unknown type.", () => {
        let changedA = u({
            type: UNKNOWN_OPERATION_TYPE
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A], [changedA]);

        perfectMatches.length.should.equal(1);
        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(0);
    });
    
    it("should merge an operation if the known operation has an unknown type.", () => {
        let changedA = u({
            type: UNKNOWN_OPERATION_TYPE
        }, A);

        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([changedA], [A]);

        perfectMatches.length.should.equal(1);
        providerOrphans.length.should.equal(0);
        knownOrphans.length.should.equal(0);

        duplicateCandidates.length.should.equal(0);
    });
});

describe("diffing operation when there are several operations", function() {
    it("should find perfect matches in any order", () => {
        let {
            perfectMatches,
            providerOrphans,
            knownOrphans,
            duplicateCandidates
        } = diffOperations([A, B, C], [copyB, copyC, copyA]);

        perfectMatches.length.should.equal(3);

        let match = perfectMatches[0];
{'fraction_non_alphanumeric': 0.1305109489051095, 'fraction_numerical': 0.010510948905109488, 'mean_word_length': 2.1824094146794675, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 18, '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': '4977996', 'n_tokens_mistral': 3081, 'n_tokens_neox': 3001, 'n_words': 621}