Browse Source

matching and reports

master
Ulrich Carmesin 2 years ago
parent
commit
4768cfd231
  1. 14
      components/testexec.py
  2. 38
      test/test_compare.py
  3. 3
      test/test_tdata.py
  4. 122
      utils/match_tool.py

14
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

38
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)

3
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)

122
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 += "</head>"
htmltxt += "<body>"
htmltxt += "<h1>"+MATCH[matching.matchtype]["title"]+"</h1>"
htmltxt += "<h4>" + MATCH[matching.matchtype]["longA"] +": " + matching.matchfiles["A"] + "</h4>"
htmltxt += "<h4>" + MATCH[matching.matchtype]["longB"] +": " + matching.matchfiles["B"] + "</h4><br>"
htmltxt += "<h4>"+MATCH[MATCH[matching.matchtype]["A"]]["long"]+": "+matching.matchfiles["A"]+"</h4>"
htmltxt += "<h4>"+MATCH[MATCH[matching.matchtype]["B"]]["long"]+": "+matching.matchfiles["B"]+"</h4><br>"
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 += "</table>"
matching.difftext += "</table>"
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 += "<td "+utils.css_tool.getInlineStyle("diffFiles", cssClass)+">" + str(row[f["field"]]) + "</td>"
text += "<td "+utils.css_tool.getInlineStyle("diffFiles", cssClass)+">"+val+"</td>"
text = "<tr><td "+utils.css_tool.getInlineStyle("diffFiles", cssClass)+">" \
+ MATCH[matching.matchtype]["short"+side] + "</td>" + text + "</tr>"
+ MATCH[MATCH[matching.matchtype][side]]["short"] + "</td>"+text+"</tr>"
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)
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 += "<td>"+str(rA[f["field"]])+"</td>"
textB += "<td>"+str(rB[f["field"]])+"</td>"
textA += "<td>"+valA+"</td>"
textB += "<td>"+valB+"</td>"
matching.setCssClass("result1")
elif (match == "hard"):
allident = False
textA += "<td "+utils.css_tool.getInlineStyle("diffFiles", classA)+">" + str(rA[f["field"]]) + "</td>"
textB += "<td "+utils.css_tool.getInlineStyle("diffFiles", classB)+">" + str(rB[f["field"]]) + "</td>"
textA += "<td "+utils.css_tool.getInlineStyle("diffFiles", classA)+">"+valA+"</td>"
textB += "<td "+utils.css_tool.getInlineStyle("diffFiles", classB)+">"+valB+"</td>"
matching.setCssClass("result3")
else:
allident = False
textA += "<td "+utils.css_tool.getInlineStyle("diffFiles", classA)+">"+str(rA[f["field"]])+" ("+match+")</td>"
textB += "<td "+utils.css_tool.getInlineStyle("diffFiles", classB)+">"+str(rB[f["field"]])+" ("+match+")</td>"
textA += "<td "+utils.css_tool.getInlineStyle("diffFiles", classA)+">"+valA+" ("+match+")</td>"
textB += "<td "+utils.css_tool.getInlineStyle("diffFiles", classB)+">"+valB+" ("+match+")</td>"
matching.setCssClass("result1")
if allident:
return "<tr><td/>"+textA+"</tr>"
text = "<tr><td>"+MATCH[matching.matchtype]["shortA"]+"</td>"+textA+"</tr><tr><td>"+MATCH[matching.matchtype]["shortB"]+"</td>"+textB+"</tr>"
text = "<tr><td>"+MATCH[MATCH[matching.matchtype]["A"]]["short"]+"</td>"+textA+"</tr>"
text += "<tr><td>"+MATCH[matching.matchtype]["shortB"]+"</td>"+textB+"</tr>"
matching.difftext += text
return text

Loading…
Cancel
Save