<repo_name>KairiGG/ENSIIE_S3-CI<file_sep>/src/book.repository.test.js
const BookRepository = require('./book.repository');

describe('Book repository Save', function () {

    test('Save a book', () => {

        const dbMock = {
            get : jest.fn().mockReturnThis(),
            push : jest.fn().mockReturnThis(),
            write : jest.fn().mockReturnThis()
        };
        const repository = new BookRepository(dbMock);
        repository.save({id: 1, name: "<NAME>"});

        expect(dbMock.write.mock.calls.length).toBe(1);
    });
});

describe('Book repository GetTotalCount', function () {

    test('Get total count of books', () => {

        const dbMock = {
            get : jest.fn().mockReturnThis(),
            size : jest.fn().mockReturnThis(),
            value : jest.fn().mockReturnValue(3)
        };
        const repository = new BookRepository(dbMock);

        expect(repository.getTotalCount()).toBe(3);
    });
});

describe('Book repository GetTotalPrice', function () {

    test('Get total price of books', () => {

        const dbMock = {
            get : jest.fn().mockReturnThis(),
            map : jest.fn().mockReturnThis(),
            value : jest.fn().mockReturnValue([5, 5, 5, 5, 5, 5, 5])
        };
        const repository = new BookRepository(dbMock);

        expect(repository.getTotalPrice()).toBe(35);
    });
});

describe('Book repository GetBookByName', function () {

    test('Get book by name', () => {

        const dbMock = {
            get : jest.fn().mockReturnThis(),
            find : jest.fn().mockReturnThis(),
            value : jest.fn().mockReturnValue({ "id": 1, "name": "test", "price": 6.1, "added_at": "2019-01-01" })
        };
        const repository = new BookRepository(dbMock);

        expect(repository.getBookByName('test')).toStrictEqual({ "id": 1, "name": "test", "price": 6.1, "added_at": "2019-01-01" });
    });
});

describe('Book repository getCountBookAddedByMonth', function () {

    test('Get count book added by month', () => {

        const dbMock = {
            get : jest.fn().mockReturnThis(),
            filter : jest.fn().mockReturnThis(),
            map : jest.fn().mockReturnThis(),
            value : jest.fn().mockReturnValue([ "2019-06-02", "2021-01-01", "2019-01-01", "2020-03-01", "2019-01-04", "2021-02-01", "2019-01-01", "2032-01-01", "2019-01-01" ])
        };
        const repository = new BookRepository(dbMock);

        expect(repository.getCountBookAddedByMonth('test')).toStrictEqual([ { year: '2019', month: 1, count: 4, count_cumulative: 4 },
  { year: '2019', month: 6, count: 1, count_cumulative: 5 },
  { year: '2020', month: 3, count: 1, count_cumulative: 1 },
  { year: '2021', month: 1, count: 1, count_cumulative: 1 },
  { year: '2021', month: 2, count: 1, count_cumulative: 2 },
  { year: '2032', month: 1, count: 1, count_cumulative: 1 } ]
);
    });
});
<file_sep>/src/interval.test.js
const Interval = require('./interval');

describe('overlaps', function () {

	test('Test overlapping, if two intervals overlap each other {(1, 3),(2, 4)}', () => {
		let interval1 = new Interval(1, 3);
		let interval2 = new Interval(2, 4);
    	expect(interval1.overlaps(interval2)).toBe(true);
	});

	test('Test overlapping, if two intervals don\'t overlap each other{(1, 2),(3, 4)}', () => {
		let interval1 = new Interval(1,2);
		let interval2 = new Interval(3,4);
		expect(interval1.overlaps(interval2)).toBe(false);
	});

	test('Test overlapping, if two intervals don\'t overlap each other{(3, 4),(1, 2)}', () => {
		let interval1 = new Interval(3,4);
		let interval2 = new Interval(1,2);
		expect(interval1.overlaps(interval2)).toBe(false);
	});
});

describe('includes', function () {

	test('Test include function, if the interval contains the argument {(1, 4),(2, 3)}', () => {
		let interval1 = new Interval(1, 4);
		let interval2 = new Interval(2, 3);
    	expect(interval1.includes(interval2)).toBe(true);
	});

	test('Test include function, if the interval start after the argument {(2, 4),(1, 3)}', () => {
		let interval1 = new Interval(2, 4);
		let interval2 = new Interval(1, 3);
    	expect(interval1.includes(interval2)).toBe(false);
	});

	test('Test include function, if the interval end before the argument {(1, 3),(2, 4)}', () => {
		let interval1 = new Interval(1,3);
		let interval2 = new Interval(2,4);
		expect(interval1.includes(interval2)).toBe(false);
	});

	test('Test include function, if the interval end equals the argument {(1, 4),(1, 4)}', () => {
		let interval1 = new Interval(1,4);
		let interval2 = new Interval(1,4);
		expect(interval1.includes(interval2)).toBe(true);
	});
});

describe('union', function () {

	test('Test union function, if the interval overlap the argument {(1, 3),(2, 4)}', () => {
		let interval1 = new Interval(1, 3);
		let interval2 = new Interval(2, 4);
    		expect(interval1.union(interval2)).toStrictEqual([new Interval(1,4)]);
	});

	test('Test union function, if the interval doesn\'t overlap the argument {(1, 2),(3, 4)}', () => {
		let interval1 = new Interval(1, 2);
		let interval2 = new Interval(3, 4);
    		expect(interval1.union(interval2)).toStrictEqual([interval1, interval2]);
	});
});

describe('intersection', function () {

	test('Test intersection function, if the interval overlap the argument {(1, 3),(2, 4)}', () => {
		let interval1 = new Interval(1, 3);
		let interval2 = new Interval(2, 4);
    		expect(interval1.intersection(interval2)).toStrictEqual(new Interval(2,3));
	});

	test('Test intersection function, if the interval doesn\'t overlap the argument {(1, 2),(3, 4)}', () => {
		let interval1 = new Interval(1, 2);
		let interval2 = new Interval(3, 4);
    		expect(interval1.intersection(interval2)).toStrictEqual(null);
	});
});

describe('exclusion', function () {

	test('Test exclusion function, if the interval overlap the argument {(1, 3),(2, 4)}', () => {
		let interval1 = new Interval(1, 3);
		let interval2 = new Interval(2, 4);
    		expect(interval1.exclusion(interval2)).toStrictEqual([new Interval(1,2), new Interval(3,4)]);
	});

	test('Test exclusion function, if the interval doesn\'t overlap the argument {(1, 2),(3, 4)}', () => {
		let interval1 = new Interval(1, 2);
		let interval2 = new Interval(3, 4);
    		expect(interval1.exclusion(interval2)).toStrictEqual([interval1, interval2]);
	});
});

<file_sep>/src/math.js
let Util = {};
Util.factorial = (n) => {
    if (n === 0) {
        return 1;
    }

    if (n >= 3000) {
        throw 'n too large'
    }

    if (n < 0) {
        throw 'n is negative'
    }

    return n * Util.factorial(n - 1);
};

/**
 * Détermine si n est un nombre premier.
 * Util.isPrime(5) => false
 * Util.isPrime(6) => true
 *
 * @param {number} n
 * @returns {boolean}
 */
Util.isPrime = function (n) {
    if (n === 1 || n === 0) {
        return false;
    }
    if (n < 0) {
        throw 'Unable to compute prime for n < 0'
    }
    for (var i = 2; i < n; i++)
        if (n % i === 0) return false;
    return true;

};


/**
 * Additionne l'ensemble des nombres premiers de 2 à n
 *
 * Util.sumPrime(6) = 2 + 3 + 5 = 10
 * Util.sumPrime(8) = 2 + 3 + 5 + 7 = 17
 *
 * @param {number} n
 * @returns {number}
 */
Util.sumPrime = function(n) {
	if(!Util.isPrime(n)) {
		throw 'n is not prime'
	}
    else {
    	let result = 0;
		for(let i = 2; i <= n; i++) {
    		if(Util.isPrime(i))
    			result += i;
    	}
    	return result;
    }
};

/**
 * Cette méthode doit retourner un tableau de 1 à n tel que:
 * - Pour les nombres multiples de 3, les remplacer par "Fizz"
 * - Pour les nombres multiples de 5, les remplacer par "Buzz"
 * - Pour les nombres multiples de 3 et 5, les remplacer par "FizzBuzz"
 *
 * Exp :
 * Util.fizzBuzz(15) => [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
 *
 * @param {number} n
 * @returns {array}
 */
Util.fizzBuzz = function(n) {
	if(n < 1)
		throw 'n should be superior to 0'
	let result = []
	for(let i=1; i < n + 1; i++)
		result.push((i%3?'':'Fizz') + (i%5?'':'Buzz') || i)
	return result;
};

/**
 * Chiffre une phrase selon la règle suivante : Les A deviennent des B, les B des C, etc.
 *
 * Exp :
 * Util.cipher("Test Unitaire") => "Uftu Tojubjsf"
 *
 * @param phrase
 * @returns {string}
 */
Util.cipher = function (phrase) {
	let charTransformation = (char) => {
		let charValue = char.charCodeAt(0);
		if(charValue < 65 || charValue > 122 
		|| (charValue > 90 && charValue < 97)) {
			return char; //special char -> return char
		} else {
			if(charValue == 90) {
				return 'A'; //'Z' case -> return 'A'
			} else if(charValue == 122) {
				return 'a'; //'z' case -> return 'a'
			} else {
				return String.fromCharCode(charValue + 1);
			}
		}
	};

	let charCollection = phrase.split("");
	return charCollection.map( c => charTransformation(c) )
			.reduce( (str, char) => str += char );
};

module.exports = Util;
<file_sep>/src/math.test.js
const Util = require('./math');

describe('isPrime', function () {

	test('Test factoriel de 0 => 1', () => {
    	expect(Util.factorial(0)).toBe(1);
	});

	test('Test factoriel de 2 => 2', () => {
		expect(Util.factorial(3)).toBe(6);
	});

	test('Test factoriel de 3 => 6', () => {
		expect(Util.factorial(3)).toBe(6);
	});

	test('Test factoriel de 3000', () => {
		expect(()=> {Util.factorial(3000)}).toThrow();
	});

	test('Test factoriel -10', () => {
		expect(()=> {Util.factorial(-10)}).toThrow(/negative/);
	});
});



describe('isPrime', function () {

    test('Test prime de 1 => false', () => {
        expect(Util.isPrime(1)).toBe(false)
    });
    test('Test prime de 0 => false', () => {
        expect(Util.isPrime(0)).toBe(false)
    });
    test('Test prime < 0 => throw exception', () => {
        expect(() => { Util.isPrime(-10) }).toThrow('Unable to compute prime for n < 0');
    });

    test.each([
        [2, true],
        [5, true],
        [17, true],
        [18, false],
        [53, true],
        [55, false],
    ])(
        'isPrime %i equals to %i',
        (n, expected) => {
            expect(Util.isPrime(n)).toBe(expected);
        }
    );
});

describe('sumPrime', function () {

	test('Test somme d\'un nombre non-premier négatif, n=-10', () => {
    	expect(() => {Util.sumPrime(-10)}).toThrow('Unable to compute prime for n < 0');
	});

	test('Test somme d\'un nombre non-premier, n=26', () => {
    	expect(() => {Util.sumPrime(26)}).toThrow('n is not prime');
	});

	test('Test somme d\'un nombre premier, n=7', () => {
    	expect(Util.sumPrime(7)).toBe(17);
	});

	test('Test somme d\'un nombre premier, n=47', () => {
    	expect(Util.sumPrime(47)).toBe(328);
	});
});

describe('fizzBuzz', function () {

	test('Test FizzBuzz n < 1, n=0', () => {
    	expect(() => {Util.fizzBuzz(0)}).toThrow('n should be superior to 0');
	});

	test('Test FizzBuzz n < 1, n=-63', () => {
    	expect(() => {Util.fizzBuzz(-63)}).toThrow('n should be superior to 0');
	});

	test('Test FizzBuzz, n=15', () => {
		let expectedResult = [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"];
    	expect(Util.fizzBuzz(15)).toStrictEqual(expectedResult);
	});

	test('Test FizzBuzz, n=30', () => {
		let expectedResult = [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"
							, 16, 17, "Fizz", 19, "Buzz", "Fizz", 22, 23, "Fizz", "Buzz", 26, "Fizz", 28, 29, "FizzBuzz"];
    	expect(Util.fizzBuzz(30)).toStrictEqual(expectedResult);
	});
});

describe('cipher', function () {
	test('Test cipher, phrase="Test Unitaire"', () => {
		expect(Util.cipher('Test Unitaire')).toBe('Uftu Vojubjsf');
	});

	test('Test cipher avec phrase contenant "z", phrase="Test Unitaire du z"', () => {
		expect(Util.cipher('Test Unitaire du z')).toBe('Uftu Vojubjsf ev a');
	});

	test('Test cipher avec phrase contenant "Z", phrase="Test Unitaire du Z"', () => {
		expect(Util.cipher('Test Unitaire du Z')).toBe('Uftu Vojubjsf ev A');
	});

	test('Test cipher avec phrase contenant des caractèresspéciaux, phrase="\'"&@=+!§^?,;é"', () => {
		expect(Util.cipher('\'"&@=+!§^?,;é')).toBe('\'"&@=+!§^?,;é');
	});

});
<file_sep>/src/test-script.js
const BookRepository = require('./book.repository');
const db = require('./db')

const repository = new BookRepository(db);
<file_sep>/src/book.repository.js
class BookRepository {

    /**
     * @param db
     */
    constructor(db) {
        this.db = db;
    }

    save (book) {
        this.db.get('books').push(book).write();
    }

    /**
     * Nombre total de livre
     */
    getTotalCount() {
		return this.db.get('books').size().value();
    }

    /**
     * Somme du prix de tous les livre
     */
    getTotalPrice() {
		return this.db.get('books').map('price').value()
		.reduce( (acc, val) => acc += val );
    }


    /**
     * Retourne un livre
     */
    getBookByName(bookName) {
		return this.db.get('books')
	  		.find({ name: bookName })
	  		.value();
    }

    /**
     * Nombre de livre ajouté par mois
     *
     *  [
     *      {
     *          year: 2017,
     *          month: 2,
     *          count: 129,
     *          count_cumulative: 129
     *      },
     *      {
     *          year: 2017,
     *          month: 3,
     *          count: 200,
     *          count_cumulative: 329
     *      },
     *      ....
     *  ]
     */
    getCountBookAddedByMonth(bookName) {
	    let dates = this.db.get('books')
                   .filter({ name: bookName})
                   .map('added_at')
                   .value()
                   .map( function(date){ return {year: new Date(date).getYear() + 1900, month: new Date(date).getMonth()}} );
        
        let planning = {};
        for(let date of dates) {
            if(!(date.year in planning))
                planning[date.year] = new Array(12).fill(0);
            planning[date.year][date.month] += 1;
        }
        
        let cumulativePlanning = JSON.parse(JSON.stringify(planning))
        for(let year in cumulativePlanning)
            for(let i = 1; i < cumulativePlanning[year].length; i++)
                cumulativePlanning[year][i] += cumulativePlanning[year][i - 1];
        
        let accounting = [];
        for(let year in planning) {
            for(let i = 0; i < planning[year].length; i++)
                if(planning[year][i] > 0)
                    accounting.push(
                        {year: year, month: i + 1, count: planning[year][i], count_cumulative: cumulativePlanning[year][i]}
                    );
        }
        
        return accounting;
    }

}


module.exports = BookRepository;
