test.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import os
  2. import unittest
  3. import argparse
  4. import threading
  5. import queue
  6. from sccd.runtime.infinity import INFINITY
  7. from sccd.runtime.event import Event
  8. from sccd.runtime.controller import Controller
  9. from lib.builder import Builder
  10. from lib.os_tools import *
  11. class PyTestCase(unittest.TestCase):
  12. def __init__(self, src_file, builder):
  13. unittest.TestCase.__init__(self)
  14. self.src_file = src_file
  15. self.builder = builder
  16. def __str__(self):
  17. return self.src_file
  18. def runTest(self):
  19. # Build & load
  20. module = self.builder.build_and_load(self.src_file)
  21. inputs = module.Test.input_events
  22. expected = module.Test.expected_events # list of lists of Event objects
  23. model = module.Model()
  24. controller = Controller(model)
  25. # generate input
  26. if inputs:
  27. for i in inputs:
  28. controller.add_input(Event(i.name, i.port, i.parameters), int(i.time_offset))
  29. pipe = queue.Queue()
  30. def model_thread():
  31. try:
  32. # Run as-fast-as-possible, always advancing time to the next item in event queue, no sleeping.
  33. # The call returns when the event queue is empty and therefore the simulation is finished.
  34. controller.run_until(INFINITY, pipe)
  35. except Exception as e:
  36. pipe.put(e, block=True, timeout=None)
  37. return
  38. pipe.put(None, block=True, timeout=None)
  39. # start the controller
  40. thread = threading.Thread(target=model_thread)
  41. thread.start()
  42. # check output
  43. slot_index = 0
  44. while True:
  45. output = pipe.get(block=True, timeout=None)
  46. if isinstance(output, Exception):
  47. thread.join()
  48. raise output # Exception was caught in Controller thread, throw it here instead.
  49. elif output is None:
  50. self.assertEqual(slot_index, len(expected), "Less output was received than expected.")
  51. thread.join()
  52. return
  53. else:
  54. self.assertLess(slot_index, len(expected), "More output was received than expected.")
  55. exp_slot = expected[slot_index]
  56. # print("slot:", slot_index, ", events: ", output)
  57. self.assertEqual(len(exp_slot), len(output), "Slot %d length differs: Expected %s, but got %s instead." % (slot_index, exp_slot, output))
  58. # sort both expected and actual lists of events before comparing,
  59. # in theory the set of events at the end of a big step is unordered
  60. key_f = lambda e: "%s.%s"%(e.port, e.name)
  61. exp_slot.sort(key=key_f)
  62. output.sort(key=key_f)
  63. for (exp_event, event) in zip(exp_slot, output):
  64. matches = True
  65. if exp_event.name != event.name :
  66. matches = False
  67. if exp_event.port != event.port :
  68. matches = False
  69. if len(exp_event.parameters) != len(event.parameters) :
  70. matches = False
  71. for index in range(len(exp_event.parameters)) :
  72. if exp_event.parameters[index] != event.parameters[index]:
  73. matches = False
  74. self.assertTrue(matches, "Slot %d entry differs: Expected %s, but got %s instead." % (slot_index, exp_slot, output))
  75. slot_index += 1
  76. if __name__ == '__main__':
  77. parser = argparse.ArgumentParser(
  78. description="Run SCCD tests.",
  79. epilog="Set environment variable SCCDDEBUG=1 to display debug information about the inner workings of state machines.")
  80. parser.add_argument('path', metavar='PATH', type=str, nargs='*', help="Tests to run. Can be a XML file or a directory. If a directory, it will be recursively scanned for XML files.")
  81. parser.add_argument('--build-dir', metavar='BUILD_DIR', type=str, default='build', help="Directory for built tests. Defaults to 'build'")
  82. args = parser.parse_args()
  83. src_files = get_files(args.path, filter=xml_filter)
  84. builder = Builder(args.build_dir)
  85. suite = unittest.TestSuite()
  86. for src_file in src_files:
  87. suite.addTest(PyTestCase(src_file, builder))
  88. if len(src_files) == 0:
  89. print("No input files specified.")
  90. print()
  91. parser.print_usage()
  92. else:
  93. unittest.TextTestRunner(verbosity=2).run(suite)