Skip to content

Commit 8926d78

Browse files
committed
DOM access coverage added
1 parent 01c6dbe commit 8926d78

File tree

4 files changed

+169
-38
lines changed

4 files changed

+169
-38
lines changed

src/main/java/ProductionCodeCoverageAnalyzer.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class ProductionCodeCoverageAnalyzer {
4040
//private static String subjectCoverageFolder = "ButtonsCoverageReport";
4141
//private static String subjectCoverageFolder = "jquery-placeholderCoverageReport";
4242
//private static String subjectCoverageFolder = "backboneCoverageReport";
43-
private static String subjectCoverageFolder = "emberCoverageReport";
43+
private static String subjectCoverageFolder = "picturefillCoverageReport";
4444

4545

4646
private static String coverageReportPath = "/Users/aminmf/Downloads/JSCover-1.0.23/target/" + subjectCoverageFolder;
@@ -63,6 +63,8 @@ public class ProductionCodeCoverageAnalyzer {
6363
private static int missedEventCallback;
6464
private static int coveredClosure;
6565
private static int missedClosure;
66+
private static int coveredDOMAccess;
67+
private static int missedDOMAccess;
6668
private static int neverExecFunCallSites;
6769
private static int totalMissedStatementLinesInMissedFunctionCounter;
6870
private static int totalMissedStatementLines;
@@ -173,6 +175,8 @@ private static void analyseJSFile(String canonicalPath, ArrayList<Integer> cover
173175
missedEventCallback += codeAnalyzer.getMissedEventCallback();
174176
coveredClosure += codeAnalyzer.getCoveredClosure();
175177
missedClosure += codeAnalyzer.getMissedClosure();
178+
coveredDOMAccess += codeAnalyzer.getCoveredDOMAccess();
179+
missedDOMAccess += codeAnalyzer.getMissedDOMAccess();
176180
neverExecFunCallSites += codeAnalyzer.getNeverExecFunCallSites();
177181
totalMissedStatementLinesInMissedFunctionCounter += codeAnalyzer.getTotalMissedStatementLinesInMissedFunctionCounter();
178182
totalMissedStatementLines += codeAnalyzer.getTotalMissedStatementLines();
@@ -189,6 +193,8 @@ private static void analyseJSFile(String canonicalPath, ArrayList<Integer> cover
189193
System.out.println("++++ missedEventCallback: " + missedEventCallback);
190194
System.out.println("++++ coveredClosure: " + coveredClosure);
191195
System.out.println("++++ missedClosure: " + missedClosure);
196+
System.out.println("++++ coveredDOMAccess: " + coveredDOMAccess);
197+
System.out.println("++++ missedDOMAccess: " + missedDOMAccess);
192198
System.out.println("++++ neverExecFunCallSites: " + neverExecFunCallSites);
193199

194200
float ratio = 0;
@@ -199,9 +205,47 @@ private static void analyseJSFile(String canonicalPath, ArrayList<Integer> cover
199205
System.out.println("@ Percentage of missed statement in missed functions = " + ratio*100 + "%");
200206
}
201207

208+
202209
System.out.println("==========================");
203-
System.out.println(coveredRegularFunc + "\t" + missedRegularFunc + "\t" + coveredCallback + "\t" + missedCallback + "\t" + coveredAsyncCallback + "\t" +
204-
missedAsyncCallback + "\t" + coveredEventCallback + "\t" + missedEventCallback + "\t" + coveredClosure + "\t" + missedClosure + "\t" + neverExecFunCallSites + "\t" + ratio*100 + "%");
210+
System.out.print(coveredRegularFunc + "\t" + missedRegularFunc + "\t" + coveredCallback + "\t" + missedCallback + "\t" +
211+
coveredAsyncCallback + "\t" + missedAsyncCallback + "\t" + coveredEventCallback + "\t" + missedEventCallback + "\t" +
212+
coveredClosure + "\t" + missedClosure + "\t" + coveredDOMAccess + "\t" + missedDOMAccess + "\t");
213+
214+
float regFuncCoverage , callbackCoverage, asyncCallbackCoverage, eventCallbackCoverage, closureCoverage, DOMAccessCoverage;
215+
if (coveredRegularFunc+missedRegularFunc!=0){
216+
regFuncCoverage = (float)coveredRegularFunc/(float)(coveredRegularFunc+missedRegularFunc);
217+
System.out.print(regFuncCoverage*100 + "%\t");
218+
}else
219+
System.out.print("\t\t");
220+
if (coveredCallback+missedCallback!=0){
221+
callbackCoverage = (float)coveredCallback/(float)(coveredCallback+missedCallback);
222+
System.out.print(callbackCoverage*100 + "%\t");
223+
}else
224+
System.out.print("\t\t");
225+
if (coveredAsyncCallback+missedAsyncCallback!=0){
226+
asyncCallbackCoverage = (float)coveredAsyncCallback/(float)(coveredAsyncCallback+missedAsyncCallback);
227+
System.out.print(asyncCallbackCoverage*100 + "%\t");
228+
}else
229+
System.out.print("\t\t");
230+
if (coveredEventCallback+missedEventCallback!=0){
231+
eventCallbackCoverage = (float)coveredEventCallback/(float)(coveredEventCallback+missedEventCallback);
232+
System.out.print(eventCallbackCoverage*100 + "%\t");
233+
}else
234+
System.out.print("\t\t");
235+
if (coveredClosure+missedClosure!=0){
236+
closureCoverage = (float)coveredClosure/(float)(coveredClosure+missedClosure);
237+
System.out.print(closureCoverage*100 + "%\t");
238+
}else
239+
System.out.print("\t\t");
240+
if (coveredDOMAccess+missedDOMAccess!=0){
241+
DOMAccessCoverage = (float)coveredDOMAccess/(float)(coveredDOMAccess+missedDOMAccess);
242+
System.out.print(DOMAccessCoverage*100 + "%\t");
243+
}else
244+
System.out.print("\t\t");
245+
246+
System.out.print(neverExecFunCallSites + "\t" + ratio*100 + "%\n");
247+
248+
205249
System.out.println("==========================");
206250

207251
}

src/main/java/TestCodePropertyAnalyzer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,18 @@
2828

2929
public class TestCodePropertyAnalyzer {
3030

31-
//private static String testsFramework = "qunit"; // {"qunit", "jasmine", "mocha"}
31+
private static String testsFramework = "qunit"; // {"qunit", "jasmine", "mocha"}
32+
private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/pageres/test/";
33+
3234
//private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/velocity/test/";
3335
//private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/lazysizes/tests/"; // => QUnit.test.apply
3436
//private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/ember.js/tests/"; => Wrong answer! also consider node-test folder
3537
//private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/sizzle/test/"; => Wrong answer!
3638
//private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/moment/src/test/";
3739

3840

39-
private static String testsFramework = "jasmine";
40-
private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/dropzone/test";
41+
//private static String testsFramework = "jasmine";
42+
//private static String testsFolder = "/Users/aminmf/Documents/JavaScriptTestsStudy/popularJS/dropzone/test";
4143

4244

4345

src/main/java/core/JSAnalyzer.java

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ public int getMissedRegularFunc() {
8585
return missedRegularFunc;
8686
}
8787

88+
private int coveredDOMAccess = 0;
89+
public int getCoveredDOMAccess() {
90+
return coveredDOMAccess;
91+
}
92+
93+
private int missedDOMAccess = 0;
94+
public int getMissedDOMAccess() {
95+
return missedDOMAccess;
96+
}
97+
8898
private int neverExecFunCallSites = 0;
8999
public int getNeverExecFunCallSites() {
90100
return neverExecFunCallSites;
@@ -368,8 +378,6 @@ public void analyzeProductionCodeCoverage(ArrayList<Integer> coveredLines, Array
368378
}
369379
}
370380

371-
372-
373381
coveredRegularFunc = astVisitor.getCoveredRegularFunc();
374382
missedRegularFunc = astVisitor.getMissedRegularFunc();
375383
coveredCallback = astVisitor.getCoveredCallback();
@@ -380,22 +388,25 @@ public void analyzeProductionCodeCoverage(ArrayList<Integer> coveredLines, Array
380388
missedEventCallback = astVisitor.getMissedEventCallback();
381389
coveredClosure = astVisitor.getCoveredClosure();
382390
missedClosure = astVisitor.getMissedClosure();
383-
384-
385-
System.out.println("++++ coveredRegularFunc: " + astVisitor.getCoveredRegularFunc());
386-
System.out.println("++++ missedRegularFunc: " + astVisitor.getMissedRegularFunc());
387-
System.out.println("++++ coveredCallback: " + astVisitor.getCoveredCallback());
388-
System.out.println("++++ missedCallback: " + astVisitor.getMissedCallback());
389-
System.out.println("++++ coveredAsyncCallback: " + astVisitor.getCoveredAsyncCallback());
390-
System.out.println("++++ missedAsyncCallback: " + astVisitor.getMissedAsyncCallback());
391-
System.out.println("++++ coveredEventCallback: " + astVisitor.getCoveredAsyncCallback());
392-
System.out.println("++++ missedEventCallback: " + astVisitor.getMissedEventCallback());
393-
System.out.println("++++ coveredClosure: " + astVisitor.getCoveredClosure());
394-
System.out.println("++++ missedClosure: " + astVisitor.getMissedClosure());
391+
coveredDOMAccess = astVisitor.getCoveredDOMAccessLines().size();
392+
missedDOMAccess = astVisitor.getMissedDOMAccessLines().size();
393+
394+
System.out.println("++++ coveredRegularFunc: " + coveredRegularFunc);
395+
System.out.println("++++ missedRegularFunc: " + missedRegularFunc);
396+
System.out.println("++++ coveredCallback: " + coveredCallback);
397+
System.out.println("++++ missedCallback: " + missedCallback);
398+
System.out.println("++++ coveredAsyncCallback: " + coveredAsyncCallback);
399+
System.out.println("++++ missedAsyncCallback: " + missedAsyncCallback);
400+
System.out.println("++++ coveredEventCallback: " + coveredEventCallback);
401+
System.out.println("++++ missedEventCallback: " + missedEventCallback);
402+
System.out.println("++++ coveredClosure: " + coveredClosure);
403+
System.out.println("++++ missedClosure: " + missedClosure);
404+
405+
System.out.println("++++ coveredDOMAccess: " + coveredDOMAccess);
406+
System.out.println("++++ missedDOMAccess: " + missedDOMAccess);
395407

396408
System.out.println("++++ neverExecFunCallSites: " + neverExecFunCallSites);
397-
398-
409+
399410
ArrayList<Integer> msimf = astVisitor.getMissedStatementInMissedFunction();
400411
//System.out.println("msimf: " + msimf);
401412
for (int i=0; i<msimf.size(); i++){

src/main/java/instrumentor/JSASTInstrumentor.java

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,26 @@ public int getCoveredRegularFunc() {
195195
return coveredRegularFunc;
196196
}
197197

198+
// DOM Access Coverage
199+
private ArrayList<Integer> coveredDOMAccessLines = new ArrayList<Integer>();
200+
public ArrayList<Integer> getCoveredDOMAccessLines() {
201+
return coveredDOMAccessLines;
202+
}
203+
private ArrayList<Integer> missedDOMAccessLines = new ArrayList<Integer>();
204+
public ArrayList<Integer> getMissedDOMAccessLines() {
205+
return missedDOMAccessLines;
206+
}
207+
208+
209+
198210
private int missedRegularFunc = 0;
199-
200-
private String testsFramework;
201-
202211
public int getMissedRegularFunc() {
203212
return missedRegularFunc;
204213
}
205214

215+
private String testsFramework;
206216

217+
207218
public void setVisitOnly(String visitOnly){
208219
this.visitOnly = visitOnly;
209220
}
@@ -559,6 +570,18 @@ private void analyzeProductionCodeFunctionCallNode(AstNode node) {
559570
if (!functionCalls.contains(targetSource))
560571
functionCalls.add(targetSource);
561572

573+
// check for DOM API accessing the DOM
574+
if (isDOMAPIMethod(targetSource)){
575+
int lineNumber = node.getLineno()+1;
576+
if (coveredStatementLines.contains(lineNumber)){
577+
if (!coveredDOMAccessLines.contains(lineNumber)) coveredDOMAccessLines.add(lineNumber);
578+
System.out.println("======== Covered DOM access at line" + (node.getLineno()+1) + " - DOM access: " + targetSource);
579+
}else{
580+
if (!missedDOMAccessLines.contains(lineNumber)) missedDOMAccessLines.add(lineNumber);
581+
System.out.println("======== Missed DOM access at line" + (node.getLineno()+1) + " - DOM access: " + targetSource);
582+
}
583+
}
584+
562585
// check for callback and if it's an event-dependent callback
563586
for (AstNode n : fcall.getArguments()){
564587
if (n.shortName().equals("Name") && coveredFunctions.contains(n.toSource())){
@@ -605,8 +628,18 @@ private void analyzeProductionCodeAssignmentNode(AstNode node) {
605628
missedEventCallback++;
606629
}
607630
//System.out.println("Event-dependent callback function: " + asmt.toSource());
608-
}
609631

632+
}else // checking for DOM element changes
633+
if (isDOMElementAttribute(varName)){
634+
int lineNumber = node.getLineno()+1;
635+
if (coveredStatementLines.contains(lineNumber)){
636+
if (!coveredDOMAccessLines.contains(lineNumber)) coveredDOMAccessLines.add(lineNumber);
637+
System.out.println("======== Covered DOM access at line" + (node.getLineno()+1) + " - DOM elem attribute: " + varName);
638+
}else{
639+
if (!missedDOMAccessLines.contains(lineNumber)) missedDOMAccessLines.add(lineNumber);
640+
System.out.println("======== Missed DOM access at line" + (node.getLineno()+1) + " - DOM elem attribute: " + varName);
641+
}
642+
}
610643
}
611644

612645
private void instrumentFunctionNode(AstNode node) {
@@ -1160,6 +1193,41 @@ public void clearFunctionsList() {
11601193
missedFunctions.clear();
11611194
}
11621195

1196+
public boolean isDOMAPIMethod(String functionName){
1197+
1198+
String[] DOMAccessMethods = {
1199+
".getElementById", ".getElementsByTagName", ".getElementsByClassName", ".getElementsByName",
1200+
".createElement", ".removeChild", ".appendChild", ".replaceChild", ".addEventListener", ".appendChild", ".adoptNode",
1201+
".blur", ".click", ".createAttribute", ".createElement", ".createTextNode", ".insertBefore", ".querySelector", ".querySelectorAll",
1202+
".removeAttribute", ".removeAttributeNode", ".removeChild", ".replaceChild", ".removeEventListener", ".setAttribute", ".setAttributeNode", ".getAttribute", ".dblclick", ".hover", ".mouseout", ".mouseover", ".scroll", ".select", ".submit", ".toggle", ".trigger", ".triggerHandler",
1203+
".onclick", ".ondblclick", ".onmouseover", ".onmouseout", ".onselect", ".onsubmit", ".ondrag", ".ondragover",
1204+
".addClass", ".removeClass", ".removeAttr", ".css", ".attr", ".prop", ".append", ".appendTo", ".prepend", ".prependTo",
1205+
".insertBefore", ".insertAfter", ".detach", ".remove", ".html"
1206+
};
1207+
1208+
for (String pattern: DOMAccessMethods)
1209+
if (functionName.endsWith(pattern))
1210+
return true;
1211+
1212+
if (functionName.equals("jQuery") || functionName.equals("$"))
1213+
return true;
1214+
1215+
return false;
1216+
}
1217+
1218+
public boolean isDOMElementAttribute(String functionName){
1219+
String[] DOMElemAtt = { ".innerHTML", ".attribute", ".onclick", ".anchors", ".documentElement", ".forms", ".head", ".images", ".links"};
1220+
for (String pattern: DOMElemAtt)
1221+
if (functionName.endsWith(pattern))
1222+
return true;
1223+
1224+
if (functionName.contains(".style."))
1225+
return true;
1226+
1227+
return false;
1228+
}
1229+
1230+
11631231
public boolean isEventMethod(String functionName){
11641232
/**
11651233
jQuery Event Methods
@@ -1199,16 +1267,15 @@ public boolean isEventMethod(String functionName){
11991267
trigger() Triggers all events bound to the selected elements
12001268
triggerHandler() Triggers all functions bound to a specified event for the selected elements
12011269
unload() Deprecated in version 1.8. Attaches an event handler to the unload event
1202-
1203-
1204-
1205-
Node.js EventEmitter => emit() : .emit(event, data, ...)
1206-
1207-
*/
1270+
1271+
1272+
Node.js EventEmitter => emit() : .emit(event, data, ...)
1273+
**/
12081274

12091275
String[] eventMethods = { ".bind", ".blur", ".change", ".click", ".dblclick", ".delegate", ".error", ".focus",
12101276
".focusin", ".focusout", ".hover", ".keydown", ".keypress", ".keyup", ".live", ".load", ".mousedown", ".mouseenter", ".mouseleave", ".mousemove",
1211-
".mouseout", ".mouseover", ".mouseup", ".on", ".one", ".ready", ".resize", ".scroll", ".select", ".submit", ".toggle", ".trigger", ".triggerHandler", ".emit", ".unload",
1277+
".mouseout", ".mouseover", ".mouseup", ".on", ".one", ".ready", ".resize", ".scroll", ".select", ".submit", ".toggle", ".trigger", ".triggerHandler", ".unload",
1278+
".emit",
12121279

12131280
".addEventListener", ".attachEvent",
12141281

@@ -1265,21 +1332,28 @@ public boolean isEventMethod(String functionName){
12651332
*/
12661333
}
12671334

1335+
12681336
public boolean isAsyncMethod(String functionName){
12691337
/**
1338+
e.g
12701339
setTimeout(func, delay, [param1, param2, ...])
12711340
setInterval(func, delay[, param1, param2, ...])
1341+
...
12721342
*/
12731343

1274-
// TODO: XHR and others from Keheliya's paper
1344+
// Updated based on http://salt.ece.ubc.ca/callback-study/#async-apis
12751345

1276-
String[] asyncMethods = { "setImmediate", "setTimeout", "setInterval"};
1346+
String[] asyncMethods = { "setImmediate", "setTimeout", "setInterval", "XMLHTTPRequest.open", "addEventListener", "onclick", "process.nextTick"};
1347+
String[] asyncIOPaterns = { "fs.", "net.", "child_process.", "crypto.", "dns.", "domain.", "http.", "https.", "net.", "tls.", "dgram."};
12771348

1278-
for (String am: asyncMethods)
1279-
if (functionName.equals(am))
1349+
for (String pattern: asyncMethods)
1350+
if (functionName.endsWith(pattern))
1351+
return true;
1352+
for (String pattern: asyncIOPaterns)
1353+
if (functionName.startsWith(pattern))
12801354
return true;
1281-
return false;
12821355

1356+
return false;
12831357
}
12841358

12851359

0 commit comments

Comments
 (0)