Forráskód Böngészése

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

Dictionary identifier names generator
Timofey Kachalov 5 éve
szülő
commit
976ca610de
28 módosított fájl, 469 hozzáadás és 24 törlés
  1. 1 1
      .travis.yml
  2. 9 0
      CHANGELOG.md
  3. 9 1
      README.md
  4. 0 0
      dist/index.browser.js
  5. 0 0
      dist/index.cli.js
  6. 0 0
      dist/index.js
  7. 2 2
      package.json
  8. 6 1
      src/cli/JavaScriptObfuscatorCLI.ts
  9. 14 0
      src/container/modules/generators/GeneratorsModule.ts
  10. 1 0
      src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts
  11. 1 0
      src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts
  12. 1 0
      src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts
  13. 1 0
      src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts
  14. 1 0
      src/enums/generators/identifier-names-generators/IdentifierNamesGenerator.ts
  15. 129 0
      src/generators/identifier-names-generators/DictionaryIdentifierNamesGenerator.ts
  16. 1 0
      src/interfaces/options/IOptions.d.ts
  17. 13 0
      src/options/Options.ts
  18. 1 0
      src/options/presets/Default.ts
  19. 1 0
      src/options/presets/NoCustomNodes.ts
  20. 4 0
      src/storages/string-array/StringArrayStorage.ts
  21. 5 6
      test/dev/dev.ts
  22. 23 0
      test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts
  23. 5 0
      test/functional-tests/javascript-obfuscator/fixtures/dictionary-identifiers.js
  24. 2 2
      test/functional-tests/node-transformers/obfuscating-transformers/class-declaration-transformer/ClassDeclarationTransformer.spec.ts
  25. 2 2
      test/functional-tests/node-transformers/obfuscating-transformers/function-declaration-transformer/FunctionDeclarationTransformer.spec.ts
  26. 9 9
      test/functional-tests/node-transformers/obfuscating-transformers/variable-declaration-transformer/VariableDeclarationTransformer.spec.ts
  27. 1 0
      test/index.spec.ts
  28. 227 0
      test/unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec.ts

+ 1 - 1
.travis.yml

@@ -2,9 +2,9 @@ sudo: false
 language: node_js
 
 node_js:
-  - "8"
   - "10"
   - "12"
+  - "13"
   - "stable"
 
 cache:

+ 9 - 0
CHANGELOG.md

@@ -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
README.md

@@ -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: `''`
 

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/index.browser.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/index.cli.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/index.js


+ 2 - 2
package.json

@@ -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
src/cli/JavaScriptObfuscatorCLI.ts

@@ -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

+ 14 - 0
src/container/modules/generators/GeneratorsModule.ts

@@ -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,

+ 1 - 0
src/custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode.ts

@@ -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();

+ 1 - 0
src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts

@@ -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
             }

+ 1 - 0
src/custom-nodes/string-array-nodes/StringArrayCallsWrapper.ts

@@ -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();

+ 1 - 0
src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts

@@ -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 - 0
src/enums/generators/identifier-names-generators/IdentifierNamesGenerator.ts

@@ -1,4 +1,5 @@
 export enum IdentifierNamesGenerator {
+    DictionaryIdentifierNamesGenerator = 'dictionary',
     HexadecimalIdentifierNamesGenerator = 'hexadecimal',
     MangledIdentifierNamesGenerator = 'mangled'
 }

+ 129 - 0
src/generators/identifier-names-generators/DictionaryIdentifierNamesGenerator.ts

@@ -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 - 0
src/interfaces/options/IOptions.d.ts

@@ -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 - 0
src/options/Options.ts

@@ -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 - 0
src/options/presets/Default.ts

@@ -18,6 +18,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
     exclude: [],
     identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
     identifiersPrefix: '',
+    identifiersDictionary: [],
     inputFileName: '',
     log: false,
     renameGlobals: false,

+ 1 - 0
src/options/presets/NoCustomNodes.ts

@@ -17,6 +17,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     exclude: [],
     identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
     identifiersPrefix: '',
+    identifiersDictionary: [],
     inputFileName: '',
     log: false,
     renameGlobals: false,

+ 4 - 0
src/storages/string-array/StringArrayStorage.ts

@@ -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
test/dev/dev.ts

@@ -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();
 

+ 23 - 0
test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts

@@ -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';/;

+ 5 - 0
test/functional-tests/javascript-obfuscator/fixtures/dictionary-identifiers.js

@@ -0,0 +1,5 @@
+(function () {
+    var test1 = 1;
+    var test2 = 2;
+    var test3 = 3;
+})();

+ 2 - 2
test/functional-tests/node-transformers/obfuscating-transformers/class-declaration-transformer/ClassDeclarationTransformer.spec.ts

@@ -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;
 

+ 2 - 2
test/functional-tests/node-transformers/obfuscating-transformers/function-declaration-transformer/FunctionDeclarationTransformer.spec.ts

@@ -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;
 

+ 9 - 9
test/functional-tests/node-transformers/obfuscating-transformers/variable-declaration-transformer/VariableDeclarationTransformer.spec.ts

@@ -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 - 0
test/index.spec.ts

@@ -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';

+ 227 - 0
test/unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec.ts

@@ -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);
+                });
+            });
+        });
+    });
+});

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott