前回の試作プログラムからもう少し改善したバージョンを作成しました。
例によって、作りかけなのできちんと動作確認できてないので注意。
check_resultの自動設定上書きと設定上書きの仕組み見直し
-
"check_result": {}の記述は実際の結果を予想の設定(expect)に上書きする動作に変更。
-
上記のcheck_resultの設定上書きを含む、プログラム実行後の結果を設定へ反映する動作を追加。
関数の引数はdictionary型のsettings1つの構成result=func(settings)にしている。
関数実行結果によって設定を変えたい場合は子の関数内でsettingsを変更すると、実行後に開始時と終了時のsettingsの差を親へと伝えていく。
多少、トリッキーな動作だが・・・、resultに設定のフィードバック情報を入れるのは通常使用に支障きたすし、消去法的に引数を介して伝えるしかない。幸い、settingsはdictionaryなのでいくらでも変数を追加できる自由度、拡張性がある。また、シンプルな挙動なのでルールが分かりやすい。
ただし、簡単に変えられすぎるので、バグで設定を書き換える危険もある。ファイルに保存する段階でユーザー確認の機構を追加する必要があるかもしれない。
RunPlanLists(settings={"data_store":{},"planlists":{},"run_plan_name_list":[]}}):
settings内にPlanlists内のrun_plan_name_listで指定されたPlanlist(複数のPlan)を順次実行。
↓ settings指定 ↑settings変更点を親に反映
ExecutePlan(settings={"data_store":{},"planlists":{},"run_plan_name":"","run_plan_number":0}):
planで設定された"type"の内部Programを起動する。
↓ settings指定 ↑settings変更点を親に反映
内部Program
RunPlanLists(settings=...):
ExecuteProgram(settings=...):
試作テスト所感X クラスの扱いが練られてない
- 現状ではinstanceの再利用までは考えないことにした。
- classの子にmethodが複数あり、それらの結果を親に通知するのが大変かと思っていましたが、シンプルにdictionaryにまとめて保存する事としました。
各methodはresultの設定で指定した名前でresult_dictionaryの子として保存する。全てのmethodの結果を親のclassの実行結果として返す。
"check_result": {
"expected": {
"result_Equals": false,
"result_GetHashCode": 52399374,
"result_GetType": {
"Error": "System.RuntimeTypecan not convert this object type",
"Result_type": "System.RuntimeType"
},
"result_ToString": "ConfigSettingDiff.HelpEntry"
}
ちなみに、この私のJSON記述法だと、settings内で"result":"result_data_name"と書くと内部メモリdata_storeに結果が格納されると動作になります。子methodの結果保存はこの応用です。
{
"test_dll": [
{
"settings": {
"argument_names": [],
"argument_types": [],
"arguments": [],
"check_result": {
"expected": {
"result_Equals": false,
"result_GetHashCode": 52399374,
"result_GetType": {
"Error": "System.RuntimeTypecan not convert this object type",
"Result_type": "System.RuntimeType"
},
"result_ToString": "ConfigSettingDiff.HelpEntry"
}
},
"class_name": "ConfigSettingDiff.HelpEntry",
"methods": [
{
"argument_names": [
"obj"
],
"argument_types": [
"Object"
],
"arguments": [
{
"key": "value"
}
],
"check_result": {
"expected": null
},
"method_name": "Equals",
"result": "result_Equals"
},
{
"argument_names": [],
"argument_types": [],
"arguments": [],
"check_result": {
"expected": 52399374
},
"method_name": "GetHashCode",
"result": "result_GetHashCode"
},
さて、Sourceは以下の通りです。
足りてないライブラリは以前のとおり、大したものではないので省略
上記以外にPlanlistのパース部、data_storeの実装など、外部プログラムを連続実行する時に欲しい機能を少し追加しました。
import ast
import inspect
import random
import json
import importlib.util
import os
import JSON_Control
from typing import List, Any
import ListControl
import DLLControl
import clr
import itertools
import copy
import SharedMemory
import SettingUtility
import ClassControl
import DictionaryControl
def get_file_type(file_path: str) -> str:
"""ファイルパスからファイルタイプを判別する純粋関数"""
_, ext = os.path.splitext(file_path)
return ext.lower()
def load_python_file(file_path: str) -> ast.Module:
"""Pythonファイルをロードする純粋関数"""
with open(file_path, 'r', encoding='utf-8') as file:
return ast.parse(file.read())
def get_function_info(file_path: str, options: dict={}) -> list:
file_type = get_file_type(file_path)
"""ロードされたファイルから関数情報を取得する純粋関数"""
function_informations = []
if file_type == '.cs':
file_name, ext = os.path.splitext(file_path)
dll_path = file_name + ".dll"
references = options.get("references","")
DLLControl.compile_source_to_dll(file_path, dll_path, references=references)
# DLL側のメソッド情報を取得
function_informations = DLLControl.get_dll_function_info(dll_path)
program_path = dll_path
elif file_type == '.dll':
function_informations = DLLControl.get_dll_function_info(file_path)
program_path = file_path
elif file_type == '.py':
loaded_file = load_python_file(file_path)
# Pythonの関数情報を取得
function_informations = get_python_function_info(loaded_file)
program_path = file_path
else:
raise ValueError(f"Unsupported file type: {file_type}")
for function_information in function_informations:
function_information["program_path"] = program_path
return function_informations
def get_python_function_info(module: ast.Module) -> list:
"""Pythonファイルから関数情報を取得する純粋関数"""
function_infos = []
for node in ast.walk(module):
if isinstance(node, ast.FunctionDef):
# クラス内の __init__ はクラスの初期化情報として別途扱うため除外
if node.name == "__init__":
continue
function_name = node.name
arguments = [arg.arg for arg in node.args.args]
function_infos.append({
"function_name": function_name,
"class_name": "", # 関数の場合は空文字列
"argument_names": arguments,
"argument_types": [None] * len(arguments) # Pythonでは型ヒントがない場合、Noneとする
})
return function_infos
def get_python_class_init_info(module: ast.Module) -> list:
"""
Pythonファイルからクラス定義を探し、コンストラクタ(__init__)の引数情報を取得する。
クラスの初期化テストとして、テスト設定に "type" を "InstantiateClass" として追加する。
"""
constructor_infos = []
for node in ast.walk(module):
if isinstance(node, ast.ClassDef):
class_name = node.name
# クラス内から __init__ を探す
init_args = []
init_types = []
for item in node.body:
if isinstance(item, ast.FunctionDef) and item.name == "__init__":
# 第一引数 self を除く
init_args = [arg.arg for arg in item.args.args[1:]]
init_types = [None] * len(init_args)
break
# コンストラクタ情報をテストケースとして追加(存在しなくても、デフォルトコンストラクタのテスト)
constructor_infos.append({
"function_name": "__init__",
"class_name": class_name,
"argument_names": init_args,
"argument_types": init_types,
"is_constructor": True # フラグでコンストラクタであることを明示
})
return constructor_infos
def infer_argument_type(argument_name, type_inference_rules):
"""引数の名前から型を推測する"""
lower_name = argument_name.lower()
if any(keyword in lower_name for keyword in type_inference_rules["numeric_keywords"]):
return "numeric"
elif any(keyword in lower_name for keyword in type_inference_rules["string_keywords"]):
return "string"
elif any(keyword in lower_name for keyword in type_inference_rules["list_keywords"]):
return "list"
elif any(keyword in lower_name for keyword in type_inference_rules["dictionary_keywords"]):
return "dictionary"
else:
return "unknown"
def generate_test_cases(function_informations, type_inference_rules):
"""テストケースを生成する(同値分割、境界値分析、ペアワイズテスト)
・function_informationに "methods" キーが存在する場合はクラス情報として扱い、
初期化(コンストラクタ)の引数と各メソッドのテスト設定をひとまとめにする。
・それ以外はグローバルな関数として扱う。
"""
test_cases = []
for info in function_informations:
program_path = info.get("program_path", "")
# クラス情報の場合("methods"キーが存在する場合)
if "methods" in info:
class_name = info.get("class_name", "")
# コンストラクタの引数情報
init_arg_names = info.get("init_argument_names", [])
init_arg_types = info.get("init_argument_types", [])
# 推論処理:不足分は型推論で補完
init_types = []
for i, arg in enumerate(init_arg_names):
if i < len(init_arg_types) and init_arg_types[i]:
init_types.append(init_arg_types[i])
else:
init_types.append(infer_argument_type(arg, type_inference_rules))
# コンストラクタ引数のテスト値の組み合わせを生成
init_arg_values_sets = [generate_argument_values(arg_type) for arg_type in init_types]
if len(init_arg_values_sets) == 0:
init_combinations = [[]]
else:
# 全組み合わせの直積を生成
init_combinations = list(itertools.product(*init_arg_values_sets))
# 各メソッドについてテストケースを生成
methods_info = info.get("methods", [])
# 各メソッドごとに、テスト値の組み合わせからテストオブジェクトのリストを作成
method_tests_lists = []
for method in methods_info:
method_name = method.get("method_name", "")
m_arg_names = method.get("argument_names", [])
m_arg_types = method.get("argument_types", [])
# 推論処理
m_types = []
for i, arg in enumerate(m_arg_names):
if i < len(m_arg_types) and m_arg_types[i]:
m_types.append(m_arg_types[i])
else:
m_types.append(infer_argument_type(arg, type_inference_rules))
# テスト値の組み合わせを生成
m_arg_values_sets = [generate_argument_values(arg_type) for arg_type in m_types]
if len(m_arg_values_sets) == 0:
m_combinations = [[]]
else:
m_combinations = list(itertools.product(*m_arg_values_sets))
# 各組み合わせごとにメソッドテスト設定を作成
method_tests = []
for comb in m_combinations:
method_tests.append({
"method_name": method_name,
"argument_names": m_arg_names,
"argument_types": m_types,
"arguments": list(comb),
"check_result": {},
"result": "result_"+method_name
})
method_tests_lists.append(method_tests)
# クラスのテストケースは、初期化引数の各組み合わせと、各メソッドのテスト設定の直積により生成
for init_comb in init_combinations:
# 各メソッドのテストケースの直積(全メソッドに対して1組み合わせずつ選ぶ)
for methods_comb in itertools.product(*method_tests_lists):
test_case = {
"type": "ExecuteProgram",
"settings": {
"program_path": program_path,
"class_name": class_name,
"argument_names": init_arg_names,
"argument_types": init_types,
"arguments": list(init_comb),
"methods": list(methods_comb),
"check_result": {},
"result": "result_"+class_name
}
}
test_cases.append(test_case)
else:
# グローバルな関数の場合の処理
class_name = info.get("class_name", "")
function_name = info.get("function_name", "")
argument_names = info.get("argument_names", [])
arguments_types = info.get("argument_types", None)
arg_types = []
if arguments_types:
for i, arg in enumerate(argument_names):
if i < len(arguments_types) and arguments_types[i]:
arg_types.append(arguments_types[i])
else:
arg_types.append(infer_argument_type(arg, type_inference_rules))
else:
arg_types = [infer_argument_type(arg, type_inference_rules) for arg in argument_names]
arg_values_sets = [generate_argument_values(arg_type) for arg_type in arg_types]
if len(arg_values_sets) == 0:
combinations = [[]]
else:
combinations = list(itertools.product(*arg_values_sets))
for arg_values in combinations:
test_case = {
"type": "ExecuteProgram",
"settings": {
"program_path": program_path,
"function_name": function_name,
"class_name": class_name,
"argument_names": argument_names,
"argument_types": arg_types,
"arguments": list(arg_values),
"check_result": {},
"result": "result_"+class_name
}
}
test_cases.append(test_case)
return test_cases
def generate_argument_values(arg_type):
"""引数の型に基づいて代表的な値を生成する(同値分割、境界値分析)"""
if arg_type == "numeric":
return [1, -1, 0, 2147483647, -2147483647]
elif arg_type == "string":
return ["", "test", "a" * 10, None]
elif arg_type == "list":
return [[], [1]]
elif arg_type == "dictionary":
return [{}, {"key": "value"}]
elif arg_type == "int":
return [1, -1, 0, 2147483647, -2147483648]
elif arg_type == "double":
return [1.0, -1.0, 0.0, 3.14, float('inf'), float('-inf'), float('nan')]
elif arg_type == "bool":
return [True, False]
elif arg_type == "DateTime":
return ["2023-10-27T10:00:00", "1970-01-01T00:00:00", None]
elif arg_type == "String":
return ["", "test", "a" * 1024, None]
elif arg_type == "String[]":
return [[""], ["test"], ["test1", "test2"], None]
elif arg_type == "List<string>":
return [[""], ["test"], ["test1", "test2"], None]
elif arg_type in ("Dictionary<string,string>", "Dictionary`2"):
return [ {"key": "value"}, {},None]
elif arg_type == "Object":
return [{"key": "value"}, None]
else:
return [None]
def pairwise_combinations(lists):
"""ペアワイズの組み合わせを生成する"""
if not lists:
yield []
elif len(lists) == 1:
for item in lists[0]:
yield [item]
else:
for pair in itertools.product(lists[0], lists[1]):
rest_lists = lists[2:]
if not rest_lists:
yield list(pair)
else:
for rest in generate_combinations(rest_lists):
yield list(pair) + rest
def generate_combinations(lists):
"""リストの組み合わせを生成する"""
if not lists:
yield []
else:
for item in lists[0]:
for rest in generate_combinations(lists[1:]):
yield [item] + rest
# --- グローバル関数用テスト実行 ---
def execute_function(settings):
program_path = settings.get("program_path", "")
function_name = settings.get("function_name", "")
class_name = settings.get("class_name", "")
argument_values = settings.get("arguments", [])
argument_names = settings.get("argument_names", [])
argument_types = settings.get("argument_types", [])
try:
if program_path.lower().endswith(".dll"):
# C#のDLLの場合
assembly = DLLControl.load_dll(os.path.abspath(program_path))
target_type = assembly.GetType(class_name)
if target_type:
method = target_type.GetMethod(function_name)
if method:
converted_args = [DLLControl.convert_python_to_cs(val, typ) for val, typ in zip(argument_values, argument_types)]
format_str = ",".join(ListControl.format_merge_multiple_list(
"{list3} {list1} = {list2}", "",
list1=argument_names, list2=converted_args, list3=argument_types))
print(f"{class_name}().{function_name}({format_str})")
if method.IsStatic:
result_value = method.Invoke(None, converted_args)
else:
# インスタンス生成(デフォルトコンストラクタ)してメソッド実行
instance = DLLControl.create_instance(assembly, class_name, *[])
result_value = instance.GetType().GetMethod(function_name).Invoke(instance, converted_args)
return result_value
else:
raise AttributeError(f"メソッドが見つかりません: {function_name}")
else:
raise AttributeError(f"クラスが見つかりません: {class_name}")
else:
# Pythonファイルの場合
spec = importlib.util.spec_from_file_location(function_name, program_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
function = getattr(module, function_name)
argument_names = get_argument_names(function)
format_str = ",".join(ListControl.format_merge_multiple_list(
"{list1} = {list2}", "",
list1=argument_names, list2=argument_values))
print(f"Function: {function_name}({format_str})")
result_value = function(*argument_values)
return result_value
except FileNotFoundError:
raise(f"ファイルが見つかりません: {program_path}")
except AttributeError as e:
raise(f"クラスのインスタンス化またはメソッド呼び出しに失敗しました: {e}")
except Exception as e:
raise(f"エラーが発生しました: {e}")
# --- クラステスト用:インスタンス生成+各メソッド実行 ---
def execute_class(settings):
program_path = settings.get("program_path", "")
class_name = settings.get("class_name", "")
init_argument_names = settings.get("argument_names", [])
init_argument_types = settings.get("argument_types", [])
init_argument_values = settings.get("arguments", [])
methods = settings.get("methods", [])
try:
if program_path.lower().endswith(".dll"):
# C#のDLLの場合
assembly = DLLControl.load_dll(os.path.abspath(program_path))
target_type = assembly.GetType(class_name)
if not target_type:
raise AttributeError(f"クラスが見つかりません: {class_name}")
converted_init_args = [DLLControl.convert_python_to_cs(val, typ) for val, typ in zip(init_argument_values, init_argument_types)]
instance = DLLControl.create_instance(assembly, class_name, *converted_init_args)
class_fmt = ",".join(ListControl.format_merge_multiple_list("{list3} {list1}={list2}", "", list1=init_argument_names, list2=converted_init_args,list3 = init_argument_types))
# 各メソッド実行
for method_setting in methods:
method_name = method_setting.get("method_name", "")
m_argument_names = method_setting.get("argument_names", [])
m_argument_types = method_setting.get("argument_types", [])
m_argument_values = method_setting.get("arguments", [])
fmt = ",".join(ListControl.format_merge_multiple_list("{list3} {list1}={list2}", "", list1=m_argument_names, list2=m_argument_values,list3 = m_argument_types))
converted_m_args = [DLLControl.convert_python_to_cs(val, typ) for val, typ in zip(m_argument_values, m_argument_types)]
print(f"{class_name}({class_fmt}).{method_name}({fmt})")
method = instance.GetType().GetMethod(method_name)
if not method:
raise AttributeError(f"メソッドが見つかりません: {method_name}")
cs_result = method.Invoke(instance, converted_m_args)
result = DLLControl.convert_cs_to_python(cs_result)
method_setting = CheckResult(method_setting,result)
else:
# Pythonクラスの場合
spec = importlib.util.spec_from_file_location(class_name, program_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
target = getattr(module, class_name)
if not inspect.isclass(target):
raise AttributeError(f"{class_name} is not a class")
instance = target(*init_argument_values)
print(f"{class_name} インスタンス生成: 引数 {list(zip(init_argument_names, init_argument_values))}")
# 各メソッド実行
for method_setting in methods:
method_name = method_setting.get("method_name", "")
m_argument_names = method_setting.get("argument_names", [])
m_argument_types = method_setting.get("argument_types", [])
m_argument_values = method_setting.get("arguments", [])
fmt = ",".join(ListControl.format_merge_multiple_list("{list1}={list2}", "", list1=m_argument_names, list2=m_argument_values))
print(f"{class_name}.{method_name}({fmt})")
if not hasattr(instance, method_name):
raise AttributeError(f"メソッドが見つかりません: {method_name}")
method = getattr(instance, method_name)
result = method(*m_argument_values)
method_setting = CheckResult(method_setting,result)
settings["methods"] = methods
return settings
except FileNotFoundError:
print(f"ファイルが見つかりません: {program_path}")
except AttributeError as e:
print(f"クラスのインスタンス生成またはメソッド呼び出しに失敗しました: {e}")
except Exception as e:
print(f"エラーが発生しました: {e}")
def create_instance(settings):
program_path = settings.get("program_path", "")
class_name = settings.get("class_name", "")
init_argument_names = settings.get("argument_names", [])
init_argument_types = settings.get("argument_types", [])
init_argument_values = settings.get("arguments", [])
if program_path.lower().endswith(".dll"):
# C# の DLL の場合
assembly = DLLControl.load_dll(os.path.abspath(program_path))
target_type = assembly.GetType(class_name)
if not target_type:
raise AttributeError(f"クラスが見つかりません: {class_name}")
converted_init_args = [DLLControl.convert_python_to_cs(val, typ) for val, typ in zip(init_argument_values, init_argument_types)]
instance = DLLControl.create_instance(assembly, class_name, *converted_init_args)
else:
# Python クラスの場合
spec = importlib.util.spec_from_file_location(class_name, program_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
target = getattr(module, class_name)
if not inspect.isclass(target):
raise AttributeError(f"{class_name} is not a class")
instance = target(*init_argument_values)
return instance
def execute_methods_cs(instance, method_setting):
method_name = method_setting.get("method_name", "")
m_argument_types = method_setting.get("argument_types", [])
m_argument_values = method_setting.get("arguments", [])
converted_m_args = [DLLControl.convert_python_to_cs(val, typ) for val, typ in zip(m_argument_values, m_argument_types)]
method = instance.GetType().GetMethod(method_name)
if not method:
raise AttributeError(f"メソッドが見つかりません: {method_name}")
cs_result = method.Invoke(instance, converted_m_args)
result = DLLControl.convert_cs_to_python(cs_result)
return result
def execute_methods_python(instance, method_setting):
method_name = method_setting.get("method_name", "")
m_argument_values = method_setting.get("arguments", [])
if not hasattr(instance, method_name):
raise AttributeError(f"メソッドが見つかりません: {method_name}")
method = getattr(instance, method_name)
result = method(*m_argument_values)
method_setting = CheckResult(method_setting,result)
return result
def method_format(method_setting):
method_name = method_setting.get("method_name", "")
m_argument_names = method_setting.get("argument_names", [])
m_argument_types = method_setting.get("argument_types", [])
m_argument_values = method_setting.get("arguments", [])
fmt = ",".join(ListControl.format_merge_multiple_list("{list3} {list1}={list2}", "", list1=m_argument_names, list2=m_argument_values, list3=m_argument_types))
return f"{method_name}({fmt})"
# --- テストケース全体の実行 ---
def ExecuteProgram(settings):
"""テストケースに基づいてプログラムを実行する"""
class_name = settings.get("class_name", "")
methods = settings.get("methods", [])
program_path = settings.get("program_path", "")
result_dictionary={}
if methods:
try:
if program_path.lower().endswith(".dll"):
instance = create_instance(settings)
for i, method_setting in enumerate(methods):
fmt = method_format(method_setting)
print(f"{program_path}-{i} {class_name}.{fmt}")
try:
result_value = execute_methods_cs(instance, method_setting)
except Exception as e:
result_value = {"success": False, "error": str(e)}
methods[i] = CheckResult(method_setting, result_value)
result_settings = method_setting.get("result")
if result_settings:
WriteDatas(result_settings,result_dictionary,result_value)
else:
instance = create_instance(settings)
for method_setting in methods:
fmt = method_format(method_setting)
print(f"{program_path}-{class_name}.{fmt}")
try:
result_value = execute_methods_python(instance, method_setting)
except Exception as e:
result_value ={"success":False,"error":str(e)}
method_setting = CheckResult(method_setting,result_value)
result_settings = method_setting.get("result")
if result_settings:
WriteDatas(result_settings,result_dictionary,result_value)
return result_dictionary
except FileNotFoundError:
raise(f"ファイルが見つかりません: {settings.get('program_path', '')}")
except AttributeError as e:
raise(f"クラスのインスタンス生成またはメソッド呼び出しに失敗しました: {e}")
except Exception as e:
raise(f"エラーが発生しました: {e}")
else:
return execute_function(settings)
def write_test_cases(program_path, output_file_path, test_data_name, type_inference_rules, options={}):
function_informations = get_function_info(program_path, options)
if not function_informations:
return
test_cases = generate_test_cases(function_informations, type_inference_rules)
test_plan_list = {test_data_name: test_cases}
# JSONファイルに出力
JSON_Control.WriteDictionary(output_file_path, test_plan_list)
return test_plan_list
def get_argument_names(func: Any) -> list:
"""
定義された引数名を取得する関数
"""
sig = inspect.signature(func)
arg_names = list(sig.parameters.keys())
return arg_names
def normalize_program_output(output):
"""
外部プログラムの戻り値 output を解析し、以下のキーを持つ辞書を返す:
- "success": 実行の成否(True/False)
- "result_value": 得られた結果または判断理由
- "error": エラー情報(あれば)
"""
if isinstance(output, dict):
result = output.get("result_value", None)
error = output.get("error", None)
success_judge = False if error else True
if result:
result_dictionary = {
"success": output.get("success", success_judge),
"result_value": result,
}
result_dictionary.update(output)
return result_dictionary
else:
if error:
return {"success": output.get("success", success_judge), "result_value": output, "error": error}
else:
return {"success": output.get("success", success_judge), "result_value": output}
elif isinstance(output, (tuple, list)):
return {"success": True, "result_value": output}
elif isinstance(output, bool):
return {"success": True, "result_value": output, "error": None}
elif isinstance(output, str):
return {"success": True, "result_value": output, "error": None}
else:
return {"success": True, "result_value": output, "error": None}
def RunPlanLists(settings):
data_store = settings.get("data_store",{})
plan_lists = settings.get("plan_lists",{})
run_plan_name_list = settings.get("run_plan_name_list")
if run_plan_name_list == "":
details = {"success":False,"error":"run_plan_name_list is nothing."}
return details
if not isinstance(run_plan_name_list,list):
run_plan_name_list = [run_plan_name_list]
for run_plan_name in run_plan_name_list:
plan_list = plan_lists.get(run_plan_name,"")
if plan_list:
if not isinstance(plan_list,list):
plan_list=[plan_list]
for num,plan in enumerate(plan_list):
plan_list_filepath = settings.get("plan_lists_file_path","")
if plan_list_filepath:
plan_lists = JSON_Control.ReadDictionary(plan_list_filepath,{},details = details)
if details.get("success",True) == False:
print(str(details))
input("file error.please push and skip."+plan_list_filepath)
plan_settings = {
"data_store":data_store,
"plan_lists":plan_lists,
"run_plan_name":run_plan_name,
"run_plan_number": num
}
result = ExecutePlan(plan_settings)
def ExecutePlan(settings):
# 実行する設定の読込
data_store = settings.get("data_store",{})
plan_lists = settings.get("plan_lists",{})
run_plan_name = settings.get("run_plan_name","")
run_plan_number = settings.get("run_plan_number","")
plan_list = plan_lists.get(run_plan_name)
if not plan_list:
return {"success":False,"error":"plan_list is nothing"}
if not isinstance(plan_list,list):
plan_list=[plan_list]
plan = plan_list[run_plan_number]
if not plan:
return {"success":False,"error":"plan is nothing"}
plan_copy = copy.deepcopy(plan)
plan_type= plan_copy.get("type","Action")
plan_settings = plan_copy.get("settings",{})
check_result = plan_settings.get("check_result",None)
# 実行するPlan内容の表示
if check_result:
plan_name =plan_copy.get("name","")
message= + plan_name+"("+str(settings)+")"
print(message)
# referenceの内容をdata_store,shared_memoryから参照して反映する。
apply_reference_values(plan_settings,data_store,shared_memory_file_path="")
#関数を実行する
try:
current_module = inspect.getmodule(inspect.currentframe())
loaded_function = ClassControl.load_function_from_module(current_module,plan_type)
plan_settings_backup = copy.deepcopy(plan_settings)
result_value = loaded_function(plan_settings)
except Exception as e:
message = str(e)
result_value = {"success":False,"error": message}
plan_settings["result_value"]=result_value
check_result = plan_settings.get("check_result",None)
if check_result is not None:
check_result_settings ={
"result_value":result_value,
"check_result":check_result
}
CheckResult(check_result_settings)
result_diff = DictionaryControl.DiffDictionaries(plan_settings_backup,plan_settings)
if result_diff:
plan["settings"] = DictionaryControl.ChangeDictionary(result_diff,plan.get("settings",{}))
result_settings = plan_settings.get("result")
if result_settings:
WriteDatas(result_settings,data_store,result_value)
def CheckResult(settings,result_value={}):
check_result = settings.get("check_result", None)
if check_result == None:
return settings
if not result_value:
result_value = settings.get("result_value")
if check_result=={}:
check_result["expected"] = result_value
settings["check_result"] = check_result
print(f"Write expected: {result_value}")
elif check_result:
expected = check_result.get("expected")
if result_value == expected:
print(f"OK Result: {result_value}")
else:
print(f"NG Result: {result_value}, expected: {expected}")
user_input = input("OverWrite the expected result setting with the actual results? :(W) ")
if user_input.upper() == "W":
check_result["expected"] = result_value
settings["check_result"] = check_result
return settings
def WriteDatas(settings,data_store,datas):
if isinstance(settings,str):
key = settings
data_store[key] = datas
print("WriteDatas("+key+":"+str(datas)+")")
if isinstance(settings,dict):
# 設定に基づいてデータを抽出して保存
for key,data_key in settings.items():
if data_key in datas:
value =datas[data_key]
data_store[key] = value
print("WriteDatas("+key+":"+str(value)+")")
def apply_reference_values(settings,data_store,shared_memory_file_path=""):
reference_list = settings.get("reference", [])
if not reference_list:
return settings
if not isinstance(reference_list,list):
reference_list =[reference_list]
for reference in reference_list:
if isinstance(reference,dict):
source_type = reference.get("source_type","data_store")
if source_type =="share_memory":
shared_memory = SharedMemory.read_from_shared_memory(shared_memory_file_path,{})
shared_memory_name = settings.get("shared_memory_name","shared_memory_name")
shared_data=shared_memory.get(shared_memory_name,{})
for key, reference_key in reference.items():
value = shared_data.get(reference_key, "")
if value:
settings[key] = value
else:
value = data_store.get(reference_key,"")
if value:
settings[key] = value
elif source_type =="data_store":
for key, reference_key in reference.items():
value = data_store.get(reference_key,"")
if value:
settings[key] = value
def main():
type_inference_rules = {
"numeric_keywords": {'size', 'count', 'width', 'height', 'ratio', 'length', 'number', 'index'},
"string_keywords": {'name', 'text', 'message', 'title', 'path', 'filename'},
"list_keywords": {"list"},
"dictionary_keywords": {"dict", "dictionary"}
}
options = {"references": [".\\Reference\\Newtonsoft.Json.13.0.3\\lib\\net35\\Newtonsoft.Json.dll"]}
data_store ={"key1":"value1","key2":"value2"}
# C# ソース(.cs)のテスト
program_path = "../../../Tools/diff.cs"
output_filename = "Test_cs.json"
data_name = "test"
test_cases = write_test_cases(program_path, output_filename, data_name, type_inference_rules, options)
if test_cases:
settings ={
"plan_lists":test_cases,
"run_plan_name_list":data_name
}
RunPlanLists(settings)
test_cases=settings.get("plan_lists")
JSON_Control.WriteDictionary(output_filename, test_cases)
#RunPlanLists(settings)
# DLL のテスト
program_path = "../../../Tools/diff.dll"
output_filename = "Test_dll.json"
data_name = "test_dll"
test_cases = write_test_cases(program_path, output_filename, data_name, type_inference_rules, options)
if test_cases:
settings ={
"plan_lists":test_cases,
"run_plan_name_list":data_name
}
RunPlanLists(settings)
test_cases=settings.get("plan_lists")
JSON_Control.WriteDictionary(output_filename, test_cases)
#RunPlanLists(settings)
# Python ファイルのテスト(クラスの初期化やメソッドのテストを含む)
program_path = "./Sources/Common/Text.py"
output_filename = "Test_py.json"
data_name = "test"
test_cases = write_test_cases(program_path, output_filename, data_name, type_inference_rules, options)
if test_cases:
settings ={
"plan_lists":test_cases,
"run_plan_name_list":data_name
}
RunPlanLists(settings)
test_cases=settings.get("plan_lists")
JSON_Control.WriteDictionary(output_filename, test_cases)
#RunPlanLists(settings)
if __name__ == "__main__":
main()