import 'mocha' ; import { expect } from 'chai' ; import { ICategory } from '@/domain/ICategory' ; import { OperatingSystem } from '@/domain/OperatingSystem' ; import { IScriptingDefinition } from '@/domain/IScriptingDefinition' ; import { ScriptingLanguage } from '@/domain/ScriptingLanguage' ; import { RecommendationLevel } from '@/domain/RecommendationLevel' ; import { getEnumValues } from '@/application/Common/Enum' ; import { CategoryCollection } from '@/domain/CategoryCollection' ; import { ScriptStub } from '@tests/unit/stubs/ScriptStub' ; import { CategoryStub } from '@tests/unit/stubs/CategoryStub' ; import { EnumRangeTestRunner } from '@tests/unit/application/Common/EnumRangeTestRunner' ; describe ( 'CategoryCollection' , ( ) => { describe ( 'getScriptsByLevel' , ( ) => { it ( 'filters out scripts without levels' , ( ) => { const recommendationLevels = getEnumValues ( RecommendationLevel ) ; const scriptsWithLevels = recommendationLevels . map ( ( level , index ) => new ScriptStub ( `Script${ index }` ) . withLevel ( level ) ) ; const toIgnore = new ScriptStub ( 'script-to-ignore' ) . withLevel ( undefined ) ; for ( const currentLevel of recommendationLevels ) { const category = new CategoryStub ( 0 ) . withScripts ( ... scriptsWithLevels ) . withScript ( toIgnore ) ; const sut = new CategoryCollectionBuilder ( ) . withActions ( [ category ] ) . construct ( ) ; const actual = sut . getScriptsByLevel ( currentLevel ) ; expect ( actual ) . to . not . include ( toIgnore ) ; } } ) ; it ( `${ RecommendationLevel [ RecommendationLevel . Standard ] } filters ${ RecommendationLevel [ RecommendationLevel . Strict ] }` , ( ) => { const level = RecommendationLevel . Standard ; const expected = [ new ScriptStub ( 'S1' ) . withLevel ( level ) , new ScriptStub ( 'S2' ) . withLevel ( level ) , ] ; const actions = [ new CategoryStub ( 3 ) . withScripts ( ... expected , new ScriptStub ( 'S3' ) . withLevel ( RecommendationLevel . Strict ) ) , ] ; const sut = new CategoryCollectionBuilder ( ) . withActions ( actions ) . construct ( ) ; const actual = sut . getScriptsByLevel ( level ) ; expect ( expected ) . to . deep . equal ( actual ) ; } ) ; it ( `${ RecommendationLevel [ RecommendationLevel . Strict ] } includes ${ RecommendationLevel [ RecommendationLevel . Standard ] }` , ( ) => { const level = RecommendationLevel . Strict ; const expected = [ new ScriptStub ( 'S1' ) . withLevel ( RecommendationLevel . Standard ) , new ScriptStub ( 'S2' ) . withLevel ( RecommendationLevel . Strict ) , ] ; const actions = [ new CategoryStub ( 3 ) . withScripts ( ... expected ) , ] ; const sut = new CategoryCollectionBuilder ( ) . withActions ( actions ) . construct ( ) ; const actual = sut . getScriptsByLevel ( level ) ; expect ( expected ) . to . deep . equal ( actual ) ; } ) ; it ( 'throws when level is undefined' , ( ) => { const sut = new CategoryCollectionBuilder ( ) . construct ( ) ; const act = ( ) => sut . getScriptsByLevel ( undefined ) ; expect ( act ) . to . throw ( 'undefined level' ) ; } ) ; it ( 'throws when level is out of range' , ( ) => { const invalidValue = 66 ; const sut = new CategoryCollectionBuilder ( ) . construct ( ) ; const act = ( ) => sut . getScriptsByLevel ( invalidValue ) ; expect ( act ) . to . throw ( `invalid level: ${ invalidValue }` ) ; } ) ; } ) ; describe ( 'actions' , ( ) => { it ( 'cannot construct without actions' , ( ) => { const categories = [ ] ; function construct ( ) { new CategoryCollectionBuilder ( ) . withActions ( categories ) . construct ( ) ; } expect ( construct ) . to . throw ( 'must consist of at least one category' ) ; } ) ; it ( 'cannot construct without scripts' , ( ) => { const categories = [ new CategoryStub ( 3 ) , new CategoryStub ( 2 ) , ] ; function construct ( ) { new CategoryCollectionBuilder ( ) . withActions ( categories ) . construct ( ) ; } expect ( construct ) . to . throw ( 'must consist of at least one script' ) ; } ) ; describe ( 'cannot construct without any recommended scripts' , ( ) => { describe ( 'single missing' , ( ) => { const recommendationLevels = getEnumValues ( RecommendationLevel ) ; for ( const missingLevel of recommendationLevels ) { it ( `when "${ RecommendationLevel [ missingLevel ] }" is missing` , ( ) => { const expectedError = `none of the scripts are recommended as "${ RecommendationLevel [ missingLevel ] }".` ; const otherLevels = recommendationLevels . filter ( ( level ) => level !== missingLevel ) ; const categories = otherLevels . map ( ( level , index ) => new CategoryStub ( index ) . withScript ( new ScriptStub ( `Script${ index }` ) . withLevel ( level ) ) ) ; const construct = ( ) => new CategoryCollectionBuilder ( ) . withActions ( categories ) . construct ( ) ; expect ( construct ) . to . throw ( expectedError ) ; } ) ; } } ) ; it ( 'multiple are missing' , ( ) => { const expectedError = 'none of the scripts are recommended as ' + `"${ RecommendationLevel [ RecommendationLevel . Standard ] }, "${ RecommendationLevel [ RecommendationLevel . Strict ] }".` ; const categories = [ new CategoryStub ( 0 ) . withScript ( new ScriptStub ( `Script${ 0 }` ) . withLevel ( undefined ) ) , ] ; const construct = ( ) => new CategoryCollectionBuilder ( ) . withActions ( categories ) . construct ( ) ; expect ( construct ) . to . throw ( expectedError ) ; } ) ; } ) ; } ) ; describe ( 'totalScripts' , ( ) => { it ( 'returns total of initial scripts' , ( ) => { const categories = [ new CategoryStub ( 1 ) . withScripts ( new ScriptStub ( 'S1' ) . withLevel ( RecommendationLevel . Standard ) ) , new CategoryStub ( 2 ) . withScripts ( new ScriptStub ( 'S2' ) , new ScriptStub ( 'S3' ) . withLevel ( RecommendationLevel . Strict ) ) , new CategoryStub ( 3 ) . withCategories ( new CategoryStub ( 4 ) . withScripts ( new ScriptStub ( 'S4' ) ) ) , ] ; const sut = new CategoryCollectionBuilder ( ) . withActions ( categories ) . construct ( ) ; expect ( sut . totalScripts ) . to . equal ( 4 ) ; } ) ; } ) ; describe ( 'totalCategories' , ( ) => { it ( 'returns total of initial categories' , ( ) => { const expected = 4 ; const categories = [ new CategoryStub ( 1 ) . withScripts ( new ScriptStub ( 'S1' ) . withLevel ( RecommendationLevel . Strict ) ) , new CategoryStub ( 2 ) . withScripts ( new ScriptStub ( 'S2' ) , new ScriptStub ( 'S3' ) ) , new CategoryStub ( 3 ) . withCategories ( new CategoryStub ( 4 ) . withScripts ( new ScriptStub ( 'S4' ) ) ) , ] ; const sut = new CategoryCollectionBuilder ( ) . withActions ( categories ) . construct ( ) ; expect ( sut . totalCategories ) . to . equal ( expected ) ; } ) ; } ) ; describe ( 'os' , ( ) => { it ( 'sets os as expected' , ( ) => { const expected = OperatingSystem . macOS ; const sut = new CategoryCollectionBuilder ( ) . withOs ( expected ) . construct ( ) ; expect ( sut . os ) . to . deep . equal ( expected ) ; } ) ; describe ( 'throws when invalid' , ( ) => { const act = ( os ) => new CategoryCollectionBuilder ( ) . withOs ( os ) . construct ( ) ; new EnumRangeTestRunner ( act ) . testOutOfRangeThrows ( ) . testUndefinedValueThrows ( ) ; } ) ; } ) ; describe ( 'scriptingDefinition' , ( ) => { it ( 'sets scriptingDefinition as expected' , ( ) => { const expected = getValidScriptingDefinition ( ) ; const sut = new CategoryCollectionBuilder ( ) . withScripting ( expected ) . construct ( ) ; expect ( sut . scripting ) . to . deep . equal ( expected ) ; } ) ; it ( 'cannot construct without initial script' , ( ) => { const scriptingDefinition = undefined ; function construct ( ) { return new CategoryCollectionBuilder ( ) . withScripting ( scriptingDefinition ) . construct ( ) ; } expect ( construct ) . to . throw ( 'undefined scripting definition' ) ; } ) ; } ) ; } ) ; function getValidScriptingDefinition ( ) { return { fileExtension : '.bat' , language : ScriptingLanguage . batchfile , startCode : 'start' , endCode : 'end' , } ; } class CategoryCollectionBuilder { private os = OperatingSystem . Windows ; private actions : readonly ICategory [ ] = [ new CategoryStub ( 1 ) . withScripts ( new ScriptStub ( 'S1' ) . withLevel ( RecommendationLevel . Standard ) , new ScriptStub ( 'S2' ) . withLevel ( RecommendationLevel . Strict ) ) , ] ; private script : IScriptingDefinition = getValidScriptingDefinition ( ) ; public withOs ( os ) { this . os = os ; return this ; } public withActions ( actions ) { this . actions = actions ; return this ; } public withScripting ( script ) { this . script = script ; return this ; } public construct ( ) { return new CategoryCollection ( this . os , this . actions , this . script ) ; } }