1#!/usr/bin/env python 2 3from __future__ import print_function 4import sys, os, re 5 6classes_ignore_list = ( 7 'OpenCV(Test)?Case', 8 'OpenCV(Test)?Runner', 9 'CvException', 10) 11 12funcs_ignore_list = ( 13 '\w+--HashCode', 14 'Mat--MatLong', 15 '\w+--Equals', 16 'Core--MinMaxLocResult', 17) 18 19class JavaParser: 20 def __init__(self): 21 self.clear() 22 23 def clear(self): 24 self.mdict = {} 25 self.tdict = {} 26 self.mwhere = {} 27 self.twhere = {} 28 self.empty_stubs_cnt = 0 29 self.r1 = re.compile("\s*public\s+(?:static\s+)?(\w+)\(([^)]*)\)") # c-tor 30 self.r2 = re.compile("\s*(?:(?:public|static|final)\s+){1,3}\S+\s+(\w+)\(([^)]*)\)") 31 self.r3 = re.compile('\s*fail\("Not yet implemented"\);') # empty test stub 32 33 34 def dict2set(self, d): 35 s = set() 36 for f in d.keys(): 37 if len(d[f]) == 1: 38 s.add(f) 39 else: 40 s |= set(d[f]) 41 return s 42 43 44 def get_tests_count(self): 45 return len(self.tdict) 46 47 def get_empty_stubs_count(self): 48 return self.empty_stubs_cnt 49 50 def get_funcs_count(self): 51 return len(self.dict2set(self.mdict)), len(self.mdict) 52 53 def get_not_tested(self): 54 mset = self.dict2set(self.mdict) 55 tset = self.dict2set(self.tdict) 56 nottested = mset - tset 57 out = set() 58 59 for name in nottested: 60 out.add(name + " " + self.mwhere[name]) 61 62 return out 63 64 65 def parse(self, path): 66 if ".svn" in path: 67 return 68 if os.path.isfile(path): 69 if path.endswith("FeatureDetector.java"): 70 for prefix1 in ("", "Grid", "Pyramid", "Dynamic"): 71 for prefix2 in ("FAST", "STAR", "MSER", "ORB", "SIFT", "SURF", "GFTT", "HARRIS", "SIMPLEBLOB", "DENSE"): 72 parser.parse_file(path,prefix1+prefix2) 73 elif path.endswith("DescriptorExtractor.java"): 74 for prefix1 in ("", "Opponent"): 75 for prefix2 in ("BRIEF", "ORB", "SIFT", "SURF"): 76 parser.parse_file(path,prefix1+prefix2) 77 elif path.endswith("GenericDescriptorMatcher.java"): 78 for prefix in ("OneWay", "Fern"): 79 parser.parse_file(path,prefix) 80 elif path.endswith("DescriptorMatcher.java"): 81 for prefix in ("BruteForce", "BruteForceHamming", "BruteForceHammingLUT", "BruteForceL1", "FlannBased", "BruteForceSL2"): 82 parser.parse_file(path,prefix) 83 else: 84 parser.parse_file(path) 85 elif os.path.isdir(path): 86 for x in os.listdir(path): 87 self.parse(path + "/" + x) 88 return 89 90 91 def parse_file(self, fname, prefix = ""): 92 istest = fname.endswith("Test.java") 93 clsname = os.path.basename(fname).replace("Test", "").replace(".java", "") 94 clsname = prefix + clsname[0].upper() + clsname[1:] 95 for cls in classes_ignore_list: 96 if re.match(cls, clsname): 97 return 98 f = open(fname, "rt") 99 linenum = 0 100 for line in f: 101 linenum += 1 102 m1 = self.r1.match(line) 103 m2 = self.r2.match(line) 104 m3 = self.r3.match(line) 105 func = '' 106 args_str = '' 107 if m1: 108 func = m1.group(1) 109 args_str = m1.group(2) 110 elif m2: 111 if "public" not in line: 112 continue 113 func = m2.group(1) 114 args_str = m2.group(2) 115 elif m3: 116 self.empty_stubs_cnt += 1 117 continue 118 else: 119 #if "public" in line: 120 #print "UNRECOGNIZED: " + line 121 continue 122 d = (self.mdict, self.tdict)[istest] 123 w = (self.mwhere, self.twhere)[istest] 124 func = re.sub(r"^test", "", func) 125 func = clsname + "--" + func[0].upper() + func[1:] 126 args_str = args_str.replace("[]", "Array").replace("...", "Array ") 127 args_str = re.sub(r"List<(\w+)>", "ListOf\g<1>", args_str) 128 args_str = re.sub(r"List<(\w+)>", "ListOf\g<1>", args_str) 129 args = [a.split()[0] for a in args_str.split(",") if a] 130 func_ex = func + "".join([a[0].upper() + a[1:] for a in args]) 131 func_loc = fname + " (line: " + str(linenum) + ")" 132 skip = False 133 for fi in funcs_ignore_list: 134 if re.match(fi, func_ex): 135 skip = True 136 break 137 if skip: 138 continue 139 if func in d: 140 d[func].append(func_ex) 141 else: 142 d[func] = [func_ex] 143 w[func_ex] = func_loc 144 w[func] = func_loc 145 146 f.close() 147 return 148 149 150if __name__ == '__main__': 151 if len(sys.argv) < 2: 152 print("Usage:\n", \ 153 os.path.basename(sys.argv[0]), \ 154 "<Classes/Tests dir1/file1> [<Classes/Tests dir2/file2> ...]\n", "Not tested methods are loggedto stdout.") 155 exit(0) 156 parser = JavaParser() 157 for x in sys.argv[1:]: 158 parser.parse(x) 159 funcs = parser.get_not_tested() 160 if funcs: 161 print ('{} {}'.format("NOT TESTED methods:\n\t", "\n\t".join(sorted(funcs)))) 162 print ("Total methods found: %i (%i)" % parser.get_funcs_count()) 163 print ('{} {}'.format("Not tested methods found:", len(funcs))) 164 print ('{} {}'.format("Total tests found:", parser.get_tests_count())) 165 print ('{} {}'.format("Empty test stubs found:", parser.get_empty_stubs_count())) 166