check-tests.py 5.41 KB
Newer Older
wester committed
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
#!/usr/bin/env python

import sys, os, re

classes_ignore_list = (
    'OpenCV(Test)?Case',
    'OpenCV(Test)?Runner',
    'CvException',
)

funcs_ignore_list = (
    '\w+--HashCode',
    'Mat--MatLong',
    '\w+--Equals',
    'Core--MinMaxLocResult',
)

class JavaParser:
    def __init__(self):
        self.clear()

    def clear(self):
        self.mdict = {}
        self.tdict = {}
        self.mwhere = {}
        self.twhere = {}
        self.empty_stubs_cnt = 0
        self.r1 = re.compile("\s*public\s+(?:static\s+)?(\w+)\(([^)]*)\)") # c-tor
        self.r2 = re.compile("\s*(?:(?:public|static|final)\s+){1,3}\S+\s+(\w+)\(([^)]*)\)")
        self.r3 = re.compile('\s*fail\("Not yet implemented"\);') # empty test stub


    def dict2set(self, d):
        s = set()
        for f in d.keys():
            if len(d[f]) == 1:
                s.add(f)
            else:
                s |= set(d[f])
        return s


    def get_tests_count(self):
        return len(self.tdict)

    def get_empty_stubs_count(self):
        return self.empty_stubs_cnt

    def get_funcs_count(self):
        return len(self.dict2set(self.mdict)), len(self.mdict)

    def get_not_tested(self):
        mset = self.dict2set(self.mdict)
        tset = self.dict2set(self.tdict)
        nottested = mset - tset
        out = set()

        for name in nottested:
            out.add(name + "   " + self.mwhere[name])

        return out


    def parse(self, path):
        if ".svn" in path:
            return
        if os.path.isfile(path):
            if path.endswith("FeatureDetector.java"):
                for prefix1 in ("", "Grid", "Pyramid", "Dynamic"):
                    for prefix2 in ("FAST", "STAR", "MSER", "ORB", "SIFT", "SURF", "GFTT", "HARRIS", "SIMPLEBLOB", "DENSE"):
                        parser.parse_file(path,prefix1+prefix2)
            elif path.endswith("DescriptorExtractor.java"):
                for prefix1 in ("", "Opponent"):
                    for prefix2 in ("BRIEF", "ORB", "SIFT", "SURF"):
                        parser.parse_file(path,prefix1+prefix2)
            elif path.endswith("GenericDescriptorMatcher.java"):
                for prefix in ("OneWay", "Fern"):
                    parser.parse_file(path,prefix)
            elif path.endswith("DescriptorMatcher.java"):
                for prefix in ("BruteForce", "BruteForceHamming", "BruteForceHammingLUT", "BruteForceL1", "FlannBased", "BruteForceSL2"):
                    parser.parse_file(path,prefix)
            else:
                parser.parse_file(path)
        elif os.path.isdir(path):
            for x in os.listdir(path):
                self.parse(path + "/" + x)
        return


    def parse_file(self, fname, prefix = ""):
        istest = fname.endswith("Test.java")
        clsname = os.path.basename(fname).replace("Test", "").replace(".java", "")
        clsname = prefix + clsname[0].upper() + clsname[1:]
        for cls in classes_ignore_list:
            if re.match(cls, clsname):
                return
        f = open(fname, "rt")
        linenum = 0
        for line in f:
            linenum += 1
            m1 = self.r1.match(line)
            m2 = self.r2.match(line)
            m3 = self.r3.match(line)
            func = ''
            args_str = ''
            if m1:
                func = m1.group(1)
                args_str = m1.group(2)
            elif m2:
                if "public" not in line:
                    continue
                func = m2.group(1)
                args_str = m2.group(2)
            elif m3:
                self.empty_stubs_cnt += 1
                continue
            else:
                #if "public" in line:
                    #print "UNRECOGNIZED: " + line
                continue
            d = (self.mdict, self.tdict)[istest]
            w = (self.mwhere, self.twhere)[istest]
            func = re.sub(r"^test", "", func)
            func = clsname + "--" + func[0].upper() + func[1:]
            args_str = args_str.replace("[]", "Array").replace("...", "Array ")
            args_str = re.sub(r"List<(\w+)>", "ListOf\g<1>", args_str)
            args_str = re.sub(r"List<(\w+)>", "ListOf\g<1>", args_str)
            args = [a.split()[0] for a in args_str.split(",") if a]
            func_ex = func + "".join([a[0].upper() + a[1:] for a in args])
            func_loc = fname + " (line: " + str(linenum)  + ")"
            skip = False
            for fi in funcs_ignore_list:
                if re.match(fi, func_ex):
                    skip = True
                    break
            if skip:
                continue
            if func in d:
                d[func].append(func_ex)
            else:
                d[func] = [func_ex]
            w[func_ex] = func_loc
            w[func] = func_loc

        f.close()
        return


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print "Usage:\n", \
            os.path.basename(sys.argv[0]), \
            "<Classes/Tests dir1/file1> [<Classes/Tests dir2/file2> ...]\n", "Not tested methods are loggedto stdout."
        exit(0)
    parser = JavaParser()
    for x in sys.argv[1:]:
        parser.parse(x)
    funcs = parser.get_not_tested()
    if funcs:
        print "NOT TESTED methods:\n\t", "\n\t".join(sorted(funcs))
    print "Total methods found: %i (%i)" % parser.get_funcs_count()
    print "Not tested methods found:", len(funcs)
    print "Total tests found:", parser.get_tests_count()
    print "Empty test stubs found:", parser.get_empty_stubs_count()