From 24135e3490a0ce3c3a8df2cbbde084537a91a9d1 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Sun, 12 Jan 2020 21:41:24 +0300 Subject: [PATCH] Added additional tests --- .../LiteralTransformer.spec.ts | 400 ++++++++++++++++++ .../fixtures/three-strings.js | 3 + test/index.spec.ts | 1 + .../StringArrayStorageAnalyzer.spec.ts | 275 ++++++++++++ 4 files changed, 679 insertions(+) create mode 100644 test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/fixtures/three-strings.js create mode 100644 test/unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec.ts diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts index 29f831a8..cf73ac2c 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts @@ -587,4 +587,404 @@ describe('LiteralTransformer', () => { assert.match(obfuscatedCode, regExp); }); }); + + describe('Rotate string array', function () { + this.timeout(100000); + + describe('Variant #1: single string array value', () => { + const samples: number = 1000; + const delta: number = 0.1; + const expectedVariantProbability: number = 1; + + const stringArrayVariant1RegExp1: RegExp = /var *_0x([a-f0-9]){4} *= *\['test'];/g; + const literalNodeVariant1RegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/g; + + let stringArrayVariant1Probability: number, + literalNodeVariant1Probability: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let stringArrayVariant1MatchesLength: number = 0; + let literalNodeVariant1MatchesLength: number = 0; + + for (let i = 0; i < samples; i++) { + const obfuscatedCode: string = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + rotateStringArray: true, + stringArray: true, + stringArrayThreshold: 1 + } + ).getObfuscatedCode(); + + if (obfuscatedCode.match(stringArrayVariant1RegExp1)) { + stringArrayVariant1MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant1RegExp)) { + literalNodeVariant1MatchesLength++; + } + } + + stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples; + literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples; + }); + + describe('String array probability', () => { + it('Variant #1: should create single string array variant', () => { + assert.closeTo(stringArrayVariant1Probability, expectedVariantProbability, delta); + }); + }); + + describe('Literal node probability', () => { + it('Variant #1: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant1Probability, expectedVariantProbability, delta); + }); + }); + }); + + describe('Variant #2: Three string array values', () => { + const samples: number = 1000; + const delta: number = 0.1; + const expectedStringArrayVariantProbability: number = 0.33; + const expectedLiteralNodeVariantProbability: number = 1; + + const stringArrayVariantRegExp1: RegExp = /var *_0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g; + const stringArrayVariantRegExp2: RegExp = /var *_0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g; + const stringArrayVariantRegExp3: RegExp = /var *_0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g; + + const literalNodeVariant1RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x2'\\);` + ); + + let stringArrayVariant1Probability: number, + stringArrayVariant2Probability: number, + stringArrayVariant3Probability: number, + literalNodeVariant1Probability: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/three-strings.js'); + + let stringArrayVariant1MatchesLength: number = 0; + let stringArrayVariant2MatchesLength: number = 0; + let stringArrayVariant3MatchesLength: number = 0; + let literalNodeVariant1MatchesLength: number = 0; + + for (let i = 0; i < samples; i++) { + const obfuscatedCode: string = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + rotateStringArray: true, + stringArray: true, + stringArrayThreshold: 1 + } + ).getObfuscatedCode(); + + if (obfuscatedCode.match(stringArrayVariantRegExp1)) { + stringArrayVariant1MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp2)) { + stringArrayVariant2MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp3)) { + stringArrayVariant3MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant1RegExp)) { + literalNodeVariant1MatchesLength++; + } + } + + stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples; + stringArrayVariant2Probability = stringArrayVariant2MatchesLength / samples; + stringArrayVariant3Probability = stringArrayVariant3MatchesLength / samples; + literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples; + }); + + describe('String array probability', () => { + it('Variant #1: should create string array variant', () => { + assert.closeTo(stringArrayVariant1Probability, expectedStringArrayVariantProbability, delta); + }); + + it('Variant #2: should create string array variant', () => { + assert.closeTo(stringArrayVariant2Probability, expectedStringArrayVariantProbability, delta); + }); + + it('Variant #3: should create string array variant', () => { + assert.closeTo(stringArrayVariant3Probability, expectedStringArrayVariantProbability, delta); + }); + }); + + describe('Literal node probability', () => { + it('Variant #1: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant1Probability, expectedLiteralNodeVariantProbability, delta); + }); + }); + }); + }); + + describe('Shuffle string array', function () { + this.timeout(100000); + + describe('Variant #1: single string array value', () => { + const samples: number = 1000; + const delta: number = 0.1; + const expectedVariantProbability: number = 1; + + const stringArrayVariantRegExp1: RegExp = /var *_0x([a-f0-9]){4} *= *\['test'];/g; + const literalNodeVariant1RegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/g; + + let stringArrayVariant1Probability: number, + literalNodeVariant1Probability: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let stringArrayVariant1MatchesLength: number = 0; + let literalNodeVariant1MatchesLength: number = 0; + + for (let i = 0; i < samples; i++) { + const obfuscatedCode: string = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + shuffleStringArray: true, + stringArray: true, + stringArrayThreshold: 1 + } + ).getObfuscatedCode(); + + if (obfuscatedCode.match(stringArrayVariantRegExp1)) { + stringArrayVariant1MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant1RegExp)) { + literalNodeVariant1MatchesLength++; + } + } + + stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples; + literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples; + }); + + describe('String array probability', () => { + it('Variant #1: should create string array variant', () => { + assert.closeTo(stringArrayVariant1Probability, expectedVariantProbability, delta); + }); + }); + + describe('Literal node probability', () => { + it('Variant #1: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant1Probability, expectedVariantProbability, delta); + }); + }); + }); + + describe('Variant #2: Three string array values', () => { + const samples: number = 1000; + const delta: number = 0.1; + const expectedVariantProbability: number = 0.166; + + const stringArrayVariantRegExp1: RegExp = /var *_0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g; + const stringArrayVariantRegExp2: RegExp = /var *_0x([a-f0-9]){4} *= *\['foo', *'baz', *'bar'];/g; + const stringArrayVariantRegExp3: RegExp = /var *_0x([a-f0-9]){4} *= *\['bar', *'foo', *'baz'];/g; + const stringArrayVariantRegExp4: RegExp = /var *_0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g; + const stringArrayVariantRegExp5: RegExp = /var *_0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g; + const stringArrayVariantRegExp6: RegExp = /var *_0x([a-f0-9]){4} *= *\['baz', *'bar', *'foo'];/g; + + const literalNodeVariant1RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x2'\\);` + ); + const literalNodeVariant2RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x0'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x2'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x1'\\);` + ); + const literalNodeVariant3RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x1'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x0'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x2'\\);` + ); + const literalNodeVariant4RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x1'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x2'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x0'\\);` + ); + const literalNodeVariant5RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x2'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x0'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x1'\\);` + ); + const literalNodeVariant6RegExp: RegExp = new RegExp( + `var *foo *= *_0x([a-f0-9]){4}\\('0x2'\\); *` + + `var *bar *= *_0x([a-f0-9]){4}\\('0x1'\\); *` + + `var *baz *= *_0x([a-f0-9]){4}\\('0x0'\\);` + ); + + let stringArrayVariant1Probability: number, + stringArrayVariant2Probability: number, + stringArrayVariant3Probability: number, + stringArrayVariant4Probability: number, + stringArrayVariant5Probability: number, + stringArrayVariant6Probability: number, + literalNodeVariant1Probability: number, + literalNodeVariant2Probability: number, + literalNodeVariant3Probability: number, + literalNodeVariant4Probability: number, + literalNodeVariant5Probability: number, + literalNodeVariant6Probability: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/three-strings.js'); + + let stringArrayVariant1MatchesLength: number = 0; + let stringArrayVariant2MatchesLength: number = 0; + let stringArrayVariant3MatchesLength: number = 0; + let stringArrayVariant4MatchesLength: number = 0; + let stringArrayVariant5MatchesLength: number = 0; + let stringArrayVariant6MatchesLength: number = 0; + let literalNodeVariant1MatchesLength: number = 0; + let literalNodeVariant2MatchesLength: number = 0; + let literalNodeVariant3MatchesLength: number = 0; + let literalNodeVariant4MatchesLength: number = 0; + let literalNodeVariant5MatchesLength: number = 0; + let literalNodeVariant6MatchesLength: number = 0; + + for (let i = 0; i < samples; i++) { + const obfuscatedCode: string = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + shuffleStringArray: true, + stringArray: true, + stringArrayThreshold: 1 + } + ).getObfuscatedCode(); + + if (obfuscatedCode.match(stringArrayVariantRegExp1)) { + stringArrayVariant1MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp2)) { + stringArrayVariant2MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp3)) { + stringArrayVariant3MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp4)) { + stringArrayVariant4MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp5)) { + stringArrayVariant5MatchesLength++; + } + + if (obfuscatedCode.match(stringArrayVariantRegExp6)) { + stringArrayVariant6MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant1RegExp)) { + literalNodeVariant1MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant2RegExp)) { + literalNodeVariant2MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant3RegExp)) { + literalNodeVariant3MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant4RegExp)) { + literalNodeVariant4MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant5RegExp)) { + literalNodeVariant5MatchesLength++; + } + + if (obfuscatedCode.match(literalNodeVariant6RegExp)) { + literalNodeVariant6MatchesLength++; + } + } + + stringArrayVariant1Probability = stringArrayVariant1MatchesLength / samples; + stringArrayVariant2Probability = stringArrayVariant2MatchesLength / samples; + stringArrayVariant3Probability = stringArrayVariant3MatchesLength / samples; + stringArrayVariant4Probability = stringArrayVariant4MatchesLength / samples; + stringArrayVariant5Probability = stringArrayVariant5MatchesLength / samples; + stringArrayVariant6Probability = stringArrayVariant6MatchesLength / samples; + literalNodeVariant1Probability = literalNodeVariant1MatchesLength / samples; + literalNodeVariant2Probability = literalNodeVariant2MatchesLength / samples; + literalNodeVariant3Probability = literalNodeVariant3MatchesLength / samples; + literalNodeVariant4Probability = literalNodeVariant4MatchesLength / samples; + literalNodeVariant5Probability = literalNodeVariant5MatchesLength / samples; + literalNodeVariant6Probability = literalNodeVariant6MatchesLength / samples; + + }); + + describe('String array probability', () => { + it('Variant #1: should create string array variant', () => { + assert.closeTo(stringArrayVariant1Probability, expectedVariantProbability, delta); + }); + + it('Variant #2: should create string array variant', () => { + assert.closeTo(stringArrayVariant2Probability, expectedVariantProbability, delta); + }); + + it('Variant #3: should create string array variant', () => { + assert.closeTo(stringArrayVariant3Probability, expectedVariantProbability, delta); + }); + + it('Variant #4: should create string array variant', () => { + assert.closeTo(stringArrayVariant4Probability, expectedVariantProbability, delta); + }); + + it('Variant #5: should create string array variant', () => { + assert.closeTo(stringArrayVariant5Probability, expectedVariantProbability, delta); + }); + + it('Variant #6: should create string array variant', () => { + assert.closeTo(stringArrayVariant6Probability, expectedVariantProbability, delta); + }); + }); + + describe('Literal node probability', () => { + it('Variant #1: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant1Probability, expectedVariantProbability, delta); + }); + + it('Variant #2: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant2Probability, expectedVariantProbability, delta); + }); + + it('Variant #3: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant3Probability, expectedVariantProbability, delta); + }); + + it('Variant #4: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant4Probability, expectedVariantProbability, delta); + }); + + it('Variant #5: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant5Probability, expectedVariantProbability, delta); + }); + + it('Variant #6: should replace literal node with call to string array variant', () => { + assert.closeTo(literalNodeVariant6Probability, expectedVariantProbability, delta); + }); + }); + }); + }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/fixtures/three-strings.js b/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/fixtures/three-strings.js new file mode 100644 index 00000000..9ed8eb4c --- /dev/null +++ b/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/fixtures/three-strings.js @@ -0,0 +1,3 @@ +var foo = 'foo'; +var bar = 'bar'; +var baz = 'baz'; diff --git a/test/index.spec.ts b/test/index.spec.ts index 2bc022c8..3f570bfa 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -7,6 +7,7 @@ require('source-map-support').install(); */ import './unit-tests/analyzers/calls-graph-analyzer/CallsGraphAnalyzer.spec'; import './unit-tests/analyzers/prevailing-kind-of-variables-analyzer/PrevailingKindOfVariablesAnalyzer.spec'; +import './unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec'; import './unit-tests/cli/sanitizers/ArraySanitizer.spec'; import './unit-tests/cli/sanitizers/BooleanSanitizer.spec'; import './unit-tests/cli/sanitizers/IdentifierNamesGeneratorSanitizer.spec'; diff --git a/test/unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec.ts b/test/unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec.ts new file mode 100644 index 00000000..c29493ff --- /dev/null +++ b/test/unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec.ts @@ -0,0 +1,275 @@ +import 'reflect-metadata'; + +import { assert } from 'chai'; +import * as ESTree from 'estree'; + +import { ServiceIdentifiers } from '../../../../src/container/ServiceIdentifiers'; + +import { TInputOptions } from '../../../../src/types/options/TInputOptions'; + +import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade'; +import { IStringArrayStorageAnalyzer } from '../../../../src/interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer'; +import { IStringArrayStorageItemData } from '../../../../src/interfaces/storages/string-array-storage/IStringArrayStorageItem'; + +import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade'; +import { NodeFactory } from '../../../../src/node/NodeFactory'; +import { NodeMetadata } from '../../../../src/node/NodeMetadata'; + +const getStringArrayStorageAnalyzer = (options: TInputOptions): IStringArrayStorageAnalyzer => { + const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade(); + + inversifyContainerFacade.load('', '', options); + + return inversifyContainerFacade.get(ServiceIdentifiers.IStringArrayStorageAnalyzer); +}; + +describe('StringArrayStorageAnalyzer', () => { + let stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer; + + describe('analyze', () => { + describe('Base analyze of the AST tree', () => { + const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo'); + const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar'); + const literalNode3: ESTree.Literal = NodeFactory.literalNode('baz'); + + const expectedStringArrayStorageItemData1: IStringArrayStorageItemData = { + encodedValue: 'foo', + decodeKey: null, + index: 0, + value: 'foo' + }; + const expectedStringArrayStorageItemData2: IStringArrayStorageItemData = { + encodedValue: 'bar', + decodeKey: null, + index: 1, + value: 'bar' + }; + const expectedStringArrayStorageItemData3: undefined = undefined; + + let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData3: IStringArrayStorageItemData | undefined; + + before(() => { + stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({ + stringArrayThreshold: 1 + }); + + const astTree: ESTree.Program = NodeFactory.programNode([ + NodeFactory.expressionStatementNode(literalNode1), + NodeFactory.expressionStatementNode(literalNode2) + ]); + + stringArrayStorageAnalyzer.analyze(astTree); + stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1); + stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2); + stringArrayStorageItemData3 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode3); + }); + + it('Variant #1: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1); + }); + + it('Variant #2: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2); + }); + + it('Variant #3: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData3, expectedStringArrayStorageItemData3); + }); + }); + + describe('Base analyze of the AST tree with string literal nodes with values shorter than allowed length', () => { + const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo'); + const literalNode2: ESTree.Literal = NodeFactory.literalNode('ba'); + + const expectedStringArrayStorageItemData1: IStringArrayStorageItemData = { + encodedValue: 'foo', + decodeKey: null, + index: 0, + value: 'foo' + }; + const expectedStringArrayStorageItemData2: undefined = undefined; + + let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined; + + before(() => { + stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({ + stringArrayThreshold: 1 + }); + + const astTree: ESTree.Program = NodeFactory.programNode([ + NodeFactory.expressionStatementNode(literalNode1), + NodeFactory.expressionStatementNode(literalNode2) + ]); + + stringArrayStorageAnalyzer.analyze(astTree); + stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1); + stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2); + }); + + it('Variant #1: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1); + }); + + it('Variant #2: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2); + }); + }); + + describe('Base analyze of the AST tree with number literal nodes', () => { + const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo'); + const literalNode2: ESTree.Literal = NodeFactory.literalNode(1); + + const expectedStringArrayStorageItemData1: IStringArrayStorageItemData = { + encodedValue: 'foo', + decodeKey: null, + index: 0, + value: 'foo' + }; + const expectedStringArrayStorageItemData2: undefined = undefined; + + let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined; + + before(() => { + stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({ + stringArrayThreshold: 1 + }); + + const astTree: ESTree.Program = NodeFactory.programNode([ + NodeFactory.expressionStatementNode(literalNode1), + NodeFactory.expressionStatementNode(literalNode2) + ]); + + stringArrayStorageAnalyzer.analyze(astTree); + stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1); + stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2); + }); + + it('Variant #1: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1); + }); + + it('Variant #2: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2); + }); + }); + + describe('Analyzes of the AST tree with ignored nodes', () => { + const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo'); + const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar'); + NodeMetadata.set(literalNode2, {ignoredNode: true}); + + const expectedStringArrayStorageItemData1: IStringArrayStorageItemData = { + encodedValue: 'foo', + decodeKey: null, + index: 0, + value: 'foo' + }; + const expectedStringArrayStorageItemData2: undefined = undefined; + + let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined; + + before(() => { + stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({ + stringArrayThreshold: 1 + }); + + const astTree: ESTree.Program = NodeFactory.programNode([ + NodeFactory.expressionStatementNode(literalNode1), + NodeFactory.expressionStatementNode(literalNode2) + ]); + + stringArrayStorageAnalyzer.analyze(astTree); + stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1); + stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2); + }); + + it('Variant #1: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1); + }); + + it('Variant #2: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2); + }); + }); + + describe('Analyzes of the AST tree string array threshold', () => { + describe('Threshold value: 0', () => { + const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo'); + const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar'); + + const expectedStringArrayStorageItemData1: undefined = undefined; + const expectedStringArrayStorageItemData2: undefined = undefined; + + let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined; + + before(() => { + stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({ + stringArrayThreshold: 0 + }); + + const astTree: ESTree.Program = NodeFactory.programNode([ + NodeFactory.expressionStatementNode(literalNode1), + NodeFactory.expressionStatementNode(literalNode2) + ]); + + stringArrayStorageAnalyzer.analyze(astTree); + stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1); + stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2); + }); + + it('Variant #1: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1); + }); + + it('Variant #2: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2); + }); + }); + + describe('Threshold value: 0.5', () => { + const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo'); + const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar'); + + const expectedStringArrayStorageItemData1: undefined = undefined; + const expectedStringArrayStorageItemData2: IStringArrayStorageItemData = { + encodedValue: 'bar', + decodeKey: null, + index: 0, + value: 'bar' + }; + + let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined; + let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined; + + before(() => { + stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({ + stringArrayThreshold: 0.5 + }); + + const astTree: ESTree.Program = NodeFactory.programNode([ + NodeFactory.expressionStatementNode(literalNode1), + NodeFactory.expressionStatementNode(literalNode2) + ]); + + stringArrayStorageAnalyzer.analyze(astTree); + stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1); + stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2); + }); + + it('Variant #1: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1); + }); + + it('Variant #2: should return correct string array storage item data for literal node #1', () => { + assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2); + }); + }); + }); + }); +});