-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
198 lines (156 loc) · 7.38 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*--------------------------------------------------------------------------
*--------------------- Automation Unit Test Generator ---------------------
*--------------------- B.Khosravifar & E.Estedlali ---------------------
*--------------------------------------------------------------------------
*/
const fs = require('fs');
const esprima = require('esprima'); // http://esprima.org
const util = require('./src/util'); // utilities
const Graph = require('./src/dft'); // Depth First Traversal
const GA = require('./src/ga'); // Genetic Algorithm
const docParser = require('./src/doc'); // document parser
const { Random, StopWatch } = require('./src/util'); // utilities
const instrument = require('./src/instrument.js');
const babel = require("@babel/core"); // https://babeljs.io
const styx = require('styx'); // https://github.com/mariusschulz/styx
const js2flowchart = require("js2flowchart"); // https://github.com/Bogdan-Lyashenko/js-code-to-svg-flowchart
const Viz = require('viz.js'); // https://github.com/mdaines/viz.js/wiki/Usage
const { Module, render } = require('viz.js/full.render.js');
const outputPath = "./output/";
const filePath = "./test-samples/fact.js";
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
const fileExt = filePath.substring(filePath.lastIndexOf('.') + 1);
//--------------------- read source code -----------------------------------
var src = fs.readFileSync(filePath, 'utf8');
console.info(`The "${fileName}.${fileExt}" source codes loaded`);
//--------------------------------------------------------------------------
//--------------------- Parse function params type -----------------------------------
var params = docParser(src);
console.info(`function `);
//--------------------------------------------------------------------------
//---------------------- Parse JavaScript into AST -------------------------
// convert any newest ES to ES5
var { code } = babel.transformSync(src, {
ast: false,
code: true,
plugins: [
// EntryTarget
'@babel/plugin-transform-classes',
// [EntryTarget, EntryOptions]
['@babel/plugin-transform-arrow-functions', { spec: true }],
// [EntryTarget, EntryOptions, string]
['@babel/plugin-transform-for-of', { loose: true }, "some-name"],
// ConfigItem
babel.createConfigItem(require("@babel/plugin-transform-spread")),
],
});
console.info(`"${fileName}" source converted to ES5 by babel`);
var ast = esprima.parse(code); // generate AST with esprima
//--------------------------------------------------------------------------
// -------------------- preprocess and regenerate code ---------------------
console.info(`preprocessing "${fileName}" source for formatting code style...`)
src = util.generate(ast);
ast = esprima.parse(src, { loc: true, range: true, comment: false });
console.info(`The AST of "${fileName}" source Parsed`);
//-------------------------------------------------------------------------
//---------------- create flow chart bt source code -----------------------
try {
const svg = js2flowchart.convertCodeToSvg(src);
fs.writeFile(outputPath + "flowChart.svg", svg, "utf-8", (err) => {
if (err) throw err;
console.log('The "flowChart.svg" file has been saved');
});
}
catch (ex) {
console.log("Error at js2flowchart:", ex);
}
//--------------------------------------------------------------------------
//---------------- create flow program by styx parser ----------------------
console.info(`creating the source flow program...`);
var flowProgram = styx.parse(ast);
//--------------------------------------------------------------------------
//------------- create control-flow-graph program by styx ------------------
// https://github.com/mariusschulz/styx-cli/blob/master/src/index.js
// exported from styx-cli
function findFlowGraphAndNameForId(flowProgram, functionId) {
if (!functionId) {
return [flowProgram.flowGraph, "Main Program"];
}
for (let i = 0, length = flowProgram.functions.length; i < length; i++) {
let fun = flowProgram.functions[i];
if (fun.id === functionId) {
return [fun.flowGraph, fun.name];
}
}
throw Error(`Couldn't find function with id ${functionId}`);
}
// $ styx testfile.js --format dot --graph 1
var [flowGraph, name] = findFlowGraphAndNameForId(flowProgram, 1);
//--------------------------------------------------------------------------
//----------------- export as grapgviz DOT format --------------------------
var cfgObj = styx.exportAsObject(flowProgram);
var graphviz = styx.exportAsDot(flowGraph, name);
console.info(`Control flow graph (CFG) graphviz data exported`);
//--------------------------------------------------------------------------
//---------------------- visualize CFG as .svg format ----------------------
var viz = new Viz({ Module, render });
viz.renderString(graphviz)
.then(result => {
let file = outputPath + "cfg.svg";
fs.writeFile(file, result, "utf-8", (err) => {
if (err)
throw err;
console.log(`The ${file} file has been saved`);
});
})
.catch(error => {
// Create a new Viz instance (@see Caveats page for more info)
viz = new Viz({ Module, render });
// Possibly display the error
console.error(error);
});
//--------------------------------------------------------------------------
//----------- modify AST by injecting extra instrumenting code -------------
var { code, cfg, params } = instrument(src, cfgObj);
let insPath = outputPath + `${fileName}.instrumented.${fileExt}`;
fs.writeFile(insPath, code, "utf-8", (err) => {
if (err)
throw err;
console.log(`The instrumented file has been saved at ${insPath}`);
});
//--------------------------------------------------------------------------
//---------------- Find all branches in Control-Flow-Graph -----------------
let graph = new Graph(cfg.nodesArray.length);
let edges = cfg.edgesKeys.map(k => k.split("-"));
for (let e = 0; e < edges.length; e++) {
let f = parseInt(edges[e][0]);
let t = parseInt(edges[e][1]);
graph.addEdge(f, t);
}
let s = cfg.nodesArray.find(n => n.isStartNode).id;
let d = cfg.nodesArray.find(n => n.isEndNode).id;
var paths = graph.getPaths(s, d);
console.info("All CFG branches path found:", JSON.stringify(paths));
//--------------------------------------------------------------------------
//------------------ Find test case by Genetic Algorithm -------------------
// N , Pop, SR, MR, ReGen, CR
// best practice: GA(200, 500, 30, 60, 10000, 75); 4775ms
// fast practice: GA(200, 500, 10, 50, 10000, 75); 2659ms
StopWatch.start();
// ------------------------------------------------------
// N , Pop, SR, MR, ReGen, CR
var ga = new GA(200, 500, 10, 50, 10000, 75);
// N: Number of Queens in the N×N Chess Board
// Pop: Population size
// SR: Selection probability %
// MR: Mutation probability %
// ReGen: Regeneration limitation
// CR: Max Chromosomes Convergence Rate %
var result = ga.Start();
console.log("Result:", result);
console.log("Generation:", ga.RegenerationCounter)
// ------------------------------------------------------
StopWatch.stop();
//--------------------------------------------------------------------------
console.log("----------- END -------------");
// $ jest test.js --collectCoverage