<commit_before>/// <reference types="mocha" />

import { expect, use } from 'chai';
import * as sinon from 'sinon';
import * as sinonChai from 'sinon-chai';
use(sinonChai);

import { CrudController } from '../crud-controller';

import { Injectable } from '../../decorators/services/injectable.decorator';
import { Request, Response } from 'express';
import { PolicyDescriptor } from '../../core/policy';
import { Db } from '../../core/db';
import { FakeDb } from '../../orm/test/fake-db';
import { FakeRequest } from '../../router/test/fake-request';
import { FakeResponse } from '../../router/test/fake-response';
import { HTTP_STATUS_ERROR, HTTP_STATUS_OK } from '../../util/http-status-type';

let any = sinon.match.any;

class TestModel {
    id: number;
    static db: Db<TestModel>;
}
class TestCrudController extends CrudController<TestModel> {
    constructor(pluralName?: string, singularName?: string) {
        super(TestModel, `TestModel`, pluralName, singularName);
    }
}

describe('CrudController', () => {
    let inst: TestCrudController;
    beforeEach(() => {
        inst = new TestCrudController();
        TestModel.db = new FakeDb<TestModel>();
    });
    
    describe('.ctor', () => {
        it('should create the singular name from the model name if one is not provided', () => {
            expect(inst.singularName).to.eq(`test-model`);
        });
        it('should use the provided singular name if one is provided', () => {
            let inst = new TestCrudController(undefined, 'my-singular-name');
            expect(inst.singularName).to.eq(`my-singular-name`);
        });
        it('should create the plural name from the model name if one is not provided', () => {
            expect(inst.pluralName).to.eq(`test-models`);
        });
        it('should use the provided plural name if one is provided', () => {
            let inst = new TestCrudController('my-plural-name');
            expect(inst.pluralName).to.eq(`my-plural-name`);
        });
    });
    
    describe('.splitOnWords', () => {
        let splitOnWords: (input: string) => IterableIterator<string>;
        beforeEach(() => {
            splitOnWords = (<any>inst).splitOnWords.bind(inst);
        });
        
        it('should yield an empty sequence on an empty input', () => {
            expect([...splitOnWords('')]).to.deep.eq([]);
        });
        it('should consider an uppercase letter the start of a new word', () => {
            expect([...splitOnWords('ABCdeF')]).to.deep.eq(['A', 'B', 'Cde', 'F']);
        });
        it('should consider an underscore the start of a new word', () => {
            expect([...splitOnWords('what_about_fish')]).to.deep.eq(['what', 'about', 'fish']);
        });
        it('should remove all underscores', () => {
            expect([...splitOnWords('___a_very___ODD_model_name____')]).to.deep.eq(['a', 'very', 'O', 'D', 'D', 'model', 'name']);
        });
    });
    
    describe('.getSingularPath', () => {
        let getSingularPath: (input: string) => string;
        beforeEach(() => {
            getSingularPath = (<any>inst).getSingularPath.bind(inst);
        });
        
        it('should return the input string if words cannot be parsed from it', () => {
            expect(getSingularPath('')).to.eq('');
            expect(getSingularPath('___')).to.eq('___');
        });
        it('should singularize the last word', () => {
            expect(getSingularPath('apples')).to.eq('apple');
            expect(getSingularPath('dog_orange_apples')).to.eq('dog-orange-apple');
        });
        it('should not modify any but the last word', () => {
            expect(getSingularPath('dogs_oranges_apples')).to.eq('dogs-oranges-apple');
        });
        it('should join the words using dashes', () => {
            expect(getSingularPath('ABCDE')).to.eq('a-b-c-d-e');
        });
        it('should transform all letters to lowercase', () => {
            expect(getSingularPath('YellowBrickRoad')).to.eq('yellow-brick-road');
        });
    });
    
    describe('.getPluralPath', () => {
        let getPluralPath: (input: string) => string;
        beforeEach(() => {
            getPluralPath = (<any>inst).getPluralPath.bind(inst);
        });
        
        it('should return the input string if words cannot be parsed from it', () => {
            expect(getPluralPath('')).to.eq('');
            expect(getPluralPath('___')).to.eq('___');
        });
        it('should pluralize the last word', () => {
            expect(getPluralPath('apple')).to.eq('apples');
            expect(getPluralPath('dogs_oranges_apple')).to.eq('dogs-oranges-apples');
        });
        it('should not modify any but the last word', () => {
            expect(getPluralPath('dog_orange_apple')).to.eq('dog-orange-apples');
        });
        it('should join the words using dashes', () => {
            expect(getPluralPath('ABCDQueue')).to.eq('a-b-c-d-queues');
        });
        it('should transform all letters to lowercase', () => {
            expect(getPluralPath('YellowBrickRoad')).to.eq('yellow-brick-roads');
        });
    });
    
    describe('.transformPathPart', () => {
        it('should replace %%PLURAL_NAME%% with the plural route path', () => {
            expect(inst.transformPathPart('blah', `one/%%PLURAL_NAME%%/three`)).to.eq(`one/${inst.pluralName}/three`);
        });
        it('should replace %%SINGULAR_NAME%% with the singular route path', () => {
            expect(inst.transformPathPart('blah', `one/%%SINGULAR_NAME%%/three`)).to.eq(`one/${inst.singularName}/three`);
        });
        it('should replace all instances of both route paths', () => {
            expect(inst.transformPathPart('blah', `one/%%SINGULAR_NAME%%/%%PLURAL_NAME%%/%%SINGULAR_NAME%%/%%PLURAL_NAME%%/three`))
                .to.eq(`one/${inst.singularName}/${inst.pluralName}/${inst.singularName}/${inst.pluralName}/three`);
        });
    });
    
    describe('.transformRoutePolicies', () => {
        let routes: [string, boolean, boolean][] = [
            ['create', true, true],
            ['update', true, true],
            ['destroy', true, true],
            ['find', true, false],
            ['count', true, false],
            ['get', true, false],
            ['', false, false]
        ];
        let defaultPolicy: PolicyDescriptor = <any>Symbol();
        let readPolicy: PolicyDescriptor = <any>Symbol();
        let mutatePolicy: PolicyDescriptor = <any>Symbol();
        beforeEach(() => {
            sinon.stub(inst, 'getReadPolicies').returns([readPolicy]);
            sinon.stub(inst, 'getMutatePolicies').returns([mutatePolicy]);
        });
        routes.forEach(([routeFnName, includeReadPolicies, includeMutatePolicies]) => {
            describe(`when transforming policies for ${routeFnName ? 'the \'' + routeFnName + '\'' : 'any other'} route`, () => {
                it('should include the policies passed in', () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    expect(policies.indexOf(defaultPolicy)).not.to.eq(-1);
                });
                it(`should ${includeReadPolicies ? '' : 'not '}include the read policies`, () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    if (includeReadPolicies) expect(policies.indexOf(readPolicy)).not.to.eq(-1);
                    else expect(policies.indexOf(readPolicy)).to.eq(-1);
                });
                it(`should ${includeMutatePolicies ? '' : 'not '}include the mutate policies`, () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    if (includeMutatePolicies) expect(policies.indexOf(mutatePolicy)).not.to.eq(-1);
                    else expect(policies.indexOf(mutatePolicy)).to.eq(-1);
                });
            });
        });
    });
    <commit_msg>test(crud-controller): add unit tests for the destroy policies<commit_after>/// <reference types="mocha" />

import { expect, use } from 'chai';
import * as sinon from 'sinon';
import * as sinonChai from 'sinon-chai';
use(sinonChai);

import { CrudController } from '../crud-controller';

import { Injectable } from '../../decorators/services/injectable.decorator';
import { Request, Response } from 'express';
import { PolicyDescriptor } from '../../core/policy';
import { Db } from '../../core/db';
import { FakeDb } from '../../orm/test/fake-db';
import { FakeRequest } from '../../router/test/fake-request';
import { FakeResponse } from '../../router/test/fake-response';
import { HTTP_STATUS_ERROR, HTTP_STATUS_OK } from '../../util/http-status-type';

let any = sinon.match.any;

class TestModel {
    id: number;
    static db: Db<TestModel>;
}
class TestCrudController extends CrudController<TestModel> {
    constructor(pluralName?: string, singularName?: string) {
        super(TestModel, `TestModel`, pluralName, singularName);
    }
}

describe('CrudController', () => {
    let inst: TestCrudController;
    beforeEach(() => {
        inst = new TestCrudController();
        TestModel.db = new FakeDb<TestModel>();
    });
    
    describe('.ctor', () => {
        it('should create the singular name from the model name if one is not provided', () => {
            expect(inst.singularName).to.eq(`test-model`);
        });
        it('should use the provided singular name if one is provided', () => {
            let inst = new TestCrudController(undefined, 'my-singular-name');
            expect(inst.singularName).to.eq(`my-singular-name`);
        });
        it('should create the plural name from the model name if one is not provided', () => {
            expect(inst.pluralName).to.eq(`test-models`);
        });
        it('should use the provided plural name if one is provided', () => {
            let inst = new TestCrudController('my-plural-name');
            expect(inst.pluralName).to.eq(`my-plural-name`);
        });
    });
    
    describe('.splitOnWords', () => {
        let splitOnWords: (input: string) => IterableIterator<string>;
        beforeEach(() => {
            splitOnWords = (<any>inst).splitOnWords.bind(inst);
        });
        
        it('should yield an empty sequence on an empty input', () => {
            expect([...splitOnWords('')]).to.deep.eq([]);
        });
        it('should consider an uppercase letter the start of a new word', () => {
            expect([...splitOnWords('ABCdeF')]).to.deep.eq(['A', 'B', 'Cde', 'F']);
        });
        it('should consider an underscore the start of a new word', () => {
            expect([...splitOnWords('what_about_fish')]).to.deep.eq(['what', 'about', 'fish']);
        });
        it('should remove all underscores', () => {
            expect([...splitOnWords('___a_very___ODD_model_name____')]).to.deep.eq(['a', 'very', 'O', 'D', 'D', 'model', 'name']);
        });
    });
    
    describe('.getSingularPath', () => {
        let getSingularPath: (input: string) => string;
        beforeEach(() => {
            getSingularPath = (<any>inst).getSingularPath.bind(inst);
        });
        
        it('should return the input string if words cannot be parsed from it', () => {
            expect(getSingularPath('')).to.eq('');
            expect(getSingularPath('___')).to.eq('___');
        });
        it('should singularize the last word', () => {
            expect(getSingularPath('apples')).to.eq('apple');
            expect(getSingularPath('dog_orange_apples')).to.eq('dog-orange-apple');
        });
        it('should not modify any but the last word', () => {
            expect(getSingularPath('dogs_oranges_apples')).to.eq('dogs-oranges-apple');
        });
        it('should join the words using dashes', () => {
            expect(getSingularPath('ABCDE')).to.eq('a-b-c-d-e');
        });
        it('should transform all letters to lowercase', () => {
            expect(getSingularPath('YellowBrickRoad')).to.eq('yellow-brick-road');
        });
    });
    
    describe('.getPluralPath', () => {
        let getPluralPath: (input: string) => string;
        beforeEach(() => {
            getPluralPath = (<any>inst).getPluralPath.bind(inst);
        });
        
        it('should return the input string if words cannot be parsed from it', () => {
            expect(getPluralPath('')).to.eq('');
            expect(getPluralPath('___')).to.eq('___');
        });
        it('should pluralize the last word', () => {
            expect(getPluralPath('apple')).to.eq('apples');
            expect(getPluralPath('dogs_oranges_apple')).to.eq('dogs-oranges-apples');
        });
        it('should not modify any but the last word', () => {
            expect(getPluralPath('dog_orange_apple')).to.eq('dog-orange-apples');
        });
        it('should join the words using dashes', () => {
            expect(getPluralPath('ABCDQueue')).to.eq('a-b-c-d-queues');
        });
        it('should transform all letters to lowercase', () => {
            expect(getPluralPath('YellowBrickRoad')).to.eq('yellow-brick-roads');
        });
    });
    
    describe('.transformPathPart', () => {
        it('should replace %%PLURAL_NAME%% with the plural route path', () => {
            expect(inst.transformPathPart('blah', `one/%%PLURAL_NAME%%/three`)).to.eq(`one/${inst.pluralName}/three`);
        });
        it('should replace %%SINGULAR_NAME%% with the singular route path', () => {
            expect(inst.transformPathPart('blah', `one/%%SINGULAR_NAME%%/three`)).to.eq(`one/${inst.singularName}/three`);
        });
        it('should replace all instances of both route paths', () => {
            expect(inst.transformPathPart('blah', `one/%%SINGULAR_NAME%%/%%PLURAL_NAME%%/%%SINGULAR_NAME%%/%%PLURAL_NAME%%/three`))
                .to.eq(`one/${inst.singularName}/${inst.pluralName}/${inst.singularName}/${inst.pluralName}/three`);
        });
    });
    
    describe('.transformRoutePolicies', () => {
        let routes: [string, boolean, boolean, boolean][] = [
            ['destroy', true, true, true],
            ['create', true, true, false],
            ['update', true, true, false],
            ['find', true, false, false],
            ['count', true, false, false],
            ['get', true, false, false],
            ['', false, false, false]
        ];
        let defaultPolicy: PolicyDescriptor = <any>Symbol();
        let readPolicy: PolicyDescriptor = <any>Symbol();
        let mutatePolicy: PolicyDescriptor = <any>Symbol();
        let destroyPolicy: PolicyDescriptor = <any>Symbol();
        beforeEach(() => {
            sinon.stub(inst, 'getReadPolicies').returns([readPolicy]);
            sinon.stub(inst, 'getMutatePolicies').returns([mutatePolicy]);
            sinon.stub(inst, 'getDestroyPolicies').returns([destroyPolicy]);
        });
        routes.forEach(([routeFnName, includeReadPolicies, includeMutatePolicies, includeDestroyPolicies]) => {
            describe(`when transforming policies for ${routeFnName ? 'the \'' + routeFnName + '\'' : 'any other'} route`, () => {
                it('should include the policies passed in', () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    expect(policies.indexOf(defaultPolicy)).not.to.eq(-1);
                });
                it(`should ${includeReadPolicies ? '' : 'not '}include the read policies`, () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    if (includeReadPolicies) expect(policies.indexOf(readPolicy)).not.to.eq(-1);
                    else expect(policies.indexOf(readPolicy)).to.eq(-1);
                });
                it(`should ${includeMutatePolicies ? '' : 'not '}include the mutate policies`, () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    if (includeMutatePolicies) expect(policies.indexOf(mutatePolicy)).not.to.eq(-1);
                    else expect(policies.indexOf(mutatePolicy)).to.eq(-1);
                });
                it(`should ${includeDestroyPolicies ? '' : 'not '}include the destroy policies`, () => {
                    let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
                    if (includeDestroyPolicies) expect(policies.indexOf(destroyPolicy)).not.to.eq(-1);
                    else expect(policies.indexOf(destroyPolicy)).to.eq(-1);
                });
            });
        });
    });
    
{'fraction_non_alphanumeric': 0.17723702998572108, 'fraction_numerical': 0.0007139457401237506, 'mean_word_length': 2.484452736318408, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 109, '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': '5315687', 'n_tokens_mistral': 4859, 'n_tokens_neox': 4853, 'n_words': 950}