diff --git a/components/testexec.py b/components/testexec.py index 48e3548..9623897 100644 --- a/components/testexec.py +++ b/components/testexec.py @@ -38,6 +38,7 @@ import components.component import basic.componentHandling import utils.db_abstract import utils.path_tool +import utils.file_tool import utils.match_tool import utils.tdata_tool import basic.constants as B @@ -259,7 +260,7 @@ class Testexecuter(): verify = job.getDebugLevel(self.name) self.m.debug(verify, "--- " + str(inspect.currentframe().f_code.co_name) + "() " + str(self.name)) - def compare_results(self, granularity): + def compare_results(self, report): """ to compare the actual result with the target result has three steps: 1 matching each element so you get a comparable pair @@ -285,16 +286,16 @@ class Testexecuter(): comp = cm.getComponent(a[0]) else: comp = self - path = os.path.join(utils.path_tool.composePatttern( + path = os.path.join(utils.path_tool.composePattern( "{"+utils.match_tool.MATCH[utils.match_tool.MATCH_SIDE_POSTACTUAL]["filepattern"]+"}", comp), a[1]+".csv") pass elif side == utils.match_tool.MATCH_SIDE_TESTCASE: if hasattr(job.par, "testcase_example"): - path = os.path.join(utils.path_tool.composePatttern( + path = os.path.join(utils.path_tool.composePattern( "{"+utils.match_tool.MATCH[utils.match_tool.MATCH_SIDE_POSTEXPECT]["filepattern"]+"}", self), t+".csv") path.replace(getattr(job.par, "testcase"), getattr(job.par, "testcase_example")) else: - path = os.path.join(utils.path_tool.composePatttern("{"+utils.match_tool.MATCH[side]["filepattern"]+"}", self), t+".csv") + path = os.path.join(utils.path_tool.composePattern("{" + utils.match_tool.MATCH[side]["filepattern"] + "}", self), t + ".csv") filedata = utils.tdata_tool.readCsv(self.m, path, self) data[side] = utils.match_tool.MATCH[side] data[side]["path"] = path @@ -302,7 +303,12 @@ class Testexecuter(): # execute the matches for type in utils.match_tool.MATCH_TYPES: matching.setData(data, type) + report.setPaths(job.par.testcase, self.name, t, type, matching.matchfiles["A"], matching.matchfiles["B"]) text = utils.match_tool.matchTree(matching) + report.setMatchResult(job.par.testcase, self.name, t, type, matching.cssClass, matching.diffText) + path = os.path.join(utils.path_tool.composePattern("{tcresult}", self), + t+"_"+utils.match_tool.MATCH[type]["filename"]+".html") + utils.file_tool.writeFileText(self.m, path, text) # write text pass pass diff --git a/test/test_compare.py b/test/test_compare.py index 67f6c12..7bf943f 100644 --- a/test/test_compare.py +++ b/test/test_compare.py @@ -1,5 +1,7 @@ import json import unittest + +import basic from basic.program import Job import utils.match_tool import utils.match_tool as M @@ -7,7 +9,7 @@ import components.component tdata = { M.MATCH_SIDE_POSTEXPECT: { - "path": "", + "path": "/home/match/postexpect.csv", "data": { "database": { "scheme": { @@ -19,7 +21,7 @@ tdata = { } }, M.MATCH_SIDE_PREACTUAL: { - "path": "", + "path": "/home/match/peract.csv", "data": { "database": { "scheme": { @@ -36,7 +38,7 @@ tdata = { } }, M.MATCH_SIDE_POSTACTUAL: { - "path": "", + "path": "/home/match/postact.csv", "data": { "database": { "scheme": { @@ -82,16 +84,19 @@ class MyTestCase(unittest.TestCase): def test_matchstart(self): job = Job("unit") + setattr(job.par, "testcase", "TC0001") comp = components.component.Component() comp.files = { "A": "/home/match/per.csv", "B": "/home/match/post.csv"} comp.conf = conf + comp.name = "component" matching = utils.match_tool.Matching(comp) matching.setData(tdata, utils.match_tool.MATCH_SUCCESS) print(matching.htmltext) - def xtest_hitmanage(self): + def test_hitmanage(self): comp = components.component.Component() comp.files = { "A": "/home/match/per.csv", "B": "/home/match/post.csv"} + comp.name = "component" comp.conf = conf matching = utils.match_tool.Matching(comp) matching.linksA = { "a0001": "null", "a0002": "null", "a0003": "null", "a0004": "null"} @@ -110,9 +115,11 @@ class MyTestCase(unittest.TestCase): tdata[M.MATCH_SIDE_PREACTUAL]["data"]["database"]["scheme"]["table"]["_data"][0], tdata[M.MATCH_SIDE_POSTACTUAL]["data"]["database"]["scheme"]["table"]["_data"][0],1) - def xtest_bestfit(self): + def test_bestfit(self): job = Job("unit") + setattr(job.par, "testcase", "TC0001") comp = components.component.Component() + comp.name = "component" comp.files = { "A": "/home/match/per.csv", "B": "/home/match/post.csv"} comp.conf = conf matching = utils.match_tool.Matching(comp) @@ -127,10 +134,12 @@ class MyTestCase(unittest.TestCase): print(json.dumps(matching.linksB)) print(json.dumps(matching.nomatch)) - def xtest_compareRow(self): + def test_compareRow(self): job = Job("unit") + setattr(job.par, "testcase", "TC0001") comp = components.component.Component() comp.files = { "A": "/home/match/per.csv", "B": "/home/match/post.csv"} + comp.name = "component" comp.conf = conf matching = self.getMatching() matching.sideA = tdata[M.MATCH_SIDE_PREACTUAL]["data"]["database"]["scheme"]["table"]["_data"] @@ -145,12 +154,16 @@ class MyTestCase(unittest.TestCase): tdata[M.MATCH_SIDE_POSTACTUAL]["data"]["database"]["scheme"]["table"]["_data"][i]) print(text) - def xtest_compareRows(self): + def test_compareRows(self): job = Job("unit") comp = components.component.Component() - comp.files = { "A": "/home/match/per.csv", "B": "/home/match/post.csv"} + comp.files = { "A": "/home/match/pre.csv", "B": "/home/match/post.csv"} + comp.name = "component" comp.conf = conf + cm = basic.componentHandling.ComponentManager() + basic.componentHandling.comps["component"] = comp matching = self.getMatching() + comp.name = "component" matching.sideA = tdata[M.MATCH_SIDE_PREACTUAL]["data"]["database"]["scheme"]["table"]["_data"] matching.sideB = tdata[M.MATCH_SIDE_POSTACTUAL]["data"]["database"]["scheme"]["table"]["_data"] linksA = {"a0001": "b0001", "a0002": "b0002" } @@ -160,11 +173,17 @@ class MyTestCase(unittest.TestCase): def test_match(self): job = Job("unit") + setattr(job.par, "testcase", "TC0001") + setattr(job.par, "tctime", "2022-03-25_19-25-31") comp = components.component.Component() comp.files = {"A": "/home/match/per.csv", "B": "/home/match/post.csv"} + comp.name = "component" + cm = basic.componentHandling.ComponentManager() + basic.componentHandling.comps["component"] = comp # tdata["postReq"] = tdata["preAct"] comp.conf = conf matching = utils.match_tool.Matching(comp) + matching.htmltext = "" matching.setData(tdata, utils.match_tool.MATCH_POSTCOND) text = utils.match_tool.matchTree(matching) print("\n-------------\n") @@ -174,8 +193,11 @@ class MyTestCase(unittest.TestCase): def getMatching(self): job = Job("unit") + setattr(job.par, "testcase", "TC0001") + setattr(job.par, "tctime", "2022-03-25_19-25-31") comp = components.component.Component() comp.files = { "A": "/home/match/per.csv", "B": "/home/match/post.csv"} + comp.name = "component" comp.conf = conf matching = utils.match_tool.Matching(comp) matching.setData(tdata, M.MATCH_SUCCESS) diff --git a/test/test_tdata.py b/test/test_tdata.py index f84f55e..f30f738 100644 --- a/test/test_tdata.py +++ b/test/test_tdata.py @@ -1,6 +1,7 @@ import unittest import utils.tdata_tool as t import basic.program +import os class MyTestCase(unittest.TestCase): def runTest(self): @@ -28,7 +29,7 @@ class MyTestCase(unittest.TestCase): "tdtyp": "csv", "tdsrc": "TC0001", "tdname": "testspec", "modus": "unit"} job.par.setParameterArgs(args) - filename = str(job.conf.confs["paths"]["testdata"]) + "/" + getattr(job.par, "tdsrc") + "/" + getattr(job.par, "tdname") + ".csv" + filename = os.path.join(job.conf.confs["paths"]["testdata"], getattr(job.par, "tdsrc"), getattr(job.par, "tdname") + ".csv") tdata = t.getCsvSpec(job.m, filename, "data") print("111") print(tdata) diff --git a/utils/match_tool.py b/utils/match_tool.py index 20b8009..80799ee 100644 --- a/utils/match_tool.py +++ b/utils/match_tool.py @@ -25,35 +25,35 @@ MATCH_SIDE_POSTEXPECT = "postexpect" MATCH_DICT_POSTEXPECT = { "short": "SN", "long": "Soll-Nachher", - "filepattern": "rsprecond" + "filepattern": "rspostcond" } MATCH_SIDE_PREACTUAL = "preactual" """ it implies the precondition of the actual execution """ MATCH_DICT_PREACTUAL = { "short": "IV", "long": "Ist-Vorher", - "filepattern": "rsprecond" + "filepattern": "tcprecond" } MATCH_SIDE_POSTACTUAL = "postactual" """ it implies the postondition of the actual execution - it is the result """ MATCH_DICT_POSTACTUAL = { "short": "IN", "long": "Ist-Nachher", - "filepattern": "rsprecond" + "filepattern": "tcpostcond" } -MATCH_SIDE_PRESTEP = "prestep" +MATCH_SIDE_PRESTEP = "preside" """ it implies the postcondition of a preceding step of the actual execution - the preceding step must be configured in the component""" MATCH_DICT_PRESTEP = { "short": "VS", "long": "Vorhergehender Schritt (Nachher)", - "filepattern": "rsprecond" + "filepattern": "rspostcond" } MATCH_SIDE_TESTCASE = "testexample" """ it implies the postcondition of an exemplary testcase - the exemplary testcase must be parametrized """ MATCH_DICT_TESTCASE = { "short": "VT", "long": "Vergleichstestfall (Nachher)", - "filepattern": "rsprecond" + "filepattern": "rspostcond" } MATCH_SIDES = [MATCH_SIDE_PREEXPECT, MATCH_SIDE_POSTEXPECT, MATCH_SIDE_PREACTUAL, MATCH_SIDE_POSTACTUAL, MATCH_SIDE_PRESTEP, MATCH_SIDE_TESTCASE] @@ -78,10 +78,6 @@ MATCH = { MATCH_PRECOND: { "A": MATCH_SIDE_PREEXPECT, "B": MATCH_SIDE_PREACTUAL, - "shortA": "SV", - "shortB": "IV", - "longA": "Soll-Vorher", - "longB": "Ist-Vorher", "mode": "info", "filename": "01_Vorbedingungen", "title": "Pruefung Vorbedingung (Soll-Vorher - Ist-Vorher)" @@ -89,10 +85,6 @@ MATCH = { MATCH_POSTCOND: { "A": MATCH_SIDE_POSTEXPECT, "B": MATCH_SIDE_POSTACTUAL, - "shortA": "SN", - "shortB": "IN", - "longA": "Soll-Nachher", - "longB": "Ist-Nachher", "mode": "hard", "filename": "00_Fachabgleich", "title": "Fachliche Auswertung (Soll-Nachher - Ist-Nachher)" @@ -100,10 +92,6 @@ MATCH = { MATCH_SUCCESS: { "A": MATCH_SIDE_PREACTUAL, "B": MATCH_SIDE_POSTACTUAL, - "shortA": "IV", - "shortB": "IN", - "longA": "Ist-Vorher", - "longB": "Ist-Nachher", "mode": "action", "filename": "04_Ablauf", "title": "Ablauf-Differenz (Ist-Vorher - Ist-Nachher)" @@ -111,10 +99,6 @@ MATCH = { MATCH_PRESTEP: { "A": MATCH_SIDE_PRESTEP, "B": MATCH_SIDE_POSTACTUAL, - "shortA": "VS", - "shortB": "IN", - "longA": "Vor-Schritt", - "longB": "Ist-Nachher", "mode": "action", "filename": "02_Vorschritt", "title": "Schritt-Differenz (Vorschritt-Nachher - Ist-Nachher)" @@ -122,10 +106,6 @@ MATCH = { MATCH_TESTEXAMPLE: { "A": MATCH_SIDE_TESTCASE, "B": MATCH_SIDE_POSTACTUAL, - "shortA": "VS", - "shortB": "IN", - "longA": "Vor-Schritt", - "longB": "Ist-Nachher", "mode": "action", "filename": "03_Vergleichstestfall", "title": "Schritt-Differenz (Vorschritt-Nachher - Ist-Nachher)" @@ -136,7 +116,7 @@ class Matching(): def __init__(self, comp): self.comp = comp self.elements = {} - self.matchfiles = comp.files + self.matchfiles = {} self.assignedFiles = {} self.linksA = {} self.linksB = {} @@ -147,6 +127,7 @@ class Matching(): self.sideB = [] self.mode = "" self.matchtype = "" + self.cssClass = "result0" def setData(self, tdata, match): """ @@ -155,20 +136,28 @@ class Matching(): :param match: kind of actual match :return: """ - self.sideA = tdata[MATCH[match]["A"]]["data"] - self.sideB = tdata[MATCH[match]["B"]]["data"] - self.matchfiles["A"] = tdata[MATCH[match]["A"]]["path"] - self.matchfiles["B"] = tdata[MATCH[match]["B"]]["path"] + sideA = MATCH[match]["A"] + sideB = MATCH[match]["B"] + self.sideA = tdata[sideA]["data"] + self.sideB = tdata[sideB]["data"] + self.matchfiles["A"] = tdata[sideA]["path"] + self.matchfiles["B"] = tdata[sideB]["path"] self.matchtype = match self.mode = MATCH[match]["mode"] self.setDiffHeader() self.report = utils.report_tool.Report.getInstance() + self.resetHits() def resetHits(self): self.linksA = {} self.linksB = {} self.nomatch = {} self.matchkeys = {} + self.cssClass = "result0" + + def setCssClass(self, cssClass): + if cssClass > self.cssClass: + self.cssClass = cssClass def isHitA(self, key): return ((key in self.linksA) and (self.linksA[key] != "null")) @@ -206,8 +195,8 @@ class Matching(): htmltxt += "" htmltxt += "" htmltxt += "

"+MATCH[matching.matchtype]["title"]+"

" - htmltxt += "

" + MATCH[matching.matchtype]["longA"] +": " + matching.matchfiles["A"] + "

" - htmltxt += "

" + MATCH[matching.matchtype]["longB"] +": " + matching.matchfiles["B"] + "


" + htmltxt += "

"+MATCH[MATCH[matching.matchtype]["A"]]["long"]+": "+matching.matchfiles["A"]+"

" + htmltxt += "

"+MATCH[MATCH[matching.matchtype]["B"]]["long"]+": "+matching.matchfiles["B"]+"


" matching.htmltext = htmltxt def setDiffFooter(self): @@ -235,6 +224,7 @@ def matchBestfit(matching, path): :param matching: :return: """ + # initialize all potential links with null i=0 if (matching.sideA is not None): for r in matching.sideA: @@ -249,11 +239,15 @@ def matchBestfit(matching, path): i += 1 ia = 0 ix = 1 + # CASE: one side is None if (matching.sideA is None) or (matching.sideB is None): return + # CASE: to match for rA in matching.sideA: ib = 0 for rB in matching.sideB: + if (matching.isHitA(composeKey("a", ia))): + continue if (matching.isHitB(composeKey("b", ib))): ib += 1 continue @@ -374,10 +368,10 @@ def getEvaluation(matching, type, acceptance, sideA, sideB): verify = int(job.getDebugLevel("match_tool"))-1 job.debug(verify, "getEvaluation "+str(sideA)+" ?= "+str(sideB)) match = getStringSimilarity(str(sideA), str(sideB)) - classA = "black" - classB = "black" + classA = "novalue" + classB = "novalue" result = "test" - if match == "99": return ["MATCH", "black", "black", "black", "black"] + if match == "99": return ["MATCH", "novalue", "novalue", "novalue", "novalue"] if acceptance == "ignore": result = "ignore" if (matching.matchtype == MATCH_POSTCOND) and (result == "test"): result = "hard" @@ -398,7 +392,7 @@ def matchDict(matching, A, B, path): job.debug(verify, "matchDict 400 " + k + ".") if k in ["_match"]: continue - if (B is not None) and (B[k]): + if (B is not None) and (k in B): if (isinstance(A[k], dict)): A[k]["_match"] = "Y" if (isinstance(B[k], dict)): B[k]["_match"] = "Y" job.debug(verify, "matchDict 404 " + k + "." + path) @@ -412,7 +406,7 @@ def matchDict(matching, A, B, path): job.debug(verify, "matchDict 412 " + k + ".") if k in ["_match"]: continue - if (A is not None) and (A[k]): + if (A is not None) and (k in A): continue elif (A is None) or (k not in A): if (A is not None) and (isinstance(A[k], dict)): B[k]["_match"] = "N" @@ -467,9 +461,11 @@ def compareRows(matching, path): matching.sideB[int(extractKeyI(matching.linksA[k]))]) else: htmltext += markRow(matching, header, matching.sideA[int(extractKeyI(k))], "A") + matching.setCssClass("result3") for k in sorted(matching.linksB): if (not matching.isHitB(k)): htmltext += markRow(matching, header, matching.sideB[int(extractKeyI(k))], "B") + matching.setCssClass("result2") htmltext += "" matching.difftext += "" return htmltext @@ -480,15 +476,20 @@ def markRow(matching, header, row, side): text = "" cssClass = "" for f in header: - if side == "A": + if not f["field"] in row: + val = "" + cssClass = "novalue" + elif side == "A": res = getEvaluation(matching, f["type"], f["acceptance"], row[f["field"]], "") + val = str(row[f["field"]]) cssClass = res[1] else: res = getEvaluation(matching, f["type"], f["acceptance"], "", row[f["field"]]) + val = str(row[f["field"]]) cssClass = res[2] - text += "" + str(row[f["field"]]) + "" + text += ""+val+"" text = "" \ - + MATCH[matching.matchtype]["short"+side] + "" + text + "" + + MATCH[MATCH[matching.matchtype][side]]["short"] + ""+text+"" matching.difftext += text return text @@ -500,26 +501,51 @@ def compareRow(matching, header, rA, rB): textA = "" textB = "" text = "" + valA = "" + valB = "" + classA = "novalue" + classB = "novalue" for f in header: print(f) - res = getEvaluation(matching, f["type"], f["acceptance"], rA[f["field"]], rB[f["field"]]) - match = res[0] - classA = res[1] - classB = res[2] + if f["field"] in rA and f["field"] in rB: + res = getEvaluation(matching, f["type"], f["acceptance"], rA[f["field"]], rB[f["field"]]) + match = res[0] + classA = res[1] + classB = res[2] + valA = str(rA[f["field"]]) + valB = str(rB[f["field"]]) + elif f["field"] in rA : + valA = str(rA[f["field"]]) + match = "ddl" + classA = "acceptA" + classB = "acceptB" + elif f["field"] in rB: + valB = str(rB[f["field"]]) + match = "ddl" + classA = "acceptA" + classB = "acceptB" + else: + match = "MATCH" + classA = "acceptA" + classB = "acceptB" if (match == "MATCH"): - textA += ""+str(rA[f["field"]])+"" - textB += ""+str(rB[f["field"]])+"" + textA += ""+valA+"" + textB += ""+valB+"" + matching.setCssClass("result1") elif (match == "hard"): allident = False - textA += "" + str(rA[f["field"]]) + "" - textB += "" + str(rB[f["field"]]) + "" + textA += ""+valA+"" + textB += ""+valB+"" + matching.setCssClass("result3") else: allident = False - textA += ""+str(rA[f["field"]])+" ("+match+")" - textB += ""+str(rB[f["field"]])+" ("+match+")" + textA += ""+valA+" ("+match+")" + textB += ""+valB+" ("+match+")" + matching.setCssClass("result1") if allident: return ""+textA+"" - text = ""+MATCH[matching.matchtype]["shortA"]+""+textA+""+MATCH[matching.matchtype]["shortB"]+""+textB+"" + text = ""+MATCH[MATCH[matching.matchtype]["A"]]["short"]+""+textA+"" + text += ""+MATCH[matching.matchtype]["shortB"]+""+textB+"" matching.difftext += text return text