Merge pull request #462 from javascript-obfuscator/dictionary-identifier-names-generator

Dictionary identifier names generator
This commit is contained in:
Timofey Kachalov
2019-12-31 14:50:24 +03:00
committed by GitHub
28 changed files with 475 additions and 30 deletions
+1 -1
View File
@@ -2,9 +2,9 @@ sudo: false
language: node_js
node_js:
- "8"
- "10"
- "12"
- "13"
- "stable"
cache:
+9
View File
@@ -1,5 +1,14 @@
Change Log
v0.20.0
---
* **Breaking:** dropped support of Node 8 because of end of maintenance support
* **New option value:** `identifierNamesGenerator` now allows to set new `dictionary` identifier names generator
* **New option:** `identifiersDictionary` sets identifiers dictionary for `identifierNamesGenerator: dictionary` option
Thanks to our contributors!
* [adiantek](https://github.com/adiantek)
v0.19.4
---
* Fixed `reservedNames` option
+9 -1
View File
@@ -292,6 +292,7 @@ Following options are available for the JS Obfuscator:
disableConsoleOutput: false,
domainLock: [],
identifierNamesGenerator: 'hexadecimal',
identifiersDictionary: [],
identifiersPrefix: '',
inputFileName: '',
log: false,
@@ -334,7 +335,8 @@ Following options are available for the JS Obfuscator:
--disable-console-output <boolean>
--domain-lock '<list>' (comma separated)
--exclude '<list>' (comma separated)
--identifier-names-generator <string> [hexadecimal, mangled]
--identifier-names-generator <string> [dictionary, hexadecimal, mangled]
--identifiers-dictionary '<list>' (comma separated)
--identifiers-prefix <string>
--log <boolean>
--rename-globals <boolean>
@@ -597,9 +599,15 @@ Type: `string` Default: `hexadecimal`
Sets identifier names generator.
Available values:
* `dictionary`: identifier names from [`identifiersDictionary`](#identifiersDictionary) list
* `hexadecimal`: identifier names like `_0xabc123`
* `mangled`: short identifier names like `a`, `b`, `c`
### `identifiersDictionary`
Type: `string[]` Default: `[]`
Sets identifiers dictionary for [`identifierNamesGenerator`](#identifierNamesGenerator): `dictionary` option
### `identifiersPrefix`
Type: `string` Default: `''`
+4 -4
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "0.19.4",
"version": "0.20.0",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
@@ -12,7 +12,7 @@
"js obfuscator"
],
"engines": {
"node": ">=8"
"node": ">=10"
},
"main": "dist/index.js",
"browser": "dist/index.browser.js",
+6 -1
View File
@@ -251,7 +251,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
.option(
'--identifier-names-generator <string>',
'Sets identifier names generator. ' +
'Values: hexadecimal, mangled. ' +
'Values: hexadecimal, mangled, dictionary. ' +
'Default: hexadecimal',
IdentifierNamesGeneratorSanitizer
)
@@ -259,6 +259,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
'--identifiers-prefix <string>',
'Sets prefix for all global identifiers.'
)
.option(
'--identifiers-dictionary <list> (comma separated, without whitespaces)',
'Identifiers dictionary (comma separated) for `--identifier-names-generator dictionary` option',
ArraySanitizer
)
.option(
'--log <boolean>', 'Enables logging of the information to the console',
BooleanSanitizer
@@ -6,11 +6,17 @@ import { IOptions } from '../../../interfaces/options/IOptions';
import { IdentifierNamesGenerator } from '../../../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
import { DictionaryIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/DictionaryIdentifierNamesGenerator';
import { HexadecimalIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator';
import { MangledIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/MangledIdentifierNamesGenerator';
export const generatorsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// identifier name generators
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
.to(DictionaryIdentifierNamesGenerator)
.inSingletonScope()
.whenTargetNamed(IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator);
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
.to(HexadecimalIdentifierNamesGenerator)
.inSingletonScope()
@@ -34,6 +40,14 @@ export const generatorsModule: interfaces.ContainerModule = new ContainerModule(
let identifierNamesGenerator: IIdentifierNamesGenerator;
switch (options.identifierNamesGenerator) {
case IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator:
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
break;
case IdentifierNamesGenerator.MangledIdentifierNamesGenerator:
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
@@ -77,6 +77,7 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.options.seed
}
).getObfuscatedCode();
@@ -77,6 +77,7 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.options.seed,
unicodeEscapeSequence: true
}
@@ -100,6 +100,7 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.options.seed
}
).getObfuscatedCode();
@@ -107,6 +107,7 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
seed: this.options.seed
}
).getObfuscatedCode();
@@ -1,4 +1,5 @@
export enum IdentifierNamesGenerator {
DictionaryIdentifierNamesGenerator = 'dictionary',
HexadecimalIdentifierNamesGenerator = 'hexadecimal',
MangledIdentifierNamesGenerator = 'mangled'
}
@@ -0,0 +1,129 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
@injectable()
export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
/**
* @type {IArrayUtils}
*/
private readonly arrayUtils: IArrayUtils;
/**
* @type {string[]}
*/
private identifierNames: string[] = [];
/**
* @type {IterableIterator<string>}
*/
private identifiersIterator: IterableIterator<string>;
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
* @param {IArrayUtils} arrayUtils
*/
constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions,
@inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
) {
super(randomGenerator, options);
this.arrayUtils = arrayUtils;
this.identifierNames = this.getInitialIdentifierNames(this.options.identifiersDictionary);
this.identifiersIterator = this.identifierNames.values();
}
/**
* @param {string} identifierName
* @returns {string | null}
*/
private static incrementIdentifierName (identifierName: string): string | null {
let newIdentifierName: string = '';
let isSuccess: boolean = false;
for (const character of identifierName) {
if (!isSuccess && character === character.toUpperCase()) {
newIdentifierName += character.toLowerCase();
} else if (!isSuccess && character === character.toLowerCase()) {
newIdentifierName += character.toUpperCase();
isSuccess = true;
} else {
newIdentifierName += character;
}
}
if (isSuccess) {
return newIdentifierName;
}
return null;
}
public generate (): string {
if (!this.identifierNames.length) {
throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
}
const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
if (!iteratorResult.done) {
return iteratorResult.value;
}
this.identifierNames = this.getIncrementedIdentifierNames(this.identifierNames);
this.identifiersIterator = this.identifierNames.values();
return this.generate();
}
/**
* @returns {string}
*/
public generateWithPrefix (): string {
const prefix: string = this.options.identifiersPrefix ?
`${this.options.identifiersPrefix}_`
: '';
const identifierName: string = this.generate();
return `${prefix}${identifierName}`.replace('__', '_');
}
/**
* @param {string[]} identifierNames
* @returns {string[]}
*/
private getInitialIdentifierNames (identifierNames: string[]): string[] {
const formattedIdentifierNames: string[] = identifierNames
.filter(Boolean)
.map((identifierName: string) => identifierName.toLowerCase());
return this.arrayUtils.shuffle(formattedIdentifierNames);
}
/**
* @param {string[]} identifierNames
* @returns {string[]}
*/
private getIncrementedIdentifierNames (identifierNames: string[]): string[] {
const formattedIdentifierNames: string[] = [];
for (const identifierName of identifierNames) {
const newIdentifierName: string | null = DictionaryIdentifierNamesGenerator
.incrementIdentifierName(identifierName);
if (newIdentifierName) {
formattedIdentifierNames.push(newIdentifierName);
}
}
return this.arrayUtils.shuffle(formattedIdentifierNames);
}
}
+1
View File
@@ -15,6 +15,7 @@ export interface IOptions {
readonly disableConsoleOutput: boolean;
readonly domainLock: string[];
readonly identifierNamesGenerator: IdentifierNamesGenerator;
readonly identifiersDictionary: string[];
readonly identifiersPrefix: string;
readonly inputFileName: string;
readonly log: boolean;
+13
View File
@@ -2,6 +2,7 @@ import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import {
ArrayNotEmpty,
ArrayUnique,
IsArray,
IsBoolean,
@@ -107,6 +108,7 @@ export class Options implements IOptions {
* @type {IdentifierNamesGenerator}
*/
@IsIn([
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
IdentifierNamesGenerator.MangledIdentifierNamesGenerator
])
@@ -118,6 +120,17 @@ export class Options implements IOptions {
@IsString()
public readonly identifiersPrefix!: string;
@IsArray()
@ArrayUnique()
@IsString({
each: true
})
@ValidateIf((options: IOptions) =>
options.identifierNamesGenerator === IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
)
@ArrayNotEmpty()
public readonly identifiersDictionary!: string[];
/**
* @type {string}
*/
+1
View File
@@ -18,6 +18,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
exclude: [],
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
identifiersPrefix: '',
identifiersDictionary: [],
inputFileName: '',
log: false,
renameGlobals: false,
+1
View File
@@ -17,6 +17,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
exclude: [],
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
identifiersPrefix: '',
identifiersDictionary: [],
inputFileName: '',
log: false,
renameGlobals: false,
@@ -50,6 +50,10 @@ export class StringArrayStorage extends ArrayStorage <string> {
public initialize (): void {
super.initialize();
if (!this.options.stringArray) {
return;
}
const baseStringArrayName: string = this.identifierNamesGenerator
.generate(StringArrayStorage.stringArrayNameLength);
const baseStringArrayCallsWrapperName: string = this.identifierNamesGenerator
+5 -6
View File
@@ -6,16 +6,15 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
var s = {
'abcdefg': 'abcdefg'
};
var abc = 1;
var cde = 1;
var fg = 1;
var sss = 1;
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false,
splitStrings: true,
splitStringsChunkLength: 4,
transformObjectKeys: true
renameGlobals: true
}
).getObfuscatedCode();
@@ -569,6 +569,29 @@ describe('JavaScriptObfuscator', () => {
});
});
describe('dictionary identifier names generator', () => {
const regExp: RegExp = /var *[ab] *= *0x1; *var *[ab] *= *0x2; *var *[AB] *= *0x3;/;
let obfuscatedCode: string;
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/dictionary-identifiers.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
identifiersDictionary: ['a', 'b']
}
).getObfuscatedCode();
});
it('should generate identifier based on the dictionary', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('parse module', () => {
describe('Variant #1: import', () => {
const importRegExp: RegExp = /import *{foo} *from *'.\/foo';/;
@@ -0,0 +1,5 @@
(function () {
var test1 = 1;
var test2 = 2;
var test3 = 3;
})();
@@ -121,8 +121,8 @@ describe('ClassDeclarationTransformer', () => {
});
describe('Variant #3: already renamed identifiers shouldn\'t be renamed twice', () => {
const classDeclarationRegExp: RegExp = /class *d *{/;
const variableDeclarationsRegExp: RegExp = /let *e, *f, *g, *h;/;
const classDeclarationRegExp: RegExp = /class *b *{/;
const variableDeclarationsRegExp: RegExp = /let *c, *d, *e, *f;/;
let obfuscatedCode: string;
@@ -145,8 +145,8 @@ describe('FunctionDeclarationTransformer', () => {
describe('Variant #5: already renamed identifiers shouldn\'t be renamed twice', () => {
describe('Variant #1', () => {
const functionDeclarationRegExp: RegExp = /function *d\(\) *{/;
const variableDeclarationsRegExp: RegExp = /let *e, *f, *g, *h;/;
const functionDeclarationRegExp: RegExp = /function *b\(\) *{/;
const variableDeclarationsRegExp: RegExp = /let *c, *d, *e, *f;/;
let obfuscatedCode: string;
@@ -426,11 +426,11 @@ describe('VariableDeclarationTransformer', () => {
describe('Variant #13: already renamed identifiers shouldn\'t be renamed twice', () => {
describe('Variant #1', () => {
const variableDeclarationRegExp: RegExp = /var *d *= *0x1;/;
const functionDeclarationRegExp1: RegExp = /function *e *\(\) *{}/;
const functionDeclarationRegExp2: RegExp = /function *f *\(\) *{}/;
const functionDeclarationRegExp3: RegExp = /function *g *\(\) *{}/;
const functionDeclarationRegExp4: RegExp = /function *h *\(\) *{}/;
const variableDeclarationRegExp: RegExp = /var *b *= *0x1;/;
const functionDeclarationRegExp1: RegExp = /function *c *\(\) *{}/;
const functionDeclarationRegExp2: RegExp = /function *d *\(\) *{}/;
const functionDeclarationRegExp3: RegExp = /function *e *\(\) *{}/;
const functionDeclarationRegExp4: RegExp = /function *f *\(\) *{}/;
let obfuscatedCode: string;
@@ -468,10 +468,10 @@ describe('VariableDeclarationTransformer', () => {
});
describe('Variant #2', () => {
const variableDeclarationRegExp1: RegExp = /var *d *= *0x1;/;
const variableDeclarationRegExp2: RegExp = /var *e;/;
const functionDeclarationRegExp: RegExp = /function *f *\(\) *{/;
const variableDeclarationRegExp3: RegExp = /var *f *= *function *\(\) *{}/;
const variableDeclarationRegExp1: RegExp = /var *b *= *0x1;/;
const variableDeclarationRegExp2: RegExp = /var *c;/;
const functionDeclarationRegExp: RegExp = /function *d *\(\) *{/;
const variableDeclarationRegExp3: RegExp = /var *d *= *function *\(\) *{}/;
let obfuscatedCode: string;
+1
View File
@@ -15,6 +15,7 @@ import './unit-tests/cli/sanitizers/StringArrayEncodingSanitizer.spec';
import './unit-tests/cli/utils/CLIUtils.spec';
import './unit-tests/cli/utils/SourceCodeReader.spec';
import './unit-tests/decorators/initializable/Initializable.spec';
import './unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec';
import './unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec';
import './unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec';
import './unit-tests/javascript-obfuscator/EspreeFacade.spec';
@@ -0,0 +1,227 @@
import 'reflect-metadata';
import { assert } from 'chai';
import { ServiceIdentifiers } from '../../../../src/container/ServiceIdentifiers';
import { IIdentifierNamesGenerator } from '../../../../src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
import { IdentifierNamesGenerator } from '../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
describe('DictionaryIdentifierNamesGenerator', () => {
describe('generate', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
dictionaryIdentifierName: string;
describe('Base behaviour', () => {
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load('', '', {
identifiersDictionary: ['a', 'b']
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
});
describe('Variant #1: first dictionary iteration', () => {
const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|b]/;
beforeEach(() => {
dictionaryIdentifierName = identifierNamesGenerator.generate();
});
it('Match #1: should return first identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
it('Match #2: should return second identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
});
describe('Variant #2: second dictionary iteration', () => {
const expectedDictionaryIdentifierNameRegExp: RegExp = /[A|B]/;
beforeEach(() => {
dictionaryIdentifierName = identifierNamesGenerator.generate();
});
it('Match #1: should return third identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
it('Match #2: should return fourth identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
});
});
describe('Empty string as dictionary value', () => {
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load('', '', {
identifiersDictionary: ['', 'a']
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
});
describe('Variant #1: Should ignore empty strings from dictionary', () => {
const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|A]/;
beforeEach(() => {
dictionaryIdentifierName = identifierNamesGenerator.generate();
});
it('Match #1: should return first identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
it('Match #2: should return second identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
});
});
describe('Multi-character string as dictionary value', () => {
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load('', '', {
identifiersDictionary: ['aa']
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
});
describe('Variant #1: Should generate identifier names based on all variants of word from dictionary', () => {
const expectedFirstIterationIdentifierName: string = 'aa';
const expectedSecondIterationIdentifierName: string = 'Aa';
const expectedThirdIterationIdentifierName: string = 'aA';
const expectedFourthIterationIdentifierName: string = 'AA';
beforeEach(() => {
dictionaryIdentifierName = identifierNamesGenerator.generate();
});
it('Match #1: should return first identifier name', () => {
assert.equal(dictionaryIdentifierName, expectedFirstIterationIdentifierName);
});
it('Match #2: should return second identifier name', () => {
assert.equal(dictionaryIdentifierName, expectedSecondIterationIdentifierName);
});
it('Match #3: should return third identifier name', () => {
assert.equal(dictionaryIdentifierName, expectedThirdIterationIdentifierName);
});
it('Match #4: should return fourth identifier name', () => {
assert.equal(dictionaryIdentifierName, expectedFourthIterationIdentifierName);
});
});
});
describe('Generate with prefix', () => {
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load('', '', {
identifiersDictionary: ['a'],
identifiersPrefix: 'foo'
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
});
describe('Variant #1: Should generate identifier names with prefix', () => {
const expectedDictionaryIdentifierNameRegExp: RegExp = /foo_[a|A]/;
beforeEach(() => {
dictionaryIdentifierName = identifierNamesGenerator.generateWithPrefix();
});
it('Match #1: should return first identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
it('Match #2: should return second identifier name', () => {
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
});
});
describe('Errors', () => {
let inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
beforeEach(() => {
inversifyContainerFacade = new InversifyContainerFacade();
});
describe('Variant #1: No more identifier variants for generation', () => {
const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|A]/;
let testFunc: () => string;
before(() => {
inversifyContainerFacade.load('', '', {
identifiersDictionary: ['a']
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
testFunc = () => identifierNamesGenerator.generate();
});
it('Match #1: should return first identifier name', () => {
dictionaryIdentifierName = testFunc();
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
it('Match #2: should return second identifier name', () => {
dictionaryIdentifierName = testFunc();
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
});
it('Should throw an error when all identifier variants are used', () => {
assert.throws(testFunc, Error);
});
});
describe('Variant #2: Empty identifiers dictionary', () => {
let testFunc: () => string;
before(() => {
inversifyContainerFacade.load('', '', {
identifiersDictionary: []
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
testFunc = () => identifierNamesGenerator.generate();
});
it('Should throw an error when identifiers dictionary is empty', () => {
assert.throws(testFunc, Error);
});
});
});
});
});