main.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import os
  2. import re
  3. import json
  4. import shutil
  5. import difflib
  6. import argparse
  7. import TraceChecker
  8. # ANSI color escape codes
  9. RED = '\033[91m' # Red color
  10. GREEN = '\033[92m' # Green color
  11. YELLOW = '\033[93m' # Yellow color
  12. ENDC = '\033[0m' # Reset color to default
  13. def sort_directories(test_directory):
  14. # Read directory names and sort using natural sort
  15. all_test_dirs = [d for d in os.listdir(test_directory) if os.path.isdir(os.path.join(test_directory, d))]
  16. return sorted(all_test_dirs, key=natural_sort_key)
  17. def natural_sort_key(s):
  18. # Split the string into a list of strings and numbers
  19. return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s)]
  20. if __name__ == '__main__':
  21. # Create the parser to get arguments of command line
  22. parser = argparse.ArgumentParser(description="Process a test folder.")
  23. parser.add_argument(
  24. '-i', '--input',
  25. type=str,
  26. required=True,
  27. help='Path to the test folder'
  28. )
  29. parser.add_argument(
  30. '-c', '--clear',
  31. action='store_true',
  32. help='Clear the output after execution'
  33. )
  34. args = parser.parse_args()
  35. source = args.input
  36. # Define the default configuration if no configuration file is given
  37. default_config = {
  38. "model": "sccd.xml",
  39. "input": "input.txt",
  40. "trace": "external",
  41. "platforms": ["Python", "ClassicDEVS"],
  42. "check_file": "expected_trace.txt"
  43. }
  44. # Add here all possible platforms (Not only the one that need to be tested but all --> resolved in config file)
  45. platforms = [TraceChecker.PythonSCCDTraceChecker(), TraceChecker.ClassicDevsSCCDTraceChecker()]
  46. sorted_dirs = sort_directories(source)
  47. results = {str(platform): [] for platform in platforms}
  48. for directory_name in sorted_dirs:
  49. full_directory = os.path.join(source, directory_name)
  50. if os.path.isdir(full_directory):
  51. print(f"Processing {directory_name}...")
  52. # Check if a user defined config exists otherwise default to the default config file
  53. config_file = os.path.join(full_directory, 'config.json')
  54. if os.path.exists(config_file):
  55. with open(config_file, 'r') as file:
  56. config_data = json.load(file)
  57. # If an option in user config is empty, replace with default
  58. for key, value in default_config.items():
  59. if key not in config_data:
  60. config_data[key] = value
  61. else:
  62. # If there is no config file found in the test, give the default config file
  63. config_data = default_config
  64. for platform in platforms:
  65. platform_name = str(platform)
  66. # For each platform to be checked for the test, compile, run, and filter necessary traces
  67. if platform_name in config_data['platforms']:
  68. platform.directory = full_directory
  69. platform.config = config_data
  70. platform.compile()
  71. platform.run()
  72. result = platform.filter()
  73. # Open the log to be compared to and write them in same format as filtered traces (list of strings)
  74. expected_log = os.path.join(full_directory, config_data["check_file"])
  75. expected_events = []
  76. if os.path.exists(expected_log):
  77. with open(expected_log, 'r') as file:
  78. expected_events = [line.strip() for line in file.readlines()]
  79. # Compare traces
  80. return_code = 1
  81. # If both traces are not the same in length, test fails
  82. if len(expected_events) != len(result):
  83. return_code = 0
  84. # If one of the trace files is empty, likely not a good option in config file
  85. if len(expected_events) == 0 and len(result) == 0:
  86. return_code = 2
  87. # Check if each line is exactly the same in both files
  88. for index, (line1, line2) in enumerate(zip(expected_events, result)):
  89. if line1 != line2:
  90. return_code = 0
  91. results[platform_name].append(return_code)
  92. # Notice the user about the test (by printing in terminal)
  93. if return_code == 0:
  94. print(f"{platform_name}: ", RED + "Failed" + ENDC)
  95. # If test fails, write the traces to a log for checking
  96. faulty_log = os.path.join(full_directory, platform_name, "faulty_log.txt")
  97. with open(faulty_log, 'w') as file:
  98. file.writelines([event + '\n' for event in result])
  99. # Use the difflib package to check on a deeper level what is different
  100. with open(expected_log, "r") as f1, open(faulty_log, "r") as f2:
  101. diff = difflib.unified_diff(f1.readlines(), f2.readlines(), fromfile=expected_log, tofile=faulty_log)
  102. for line in diff:
  103. print("\t" + line)
  104. elif return_code == 1:
  105. print(f"{platform_name}: ", GREEN + "Passed" + ENDC)
  106. else:
  107. print(f"{platform_name}: ", YELLOW + "Need more detailed testing" + ENDC)
  108. # Print summary
  109. print("\nTest Summary:")
  110. for platform in platforms:
  111. platform_name = str(platform)
  112. print(f"\n{platform_name} Results:")
  113. print(f"Passed: {GREEN}{results[platform_name].count(1)}{ENDC}")
  114. print(f"Failed: {RED}{results[platform_name].count(0)}{ENDC}")
  115. print(f"Warnings: {YELLOW}{results[platform_name].count(2)}{ENDC}")
  116. # If clear option (-c) is specified, perform the clear operation
  117. if args.clear:
  118. print("Resetting environment...")
  119. # Iterate over each folder inside the parent directory
  120. for folder_name in os.listdir(source):
  121. folder_path = os.path.join(source, folder_name)
  122. # Check if the path is a directory and not a file
  123. if os.path.isdir(folder_path):
  124. for platform in platforms:
  125. platform_name = str(platform)
  126. path = os.path.join(folder_path, platform_name)
  127. if os.path.exists(path):
  128. shutil.rmtree(path)
  129. print(f"Deleted {path}")