408 lines
15 KiB
Python
408 lines
15 KiB
Python
|
|
from typing import List
|
|||
|
|
from apps.dict.models import DictItem
|
|||
|
|
from apps.project.models import TestDemand
|
|||
|
|
from html.parser import HTMLParser
|
|||
|
|
from django.db.models import QuerySet
|
|||
|
|
# 导入生成文档检查器log - 单例模式
|
|||
|
|
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
|||
|
|
|
|||
|
|
logger = GenerateLogger(model='字典模块')
|
|||
|
|
|
|||
|
|
# 传入一个字符串数字以及字典标志code,返回真实的title名字
|
|||
|
|
def get_str_dict(a, dict_code):
|
|||
|
|
dict_obj = DictItem.objects.filter(dict__code=dict_code, key=a).first()
|
|||
|
|
if dict_obj:
|
|||
|
|
return dict_obj.title
|
|||
|
|
else:
|
|||
|
|
# 如果用户没填写内容则记录检查中心log
|
|||
|
|
logger.write_warning_log(fragment='字典数据缺失', message=f'字典数据{dict_code}数据缺失,请检查相应数据是否存在')
|
|||
|
|
return ''
|
|||
|
|
|
|||
|
|
# 传入一个字符串数字以及字典标志code,返回字典所属的缩写(show_title)
|
|||
|
|
def get_str_abbr(a, dict_code):
|
|||
|
|
dict_obj = DictItem.objects.filter(dict__code=dict_code, key=a).first()
|
|||
|
|
if dict_obj:
|
|||
|
|
return dict_obj.show_title
|
|||
|
|
else:
|
|||
|
|
logger.write_warning_log(fragment='字典数据缺失',
|
|||
|
|
message=f'查询字段数据缩写问题,字典数据{dict_code}数据可能缺失')
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
# 传入一个字符串数组(测试项类型),字典标志code,返回(真实title,sort)
|
|||
|
|
def get_str_dict_plus(a, dict_code):
|
|||
|
|
dict_obj = DictItem.objects.filter(dict__code=dict_code, key=a).first()
|
|||
|
|
if dict_obj:
|
|||
|
|
return dict_obj.title, dict_obj.sort
|
|||
|
|
else:
|
|||
|
|
logger.write_warning_log(fragment='字典数据查询错误', message=f'字典{dict_code}未查询到数据,请检查')
|
|||
|
|
return "", 1
|
|||
|
|
|
|||
|
|
# 找到testType字典中的缩写,例如“DC”“FT”
|
|||
|
|
def get_testType(a, dict_code):
|
|||
|
|
dict_obj = DictItem.objects.filter(dict__code=dict_code, key=a).first()
|
|||
|
|
if dict_obj:
|
|||
|
|
return dict_obj.show_title
|
|||
|
|
else:
|
|||
|
|
logger.write_warning_log(fragment='字典数据查询错误',
|
|||
|
|
message=f'查询字段数据缩写问题,字典数据{dict_code}数据可能缺失')
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
# 标识处理:获取测试需求(测试项的)生成文档的ident(标识)
|
|||
|
|
def get_ident(test_item):
|
|||
|
|
# key_index = int(test_item.key.split("-")[-1]) + 1
|
|||
|
|
# test_index = str(key_index).rjust(3, '0')
|
|||
|
|
reveal_ident = "_".join(
|
|||
|
|
["XQ", get_testType(test_item.testType, "testType"), test_item.ident])
|
|||
|
|
return reveal_ident
|
|||
|
|
|
|||
|
|
# 标识处理:传入demand的ident以及case,返回case的ident
|
|||
|
|
def get_case_ident(demand_ident, case):
|
|||
|
|
key_index = int(case.key.split("-")[-1]) + 1
|
|||
|
|
test_index = str(key_index).rjust(3, '0')
|
|||
|
|
reveal_ident = "_".join([demand_ident.replace("XQ", "YL"), test_index])
|
|||
|
|
return reveal_ident
|
|||
|
|
|
|||
|
|
# 传入字典code,以及字符串数组返回一个数组,每个数组是dict
|
|||
|
|
def get_list_dict(dict_code: str, str_list: List[str]):
|
|||
|
|
result = []
|
|||
|
|
qss = DictItem.objects.filter(dict__code=dict_code)
|
|||
|
|
for st in str_list:
|
|||
|
|
res = {}
|
|||
|
|
for qs in qss:
|
|||
|
|
if st == qs.key:
|
|||
|
|
res['ident_version'] = qs.title
|
|||
|
|
res['doc_name'] = qs.doc_name
|
|||
|
|
res['publish_date'] = qs.publish_date
|
|||
|
|
res['source'] = qs.source
|
|||
|
|
result.append(res)
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
# 传入字典code,以及字符串数组返回一个列表,每个元素是dict,包含字典item很多信息
|
|||
|
|
def get_list_dict_info(dict_code, str_list):
|
|||
|
|
"""传入字典的字符串列表,输出每个元素为dict的列表信息"""
|
|||
|
|
result = []
|
|||
|
|
qss = DictItem.objects.filter(dict__code=dict_code) # type:ignore
|
|||
|
|
for st in str_list:
|
|||
|
|
res = {}
|
|||
|
|
for qs in qss:
|
|||
|
|
if st == qs.key:
|
|||
|
|
res['title'] = qs.title
|
|||
|
|
res['index'] = qs.sort
|
|||
|
|
result.append(res)
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
# 传入字典code,以及单个字典字符串,输出一个dict带信息
|
|||
|
|
def get_dict_info(dict_code, item_str):
|
|||
|
|
"""传入字典的字符串单个表示,输出dict包含排序index字段"""
|
|||
|
|
qss = DictItem.objects.filter(dict__code=dict_code)
|
|||
|
|
res = {}
|
|||
|
|
for qs in qss:
|
|||
|
|
if item_str == qs.key:
|
|||
|
|
res['title'] = qs.title
|
|||
|
|
res['index'] = qs.sort
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
# 简单HTML解析器 - 解析富文本的parser - 复杂的使用apps/createDocument/extensions/parse_rich_text.py
|
|||
|
|
class MyHTMLParser(HTMLParser):
|
|||
|
|
def __init__(self):
|
|||
|
|
HTMLParser.__init__(self)
|
|||
|
|
self.allStrList = []
|
|||
|
|
|
|||
|
|
def error(self, message):
|
|||
|
|
print("HTML解析器出错,error信息为:", message)
|
|||
|
|
|
|||
|
|
def handle_starttag(self, tag, attrs):
|
|||
|
|
if tag == 'img':
|
|||
|
|
img_base64 = attrs[0][1]
|
|||
|
|
self.allStrList.append(img_base64)
|
|||
|
|
|
|||
|
|
def handle_endtag(self, tag):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def handle_data(self, data):
|
|||
|
|
if data != '\n':
|
|||
|
|
self.allStrList.append(data)
|
|||
|
|
|
|||
|
|
# 不提取图片的HTML解析器
|
|||
|
|
class MyHTMLParser_p(HTMLParser):
|
|||
|
|
def __init__(self):
|
|||
|
|
HTMLParser.__init__(self)
|
|||
|
|
self.allStrList = []
|
|||
|
|
|
|||
|
|
def handle_data(self, data):
|
|||
|
|
if data != '\n':
|
|||
|
|
self.allStrList.append(data)
|
|||
|
|
|
|||
|
|
def create_problem_grade_str(problems):
|
|||
|
|
"""传入问题qs,生成到文档的字符串:严重问题4个、一般问题10个"""
|
|||
|
|
problem_r1_grade_dict = {}
|
|||
|
|
for problem in problems:
|
|||
|
|
grade_key: str = get_str_dict(problem.grade, 'problemGrade')
|
|||
|
|
if grade_key in problem_r1_grade_dict.keys():
|
|||
|
|
problem_r1_grade_dict[grade_key] += 1
|
|||
|
|
else:
|
|||
|
|
problem_r1_grade_dict[grade_key] = 1
|
|||
|
|
problem_r1_grade_list = []
|
|||
|
|
for key, value in problem_r1_grade_dict.items():
|
|||
|
|
problem_r1_grade_list.append("".join([f"{key}问题", f"{value}个"]))
|
|||
|
|
return "、".join(problem_r1_grade_list)
|
|||
|
|
|
|||
|
|
def create_problem_type_str(problems):
|
|||
|
|
"""传入问题qs,生成到文档的字符串:文档问题1个,程序问题10个"""
|
|||
|
|
problem_r1_type_dict = {}
|
|||
|
|
for problem in problems:
|
|||
|
|
type_key: str = get_str_dict(problem.type, 'problemType')
|
|||
|
|
if type_key in problem_r1_type_dict.keys():
|
|||
|
|
problem_r1_type_dict[type_key] += 1
|
|||
|
|
else:
|
|||
|
|
problem_r1_type_dict[type_key] = 1
|
|||
|
|
problem_r1_type_list = []
|
|||
|
|
for key, value in problem_r1_type_dict.items():
|
|||
|
|
problem_r1_type_list.append("".join([f"{key}", f"{value}个"]))
|
|||
|
|
return "、".join(problem_r1_type_list)
|
|||
|
|
|
|||
|
|
def create_str_testType_list(cases):
|
|||
|
|
"""传入用例的qs,生成其测试类型的字符串:例如包含xxx测试5个,xxx测试11个,返回的是元组第二个元素表示测试类型个数"""
|
|||
|
|
test_type_set: set = set()
|
|||
|
|
for case in cases:
|
|||
|
|
demand: TestDemand = case.test
|
|||
|
|
test_type_set.add(demand.testType)
|
|||
|
|
test_type_list = get_list_dict_info('testType', list(test_type_set))
|
|||
|
|
test_type_list.sort(key=lambda x: int(x['index']))
|
|||
|
|
round1_testType_list = list(map(lambda x: x['title'], test_type_list))
|
|||
|
|
return round1_testType_list, len(test_type_list)
|
|||
|
|
|
|||
|
|
def util_func(item):
|
|||
|
|
"""辅助函数,将下面函数返回的summary_list改造为以需求类型执行统计列表"""
|
|||
|
|
transform_item = {'title': item['title'], 'total_count': 0, 'exe_count': 0, 'not_exe_count': 0, 'pass_count': 0,
|
|||
|
|
'not_pass_count': 0}
|
|||
|
|
for it in item['demand_list']:
|
|||
|
|
transform_item['total_count'] += it['total_count']
|
|||
|
|
transform_item['exe_count'] += it['exe_count']
|
|||
|
|
transform_item['not_exe_count'] += it['not_exe_count']
|
|||
|
|
transform_item['pass_count'] += it['pass_count']
|
|||
|
|
transform_item['not_pass_count'] += it['not_pass_count']
|
|||
|
|
return transform_item
|
|||
|
|
|
|||
|
|
def create_demand_summary(demands: QuerySet, project_ident: str):
|
|||
|
|
"""
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
'title':'功能测试_5',
|
|||
|
|
'demand_list':[
|
|||
|
|
{
|
|||
|
|
'name': '测试项1',
|
|||
|
|
'total_count': 1,
|
|||
|
|
'exe_count': 1,
|
|||
|
|
'not_exe_count': 0,
|
|||
|
|
'pass_count': 1,
|
|||
|
|
'not_pass_count': 0,
|
|||
|
|
'conclusion': '通过',
|
|||
|
|
'problems': '/'
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
]
|
|||
|
|
"""
|
|||
|
|
summary_dict = {} # 后面再变为数组
|
|||
|
|
# 1.首先根据testType字段生成一个一个dict
|
|||
|
|
for demand in demands:
|
|||
|
|
# 取出testType -> '4'(后面查字典)
|
|||
|
|
test_type_num = demand.testType
|
|||
|
|
# 查出需求类型的sort与testType真实名字,组合为一个字符串作为key
|
|||
|
|
testTypeStr, testTypeSort = get_str_dict_plus(test_type_num, 'testType')
|
|||
|
|
testType_info = testTypeStr + '_' + str(testTypeSort)
|
|||
|
|
demand_dict = {
|
|||
|
|
'name': demand.name,
|
|||
|
|
'total_count': 0,
|
|||
|
|
'exe_count': 0,
|
|||
|
|
'not_exe_count': 0,
|
|||
|
|
'pass_count': 0,
|
|||
|
|
'not_pass_count': 0,
|
|||
|
|
'conclusion': '通过',
|
|||
|
|
'problems': "/"
|
|||
|
|
}
|
|||
|
|
# 查询当前测试需求下用例
|
|||
|
|
demand_problem_list = set()
|
|||
|
|
for case in demand.tcField.all():
|
|||
|
|
demand_dict['total_count'] += 1
|
|||
|
|
# 要遍历下面的测试步骤
|
|||
|
|
isPassed = True
|
|||
|
|
isExe = True
|
|||
|
|
for step in case.step.all():
|
|||
|
|
# 所有步骤有一个未通过则是未通过,所有都执行则是已执行
|
|||
|
|
if step.passed == '2':
|
|||
|
|
isPassed = False
|
|||
|
|
isExe = True
|
|||
|
|
break
|
|||
|
|
if step.passed == '3':
|
|||
|
|
isExe = False
|
|||
|
|
if isPassed:
|
|||
|
|
demand_dict['pass_count'] += 1
|
|||
|
|
else:
|
|||
|
|
demand_dict['not_pass_count'] += 1
|
|||
|
|
demand_dict['conclusion'] = '未通过'
|
|||
|
|
if isExe:
|
|||
|
|
demand_dict['exe_count'] += 1
|
|||
|
|
else:
|
|||
|
|
demand_dict['not_exe_count'] += 1
|
|||
|
|
# 查询每个用例下面的问题单,将问题单的ident弄出来
|
|||
|
|
for problem in case.caseField.all():
|
|||
|
|
problem_ident = 'PT_' + project_ident + '_' + problem.ident.rjust(3, '0')
|
|||
|
|
demand_problem_list.add(problem_ident)
|
|||
|
|
if len(list(demand_problem_list)) > 0:
|
|||
|
|
demand_dict['problems'] = "\a".join(list(demand_problem_list))
|
|||
|
|
if testType_info in summary_dict.keys():
|
|||
|
|
summary_dict[testType_info].append(demand_dict)
|
|||
|
|
else:
|
|||
|
|
summary_dict[testType_info] = [demand_dict]
|
|||
|
|
summary_list = []
|
|||
|
|
for key, value in summary_dict.items():
|
|||
|
|
one_dict = {
|
|||
|
|
'title': key,
|
|||
|
|
'demand_list': value
|
|||
|
|
}
|
|||
|
|
summary_list.append(one_dict)
|
|||
|
|
# 根据其排序
|
|||
|
|
summary_list.sort(key=lambda x: int(x['title'].split('_')[-1]))
|
|||
|
|
# 然后将_5这种替换掉
|
|||
|
|
for one in summary_list:
|
|||
|
|
one['title'] = one['title'].split("_")[0]
|
|||
|
|
# ~~~~还需要返回一个 -> 测试类型的用例执行情况
|
|||
|
|
demandType_exe_list = list(map(util_func, summary_list))
|
|||
|
|
return summary_list, demandType_exe_list
|
|||
|
|
|
|||
|
|
def create_problem_table(problems):
|
|||
|
|
"""传入问题单qs,输出按问题种类分的问题统计表的数据"""
|
|||
|
|
res_list = [{
|
|||
|
|
'name': '一般问题',
|
|||
|
|
'xq_count': 0,
|
|||
|
|
'sj_count': 0,
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'bm_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'other_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}, {
|
|||
|
|
'name': '严重问题',
|
|||
|
|
'xq_count': 0,
|
|||
|
|
'sj_count': 0,
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'bm_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'other_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}, {
|
|||
|
|
'name': '建议',
|
|||
|
|
'xq_count': 0,
|
|||
|
|
'sj_count': 0,
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'bm_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'other_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}, {
|
|||
|
|
'name': '重大问题',
|
|||
|
|
'xq_count': 0,
|
|||
|
|
'sj_count': 0,
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'bm_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'other_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}]
|
|||
|
|
|
|||
|
|
for problem in problems:
|
|||
|
|
index = int(problem.grade) - 1
|
|||
|
|
if problem.type == '1':
|
|||
|
|
res_list[index]['other_count'] += 1
|
|||
|
|
elif problem.type == '2':
|
|||
|
|
res_list[index]['wd_count'] += 1
|
|||
|
|
elif problem.type == '3':
|
|||
|
|
res_list[index]['bm_count'] += 1
|
|||
|
|
elif problem.type == '4':
|
|||
|
|
res_list[index]['sj_count'] += 1
|
|||
|
|
elif problem.type == '5':
|
|||
|
|
res_list[index]['xq_count'] += 1
|
|||
|
|
elif problem.type == '6':
|
|||
|
|
res_list[index]['data_count'] += 1
|
|||
|
|
|
|||
|
|
# 是否归零
|
|||
|
|
if problem.status == '1':
|
|||
|
|
res_list[index]['closed_count'] += 1
|
|||
|
|
else:
|
|||
|
|
res_list[index]['non_closed_count'] += 1
|
|||
|
|
return res_list
|
|||
|
|
|
|||
|
|
def create_problem_type_table(problems):
|
|||
|
|
"""传入问题qs,解析出按测试类型分的问题统计表格"""
|
|||
|
|
res_list = [{
|
|||
|
|
'name': '一般问题',
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'jt_count': 0,
|
|||
|
|
'dm_count': 0,
|
|||
|
|
'dt_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}, {
|
|||
|
|
'name': '严重问题',
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'jt_count': 0,
|
|||
|
|
'dm_count': 0,
|
|||
|
|
'dt_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}, {
|
|||
|
|
'name': '建议',
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'jt_count': 0,
|
|||
|
|
'dm_count': 0,
|
|||
|
|
'dt_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}, {
|
|||
|
|
'name': '重大问题',
|
|||
|
|
'wd_count': 0,
|
|||
|
|
'jt_count': 0,
|
|||
|
|
'dm_count': 0,
|
|||
|
|
'dt_count': 0,
|
|||
|
|
'data_count': 0,
|
|||
|
|
'closed_count': 0,
|
|||
|
|
'non_closed_count': 0,
|
|||
|
|
}]
|
|||
|
|
|
|||
|
|
for problem in problems:
|
|||
|
|
index = int(problem.grade) - 1
|
|||
|
|
belong_demand: TestDemand = problem.case.all()[0].test
|
|||
|
|
if belong_demand.testType == '8': # 属于文档审查问题
|
|||
|
|
res_list[index]['wd_count'] += 1
|
|||
|
|
elif belong_demand.testType == '15': # 属于静态分析问题
|
|||
|
|
res_list[index]['jt_count'] += 1
|
|||
|
|
elif belong_demand.testType == '2' or belong_demand.testType == '3': # 属于代码审查和走查
|
|||
|
|
res_list[index]['dm_count'] += 1
|
|||
|
|
else: # 属于动态发现问题
|
|||
|
|
res_list[index]['dt_count'] += 1
|
|||
|
|
|
|||
|
|
# 是否归零
|
|||
|
|
if problem.status == '1':
|
|||
|
|
res_list[index]['closed_count'] += 1
|
|||
|
|
else:
|
|||
|
|
res_list[index]['non_closed_count'] += 1
|
|||
|
|
return res_list
|
|||
|
|
|
|||
|
|
def get_demand_testTypes(demand_qs) -> str:
|
|||
|
|
"""传入测试项qs,返回字符串类似于“静态分析、代码审查、功能测试等”"""
|
|||
|
|
testType_list = list(demand_qs.values("testType").distinct().order_by('testType'))
|
|||
|
|
t_code_list = [item['testType'] for item in testType_list]
|
|||
|
|
t_code_list = get_list_dict_info('testType', t_code_list)
|
|||
|
|
t_code_list.sort(key=lambda x: int(x['index']))
|
|||
|
|
t_str = [item['title'] for item in t_code_list]
|
|||
|
|
return '、'.join(t_str) if len(t_str) > 0 else "测试"
|