check-tests.py 5.5 KB

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