cosmos 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (912) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +48 -48
  4. data/.travis.yml +7 -7
  5. data/CONTRIBUTING.txt +50 -50
  6. data/Gemfile +6 -6
  7. data/Guardfile +27 -27
  8. data/LICENSE.txt +879 -879
  9. data/Manifest.txt +1116 -1114
  10. data/README.md +109 -107
  11. data/Rakefile +214 -214
  12. data/autohotkey/config/data/diamond.STL +57 -57
  13. data/autohotkey/config/system/system.txt +34 -34
  14. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  15. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  16. data/autohotkey/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  17. data/autohotkey/config/targets/COSMOS/target.txt +5 -5
  18. data/autohotkey/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  19. data/autohotkey/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  20. data/autohotkey/config/targets/INST/cmd_tlm_server.txt +5 -5
  21. data/autohotkey/config/targets/INST/lib/example_limits_response.rb +30 -30
  22. data/autohotkey/config/targets/INST/lib/sim_inst.rb +305 -294
  23. data/autohotkey/config/targets/INST/screens/adcs.txt +46 -46
  24. data/autohotkey/config/targets/INST/screens/array.txt +7 -7
  25. data/autohotkey/config/targets/INST/screens/block.txt +8 -8
  26. data/autohotkey/config/targets/INST/screens/commanding.txt +30 -30
  27. data/autohotkey/config/targets/INST/screens/graphs.txt +14 -14
  28. data/autohotkey/config/targets/INST/screens/ground.txt +25 -25
  29. data/autohotkey/config/targets/INST/screens/health_status.txt +33 -33
  30. data/autohotkey/config/targets/INST/screens/hs.txt +49 -49
  31. data/autohotkey/config/targets/INST/screens/image.txt +21 -21
  32. data/autohotkey/config/targets/INST/screens/latest.txt +23 -23
  33. data/autohotkey/config/targets/INST/screens/mech.txt +25 -25
  34. data/autohotkey/config/targets/INST/screens/other.txt +25 -25
  35. data/autohotkey/config/targets/INST/screens/params.txt +25 -25
  36. data/autohotkey/config/targets/INST/screens/tabs.txt +68 -68
  37. data/autohotkey/config/targets/INST/target.txt +26 -26
  38. data/autohotkey/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  39. data/autohotkey/config/targets/META/cmd_tlm/meta_tlm.txt +9 -9
  40. data/autohotkey/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  41. data/autohotkey/config/targets/SYSTEM/screens/error.txt +11 -11
  42. data/autohotkey/config/tools/cmd_tlm_server/cmd_tlm_server.txt +22 -22
  43. data/autohotkey/config/tools/data_viewer/data_viewer.txt +11 -11
  44. data/autohotkey/config/tools/handbook_creator/handbook_creator.txt +49 -49
  45. data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  46. data/autohotkey/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  47. data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  48. data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +25 -25
  49. data/autohotkey/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  50. data/autohotkey/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  51. data/autohotkey/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  52. data/autohotkey/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  53. data/autohotkey/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  54. data/autohotkey/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  55. data/autohotkey/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  56. data/autohotkey/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  57. data/autohotkey/config/tools/handbook_creator/templates/title.html.erb +1 -1
  58. data/autohotkey/config/tools/launcher/launcher.txt +38 -38
  59. data/autohotkey/config/tools/script_runner/script_runner.txt +3 -3
  60. data/autohotkey/config/tools/table_manager/ConfigTables_def.txt +8 -8
  61. data/autohotkey/config/tools/table_manager/OneDimensionalTable_def.txt +19 -19
  62. data/autohotkey/config/tools/table_manager/TwoDimensionalTable_def.txt +248 -248
  63. data/autohotkey/config/tools/test_runner/test_runner.txt +8 -8
  64. data/autohotkey/config/tools/test_runner/test_runner2.txt +11 -11
  65. data/autohotkey/config/tools/test_runner/test_runner3.txt +6 -6
  66. data/autohotkey/config/tools/test_runner/test_runner4.txt +1 -1
  67. data/autohotkey/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  68. data/autohotkey/config/tools/tlm_extractor/tlm_extractor2.txt +9 -9
  69. data/autohotkey/config/tools/tlm_grapher/bad.txt +50 -50
  70. data/autohotkey/config/tools/tlm_grapher/temp1-4.txt +51 -51
  71. data/autohotkey/config/tools/tlm_grapher/test2.txt +111 -111
  72. data/autohotkey/config/tools/tlm_viewer/tlm_viewer.txt +24 -24
  73. data/autohotkey/config/tools/tlm_viewer/tlm_viewer2.txt +4 -4
  74. data/autohotkey/config/tools/tlm_viewer/tlm_viewer3.txt +3 -3
  75. data/autohotkey/lib/example_background_task.rb +42 -42
  76. data/autohotkey/lib/user_version.rb +3 -3
  77. data/autohotkey/procedures/clear_util.rb +7 -7
  78. data/autohotkey/procedures/collect.rb +18 -18
  79. data/autohotkey/procedures/collect_util.rb +14 -14
  80. data/autohotkey/procedures/example_test.rb +67 -67
  81. data/autohotkey/procedures/example_test2.rb +74 -74
  82. data/autohotkey/procedures/script_test.rb +17 -17
  83. data/autohotkey/procedures/syntax_error.rb +18 -18
  84. data/autohotkey/tools/CmdExtractorAHK +16 -16
  85. data/autohotkey/tools/CmdSender +14 -14
  86. data/autohotkey/tools/CmdSenderAHK +18 -18
  87. data/autohotkey/tools/CmdTlmServer +14 -14
  88. data/autohotkey/tools/CmdTlmServerAHK +28 -28
  89. data/autohotkey/tools/CmdTlmServerAHK2 +17 -17
  90. data/autohotkey/tools/DataViewer +14 -14
  91. data/autohotkey/tools/DataViewerAHK +17 -17
  92. data/autohotkey/tools/HandbookCreatorAHK +20 -20
  93. data/autohotkey/tools/LauncherAHK +17 -17
  94. data/autohotkey/tools/LimitsMonitorAHK +20 -20
  95. data/autohotkey/tools/OpenGLBuilderAHK +20 -20
  96. data/autohotkey/tools/PacketViewer +14 -14
  97. data/autohotkey/tools/PacketViewerAHK +18 -18
  98. data/autohotkey/tools/PacketViewerAHK2 +17 -17
  99. data/autohotkey/tools/Replay +14 -14
  100. data/autohotkey/tools/Replay.bat +59 -59
  101. data/autohotkey/tools/ReplayAHK +17 -17
  102. data/autohotkey/tools/ScriptRunner +14 -14
  103. data/autohotkey/tools/ScriptRunnerAHK +20 -20
  104. data/autohotkey/tools/ScriptRunnerAHK2 +17 -17
  105. data/autohotkey/tools/TableManager +14 -14
  106. data/autohotkey/tools/TableManagerAHK +30 -30
  107. data/autohotkey/tools/TestRunner +15 -15
  108. data/autohotkey/tools/TestRunnerAHK +17 -17
  109. data/autohotkey/tools/TestRunnerAHK2 +17 -17
  110. data/autohotkey/tools/TestRunnerAHK3 +17 -17
  111. data/autohotkey/tools/TestRunnerAHK4 +17 -17
  112. data/autohotkey/tools/TlmExtractor +15 -15
  113. data/autohotkey/tools/TlmExtractorAHK +19 -19
  114. data/autohotkey/tools/TlmExtractorAHK2 +16 -16
  115. data/autohotkey/tools/TlmExtractorAHK3 +16 -16
  116. data/autohotkey/tools/TlmGrapher +14 -14
  117. data/autohotkey/tools/TlmGrapherAHK +19 -19
  118. data/autohotkey/tools/TlmGrapherAHK2 +23 -23
  119. data/autohotkey/tools/TlmGrapherAHK3 +17 -17
  120. data/autohotkey/tools/TlmGrapherAHK4 +17 -17
  121. data/autohotkey/tools/TlmViewer +14 -14
  122. data/autohotkey/tools/TlmViewerAHK +28 -28
  123. data/autohotkey/tools/TlmViewerAHK2 +18 -18
  124. data/autohotkey/tools/TlmViewerAHK3 +18 -18
  125. data/autohotkey/tools/TlmViewerAHK4 +18 -18
  126. data/autohotkey/tools/TlmViewerAHK5 +18 -18
  127. data/autohotkey/tools/autohotkey.rb +37 -37
  128. data/autohotkey/tools/cmd_extractor.ahk +27 -27
  129. data/autohotkey/tools/cmd_sender.ahk +182 -162
  130. data/autohotkey/tools/cmd_tlm_server.ahk +89 -89
  131. data/autohotkey/tools/cmd_tlm_server2.ahk +45 -45
  132. data/autohotkey/tools/data_viewer.ahk +135 -135
  133. data/autohotkey/tools/handbook_creator.ahk +23 -23
  134. data/autohotkey/tools/launcher.ahk +41 -41
  135. data/autohotkey/tools/limits_monitor.ahk +70 -70
  136. data/autohotkey/tools/open_gl_builder.ahk +134 -134
  137. data/autohotkey/tools/packet_viewer.ahk +143 -143
  138. data/autohotkey/tools/packet_viewer2.ahk +9 -9
  139. data/autohotkey/tools/replay.ahk +98 -98
  140. data/autohotkey/tools/script_runner.ahk +589 -589
  141. data/autohotkey/tools/script_runner2.ahk +34 -31
  142. data/autohotkey/tools/table_manager.ahk +220 -220
  143. data/autohotkey/tools/test_runner.ahk +262 -259
  144. data/autohotkey/tools/test_runner2.ahk +52 -52
  145. data/autohotkey/tools/test_runner3.ahk +13 -13
  146. data/autohotkey/tools/tlm_extractor.ahk +272 -272
  147. data/autohotkey/tools/tlm_grapher.ahk +642 -642
  148. data/autohotkey/tools/tlm_grapher2.ahk +115 -115
  149. data/autohotkey/tools/tlm_grapher3.ahk +24 -24
  150. data/autohotkey/tools/tlm_viewer.ahk +133 -133
  151. data/autohotkey/tools/tlm_viewer2.ahk +50 -49
  152. data/autohotkey/tools/tlm_viewer4.ahk +4 -4
  153. data/autohotkey/tools/tlm_viewer5.ahk +20 -20
  154. data/bin/cosmos +96 -96
  155. data/bin/cstol_converter +1166 -1166
  156. data/bin/rubysloc +85 -85
  157. data/cosmos.gemspec +98 -97
  158. data/data/about.txt +4 -4
  159. data/data/crc.txt +306 -305
  160. data/data/diamond.STL +57 -57
  161. data/data/legal.txt +9 -9
  162. data/demo/Gemfile +6 -6
  163. data/demo/Launcher +15 -15
  164. data/demo/Launcher.bat +59 -59
  165. data/demo/Rakefile +61 -61
  166. data/demo/config/data/crc.txt +222 -206
  167. data/demo/config/data/diamond.STL +57 -57
  168. data/demo/config/data/meta_init.txt +4 -4
  169. data/demo/config/system/system.txt +34 -34
  170. data/demo/config/system/system2.txt +33 -33
  171. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  172. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  173. data/demo/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  174. data/demo/config/targets/COSMOS/screens/limits_change.txt +20 -20
  175. data/demo/config/targets/COSMOS/screens/version.txt +19 -19
  176. data/demo/config/targets/COSMOS/target.txt +11 -11
  177. data/demo/config/targets/EXAMPLE/cmd_tlm/example_cmds.txt +2 -2
  178. data/demo/config/targets/EXAMPLE/cmd_tlm/example_tlm.txt +3 -3
  179. data/demo/config/targets/EXAMPLE/cmd_tlm_server.txt +6 -6
  180. data/demo/config/targets/EXAMPLE/lib/example_interface.rb +22 -22
  181. data/demo/config/targets/EXAMPLE/target.txt +6 -6
  182. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  183. data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  184. data/demo/config/targets/INST/cmd_tlm_server.txt +5 -5
  185. data/demo/config/targets/INST/lib/example_limits_response.rb +30 -30
  186. data/demo/config/targets/INST/lib/sim_inst.rb +305 -294
  187. data/demo/config/targets/INST/screens/adcs.txt +46 -46
  188. data/demo/config/targets/INST/screens/array.txt +15 -15
  189. data/demo/config/targets/INST/screens/block.txt +8 -8
  190. data/demo/config/targets/INST/screens/commanding.txt +30 -30
  191. data/demo/config/targets/INST/screens/graphs.txt +14 -14
  192. data/demo/config/targets/INST/screens/ground.txt +25 -25
  193. data/demo/config/targets/INST/screens/hs.txt +44 -44
  194. data/demo/config/targets/INST/screens/latest.txt +23 -23
  195. data/demo/config/targets/INST/screens/other.txt +29 -29
  196. data/demo/config/targets/INST/screens/tabs.txt +70 -70
  197. data/demo/config/targets/INST/target.txt +33 -33
  198. data/demo/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  199. data/demo/config/targets/META/cmd_tlm/meta_tlm.txt +13 -13
  200. data/demo/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  201. data/demo/config/targets/SYSTEM/cmd_tlm/override.txt +29 -29
  202. data/demo/config/targets/SYSTEM/screens/status.txt +12 -12
  203. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_cmds.txt +13 -12
  204. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_tlm.txt +3 -3
  205. data/demo/config/targets/TEMPLATED/cmd_tlm_server.txt +6 -6
  206. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +54 -48
  207. data/demo/config/targets/TEMPLATED/target.txt +6 -6
  208. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +33 -33
  209. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +29 -29
  210. data/demo/config/tools/data_viewer/data_viewer.txt +11 -11
  211. data/demo/config/tools/handbook_creator/handbook_creator.txt +66 -66
  212. data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  213. data/demo/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  214. data/demo/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  215. data/demo/config/tools/handbook_creator/templates/header.html.erb +25 -25
  216. data/demo/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  217. data/demo/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  218. data/demo/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  219. data/demo/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  220. data/demo/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  221. data/demo/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  222. data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  223. data/demo/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  224. data/demo/config/tools/handbook_creator/templates/title.html.erb +1 -1
  225. data/demo/config/tools/launcher/launcher.txt +45 -45
  226. data/demo/config/tools/launcher/launcher2.txt +45 -45
  227. data/demo/config/tools/script_runner/script_runner.txt +3 -3
  228. data/demo/config/tools/table_manager/ConfigTables_def.txt +8 -8
  229. data/demo/config/tools/table_manager/ExampleTableDefinition.txt +24 -24
  230. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +25 -25
  231. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +25 -25
  232. data/demo/config/tools/table_manager/PPSSelectionTable_def.txt +8 -8
  233. data/demo/config/tools/table_manager/TLMMonitoringTable_def.txt +248 -248
  234. data/demo/config/tools/test_runner/test_runner.txt +17 -17
  235. data/demo/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  236. data/demo/config/tools/tlm_extractor/tlm_extractor2.txt +2 -2
  237. data/demo/config/tools/tlm_extractor/tlm_extractor3.txt +2 -2
  238. data/demo/config/tools/tlm_extractor/tlm_extractor4.txt +2 -2
  239. data/demo/config/tools/tlm_viewer/tlm_viewer.txt +41 -41
  240. data/demo/lib/example_background_task.rb +57 -52
  241. data/demo/lib/example_target.rb +113 -108
  242. data/demo/lib/scpi_target.rb +74 -74
  243. data/demo/lib/user_version.rb +3 -3
  244. data/demo/procedures/checks.rb +11 -11
  245. data/demo/procedures/clear_util.rb +7 -7
  246. data/demo/procedures/collect.rb +18 -18
  247. data/demo/procedures/collect_util.rb +14 -14
  248. data/demo/procedures/cosmos_api_test.rb +293 -293
  249. data/demo/procedures/disconnect.rb +29 -29
  250. data/demo/procedures/example_test.rb +182 -182
  251. data/demo/procedures/plot_test.rb +8 -8
  252. data/demo/procedures/run_example_test.rb +3 -3
  253. data/demo/procedures/test.rb +51 -51
  254. data/demo/tools/CmdExtractor +15 -15
  255. data/demo/tools/CmdExtractor.bat +59 -59
  256. data/demo/tools/CmdSender +15 -15
  257. data/demo/tools/CmdSender.bat +59 -59
  258. data/demo/tools/CmdTlmServer +15 -15
  259. data/demo/tools/CmdTlmServer.bat +59 -59
  260. data/demo/tools/DataViewer +15 -15
  261. data/demo/tools/DataViewer.bat +59 -59
  262. data/demo/tools/ExampleTarget +15 -15
  263. data/demo/tools/ExampleTarget.bat +59 -59
  264. data/demo/tools/HandbookCreator +15 -15
  265. data/demo/tools/HandbookCreator.bat +61 -61
  266. data/demo/tools/Launcher +15 -15
  267. data/demo/tools/Launcher.bat +59 -59
  268. data/demo/tools/LimitsMonitor +15 -15
  269. data/demo/tools/LimitsMonitor.bat +59 -59
  270. data/demo/tools/OpenGLBuilder +15 -15
  271. data/demo/tools/OpenGLBuilder.bat +59 -59
  272. data/demo/tools/PacketViewer +15 -15
  273. data/demo/tools/PacketViewer.bat +59 -59
  274. data/demo/tools/Replay +15 -15
  275. data/demo/tools/Replay.bat +59 -59
  276. data/demo/tools/ScpiTarget +15 -15
  277. data/demo/tools/ScpiTarget.bat +59 -59
  278. data/demo/tools/ScriptRunner +15 -15
  279. data/demo/tools/ScriptRunner.bat +59 -59
  280. data/demo/tools/TableManager +15 -15
  281. data/demo/tools/TableManager.bat +59 -59
  282. data/demo/tools/TestRunner +15 -15
  283. data/demo/tools/TestRunner.bat +59 -59
  284. data/demo/tools/TlmExtractor +15 -15
  285. data/demo/tools/TlmExtractor.bat +59 -59
  286. data/demo/tools/TlmGrapher +15 -15
  287. data/demo/tools/TlmGrapher.bat +59 -59
  288. data/demo/tools/TlmViewer +15 -15
  289. data/demo/tools/TlmViewer.bat +59 -59
  290. data/demo/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  291. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  292. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  293. data/demo/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  294. data/demo/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  295. data/demo/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  296. data/demo/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  297. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  298. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  299. data/demo/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  300. data/demo/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  301. data/demo/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  302. data/demo/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  303. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  304. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  305. data/demo/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  306. data/demo/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  307. data/demo/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  308. data/demo/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  309. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  310. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  311. data/demo/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  312. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  313. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  314. data/demo/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  315. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  316. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  317. data/demo/tools/mac/Replay.app/Contents/Info.plist +38 -38
  318. data/demo/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  319. data/demo/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  320. data/demo/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  321. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  322. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  323. data/demo/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  324. data/demo/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  325. data/demo/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  326. data/demo/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  327. data/demo/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  328. data/demo/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  329. data/demo/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  330. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  331. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  332. data/demo/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  333. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  334. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  335. data/demo/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  336. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  337. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  338. data/ext/cosmos/ext/array/array.c +111 -111
  339. data/ext/cosmos/ext/array/extconf.rb +13 -13
  340. data/ext/cosmos/ext/buffered_file/buffered_file.c +167 -167
  341. data/ext/cosmos/ext/buffered_file/extconf.rb +13 -13
  342. data/ext/cosmos/ext/config_parser/config_parser.c +237 -237
  343. data/ext/cosmos/ext/config_parser/extconf.rb +13 -13
  344. data/ext/cosmos/ext/cosmos_io/cosmos_io.c +117 -117
  345. data/ext/cosmos/ext/cosmos_io/extconf.rb +13 -13
  346. data/ext/cosmos/ext/crc/crc.c +341 -341
  347. data/ext/cosmos/ext/crc/extconf.rb +12 -12
  348. data/ext/cosmos/ext/line_graph/extconf.rb +13 -13
  349. data/ext/cosmos/ext/line_graph/line_graph.c +501 -501
  350. data/ext/cosmos/ext/low_fragmentation_array/extconf.rb +12 -12
  351. data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +261 -261
  352. data/ext/cosmos/ext/packet/extconf.rb +13 -13
  353. data/ext/cosmos/ext/packet/packet.c +339 -339
  354. data/ext/cosmos/ext/platform/extconf.rb +13 -13
  355. data/ext/cosmos/ext/platform/platform.c +81 -81
  356. data/ext/cosmos/ext/polynomial_conversion/extconf.rb +13 -13
  357. data/ext/cosmos/ext/polynomial_conversion/polynomial_conversion.c +73 -73
  358. data/ext/cosmos/ext/string/extconf.rb +13 -13
  359. data/ext/cosmos/ext/string/string.c +49 -49
  360. data/ext/cosmos/ext/structure/structure.c +894 -894
  361. data/ext/cosmos/ext/tabbed_plots_config/extconf.rb +13 -13
  362. data/ext/cosmos/ext/tabbed_plots_config/tabbed_plots_config.c +51 -51
  363. data/ext/cosmos/ext/telemetry/extconf.rb +13 -13
  364. data/ext/cosmos/ext/telemetry/telemetry.c +306 -306
  365. data/ext/mkrf_conf.rb +40 -40
  366. data/install/Gemfile +6 -6
  367. data/install/Launcher +14 -14
  368. data/install/Launcher.bat +59 -59
  369. data/install/Rakefile +61 -61
  370. data/install/config/data/crc.txt +134 -133
  371. data/install/config/system/system.txt +29 -29
  372. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  373. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  374. data/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  375. data/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  376. data/install/config/targets/COSMOS/screens/version.txt +19 -19
  377. data/install/config/targets/COSMOS/target.txt +8 -8
  378. data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  379. data/install/config/tools/data_viewer/data_viewer.txt +3 -3
  380. data/install/config/tools/handbook_creator/handbook_creator.txt +49 -49
  381. data/install/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  382. data/install/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  383. data/install/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  384. data/install/config/tools/handbook_creator/templates/header.html.erb +25 -25
  385. data/install/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  386. data/install/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  387. data/install/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  388. data/install/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  389. data/install/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  390. data/install/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  391. data/install/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  392. data/install/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  393. data/install/config/tools/handbook_creator/templates/title.html.erb +1 -1
  394. data/install/config/tools/launcher/launcher.txt +39 -39
  395. data/install/config/tools/script_runner/script_runner.txt +3 -3
  396. data/install/config/tools/test_runner/test_runner.txt +8 -8
  397. data/install/config/tools/tlm_viewer/tlm_viewer.txt +5 -5
  398. data/install/lib/user_version.rb +3 -3
  399. data/install/tools/CmdExtractor +15 -15
  400. data/install/tools/CmdExtractor.bat +59 -59
  401. data/install/tools/CmdSender +15 -15
  402. data/install/tools/CmdSender.bat +59 -59
  403. data/install/tools/CmdTlmServer +15 -15
  404. data/install/tools/CmdTlmServer.bat +59 -59
  405. data/install/tools/DataViewer +15 -15
  406. data/install/tools/DataViewer.bat +59 -59
  407. data/install/tools/HandbookCreator +15 -15
  408. data/install/tools/HandbookCreator.bat +61 -61
  409. data/install/tools/Launcher +15 -15
  410. data/install/tools/Launcher.bat +59 -59
  411. data/install/tools/LimitsMonitor +15 -15
  412. data/install/tools/LimitsMonitor.bat +59 -59
  413. data/install/tools/OpenGLBuilder +15 -15
  414. data/install/tools/OpenGLBuilder.bat +59 -59
  415. data/install/tools/PacketViewer +15 -15
  416. data/install/tools/PacketViewer.bat +59 -59
  417. data/install/tools/Replay +15 -15
  418. data/install/tools/Replay.bat +59 -59
  419. data/install/tools/ScriptRunner +15 -15
  420. data/install/tools/ScriptRunner.bat +59 -59
  421. data/install/tools/TableManager +15 -15
  422. data/install/tools/TableManager.bat +59 -59
  423. data/install/tools/TestRunner +15 -15
  424. data/install/tools/TestRunner.bat +59 -59
  425. data/install/tools/TlmExtractor +15 -15
  426. data/install/tools/TlmExtractor.bat +59 -59
  427. data/install/tools/TlmGrapher +15 -15
  428. data/install/tools/TlmGrapher.bat +59 -59
  429. data/install/tools/TlmViewer +15 -15
  430. data/install/tools/TlmViewer.bat +59 -59
  431. data/install/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  432. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  433. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  434. data/install/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  435. data/install/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  436. data/install/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  437. data/install/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  438. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  439. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  440. data/install/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  441. data/install/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  442. data/install/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  443. data/install/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  444. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  445. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  446. data/install/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  447. data/install/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  448. data/install/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  449. data/install/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  450. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  451. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  452. data/install/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  453. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  454. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  455. data/install/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  456. data/install/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  457. data/install/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  458. data/install/tools/mac/Replay.app/Contents/Info.plist +38 -38
  459. data/install/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  460. data/install/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  461. data/install/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  462. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  463. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  464. data/install/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  465. data/install/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  466. data/install/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  467. data/install/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  468. data/install/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  469. data/install/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  470. data/install/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  471. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  472. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  473. data/install/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  474. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  475. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  476. data/install/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  477. data/install/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  478. data/install/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  479. data/lib/cosmos.rb +63 -63
  480. data/lib/cosmos/ccsds/ccsds_packet.rb +63 -63
  481. data/lib/cosmos/ccsds/ccsds_parser.rb +143 -143
  482. data/lib/cosmos/config/config_parser.rb +324 -324
  483. data/lib/cosmos/conversions.rb +13 -13
  484. data/lib/cosmos/conversions/conversion.rb +47 -47
  485. data/lib/cosmos/conversions/generic_conversion.rb +55 -55
  486. data/lib/cosmos/conversions/new_packet_log_conversion.rb +45 -45
  487. data/lib/cosmos/conversions/polynomial_conversion.rb +57 -57
  488. data/lib/cosmos/conversions/processor_conversion.rb +46 -46
  489. data/lib/cosmos/conversions/received_count_conversion.rb +33 -33
  490. data/lib/cosmos/conversions/received_time_formatted_conversion.rb +37 -37
  491. data/lib/cosmos/conversions/received_time_seconds_conversion.rb +37 -37
  492. data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +128 -128
  493. data/lib/cosmos/conversions/unix_time_conversion.rb +50 -50
  494. data/lib/cosmos/conversions/unix_time_formatted_conversion.rb +44 -44
  495. data/lib/cosmos/conversions/unix_time_seconds_conversion.rb +44 -44
  496. data/lib/cosmos/core_ext.rb +18 -18
  497. data/lib/cosmos/core_ext/array.rb +354 -354
  498. data/lib/cosmos/core_ext/class.rb +51 -51
  499. data/lib/cosmos/core_ext/cosmos_io.rb +29 -29
  500. data/lib/cosmos/core_ext/exception.rb +52 -52
  501. data/lib/cosmos/core_ext/file.rb +75 -75
  502. data/lib/cosmos/core_ext/hash.rb +28 -28
  503. data/lib/cosmos/core_ext/io.rb +75 -75
  504. data/lib/cosmos/core_ext/kernel.rb +38 -38
  505. data/lib/cosmos/core_ext/math.rb +119 -119
  506. data/lib/cosmos/core_ext/matrix.rb +146 -146
  507. data/lib/cosmos/core_ext/objectspace.rb +29 -29
  508. data/lib/cosmos/core_ext/range.rb +22 -22
  509. data/lib/cosmos/core_ext/socket.rb +32 -32
  510. data/lib/cosmos/core_ext/string.rb +310 -310
  511. data/lib/cosmos/core_ext/stringio.rb +24 -24
  512. data/lib/cosmos/core_ext/time.rb +446 -446
  513. data/lib/cosmos/gui/choosers/combobox_chooser.rb +130 -130
  514. data/lib/cosmos/gui/choosers/file_chooser.rb +68 -68
  515. data/lib/cosmos/gui/choosers/float_chooser.rb +82 -82
  516. data/lib/cosmos/gui/choosers/integer_chooser.rb +80 -80
  517. data/lib/cosmos/gui/choosers/string_chooser.rb +53 -53
  518. data/lib/cosmos/gui/choosers/telemetry_chooser.rb +317 -317
  519. data/lib/cosmos/gui/dialogs/about_dialog.rb +128 -128
  520. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +136 -136
  521. data/lib/cosmos/gui/dialogs/cmd_details_dialog.rb +52 -52
  522. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +149 -149
  523. data/lib/cosmos/gui/dialogs/details_dialog.rb +174 -174
  524. data/lib/cosmos/gui/dialogs/exception_dialog.rb +97 -97
  525. data/lib/cosmos/gui/dialogs/exception_list_dialog.rb +59 -59
  526. data/lib/cosmos/gui/dialogs/find_replace_dialog.rb +196 -196
  527. data/lib/cosmos/gui/dialogs/legal_dialog.rb +169 -168
  528. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +118 -118
  529. data/lib/cosmos/gui/dialogs/progress_dialog.rb +270 -262
  530. data/lib/cosmos/gui/dialogs/pry_dialog.rb +165 -161
  531. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +37 -37
  532. data/lib/cosmos/gui/dialogs/select_dialog.rb +54 -54
  533. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +131 -131
  534. data/lib/cosmos/gui/dialogs/splash.rb +113 -113
  535. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +206 -206
  536. data/lib/cosmos/gui/dialogs/tlm_edit_dialog.rb +81 -81
  537. data/lib/cosmos/gui/line_graph/line_graph.rb +456 -456
  538. data/lib/cosmos/gui/line_graph/line_graph_dialog.rb +34 -34
  539. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +494 -494
  540. data/lib/cosmos/gui/line_graph/line_graph_popups.rb +116 -116
  541. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +460 -460
  542. data/lib/cosmos/gui/line_graph/line_graph_script.rb +26 -26
  543. data/lib/cosmos/gui/line_graph/lines.rb +290 -290
  544. data/lib/cosmos/gui/line_graph/overview_graph.rb +459 -459
  545. data/lib/cosmos/gui/opengl/earth_model.rb +22 -22
  546. data/lib/cosmos/gui/opengl/gl_bounds.rb +67 -67
  547. data/lib/cosmos/gui/opengl/gl_light.rb +39 -39
  548. data/lib/cosmos/gui/opengl/gl_material.rb +29 -29
  549. data/lib/cosmos/gui/opengl/gl_scene.rb +72 -72
  550. data/lib/cosmos/gui/opengl/gl_shape.rb +146 -146
  551. data/lib/cosmos/gui/opengl/gl_viewer.rb +724 -712
  552. data/lib/cosmos/gui/opengl/gl_viewport.rb +35 -35
  553. data/lib/cosmos/gui/opengl/moon_model.rb +22 -22
  554. data/lib/cosmos/gui/opengl/opengl.rb +8 -8
  555. data/lib/cosmos/gui/opengl/stl_reader.rb +211 -211
  556. data/lib/cosmos/gui/opengl/stl_shape.rb +124 -124
  557. data/lib/cosmos/gui/opengl/texture_mapped_sphere.rb +202 -202
  558. data/lib/cosmos/gui/qt.rb +813 -786
  559. data/lib/cosmos/gui/qt_tool.rb +378 -373
  560. data/lib/cosmos/gui/text/completion.rb +381 -381
  561. data/lib/cosmos/gui/text/completion_line_edit.rb +30 -30
  562. data/lib/cosmos/gui/text/completion_text_edit.rb +179 -179
  563. data/lib/cosmos/gui/text/ruby_editor.rb +395 -395
  564. data/lib/cosmos/gui/utilities/screenshot.rb +25 -25
  565. data/lib/cosmos/gui/utilities/script_module_gui.rb +203 -203
  566. data/lib/cosmos/gui/widgets/full_text_search_line_edit.rb +161 -161
  567. data/lib/cosmos/gui/widgets/packet_log_frame.rb +305 -305
  568. data/lib/cosmos/gui/widgets/realtime_button_bar.rb +98 -98
  569. data/lib/cosmos/interfaces.rb +11 -11
  570. data/lib/cosmos/interfaces/cmd_tlm_server_interface.rb +153 -149
  571. data/lib/cosmos/interfaces/interface.rb +213 -213
  572. data/lib/cosmos/interfaces/linc_interface.rb +360 -360
  573. data/lib/cosmos/interfaces/serial_interface.rb +76 -76
  574. data/lib/cosmos/interfaces/simulated_target_interface.rb +129 -128
  575. data/lib/cosmos/interfaces/stream_interface.rb +156 -156
  576. data/lib/cosmos/interfaces/tcpip_client_interface.rb +60 -60
  577. data/lib/cosmos/interfaces/tcpip_server_interface.rb +154 -154
  578. data/lib/cosmos/interfaces/udp_interface.rb +173 -173
  579. data/lib/cosmos/io/buffered_file.rb +11 -11
  580. data/lib/cosmos/io/cosmos_snmp.rb +50 -50
  581. data/lib/cosmos/io/io_multiplexer.rb +89 -89
  582. data/lib/cosmos/io/json_drb.rb +344 -320
  583. data/lib/cosmos/io/json_drb_object.rb +137 -137
  584. data/lib/cosmos/io/json_rpc.rb +365 -365
  585. data/lib/cosmos/io/posix_serial_driver.rb +145 -145
  586. data/lib/cosmos/io/raw_logger.rb +174 -174
  587. data/lib/cosmos/io/raw_logger_pair.rb +71 -71
  588. data/lib/cosmos/io/serial_driver.rb +85 -85
  589. data/lib/cosmos/io/stderr.rb +36 -36
  590. data/lib/cosmos/io/stdout.rb +36 -36
  591. data/lib/cosmos/io/tcpip_server.rb +583 -532
  592. data/lib/cosmos/io/udp_sockets.rb +152 -152
  593. data/lib/cosmos/io/win32_serial_driver.rb +147 -147
  594. data/lib/cosmos/packet_logs.rb +6 -6
  595. data/lib/cosmos/packet_logs/meta_packet_log_writer.rb +107 -107
  596. data/lib/cosmos/packet_logs/packet_log_reader.rb +441 -439
  597. data/lib/cosmos/packet_logs/packet_log_writer.rb +321 -309
  598. data/lib/cosmos/packet_logs/packet_log_writer_pair.rb +30 -30
  599. data/lib/cosmos/packets/binary_accessor.rb +921 -921
  600. data/lib/cosmos/packets/commands.rb +291 -291
  601. data/lib/cosmos/packets/limits.rb +263 -263
  602. data/lib/cosmos/packets/limits_response.rb +38 -38
  603. data/lib/cosmos/packets/packet.rb +714 -699
  604. data/lib/cosmos/packets/packet_config.rb +1034 -1034
  605. data/lib/cosmos/packets/packet_item.rb +317 -317
  606. data/lib/cosmos/packets/packet_item_limits.rb +128 -128
  607. data/lib/cosmos/packets/structure.rb +421 -386
  608. data/lib/cosmos/packets/structure_item.rb +233 -233
  609. data/lib/cosmos/packets/telemetry.rb +317 -317
  610. data/lib/cosmos/processors.rb +6 -6
  611. data/lib/cosmos/processors/new_packet_log_processor.rb +34 -34
  612. data/lib/cosmos/processors/processor.rb +71 -71
  613. data/lib/cosmos/processors/statistics_processor.rb +65 -65
  614. data/lib/cosmos/processors/watermark_processor.rb +44 -44
  615. data/lib/cosmos/script.rb +9 -9
  616. data/lib/cosmos/script/extract.rb +115 -115
  617. data/lib/cosmos/script/script.rb +1513 -1493
  618. data/lib/cosmos/streams/burst_stream_protocol.rb +25 -25
  619. data/lib/cosmos/streams/fixed_stream_protocol.rb +111 -111
  620. data/lib/cosmos/streams/length_stream_protocol.rb +140 -140
  621. data/lib/cosmos/streams/preidentified_stream_protocol.rb +118 -118
  622. data/lib/cosmos/streams/serial_stream.rb +152 -143
  623. data/lib/cosmos/streams/stream.rb +57 -57
  624. data/lib/cosmos/streams/stream_protocol.rb +369 -369
  625. data/lib/cosmos/streams/tcpip_client_stream.rb +77 -77
  626. data/lib/cosmos/streams/tcpip_socket_stream.rb +139 -139
  627. data/lib/cosmos/streams/template_stream_protocol.rb +140 -140
  628. data/lib/cosmos/streams/terminated_stream_protocol.rb +81 -81
  629. data/lib/cosmos/system.rb +4 -4
  630. data/lib/cosmos/system/system.rb +558 -558
  631. data/lib/cosmos/system/target.rb +178 -178
  632. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +254 -253
  633. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +716 -716
  634. data/lib/cosmos/tools/cmd_sender/cmd_sender_item_delegate.rb +77 -77
  635. data/lib/cosmos/tools/cmd_sender/cmd_sender_text_edit.rb +70 -70
  636. data/lib/cosmos/tools/cmd_tlm_server/api.rb +936 -940
  637. data/lib/cosmos/tools/cmd_tlm_server/background_task.rb +46 -46
  638. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +67 -63
  639. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +511 -497
  640. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +241 -241
  641. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +1033 -1008
  642. data/lib/cosmos/tools/cmd_tlm_server/commanding.rb +112 -112
  643. data/lib/cosmos/tools/cmd_tlm_server/connections.rb +176 -176
  644. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +241 -221
  645. data/lib/cosmos/tools/cmd_tlm_server/interfaces.rb +127 -127
  646. data/lib/cosmos/tools/cmd_tlm_server/packet_logging.rb +132 -132
  647. data/lib/cosmos/tools/cmd_tlm_server/router_thread.rb +66 -66
  648. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +97 -97
  649. data/lib/cosmos/tools/data_viewer/data_viewer.rb +628 -600
  650. data/lib/cosmos/tools/data_viewer/data_viewer_component.rb +167 -167
  651. data/lib/cosmos/tools/data_viewer/dump_component.rb +40 -40
  652. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +149 -149
  653. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +360 -360
  654. data/lib/cosmos/tools/launcher/launcher.rb +184 -184
  655. data/lib/cosmos/tools/launcher/launcher_config.rb +175 -167
  656. data/lib/cosmos/tools/launcher/launcher_multitool.rb +40 -41
  657. data/lib/cosmos/tools/launcher/launcher_tool.rb +104 -104
  658. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +796 -768
  659. data/lib/cosmos/tools/opengl_builder/opengl_builder.rb +416 -416
  660. data/lib/cosmos/tools/opengl_builder/scene_config.rb +118 -118
  661. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +525 -525
  662. data/lib/cosmos/tools/replay/replay.rb +495 -488
  663. data/lib/cosmos/tools/replay/replay_server.rb +91 -91
  664. data/lib/cosmos/tools/script_runner/script_audit.rb +147 -139
  665. data/lib/cosmos/tools/script_runner/script_runner.rb +914 -914
  666. data/lib/cosmos/tools/script_runner/script_runner_config.rb +40 -40
  667. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +1892 -1859
  668. data/lib/cosmos/tools/table_manager/table.rb +70 -70
  669. data/lib/cosmos/tools/table_manager/table_config.rb +764 -764
  670. data/lib/cosmos/tools/table_manager/table_item.rb +74 -74
  671. data/lib/cosmos/tools/table_manager/table_manager.rb +1065 -1065
  672. data/lib/cosmos/tools/table_manager/table_manager_core.rb +539 -539
  673. data/lib/cosmos/tools/test_runner/results_writer.rb +283 -283
  674. data/lib/cosmos/tools/test_runner/test.rb +480 -480
  675. data/lib/cosmos/tools/test_runner/test_runner.rb +1157 -1157
  676. data/lib/cosmos/tools/test_runner/test_runner_chooser.rb +338 -338
  677. data/lib/cosmos/tools/tlm_extractor/text_item_chooser.rb +60 -60
  678. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +1008 -1008
  679. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +371 -371
  680. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +60 -60
  681. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +75 -75
  682. data/lib/cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder.rb +44 -44
  683. data/lib/cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder.rb +94 -94
  684. data/lib/cosmos/tools/tlm_grapher/data_object_editors/data_object_editor.rb +61 -61
  685. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +180 -180
  686. data/lib/cosmos/tools/tlm_grapher/data_object_editors/linegraph_data_object_editor.rb +141 -141
  687. data/lib/cosmos/tools/tlm_grapher/data_object_editors/singlexy_data_object_editor.rb +30 -30
  688. data/lib/cosmos/tools/tlm_grapher/data_object_editors/xy_data_object_editor.rb +173 -173
  689. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +177 -177
  690. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +412 -409
  691. data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +176 -176
  692. data/lib/cosmos/tools/tlm_grapher/data_objects/singlexy_data_object.rb +25 -25
  693. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +323 -320
  694. data/lib/cosmos/tools/tlm_grapher/plot_editors/linegraph_plot_editor.rb +181 -181
  695. data/lib/cosmos/tools/tlm_grapher/plot_editors/plot_editor.rb +28 -28
  696. data/lib/cosmos/tools/tlm_grapher/plot_editors/singlexy_plot_editor.rb +30 -30
  697. data/lib/cosmos/tools/tlm_grapher/plot_editors/xy_plot_editor.rb +59 -59
  698. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/linegraph_plot_gui_object.rb +172 -172
  699. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/singlexy_plot_gui_object.rb +27 -27
  700. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/xy_plot_gui_object.rb +74 -74
  701. data/lib/cosmos/tools/tlm_grapher/plots/linegraph_plot.rb +201 -201
  702. data/lib/cosmos/tools/tlm_grapher/plots/plot.rb +69 -69
  703. data/lib/cosmos/tools/tlm_grapher/plots/singlexy_plot.rb +20 -20
  704. data/lib/cosmos/tools/tlm_grapher/plots/xy_plot.rb +61 -61
  705. data/lib/cosmos/tools/tlm_grapher/tabbed_plots/overview_tabbed_plots.rb +1278 -1278
  706. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +430 -430
  707. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_data_object_editor.rb +107 -107
  708. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_logfile_thread.rb +111 -95
  709. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor.rb +101 -101
  710. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +72 -66
  711. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tab.rb +57 -57
  712. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +1004 -1004
  713. data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +87 -87
  714. data/lib/cosmos/tools/tlm_viewer/screen.rb +486 -458
  715. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +563 -544
  716. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +287 -287
  717. data/lib/cosmos/tools/tlm_viewer/widgets.rb +53 -53
  718. data/lib/cosmos/tools/tlm_viewer/widgets/aging_widget.rb +110 -110
  719. data/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb +70 -70
  720. data/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb +61 -61
  721. data/lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb +39 -39
  722. data/lib/cosmos/tools/tlm_viewer/widgets/canvas_widget.rb +62 -62
  723. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimage_widget.rb +41 -41
  724. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimagevalue_widget.rb +57 -57
  725. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabel_widget.rb +37 -37
  726. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabelvalue_widget.rb +56 -56
  727. data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +55 -55
  728. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +66 -66
  729. data/lib/cosmos/tools/tlm_viewer/widgets/canvasvalue_widget.rb +124 -124
  730. data/lib/cosmos/tools/tlm_viewer/widgets/checkbutton_widget.rb +31 -31
  731. data/lib/cosmos/tools/tlm_viewer/widgets/combobox_widget.rb +30 -30
  732. data/lib/cosmos/tools/tlm_viewer/widgets/formatfontvalue_widget.rb +36 -36
  733. data/lib/cosmos/tools/tlm_viewer/widgets/formatvalue_widget.rb +35 -35
  734. data/lib/cosmos/tools/tlm_viewer/widgets/horizontal_widget.rb +27 -27
  735. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalbox_widget.rb +31 -31
  736. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalline_widget.rb +26 -26
  737. data/lib/cosmos/tools/tlm_viewer/widgets/label_widget.rb +29 -29
  738. data/lib/cosmos/tools/tlm_viewer/widgets/labelformatvalue_widget.rb +39 -39
  739. data/lib/cosmos/tools/tlm_viewer/widgets/labelprogressbar_widget.rb +38 -38
  740. data/lib/cosmos/tools/tlm_viewer/widgets/labeltrendlimitsbar_widget.rb +38 -38
  741. data/lib/cosmos/tools/tlm_viewer/widgets/labelvalue_widget.rb +39 -39
  742. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluedesc_widget.rb +42 -42
  743. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluelimitsbar_widget.rb +37 -37
  744. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluerangebar_widget.rb +37 -37
  745. data/lib/cosmos/tools/tlm_viewer/widgets/layout_widget.rb +34 -34
  746. data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +178 -178
  747. data/lib/cosmos/tools/tlm_viewer/widgets/linegraph_widget.rb +54 -54
  748. data/lib/cosmos/tools/tlm_viewer/widgets/matrixbycolumns_widget.rb +47 -47
  749. data/lib/cosmos/tools/tlm_viewer/widgets/multi_widget.rb +116 -116
  750. data/lib/cosmos/tools/tlm_viewer/widgets/progressbar_widget.rb +34 -34
  751. data/lib/cosmos/tools/tlm_viewer/widgets/radiobutton_widget.rb +30 -30
  752. data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +57 -57
  753. data/lib/cosmos/tools/tlm_viewer/widgets/screenshotbutton_widget.rb +34 -34
  754. data/lib/cosmos/tools/tlm_viewer/widgets/scrollwindow_widget.rb +35 -35
  755. data/lib/cosmos/tools/tlm_viewer/widgets/sectionheader_widget.rb +33 -33
  756. data/lib/cosmos/tools/tlm_viewer/widgets/tabbook_widget.rb +26 -26
  757. data/lib/cosmos/tools/tlm_viewer/widgets/tabitem_widget.rb +28 -28
  758. data/lib/cosmos/tools/tlm_viewer/widgets/textbox_widget.rb +47 -47
  759. data/lib/cosmos/tools/tlm_viewer/widgets/textfield_widget.rb +26 -26
  760. data/lib/cosmos/tools/tlm_viewer/widgets/timegraph_widget.rb +88 -88
  761. data/lib/cosmos/tools/tlm_viewer/widgets/title_widget.rb +27 -27
  762. data/lib/cosmos/tools/tlm_viewer/widgets/trendbar_widget.rb +130 -130
  763. data/lib/cosmos/tools/tlm_viewer/widgets/trendlimitsbar_widget.rb +46 -46
  764. data/lib/cosmos/tools/tlm_viewer/widgets/value_widget.rb +43 -43
  765. data/lib/cosmos/tools/tlm_viewer/widgets/valuelimitsbar_widget.rb +37 -37
  766. data/lib/cosmos/tools/tlm_viewer/widgets/valuerangebar_widget.rb +37 -37
  767. data/lib/cosmos/tools/tlm_viewer/widgets/vertical_widget.rb +35 -35
  768. data/lib/cosmos/tools/tlm_viewer/widgets/verticalbox_widget.rb +37 -37
  769. data/lib/cosmos/tools/tlm_viewer/widgets/widget.rb +257 -257
  770. data/lib/cosmos/top_level.rb +647 -596
  771. data/lib/cosmos/utilities.rb +11 -10
  772. data/lib/cosmos/utilities/crc.rb +166 -166
  773. data/lib/cosmos/utilities/csv.rb +83 -83
  774. data/lib/cosmos/utilities/logger.rb +137 -137
  775. data/lib/cosmos/utilities/low_fragmentation_array.rb +11 -11
  776. data/lib/cosmos/utilities/message_log.rb +74 -74
  777. data/lib/cosmos/utilities/quaternion.rb +258 -258
  778. data/lib/cosmos/utilities/ruby_lex_utils.rb +313 -313
  779. data/lib/cosmos/utilities/simulated_target.rb +99 -99
  780. data/lib/cosmos/utilities/sleeper.rb +44 -0
  781. data/lib/cosmos/version.rb +12 -12
  782. data/lib/cosmos/win32/excel.rb +66 -66
  783. data/lib/cosmos/win32/win32.rb +387 -387
  784. data/lib/cosmos/win32/win32_main.rb +311 -311
  785. data/roodi.yml +24 -24
  786. data/run_gui_tests.bat +32 -32
  787. data/spec/ccsds/ccsds_packet_spec.rb +67 -67
  788. data/spec/ccsds/ccsds_parser_spec.rb +148 -148
  789. data/spec/config/config_parser_spec.rb +322 -322
  790. data/spec/conversions/conversion_spec.rb +31 -31
  791. data/spec/conversions/generic_conversion_spec.rb +45 -45
  792. data/spec/conversions/new_packet_log_conversion_spec.rb +39 -39
  793. data/spec/conversions/polynomial_conversion_spec.rb +40 -40
  794. data/spec/conversions/processor_conversion_spec.rb +45 -45
  795. data/spec/conversions/received_count_conversion_spec.rb +43 -43
  796. data/spec/conversions/received_time_formatted_conversion_spec.rb +49 -49
  797. data/spec/conversions/received_time_seconds_conversion_spec.rb +50 -50
  798. data/spec/conversions/segmented_polynomial_conversion_spec.rb +51 -51
  799. data/spec/conversions/unix_time_formatted_conversion_spec.rb +74 -74
  800. data/spec/conversions/unix_time_seconds_conversion_spec.rb +76 -76
  801. data/spec/core_ext/array_spec.rb +186 -186
  802. data/spec/core_ext/class_spec.rb +36 -36
  803. data/spec/core_ext/cosmos_io_spec.rb +77 -77
  804. data/spec/core_ext/exception_spec.rb +91 -91
  805. data/spec/core_ext/file_spec.rb +72 -72
  806. data/spec/core_ext/hash_spec.rb +24 -24
  807. data/spec/core_ext/io_spec.rb +46 -46
  808. data/spec/core_ext/kernel_spec.rb +54 -54
  809. data/spec/core_ext/math_spec.rb +116 -116
  810. data/spec/core_ext/matrix_spec.rb +66 -66
  811. data/spec/core_ext/objectspace_spec.rb +29 -29
  812. data/spec/core_ext/range_spec.rb +21 -21
  813. data/spec/core_ext/socket_spec.rb +32 -32
  814. data/spec/core_ext/string_spec.rb +223 -223
  815. data/spec/core_ext/stringio_spec.rb +21 -21
  816. data/spec/core_ext/time_spec.rb +151 -151
  817. data/spec/gui/line_graph/line_clip_spec.rb +322 -322
  818. data/spec/install/config/system/system.txt +33 -33
  819. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  820. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  821. data/spec/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  822. data/spec/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  823. data/spec/install/config/targets/COSMOS/screens/version.txt +19 -19
  824. data/spec/install/config/targets/COSMOS/target.txt +5 -5
  825. data/spec/install/config/targets/INST/cmd_tlm/inst_cmd_linc.txt +30 -30
  826. data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +111 -111
  827. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm.txt +236 -236
  828. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm_linc.txt +25 -25
  829. data/spec/install/config/targets/INST/cmd_tlm_server.txt +5 -5
  830. data/spec/install/config/targets/INST/lib/sim_inst.rb +305 -294
  831. data/spec/install/config/targets/INST/target.txt +10 -10
  832. data/spec/install/config/targets/META/cmd_tlm/meta_cmd.txt +4 -4
  833. data/spec/install/config/targets/META/cmd_tlm/meta_tlm.txt +4 -4
  834. data/spec/install/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  835. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +150 -150
  836. data/spec/interfaces/interface_spec.rb +130 -131
  837. data/spec/interfaces/linc_interface_spec.rb +199 -199
  838. data/spec/interfaces/serial_interface_spec.rb +56 -56
  839. data/spec/interfaces/simulated_target_interface_spec.rb +128 -128
  840. data/spec/interfaces/stream_interface_spec.rb +157 -157
  841. data/spec/interfaces/tcpip_client_interface_spec.rb +54 -54
  842. data/spec/interfaces/tcpip_server_interface_spec.rb +151 -151
  843. data/spec/interfaces/udp_interface_spec.rb +175 -177
  844. data/spec/io/buffered_file_spec.rb +113 -113
  845. data/spec/io/io_multiplexer_spec.rb +94 -94
  846. data/spec/io/json_drb_object_spec.rb +99 -99
  847. data/spec/io/json_drb_spec.rb +311 -311
  848. data/spec/io/json_rpc_spec.rb +264 -264
  849. data/spec/io/raw_logger_pair_spec.rb +76 -76
  850. data/spec/io/raw_logger_spec.rb +133 -133
  851. data/spec/io/serial_driver_spec.rb +61 -61
  852. data/spec/io/stderr_spec.rb +32 -32
  853. data/spec/io/stdout_spec.rb +32 -32
  854. data/spec/io/tcpip_server_spec.rb +338 -338
  855. data/spec/io/udp_sockets_spec.rb +94 -94
  856. data/spec/io/win32_serial_driver_spec.rb +88 -88
  857. data/spec/packet_logs/meta_packet_log_writer_spec.rb +170 -170
  858. data/spec/packet_logs/packet_log_reader_spec.rb +408 -408
  859. data/spec/packet_logs/packet_log_writer_pair_spec.rb +30 -30
  860. data/spec/packet_logs/packet_log_writer_spec.rb +223 -223
  861. data/spec/packets/binary_accessor_spec.rb +2073 -2073
  862. data/spec/packets/commands_spec.rb +369 -369
  863. data/spec/packets/limits_response_spec.rb +25 -25
  864. data/spec/packets/limits_spec.rb +326 -326
  865. data/spec/packets/packet_config_spec.rb +1620 -1620
  866. data/spec/packets/packet_item_limits_spec.rb +161 -161
  867. data/spec/packets/packet_item_spec.rb +386 -386
  868. data/spec/packets/packet_spec.rb +1057 -949
  869. data/spec/packets/structure_item_spec.rb +195 -195
  870. data/spec/packets/structure_spec.rb +419 -419
  871. data/spec/packets/telemetry_spec.rb +535 -535
  872. data/spec/processors/new_packet_log_processor_spec.rb +39 -39
  873. data/spec/processors/processor_spec.rb +55 -55
  874. data/spec/processors/statistics_processor_spec.rb +60 -60
  875. data/spec/processors/watermark_processor_spec.rb +51 -51
  876. data/spec/script/script_spec.rb +654 -654
  877. data/spec/spec_helper.rb +154 -148
  878. data/spec/streams/burst_stream_protocol_spec.rb +32 -32
  879. data/spec/streams/fixed_stream_protocol_spec.rb +110 -110
  880. data/spec/streams/length_stream_protocol_spec.rb +297 -297
  881. data/spec/streams/preidentified_stream_protocol_spec.rb +118 -118
  882. data/spec/streams/serial_stream_spec.rb +105 -105
  883. data/spec/streams/stream_protocol_spec.rb +332 -332
  884. data/spec/streams/stream_spec.rb +29 -29
  885. data/spec/streams/tcpip_client_stream_spec.rb +54 -54
  886. data/spec/streams/tcpip_socket_stream_spec.rb +146 -146
  887. data/spec/streams/template_stream_protocol_spec.rb +151 -151
  888. data/spec/streams/terminated_stream_protocol_spec.rb +123 -123
  889. data/spec/system/system_spec.rb +645 -645
  890. data/spec/system/target_spec.rb +248 -248
  891. data/spec/tools/cmd_tlm_server/api_spec.rb +1087 -1113
  892. data/spec/tools/cmd_tlm_server/background_task_spec.rb +32 -32
  893. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +81 -81
  894. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +411 -411
  895. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +415 -415
  896. data/spec/tools/cmd_tlm_server/commanding_spec.rb +123 -123
  897. data/spec/tools/cmd_tlm_server/connections_spec.rb +147 -147
  898. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +306 -306
  899. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +252 -238
  900. data/spec/tools/cmd_tlm_server/packet_logging_spec.rb +143 -143
  901. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +98 -101
  902. data/spec/tools/cmd_tlm_server/routers_spec.rb +223 -208
  903. data/spec/top_level/top_level_spec.rb +334 -321
  904. data/spec/utilities/crc_spec.rb +45 -45
  905. data/spec/utilities/csv_spec.rb +97 -97
  906. data/spec/utilities/logger_spec.rb +102 -102
  907. data/spec/utilities/message_log_spec.rb +89 -89
  908. data/spec/utilities/quaternion_spec.rb +107 -107
  909. data/spec/utilities/ruby_lex_utils_spec.rb +86 -86
  910. data/tasks/manifest.rake +22 -22
  911. data/tasks/spec.rake +23 -23
  912. metadata +18 -2
@@ -1,1157 +1,1157 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
-
11
- require 'cosmos'
12
- Cosmos.catch_fatal_exception do
13
- require 'ostruct'
14
- require 'cosmos/gui/qt_tool'
15
- require 'cosmos/tools/test_runner/test'
16
- require 'cosmos/tools/test_runner/results_writer'
17
- require 'cosmos/tools/test_runner/test_runner_chooser'
18
- require 'cosmos/tools/script_runner/script_runner_frame'
19
- require 'cosmos/tools/script_runner/script_audit'
20
- require 'cosmos/gui/dialogs/progress_dialog'
21
- require 'cosmos/gui/dialogs/scroll_text_dialog'
22
- require 'yard'
23
- end
24
-
25
- module Cosmos
26
-
27
- # Placeholder for all tests discovered without assigned TestSuites
28
- class UnassignedTestSuite < TestSuite
29
- end
30
-
31
- # TestRunner provides a framework for running repeatable sets of tests.
32
- # Individual Test Cases are grouped into Test Groups which are collected into
33
- # Test Suites. Test Cases can have manual sections and can be looped
34
- # indefinitely. After all the tests have run a test report is generated which
35
- # lists the pass / fail status of each test case.
36
- class TestRunner < QtTool
37
- slots 'status_timeout()'
38
-
39
- @@test_suites = []
40
- @@suites = {}
41
- @@results_writer = ResultsWriter.new
42
- @@settings = {}
43
- @@started_success = false
44
- @@instance = nil
45
-
46
- UNASSIGNED_SUITE_DESCRIPTION = "This Test Suite is created automatically " \
47
- "by Test Runner to hold all Tests that have not been added to Test " \
48
- "Suites. Consider adding these tests to explicit Test Suites to " \
49
- "eliminate this catch all Test Suite."
50
-
51
- def initialize(options)
52
- # All code before super is executed twice in RubyQt Based classes
53
- super(options) # MUST BE FIRST
54
- Cosmos.load_cosmos_icon("test_runner.png")
55
-
56
- # Add procedures to search path
57
- System.paths['PROCEDURES'].each do |path|
58
- Cosmos.add_to_search_path(path)
59
- end
60
-
61
- initialize_actions()
62
- initialize_menus()
63
- initialize_central_widget()
64
- complete_initialize()
65
-
66
- # Instance variables
67
- @utilities = []
68
- @procedure_dirs = System.paths['PROCEDURES']
69
- @server_config_file = options.server_config_file
70
- @ignore_tests = []
71
- @ignore_test_suites = []
72
- Splash.execute(self) do |splash|
73
- ConfigParser.splash = splash
74
- process_config(options.config_file)
75
- ConfigParser.splash = nil
76
- end
77
-
78
- # Timeout to update executing test case status
79
- @timer = Qt::Timer.new(self)
80
- connect(@timer, SIGNAL('timeout()'), self, SLOT('status_timeout()'))
81
- @timer.method_missing(:start, 100)
82
-
83
- @@instance = self
84
- end
85
-
86
- def initialize_actions
87
- super()
88
-
89
- # File Actions
90
- @show_last = Qt::Action.new(tr('Show &Results'), self)
91
- @show_last_keyseq = Qt::KeySequence.new(tr('Ctrl+R'))
92
- @show_last.shortcut = @show_last_keyseq
93
- @show_last.statusTip = tr('Show the Results dialog from the last run')
94
- @show_last.connect(SIGNAL('triggered()')) { show_results }
95
-
96
- @select = Qt::Action.new(tr('Test &Selection'), self)
97
- @select_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
98
- @select.shortcut = @select_keyseq
99
- @select.statusTip = tr('Select Test Suites/Groups/Cases')
100
- @select.connect(SIGNAL('triggered()')) { show_select}
101
-
102
- # Script Actions
103
- @test_results_log_message = Qt::Action.new(tr('Log Message to Test Results'), self)
104
- @test_results_log_message.statusTip = tr('Log Message to Test Results')
105
- @test_results_log_message.connect(SIGNAL('triggered()')) { on_test_results_log_message() }
106
- @test_results_log_message.setEnabled(false)
107
-
108
- @script_log_message = Qt::Action.new(tr('Log Message to Script Log'), self)
109
- @script_log_message.statusTip = tr('Log Message to Script Log')
110
- @script_log_message.connect(SIGNAL('triggered()')) { on_script_log_message() }
111
- @script_log_message.setEnabled(false)
112
-
113
- @show_call_stack = Qt::Action.new(tr('Show Call Stack'), self)
114
- @show_call_stack.statusTip = tr('Show Call Stack')
115
- @show_call_stack.connect(SIGNAL('triggered()')) { on_script_call_stack }
116
- @show_call_stack.setEnabled(false)
117
-
118
- @toggle_debug = Qt::Action.new(Cosmos.get_icon('bug.png'), tr('&Toggle Debug'), self)
119
- @toggle_debug_keyseq = Qt::KeySequence.new(tr('Ctrl+D'))
120
- @toggle_debug.shortcut = @toggle_debug_keyseq
121
- @toggle_debug.statusTip = tr('Toggle Debug')
122
- @toggle_debug.connect(SIGNAL('triggered()')) { on_script_toggle_debug }
123
- @toggle_debug.setEnabled(false)
124
-
125
- @script_disconnect = Qt::Action.new(Cosmos.get_icon('disconnected.png'), tr('&Toggle Disconnect'), self)
126
- @script_disconnect_keyseq = Qt::KeySequence.new(tr('Ctrl+T'))
127
- @script_disconnect.shortcut = @script_disconnect_keyseq
128
- @script_disconnect.statusTip = tr('Toggle disconnect from the server')
129
- @script_disconnect.connect(SIGNAL('triggered()')) { on_script_toggle_disconnect() }
130
-
131
- @script_audit = Qt::Action.new(tr('&Generate Cmd/Tlm Audit'), self)
132
- @script_audit.statusTip = tr('Generate audit about commands sent and telemetry checked')
133
- @script_audit.connect(SIGNAL('triggered()')) { script_audit() }
134
- end
135
-
136
- def initialize_menus
137
- # File Menu
138
- @file_menu = menuBar.addMenu(tr('&File'))
139
- @file_menu.addAction(@show_last)
140
- @file_menu.addAction(@select)
141
- @file_menu.addSeparator()
142
- @file_menu.addAction(@exit_action)
143
-
144
- # Script Menu
145
- @script_menu = menuBar.addMenu(tr('&Script'))
146
- @script_menu.addAction(@test_results_log_message)
147
- @script_menu.addAction(@script_log_message)
148
- @script_menu.addAction(@show_call_stack)
149
- @script_menu.addAction(@toggle_debug)
150
- @script_menu.addAction(@script_disconnect)
151
- @script_menu.addSeparator()
152
- @script_menu.addAction(@script_audit)
153
-
154
- # Help Menu
155
- @about_string = "Test Runner provides a framework for developing high " \
156
- "level tests that interact with a system using commands and telemetry."
157
-
158
- initialize_help_menu()
159
- end
160
-
161
- def initialize_central_widget
162
- # Create the top level vertical layout
163
- @central_widget = Qt::Widget.new()
164
- @frame = Qt::VBoxLayout.new(@central_widget)
165
-
166
- @horizontal_frame = Qt::HBoxLayout.new
167
- @horizontal_frame.setContentsMargins(0,0,0,0)
168
- @frame.addLayout(@horizontal_frame)
169
-
170
- # Check boxes
171
- @pause_on_error = Qt::CheckBox.new('Pause on Error')
172
- @pause_on_error.setChecked(true)
173
- @continue_test_case_after_error = Qt::CheckBox.new('Continue Test Case after Error')
174
- @continue_test_case_after_error.setChecked(true)
175
- @abort_testing_after_error = Qt::CheckBox.new('Abort Testing after Error')
176
- @abort_testing_after_error.setChecked(false)
177
-
178
- @checkbox_frame = Qt::VBoxLayout.new
179
- @checkbox_frame.setContentsMargins(0,0,0,0)
180
- @checkbox_frame.addWidget(@pause_on_error)
181
- @checkbox_frame.addWidget(@continue_test_case_after_error)
182
- @checkbox_frame.addWidget(@abort_testing_after_error)
183
- @horizontal_frame.addLayout(@checkbox_frame)
184
-
185
- # Separator Between checkboxes
186
- @sep1 = Qt::Frame.new(@central_widget)
187
- @sep1.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
188
- @horizontal_frame.addWidget(@sep1)
189
-
190
- @manual = Qt::CheckBox.new('Manual')
191
- @manual.setChecked(true)
192
- @manual.connect(SIGNAL('stateChanged(int)')) do
193
- if @manual.isChecked()
194
- $manual = true
195
- else
196
- $manual = false
197
- end
198
- 0
199
- end
200
- $manual = true
201
- @loop_testing = Qt::CheckBox.new('Loop Testing')
202
- @loop_testing.setChecked(false)
203
- @loop_testing.connect(SIGNAL('stateChanged(int)')) do
204
- if @loop_testing.isChecked()
205
- $loop_testing = true
206
- @break_loop_after_error.setEnabled(true)
207
- else
208
- $loop_testing = false
209
- @break_loop_after_error.setEnabled(false)
210
- end
211
- 0
212
- end
213
- $loop_testing = false
214
- @break_loop_after_error = Qt::CheckBox.new('Break Loop after Error')
215
- @break_loop_after_error.setChecked(false)
216
- @break_loop_after_error.setEnabled(false)
217
-
218
- @checkbox_frame = Qt::VBoxLayout.new
219
- @checkbox_frame.setContentsMargins(0,0,0,0)
220
- @checkbox_frame.addWidget(@manual)
221
- @checkbox_frame.addWidget(@loop_testing)
222
- @checkbox_frame.addWidget(@break_loop_after_error)
223
- @horizontal_frame.addLayout(@checkbox_frame)
224
-
225
- # Separator Between checkboxes
226
- @sep2 = Qt::Frame.new(@central_widget)
227
- @sep2.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
228
- @horizontal_frame.addStretch
229
- @horizontal_frame.addWidget(@sep2)
230
-
231
- # Create comboboxes and Start buttons
232
- @test_runner_chooser = TestRunnerChooser.new(self)
233
- @test_runner_chooser.setContentsMargins(0,0,0,0)
234
- @test_runner_chooser.test_suite_start_callback = method(:handle_start)
235
- @test_runner_chooser.test_start_callback = method(:handle_start)
236
- @test_runner_chooser.test_case_start_callback = method(:handle_start)
237
- @test_runner_chooser.test_suite_setup_callback = method(:handle_setup)
238
- @test_runner_chooser.test_setup_callback = method(:handle_setup)
239
- @test_runner_chooser.test_suite_teardown_callback = method(:handle_teardown)
240
- @test_runner_chooser.test_teardown_callback = method(:handle_teardown)
241
- @horizontal_frame.addWidget(@test_runner_chooser)
242
-
243
- # Executing Test Case Status
244
- @executing_status = Qt::HBoxLayout.new
245
- @executing_test_case_label = Qt::Label.new('Executing Test Case:')
246
- @executing_status.addWidget(@executing_test_case_label)
247
- @test_status = Qt::LineEdit.new
248
- @test_status.setReadOnly(true)
249
- @executing_status.addWidget(@test_status)
250
- @pass_label = Qt::Label.new('Pass:')
251
- @executing_status.addWidget(@pass_label)
252
- @pass_count = Qt::LineEdit.new
253
- @pass_count.setFixedWidth(40)
254
- @pass_count.setReadOnly(true)
255
- @pass_count.setAlignment(Qt::AlignHCenter)
256
- @pass_count.setColors(Cosmos::GREEN, Cosmos::WHITE)
257
- @executing_status.addWidget(@pass_count)
258
- @skip_label = Qt::Label.new('Skip:')
259
- @executing_status.addWidget(@skip_label)
260
- @skip_count = Qt::LineEdit.new
261
- @skip_count.setFixedWidth(40)
262
- @skip_count.setReadOnly(true)
263
- @skip_count.setAlignment(Qt::AlignHCenter)
264
- @skip_count.setColors(Cosmos::YELLOW, Cosmos::WHITE)
265
- @executing_status.addWidget(@skip_count)
266
- @fail_label = Qt::Label.new('Fail:')
267
- @executing_status.addWidget(@fail_label)
268
- @fail_count = Qt::LineEdit.new
269
- @fail_count.setFixedWidth(40)
270
- @fail_count.setReadOnly(true)
271
- @fail_count.setAlignment(Qt::AlignHCenter)
272
- @fail_count.setColors(Cosmos::RED, Cosmos::WHITE)
273
- @executing_status.addWidget(@fail_count)
274
- @progress_bar = Qt::ProgressBar.new
275
- @progress_bar.setFixedWidth(200)
276
- @progress_bar.setMinimum(0)
277
- @progress_bar.setMaximum(100)
278
- @executing_status.addWidget(@progress_bar)
279
- @frame.addLayout(@executing_status)
280
-
281
- # Separator before ScriptRunnerFrame
282
- @sep3 = Qt::Frame.new(@central_widget)
283
- @sep3.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)
284
- @frame.addWidget(@sep3)
285
-
286
- @script_runner_frame = ScriptRunnerFrame.new(self)
287
- @script_runner_frame.setContentsMargins(0,0,0,0)
288
- @script_runner_frame.stop_callback = method(:handle_stop)
289
- @script_runner_frame.allow_start = false
290
- ScriptRunnerFrame.pause_on_error = true
291
- @script_runner_frame.continue_after_error = true
292
- @script_runner_frame.error_callback = method(:handle_error)
293
- Test.abort_on_exception = false
294
- @frame.addWidget(@script_runner_frame)
295
-
296
- setCentralWidget(@central_widget)
297
-
298
- # Display a blank message to force the statusBar to show
299
- statusBar.showMessage("")
300
- end
301
-
302
- def status_timeout
303
- pass_count = TestStatus.instance.pass_count
304
- skip_count = TestStatus.instance.skip_count
305
- fail_count = TestStatus.instance.fail_count
306
- @test_status.text = TestStatus.instance.status
307
- @pass_count.text = pass_count.to_s
308
- @skip_count.text = skip_count.to_s
309
- @fail_count.text = fail_count.to_s
310
- if TestStatus.instance.status != ''
311
- run_count = pass_count + skip_count + fail_count
312
- total_count = TestStatus.instance.total
313
- mod_run_count = run_count % total_count
314
- progress = ((mod_run_count.to_f / total_count) * 100.0).to_i
315
- @progress_bar.setValue(progress)
316
- else
317
- @progress_bar.setValue(0)
318
- end
319
- end
320
-
321
- def self.results_writer
322
- @@results_writer
323
- end
324
-
325
- def self.exec_test(result_string, test_suite_class, test_class = nil, test_case = nil)
326
- @@started_success = false
327
- @@test_suites.each do |test_suite|
328
- if test_suite.class == test_suite_class
329
- @@started_success = @@results_writer.collect_metadata(@@instance)
330
- if @@started_success
331
- @@results_writer.start(result_string, test_suite_class, test_class, test_case, @@settings)
332
- loop do
333
- yield(test_suite)
334
- break if not @@settings['Loop Testing'] or (TestStatus.instance.fail_count > 0 and @@settings['Break Loop after Error'])
335
- end
336
- end
337
- break
338
- end
339
- end
340
- end
341
-
342
- def self.start(test_suite_class, test_class = nil, test_case = nil)
343
- result = []
344
- exec_test('', test_suite_class, test_class, test_case) do |test_suite|
345
- if test_case
346
- result = test_suite.run_test_case(test_class, test_case)
347
- @@results_writer.process_result(result)
348
- raise StopScript if (result.exceptions and Test.abort_on_exception) or result.stopped
349
- elsif test_class
350
- test_suite.run_test(test_class) { |current_result| @@results_writer.process_result(current_result); raise StopScript if current_result.stopped }
351
- else
352
- test_suite.run { |current_result| @@results_writer.process_result(current_result); raise StopScript if current_result.stopped }
353
- end
354
- end
355
- end
356
-
357
- def self.start_setup(test_suite_class, test_class = nil)
358
- exec_test('Manual Setup', test_suite_class, test_class) do |test_suite|
359
- if test_class
360
- result = test_suite.run_test_setup(test_class)
361
- else
362
- result = test_suite.run_setup
363
- end
364
- if result
365
- @@results_writer.process_result(result)
366
- raise StopScript if result.stopped
367
- end
368
- end
369
- end
370
-
371
- def self.start_teardown(test_suite_class, test_class = nil)
372
- exec_test('Manual Teardown', test_suite_class, test_class) do |test_suite|
373
- if test_class
374
- result = test_suite.run_test_teardown(test_class)
375
- else
376
- result = test_suite.run_teardown
377
- end
378
- if result
379
- @@results_writer.process_result(result)
380
- raise StopScript if result.stopped
381
- end
382
- end
383
- end
384
-
385
- def continue_without_pausing_on_errors?
386
- if !@pause_on_error.isChecked()
387
- msg = ""
388
- if @continue_test_case_after_error.isChecked() and @abort_testing_after_error.isChecked()
389
- msg = "the currently executing test case will run to completion before aborting"
390
- elsif !@continue_test_case_after_error.isChecked() and @abort_testing_after_error.isChecked()
391
- msg = "all testing will be aborted on an error"
392
- elsif @continue_test_case_after_error.isChecked() and !@abort_testing_after_error.isChecked()
393
- msg = "all testing will run to completion"
394
- else
395
- msg = "the next test case will start executing"
396
- end
397
-
398
- if Qt::MessageBox.warning(self, "Warning", "If an error occurs, testing will not pause and #{msg}. Continue?", Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::Yes) == Qt::MessageBox::No
399
- return false
400
- end
401
- end
402
- true
403
- end
404
-
405
- def continue_loop_testing?
406
- if @loop_testing.isChecked()
407
- msg = ""
408
- if @break_loop_after_error.isChecked()
409
- msg = "unless an error occurs"
410
- else
411
- msg = "until explicitly stopped"
412
- end
413
-
414
- if Qt::MessageBox.warning(self, "Warning", "Loop testing is enabled. Tests will run forever #{msg}. Continue?", Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::Yes) == Qt::MessageBox::No
415
- return false
416
- end
417
- end
418
- true
419
- end
420
-
421
- ###########################################
422
- # Callbacks
423
- ###########################################
424
-
425
- def generic_handler(test_suite, test = nil, test_case = nil)
426
- return unless continue_without_pausing_on_errors?
427
- return unless continue_loop_testing?()
428
-
429
- # TODO: This can take a while depending on the number of tests and their
430
- # complexity. Consider making a progress bar for this.
431
- require_utilities()
432
- handle_check_buttons()
433
- @script_runner_frame.stop_message_log
434
- yield
435
- @script_runner_frame.run
436
- end
437
-
438
- def handle_start(test_suite, test = nil, test_case = nil)
439
- generic_handler(test_suite, test, test_case) do
440
- if test_case
441
- @script_runner_frame.set_text("TestRunner.start(#{test_suite}, #{test}, '#{test_case}')", "#{test_suite}_#{test}_#{test_case}")
442
- elsif test
443
- @script_runner_frame.set_text("TestRunner.start(#{test_suite}, #{test})", "#{test_suite}_#{test}")
444
- else
445
- @script_runner_frame.set_text("TestRunner.start(#{test_suite})", test_suite)
446
- end
447
- end
448
- end
449
-
450
- def handle_setup(test_suite, test = nil)
451
- generic_handler(test_suite, test) do
452
- if test
453
- @script_runner_frame.set_text("TestRunner.start_setup(#{test_suite}, #{test})", "#{test_suite}_#{test}_setup")
454
- else
455
- @script_runner_frame.set_text("TestRunner.start_setup(#{test_suite})", "#{test_suite}_setup")
456
- end
457
- end
458
- end
459
-
460
- def handle_teardown(test_suite, test = nil)
461
- generic_handler(test_suite, test) do
462
- if test
463
- @script_runner_frame.set_text("TestRunner.start_teardown(#{test_suite}, #{test})", "#{test_suite}_#{test}_teardown")
464
- else
465
- @script_runner_frame.set_text("TestRunner.start_teardown(#{test_suite})", "#{test_suite}_teardown")
466
- end
467
- end
468
- end
469
-
470
- def handle_check_buttons
471
- if @pause_on_error.isChecked()
472
- ScriptRunnerFrame.pause_on_error = true
473
- else
474
- ScriptRunnerFrame.pause_on_error = false
475
- end
476
-
477
- if @continue_test_case_after_error.isChecked()
478
- @script_runner_frame.continue_after_error = true
479
- else
480
- @script_runner_frame.continue_after_error = false
481
- end
482
-
483
- if @abort_testing_after_error.isChecked()
484
- Test.abort_on_exception = true
485
- else
486
- Test.abort_on_exception = false
487
- end
488
-
489
- @@settings['Pause on Error'] = @pause_on_error.isChecked()
490
- @@settings['Continue Test Case after Error'] = @continue_test_case_after_error.isChecked()
491
- @@settings['Abort Testing after Error'] = @abort_testing_after_error.isChecked()
492
- @@settings['Manual'] = @manual.isChecked()
493
- @@settings['Loop Testing'] = @loop_testing.isChecked()
494
- @@settings['Break Loop after Error'] = @break_loop_after_error.isChecked()
495
-
496
- disable_while_running()
497
- end
498
-
499
- def handle_stop(script_runner_frame)
500
- if @@started_success
501
- @@results_writer.complete
502
- if @@results_writer.data_package
503
- ProgressDialog.execute(self, 'Data Package Creation Progress', 600, 300) do |progress_dialog|
504
- @@results_writer.create_data_package(progress_dialog)
505
- end
506
- end
507
- end
508
- enable_while_stopped()
509
- show_results() if @@started_success
510
- end
511
-
512
- def handle_error(script_runner_frame)
513
- if @continue_test_case_after_error.isChecked()
514
- script_runner_frame.enable_retry()
515
- else
516
- script_runner_frame.disable_retry()
517
- end
518
- end
519
-
520
- def disable_while_running
521
- TestStatus.instance.status = ''
522
- TestStatus.instance.pass_count = 0
523
- TestStatus.instance.skip_count = 0
524
- TestStatus.instance.fail_count = 0
525
- @manual.setEnabled(false)
526
- @pause_on_error.setEnabled(false)
527
- @continue_test_case_after_error.setEnabled(false)
528
- @abort_testing_after_error.setEnabled(false)
529
- @loop_testing.setEnabled(false)
530
- @break_loop_after_error.setEnabled(false)
531
- @test_runner_chooser.setEnabled(false)
532
- @show_last.setEnabled(false)
533
- @select.setEnabled(false)
534
- @test_results_log_message.setEnabled(true)
535
- @script_log_message.setEnabled(true)
536
- @show_call_stack.setEnabled(true)
537
- end
538
-
539
- def enable_while_stopped
540
- @manual.setEnabled(true)
541
- @pause_on_error.setEnabled(true)
542
- @continue_test_case_after_error.setEnabled(true)
543
- @abort_testing_after_error.setEnabled(true)
544
- @loop_testing.setEnabled(true)
545
- @break_loop_after_error.setEnabled(true) if @loop_testing.isChecked()
546
- @test_runner_chooser.setEnabled(true)
547
- @show_last.setEnabled(true)
548
- @select.setEnabled(true)
549
- @test_results_log_message.setEnabled(false)
550
- @script_log_message.setEnabled(false)
551
- @show_call_stack.setEnabled(false)
552
- TestStatus.instance.status = ''
553
- end
554
-
555
- def closeEvent(event)
556
- if @script_runner_frame.prompt_if_running_on_close()
557
- shutdown_cmd_tlm()
558
- @script_runner_frame.stop_message_log
559
- super(event)
560
- else
561
- event.ignore()
562
- end
563
- end
564
-
565
- def on_test_results_log_message
566
- message = get_scriptrunner_log_message('Test Results Text Entry', 'Enter text to log to the test results file')
567
- if message
568
- Cosmos::Test.puts('User logged: ' + message.to_s)
569
- @script_runner_frame.handle_output_io
570
- end
571
- end
572
-
573
- def on_script_log_message
574
- message = get_scriptrunner_log_message()
575
- if message
576
- @script_runner_frame.scriptrunner_puts 'User logged: ' + message.to_s
577
- @script_runner_frame.handle_output_io
578
- end
579
- end
580
-
581
- def on_script_call_stack
582
- trace = @script_runner_frame.current_backtrace
583
- ScrollTextDialog.new(self, 'Call Stack', trace.join("\n"))
584
- end
585
-
586
- def on_script_toggle_debug
587
- @script_runner_frame.toggle_debug
588
- end
589
-
590
- def on_script_toggle_disconnect
591
- @server_config_file = @script_runner_frame.toggle_disconnect(@server_config_file)
592
- end
593
-
594
- include ScriptAudit # script_audit()
595
-
596
- def require_utilities
597
- ScriptRunnerFrame.instance = @script_runner_frame
598
- build = false
599
- @utilities.each do |utility|
600
- if require_utility(utility)
601
- build = true
602
- end
603
- end
604
- if build
605
- build_test_suites()
606
- end
607
- ScriptRunnerFrame.instance = nil
608
- end
609
-
610
- # Show Dialog box with textfield containing results
611
- def show_results
612
- if @@results_writer.filename
613
- results_text = File.read(@@results_writer.filename)
614
-
615
- dialog = Qt::Dialog.new(self) do |box|
616
- box.setWindowTitle('Results')
617
- box.resize(600, 600)
618
- text_field = Qt::PlainTextEdit.new
619
- text_field.setReadOnly(true)
620
- orig_font = text_field.font
621
- text_field.setFont(Cosmos.getFont(orig_font.family, orig_font.point_size+2))
622
- text_field.setWordWrapMode(Qt::TextOption::NoWrap)
623
- state = :NORMAL
624
- results_text.each_line do |line|
625
- state = :NORMAL if line[0..0] != ' ' and line.strip.length != 0
626
- if line =~ /:PASS/
627
- text_field.appendText(line, Cosmos::GREEN)
628
- state = :PASS
629
- elsif line =~ /:SKIP/
630
- text_field.appendText(line, Cosmos::YELLOW)
631
- state = :SKIP
632
- elsif line =~ /:FAIL/
633
- text_field.appendText(line, Cosmos::RED)
634
- state = :FAIL
635
- else
636
- case state
637
- when :NORMAL
638
- text_field.appendText(line)
639
- when :PASS
640
- text_field.appendText(line, Cosmos::GREEN)
641
- when :SKIP
642
- text_field.appendText(line, Cosmos::YELLOW)
643
- when :FAIL
644
- text_field.appendText(line, Cosmos::RED)
645
- end
646
- end
647
- end
648
-
649
- vframe = Qt::VBoxLayout.new
650
- vframe.addWidget(text_field)
651
-
652
- # Separator Between checkboxes
653
- sep = Qt::Frame.new(box)
654
- sep.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
655
- vframe.addWidget(sep)
656
-
657
- ok = Qt::PushButton.new('OK')
658
- ok.setDefault(true)
659
- ok.connect(SIGNAL('clicked(bool)')) { box.accept }
660
- vframe.addWidget(ok)
661
- box.setLayout(vframe)
662
- end
663
- dialog.exec
664
- dialog.dispose
665
- end
666
- end
667
-
668
- def create_node(yard_doc, name, tree)
669
- node = Qt::TreeWidgetItem.new([name])
670
- node.setCheckState(0, Qt::Unchecked)
671
- yield node
672
- description = yard_doc.nil? ? "" : yard_doc.docstring
673
- description = UNASSIGNED_SUITE_DESCRIPTION if name == "UnassignedTestSuite"
674
- desc_label = Qt::Label.new(description.gsub(/\n/,' '))
675
- desc_label.setMinimumHeight(desc_label.fontMetrics.height * 2)
676
- desc_label.setWordWrap(true)
677
- tree.setItemWidget(node, 1, desc_label)
678
- return node
679
- end
680
-
681
- # Show Dialog box with tree of tests to allow the user to select
682
- # a subset of tests. This also shows the Test Descriptions.
683
- def show_select
684
- dialog = Qt::Dialog.new(self) do |box|
685
- box.setWindowTitle('Test Selections')
686
- box.resize(650, 600)
687
- @procedure_dirs.each do |dir|
688
- # Set the logging level to ERROR to avoid output if one of the
689
- # scripts we are parsing has syntax errors
690
- YARD.parse(File.join(dir, '**', '*.rb'), [], YARD::Logger::ERROR)
691
- end
692
-
693
- tree = Qt::TreeWidget.new
694
- tree.setColumnCount(2)
695
- tree.setHeaderLabels(["Name", "Description"])
696
- tree.connect(SIGNAL('itemClicked(QTreeWidgetItem*, int)')) do |widget, column|
697
- tree.topLevelItems do |suite_node|
698
- if suite_node != widget.topLevel
699
- suite_node.setCheckStateAll(Qt::Unchecked)
700
- end
701
- end
702
- end
703
-
704
- orig_font = nil
705
- @@test_suites.each do |suite|
706
- next if suite.name == "Cosmos::CustomTestSuite"
707
- doc = YARD::Registry.resolve(nil, suite.name)
708
- suite_node = create_node(doc, suite.name, tree) do |node|
709
- orig_font = node.font(0)
710
- new_font = Cosmos.getFont(orig_font.family,
711
- orig_font.point_size+5,
712
- Qt::Font::Bold)
713
- node.setFont(0, new_font)
714
- tree.addTopLevelItem(node)
715
- end
716
-
717
- if suite.respond_to? :setup
718
- doc = YARD::Registry.resolve(P(suite.name.to_s), "#setup", true)
719
- create_node(doc, "setup", tree) do |node|
720
- font = Cosmos.getFont(orig_font.family,
721
- orig_font.point_size,
722
- Qt::Font::Normal,
723
- true) # italic
724
- node.setFont(0, font)
725
- suite_node.addChild(node)
726
- end
727
- end
728
-
729
- suite.tests.each do |test_class, test|
730
- doc = YARD::Registry.resolve(nil, test.name)
731
- test_node = create_node(doc, test.name, tree) do |node|
732
- font = Cosmos.getFont(orig_font.family,
733
- orig_font.point_size + 2,
734
- Qt::Font::Bold)
735
- node.setFont(0, font)
736
- suite_node.addChild(node)
737
- node.setExpanded(true)
738
- end
739
-
740
- if test.respond_to? :setup
741
- doc = YARD::Registry.resolve(P(test_class.to_s), "#setup", true)
742
- create_node(doc, "setup", tree) do |node|
743
- font = Cosmos.getFont(orig_font.family,
744
- orig_font.point_size,
745
- Qt::Font::Normal,
746
- true) # italic
747
- node.setFont(0, font)
748
- test_node.addChild(node)
749
- end
750
- end
751
-
752
- test_class.test_cases.each do |tc|
753
- doc = YARD::Registry.resolve(P(test_class.to_s), "##{tc.to_s}", true)
754
- create_node(doc, tc.to_s, tree) do |node|
755
- test_node.addChild(node)
756
- end
757
- end
758
-
759
- if test.respond_to? :teardown
760
- doc = YARD::Registry.resolve(P(test_class.to_s), "#teardown", true)
761
- create_node(doc, "teardown", tree) do |node|
762
- font = Cosmos.getFont(orig_font.family,
763
- orig_font.point_size,
764
- Qt::Font::Normal,
765
- true) # italic
766
- node.setFont(0, font)
767
- test_node.addChild(node)
768
- end
769
- end
770
- end # suite.tests.each
771
-
772
- if suite.respond_to? :teardown
773
- doc = YARD::Registry.resolve(P(suite.name.to_s), "#teardown", true)
774
- create_node(doc, "teardown", tree) do |node|
775
- font = Cosmos.getFont(orig_font.family,
776
- orig_font.point_size,
777
- Qt::Font::Normal,
778
- true) # italic
779
- node.setFont(0, font)
780
- suite_node.addChild(node)
781
- end
782
- end
783
- end
784
-
785
- tree.resizeColumnToContents(0)
786
- dialog_layout = Qt::VBoxLayout.new
787
- text = "Select test cases to be run in a newly created 'CustomTestSuite'. "\
788
- "Note that tests can only be added from a single existing Test Suite. " \
789
- "Thus clicking on something in another Test Suite deselects anything " \
790
- "currently selected."
791
- instructions = Qt::Label.new(text)
792
- instructions.setWordWrap(true)
793
- dialog_layout.addWidget(instructions)
794
- dialog_layout.addWidget(tree)
795
-
796
- # Separator Between checkboxes
797
- sep = Qt::Frame.new(box)
798
- sep.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
799
- dialog_layout.addWidget(sep)
800
-
801
- button_box = Qt::DialogButtonBox.new(Qt::DialogButtonBox::Ok |
802
- Qt::DialogButtonBox::Cancel)
803
- connect(button_box, SIGNAL('rejected()'), box, SLOT('reject()'))
804
- connect(button_box, SIGNAL('accepted()')) do
805
- Cosmos.module_eval("class CustomTestSuite < TestSuite; end")
806
- tree.topLevelItems do |suite_node|
807
- next if suite_node.checkState == Qt::Unchecked
808
- cur_suite = OpenStruct.new(:setup=>false, :teardown=>false, :tests=>{})
809
- suite = CustomTestSuite.new
810
- begin
811
- # Remove any previously defined suite setup methods
812
- CustomTestSuite.send(:remove_method, :setup)
813
- rescue NameError
814
- # NameError is raised if no setup method was defined
815
- end
816
- begin
817
- # Remove any previously defined suite teardown methods
818
- CustomTestSuite.send(:remove_method, :teardown)
819
- rescue NameError
820
- # NameError is raised if no teardown method was defined
821
- end
822
-
823
- suite_node.children do |test_node|
824
- if test_node.checkState == Qt::Checked
825
- if test_node.text == 'setup'
826
- cur_suite.setup = true
827
- # Find the suite instance among the test suites
828
- inst = @@test_suites.detect {|my_suite| my_suite.class.to_s == suite_node.text}
829
- # Create a lambda which will call that one setup method
830
- body = lambda { inst.setup }
831
- CustomTestSuite.send(:define_method, :setup, &body)
832
- end
833
- if test_node.text == 'teardown'
834
- cur_suite.teardown = true
835
- # Find the suite instance among the test suites
836
- inst = @@test_suites.detect {|my_suite| my_suite.class.to_s == suite_node.text}
837
- # Create a lambda which will call that one teardown method
838
- body = lambda { inst.teardown}
839
- CustomTestSuite.send(:define_method, :teardown, &body)
840
- end
841
- end
842
-
843
- test_node.children do |test_case|
844
- next if test_case.checkState == Qt::Unchecked
845
- node = cur_suite.tests[test_node.text] ||=
846
- OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
847
-
848
- case test_case.text
849
- when 'setup'
850
- suite.add_test_setup(test_node.text)
851
- node.setup = true
852
- when 'teardown'
853
- suite.add_test_teardown(test_node.text)
854
- node.teardown = true
855
- else
856
- suite.add_test_case(test_node.text, test_case.text)
857
- node.cases << test_case.text
858
- end
859
- end
860
- end
861
- @@suites["CustomTestSuite"] = cur_suite
862
- @@test_suites = @@test_suites.select {|my_suite| my_suite.class != CustomTestSuite}
863
- @@test_suites << suite
864
- end
865
- Qt.execute_in_main_thread(true) do
866
- @test_runner_chooser.test_suites = @@suites
867
- @test_runner_chooser.select_suite("CustomTestSuite")
868
- end
869
- box.accept
870
- end
871
- dialog_layout.addWidget(button_box)
872
- box.setLayout(dialog_layout)
873
- end
874
- dialog.raise
875
- dialog.exec
876
- dialog.dispose
877
- end
878
-
879
- def process_config(filename)
880
- ScriptRunnerFrame.instance = @script_runner_frame
881
-
882
- # Remember all the requires that fail and warn the user
883
- require_errors = []
884
-
885
- # Ensure the file exists
886
- raise "Configuration File: #{filename} does not exist" unless test(?f, filename)
887
- parser = ConfigParser.new
888
- parser.parse_file(filename) do |keyword, params|
889
- case keyword
890
- when 'REQUIRE_UTILITY'
891
- parser.verify_num_parameters(1, 1, "REQUIRE_UTILITY <filename>")
892
- begin
893
- require_utility params[0]
894
- @utilities << params[0]
895
- rescue Exception => err
896
- require_errors << "<b>#{params[0]}</b>:\n#{err.formatted}\n"
897
- end
898
-
899
- when 'RESULTS_WRITER'
900
- data_package = @@results_writer.data_package
901
- metadata = @@results_writer.metadata
902
- parser.verify_num_parameters(1, nil, "RESULTS_WRITER <filename> <class specific options>")
903
- results_class = Cosmos.require_class(params[0])
904
- if params[1]
905
- @@results_writer = results_class.new(*params[1..-1])
906
- else
907
- @@results_writer = results_class.new
908
- end
909
- @@results_writer.data_package = data_package
910
- @@results_writer.metadata = metadata
911
-
912
- when 'ALLOW_DEBUG'
913
- parser.verify_num_parameters(0, 0, "ALLOW_DEBUG")
914
- Qt.execute_in_main_thread(true) { @toggle_debug.setEnabled(true) }
915
-
916
- when 'PAUSE_ON_ERROR'
917
- parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
918
- Qt.execute_in_main_thread(true) do
919
- @pause_on_error.setChecked(ConfigParser.handle_true_false(params[0]))
920
- end
921
-
922
- when 'CONTINUE_TEST_CASE_AFTER_ERROR'
923
- parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
924
- Qt.execute_in_main_thread(true) { @continue_test_case_after_error.setChecked(ConfigParser.handle_true_false(params[0])) }
925
-
926
- when 'ABORT_TESTING_AFTER_ERROR'
927
- parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
928
- Qt.execute_in_main_thread(true) { @abort_testing_after_error.setChecked(ConfigParser.handle_true_false(params[0])) }
929
-
930
- when 'MANUAL'
931
- parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
932
- Qt.execute_in_main_thread(true) do
933
- @manual.setChecked(ConfigParser.handle_true_false(params[0]))
934
- if @manual.isChecked()
935
- $manual = true
936
- else
937
- $manual = false
938
- end
939
- end
940
-
941
- when 'LOOP_TESTING'
942
- parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
943
- Qt.execute_in_main_thread(true) do
944
- @loop_testing.setChecked(ConfigParser.handle_true_false(params[0]))
945
- if @loop_testing.isChecked()
946
- $loop_testing = true
947
- @break_loop_after_error.setEnabled(true)
948
- else
949
- $loop_testing = false
950
- @break_loop_after_error.setEnabled(false)
951
- end
952
- end
953
-
954
- when 'BREAK_LOOP_AFTER_ERROR'
955
- parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
956
- Qt.execute_in_main_thread(true) { @break_loop_after_error.setChecked(ConfigParser.handle_true_false(params[0])) }
957
-
958
- when 'IGNORE_TEST'
959
- parser.verify_num_parameters(1, 1, "#{keyword} <Test Class Name (case sensitive)>")
960
- @ignore_tests << params[0]
961
-
962
- when 'IGNORE_TEST_SUITE'
963
- parser.verify_num_parameters(1, 1, "#{keyword} <Test Suite Class Name (case sensitive)>")
964
- @ignore_test_suites << params[0]
965
-
966
- when 'LINE_DELAY'
967
- parser.verify_num_parameters(1, 1, "#{keyword} <Line Delay in Seconds>")
968
- ScriptRunnerFrame.line_delay = params[0].to_f
969
-
970
- when 'MONITOR_LIMITS'
971
- parser.verify_num_parameters(0, 0, keyword)
972
- ScriptRunnerFrame.monitor_limits = true
973
-
974
- when 'PAUSE_ON_RED'
975
- parser.verify_num_parameters(0, 0, keyword)
976
- ScriptRunnerFrame.monitor_limits = true
977
- ScriptRunnerFrame.pause_on_red = true
978
-
979
- when 'CREATE_DATA_PACKAGE'
980
- parser.verify_num_parameters(0, 0, keyword)
981
- @@results_writer.data_package = true
982
-
983
- when 'AUTO_CYCLE_LOGS'
984
- parser.verify_num_parameters(0, 0, keyword)
985
- @@results_writer.auto_cycle_logs = true
986
-
987
- # TODO: Deprecate COLLECT_META_DATA
988
- when 'COLLECT_METADATA', 'COLLECT_META_DATA'
989
- parser.verify_num_parameters(2, 2, "#{keyword} <Metadata Target Name> <Metadata Packet Name>")
990
- System.telemetry.packet(params[0], params[1])
991
- @@results_writer.metadata = [params[0], params[1]]
992
-
993
- else
994
- raise "Unhandled keyword: #{keyword}" if keyword
995
- end
996
- end
997
-
998
- # Warn the user about all the requires that failed
999
- unless require_errors.empty?
1000
- Qt.execute_in_main_thread(true) do
1001
- message = "While loading the Test Runner configuration file: #{filename}."
1002
- message << "\n\nThe following errors occurred:\n#{require_errors.join("\n")}" unless require_errors.empty?
1003
- ScrollTextDialog.new(self, "TestRunner Errors", message)
1004
- end
1005
- end
1006
-
1007
- # Build Test objects
1008
- build_test_suites()
1009
-
1010
- ScriptRunnerFrame.instance = nil
1011
- end
1012
-
1013
- def build_test_suites
1014
- ScriptRunnerFrame.instance.use_instrumentation = false
1015
-
1016
- ignored_test_classes = []
1017
- ignored_test_suite_classes = []
1018
-
1019
- @ignore_tests.each do |test_name|
1020
- begin
1021
- klass = Object.const_get(test_name)
1022
- ignored_test_classes << klass if klass
1023
- rescue
1024
- end
1025
- end
1026
-
1027
- @ignore_test_suites.each do |test_suite_name|
1028
- begin
1029
- klass = Object.const_get(test_suite_name)
1030
- ignored_test_suite_classes << klass if klass
1031
- rescue
1032
- end
1033
- end
1034
-
1035
- # Build list of TestSuites and Tests
1036
- @@test_suites = []
1037
- tests = []
1038
- ObjectSpace.each_object(Class) do |object|
1039
- if (object.ancestors.include?(TestSuite) &&
1040
- object != TestSuite &&
1041
- !ignored_test_suite_classes.include?(object))
1042
- @@test_suites << object.new
1043
- end
1044
- if (object.ancestors.include?(Test) &&
1045
- object != Test &&
1046
- !ignored_test_classes.include?(object))
1047
- tests << object
1048
- end
1049
- end
1050
- # Raise error if no test suites or tests
1051
- if @@test_suites.empty? || tests.empty?
1052
- msg = "No TestSuites or no Test classes found"
1053
- if !ignored_test_suite_classes.empty?
1054
- msg += "\n\nThe following TestSuites were found but ignored:\n#{ignored_test_suite_classes.join(", ")}"
1055
- end
1056
- if !ignored_test_classes.empty?
1057
- msg += "\n\nThe following Tests were found but ignored:\n#{ignored_test_classes.join(", ")}"
1058
- end
1059
- Qt.execute_in_main_thread(true) do
1060
- Qt::MessageBox.critical(self, 'Error', msg)
1061
- end
1062
- exit 1
1063
- end
1064
-
1065
- # Create TestSuite for unassigned Tests
1066
- @@test_suites.sort!
1067
- @@test_suites.each do |test_suite|
1068
- tests_to_delete = []
1069
- tests.each { |test| tests_to_delete << test if test_suite.tests[test] }
1070
- tests_to_delete.each { |test| tests.delete(test) }
1071
- end
1072
- if tests.empty?
1073
- @@test_suites = @@test_suites.select {|suite| suite.class != UnassignedTestSuite}
1074
- else
1075
- uts = @@test_suites.select {|suite| suite.class == UnassignedTestSuite}[0]
1076
- tests.each { |test| uts.add_test(test) }
1077
- end
1078
-
1079
- ScriptRunnerFrame.instance.use_instrumentation = true
1080
- @@test_suites.each do |suite|
1081
- cur_suite = OpenStruct.new(:setup=>false, :teardown=>false, :tests=>{})
1082
- cur_suite.setup = true if suite.class.method_defined?(:setup)
1083
- cur_suite.teardown = true if suite.class.method_defined?(:teardown)
1084
-
1085
- suite.plans.each do |test_type, test_class, test_case|
1086
- case test_type
1087
- when :TEST
1088
- cur_suite.tests[test_class.name] ||=
1089
- OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1090
- cur_suite.tests[test_class.name].cases.concat(test_class.test_cases)
1091
- cur_suite.tests[test_class.name].cases.uniq!
1092
- cur_suite.tests[test_class.name].cases.sort!
1093
- cur_suite.tests[test_class.name].setup = true if test_class.method_defined?(:setup)
1094
- cur_suite.tests[test_class.name].teardown = true if test_class.method_defined?(:teardown)
1095
- when :TEST_CASE
1096
- cur_suite.tests[test_class.name] ||=
1097
- OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1098
- # Explicitly check for this method and raise an error if it does not exist
1099
- if test_class.method_defined?(test_case.intern)
1100
- cur_suite.tests[test_class.name].cases << test_case
1101
- cur_suite.tests[test_class.name].cases.uniq!
1102
- cur_suite.tests[test_class.name].cases.sort!
1103
- else
1104
- raise "#{test_class} does not have a #{test_case} method defined."
1105
- end
1106
- cur_suite.tests[test_class.name].setup = true if test_class.method_defined?(:setup)
1107
- cur_suite.tests[test_class.name].teardown = true if test_class.method_defined?(:teardown)
1108
- when :TEST_SETUP
1109
- cur_suite.tests[test_class.name] ||=
1110
- OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1111
- # Explicitly check for the setup method and raise an error if it does not exist
1112
- if test_class.method_defined?(:setup)
1113
- cur_suite.tests[test_class.name].setup = true
1114
- else
1115
- raise "#{test_class} does not have a setup method defined."
1116
- end
1117
- when :TEST_TEARDOWN
1118
- cur_suite.tests[test_class.name] ||=
1119
- OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1120
- # Explicitly check for the teardown method and raise an error if it does not exist
1121
- if test_class.method_defined?(:teardown)
1122
- cur_suite.tests[test_class.name].teardown = true
1123
- else
1124
- raise "#{test_class} does not have a teardown method defined."
1125
- end
1126
- end
1127
- end
1128
- @@suites[suite.name.split('::')[-1]] = cur_suite
1129
- end
1130
- Qt.execute_in_main_thread(true) { @test_runner_chooser.test_suites = @@suites }
1131
- end
1132
-
1133
- def self.run(option_parser = nil, options = nil)
1134
- Cosmos.catch_fatal_exception do
1135
- unless option_parser and options
1136
- option_parser, options = create_default_options()
1137
- options.width = 800
1138
- options.height = 700
1139
- options.title = "Test Runner"
1140
- options.auto_size = false
1141
- options.config_file = File.join(Cosmos::USERPATH, 'config', 'tools', 'test_runner', 'test_runner.txt')
1142
- options.server_config_file = CmdTlmServer::DEFAULT_CONFIG_FILE
1143
- option_parser.separator "Test Runner Specific Options:"
1144
- option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
1145
- options.config_file = File.join(Cosmos::USERPATH, 'config', 'tools', 'test_runner', arg)
1146
- end
1147
- option_parser.on("-s", "--server FILE", "Use the specified server configuration file for disconnect mode") do |arg|
1148
- options.server_config_file = arg
1149
- end
1150
- end
1151
-
1152
- super(option_parser, options)
1153
- end
1154
- end
1155
- end # class TestRunner
1156
-
1157
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'cosmos'
12
+ Cosmos.catch_fatal_exception do
13
+ require 'ostruct'
14
+ require 'cosmos/gui/qt_tool'
15
+ require 'cosmos/tools/test_runner/test'
16
+ require 'cosmos/tools/test_runner/results_writer'
17
+ require 'cosmos/tools/test_runner/test_runner_chooser'
18
+ require 'cosmos/tools/script_runner/script_runner_frame'
19
+ require 'cosmos/tools/script_runner/script_audit'
20
+ require 'cosmos/gui/dialogs/progress_dialog'
21
+ require 'cosmos/gui/dialogs/scroll_text_dialog'
22
+ require 'yard'
23
+ end
24
+
25
+ module Cosmos
26
+
27
+ # Placeholder for all tests discovered without assigned TestSuites
28
+ class UnassignedTestSuite < TestSuite
29
+ end
30
+
31
+ # TestRunner provides a framework for running repeatable sets of tests.
32
+ # Individual Test Cases are grouped into Test Groups which are collected into
33
+ # Test Suites. Test Cases can have manual sections and can be looped
34
+ # indefinitely. After all the tests have run a test report is generated which
35
+ # lists the pass / fail status of each test case.
36
+ class TestRunner < QtTool
37
+ slots 'status_timeout()'
38
+
39
+ @@test_suites = []
40
+ @@suites = {}
41
+ @@results_writer = ResultsWriter.new
42
+ @@settings = {}
43
+ @@started_success = false
44
+ @@instance = nil
45
+
46
+ UNASSIGNED_SUITE_DESCRIPTION = "This Test Suite is created automatically " \
47
+ "by Test Runner to hold all Tests that have not been added to Test " \
48
+ "Suites. Consider adding these tests to explicit Test Suites to " \
49
+ "eliminate this catch all Test Suite."
50
+
51
+ def initialize(options)
52
+ # All code before super is executed twice in RubyQt Based classes
53
+ super(options) # MUST BE FIRST
54
+ Cosmos.load_cosmos_icon("test_runner.png")
55
+
56
+ # Add procedures to search path
57
+ System.paths['PROCEDURES'].each do |path|
58
+ Cosmos.add_to_search_path(path)
59
+ end
60
+
61
+ initialize_actions()
62
+ initialize_menus()
63
+ initialize_central_widget()
64
+ complete_initialize()
65
+
66
+ # Instance variables
67
+ @utilities = []
68
+ @procedure_dirs = System.paths['PROCEDURES']
69
+ @server_config_file = options.server_config_file
70
+ @ignore_tests = []
71
+ @ignore_test_suites = []
72
+ Splash.execute(self) do |splash|
73
+ ConfigParser.splash = splash
74
+ process_config(options.config_file)
75
+ ConfigParser.splash = nil
76
+ end
77
+
78
+ # Timeout to update executing test case status
79
+ @timer = Qt::Timer.new(self)
80
+ connect(@timer, SIGNAL('timeout()'), self, SLOT('status_timeout()'))
81
+ @timer.method_missing(:start, 100)
82
+
83
+ @@instance = self
84
+ end
85
+
86
+ def initialize_actions
87
+ super()
88
+
89
+ # File Actions
90
+ @show_last = Qt::Action.new(tr('Show &Results'), self)
91
+ @show_last_keyseq = Qt::KeySequence.new(tr('Ctrl+R'))
92
+ @show_last.shortcut = @show_last_keyseq
93
+ @show_last.statusTip = tr('Show the Results dialog from the last run')
94
+ @show_last.connect(SIGNAL('triggered()')) { show_results }
95
+
96
+ @select = Qt::Action.new(tr('Test &Selection'), self)
97
+ @select_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
98
+ @select.shortcut = @select_keyseq
99
+ @select.statusTip = tr('Select Test Suites/Groups/Cases')
100
+ @select.connect(SIGNAL('triggered()')) { show_select}
101
+
102
+ # Script Actions
103
+ @test_results_log_message = Qt::Action.new(tr('Log Message to Test Results'), self)
104
+ @test_results_log_message.statusTip = tr('Log Message to Test Results')
105
+ @test_results_log_message.connect(SIGNAL('triggered()')) { on_test_results_log_message() }
106
+ @test_results_log_message.setEnabled(false)
107
+
108
+ @script_log_message = Qt::Action.new(tr('Log Message to Script Log'), self)
109
+ @script_log_message.statusTip = tr('Log Message to Script Log')
110
+ @script_log_message.connect(SIGNAL('triggered()')) { on_script_log_message() }
111
+ @script_log_message.setEnabled(false)
112
+
113
+ @show_call_stack = Qt::Action.new(tr('Show Call Stack'), self)
114
+ @show_call_stack.statusTip = tr('Show Call Stack')
115
+ @show_call_stack.connect(SIGNAL('triggered()')) { on_script_call_stack }
116
+ @show_call_stack.setEnabled(false)
117
+
118
+ @toggle_debug = Qt::Action.new(Cosmos.get_icon('bug.png'), tr('&Toggle Debug'), self)
119
+ @toggle_debug_keyseq = Qt::KeySequence.new(tr('Ctrl+D'))
120
+ @toggle_debug.shortcut = @toggle_debug_keyseq
121
+ @toggle_debug.statusTip = tr('Toggle Debug')
122
+ @toggle_debug.connect(SIGNAL('triggered()')) { on_script_toggle_debug }
123
+ @toggle_debug.setEnabled(false)
124
+
125
+ @script_disconnect = Qt::Action.new(Cosmos.get_icon('disconnected.png'), tr('&Toggle Disconnect'), self)
126
+ @script_disconnect_keyseq = Qt::KeySequence.new(tr('Ctrl+T'))
127
+ @script_disconnect.shortcut = @script_disconnect_keyseq
128
+ @script_disconnect.statusTip = tr('Toggle disconnect from the server')
129
+ @script_disconnect.connect(SIGNAL('triggered()')) { on_script_toggle_disconnect() }
130
+
131
+ @script_audit = Qt::Action.new(tr('&Generate Cmd/Tlm Audit'), self)
132
+ @script_audit.statusTip = tr('Generate audit about commands sent and telemetry checked')
133
+ @script_audit.connect(SIGNAL('triggered()')) { script_audit() }
134
+ end
135
+
136
+ def initialize_menus
137
+ # File Menu
138
+ @file_menu = menuBar.addMenu(tr('&File'))
139
+ @file_menu.addAction(@show_last)
140
+ @file_menu.addAction(@select)
141
+ @file_menu.addSeparator()
142
+ @file_menu.addAction(@exit_action)
143
+
144
+ # Script Menu
145
+ @script_menu = menuBar.addMenu(tr('&Script'))
146
+ @script_menu.addAction(@test_results_log_message)
147
+ @script_menu.addAction(@script_log_message)
148
+ @script_menu.addAction(@show_call_stack)
149
+ @script_menu.addAction(@toggle_debug)
150
+ @script_menu.addAction(@script_disconnect)
151
+ @script_menu.addSeparator()
152
+ @script_menu.addAction(@script_audit)
153
+
154
+ # Help Menu
155
+ @about_string = "Test Runner provides a framework for developing high " \
156
+ "level tests that interact with a system using commands and telemetry."
157
+
158
+ initialize_help_menu()
159
+ end
160
+
161
+ def initialize_central_widget
162
+ # Create the top level vertical layout
163
+ @central_widget = Qt::Widget.new()
164
+ @frame = Qt::VBoxLayout.new(@central_widget)
165
+
166
+ @horizontal_frame = Qt::HBoxLayout.new
167
+ @horizontal_frame.setContentsMargins(0,0,0,0)
168
+ @frame.addLayout(@horizontal_frame)
169
+
170
+ # Check boxes
171
+ @pause_on_error = Qt::CheckBox.new('Pause on Error')
172
+ @pause_on_error.setChecked(true)
173
+ @continue_test_case_after_error = Qt::CheckBox.new('Continue Test Case after Error')
174
+ @continue_test_case_after_error.setChecked(true)
175
+ @abort_testing_after_error = Qt::CheckBox.new('Abort Testing after Error')
176
+ @abort_testing_after_error.setChecked(false)
177
+
178
+ @checkbox_frame = Qt::VBoxLayout.new
179
+ @checkbox_frame.setContentsMargins(0,0,0,0)
180
+ @checkbox_frame.addWidget(@pause_on_error)
181
+ @checkbox_frame.addWidget(@continue_test_case_after_error)
182
+ @checkbox_frame.addWidget(@abort_testing_after_error)
183
+ @horizontal_frame.addLayout(@checkbox_frame)
184
+
185
+ # Separator Between checkboxes
186
+ @sep1 = Qt::Frame.new(@central_widget)
187
+ @sep1.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
188
+ @horizontal_frame.addWidget(@sep1)
189
+
190
+ @manual = Qt::CheckBox.new('Manual')
191
+ @manual.setChecked(true)
192
+ @manual.connect(SIGNAL('stateChanged(int)')) do
193
+ if @manual.isChecked()
194
+ $manual = true
195
+ else
196
+ $manual = false
197
+ end
198
+ 0
199
+ end
200
+ $manual = true
201
+ @loop_testing = Qt::CheckBox.new('Loop Testing')
202
+ @loop_testing.setChecked(false)
203
+ @loop_testing.connect(SIGNAL('stateChanged(int)')) do
204
+ if @loop_testing.isChecked()
205
+ $loop_testing = true
206
+ @break_loop_after_error.setEnabled(true)
207
+ else
208
+ $loop_testing = false
209
+ @break_loop_after_error.setEnabled(false)
210
+ end
211
+ 0
212
+ end
213
+ $loop_testing = false
214
+ @break_loop_after_error = Qt::CheckBox.new('Break Loop after Error')
215
+ @break_loop_after_error.setChecked(false)
216
+ @break_loop_after_error.setEnabled(false)
217
+
218
+ @checkbox_frame = Qt::VBoxLayout.new
219
+ @checkbox_frame.setContentsMargins(0,0,0,0)
220
+ @checkbox_frame.addWidget(@manual)
221
+ @checkbox_frame.addWidget(@loop_testing)
222
+ @checkbox_frame.addWidget(@break_loop_after_error)
223
+ @horizontal_frame.addLayout(@checkbox_frame)
224
+
225
+ # Separator Between checkboxes
226
+ @sep2 = Qt::Frame.new(@central_widget)
227
+ @sep2.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
228
+ @horizontal_frame.addStretch
229
+ @horizontal_frame.addWidget(@sep2)
230
+
231
+ # Create comboboxes and Start buttons
232
+ @test_runner_chooser = TestRunnerChooser.new(self)
233
+ @test_runner_chooser.setContentsMargins(0,0,0,0)
234
+ @test_runner_chooser.test_suite_start_callback = method(:handle_start)
235
+ @test_runner_chooser.test_start_callback = method(:handle_start)
236
+ @test_runner_chooser.test_case_start_callback = method(:handle_start)
237
+ @test_runner_chooser.test_suite_setup_callback = method(:handle_setup)
238
+ @test_runner_chooser.test_setup_callback = method(:handle_setup)
239
+ @test_runner_chooser.test_suite_teardown_callback = method(:handle_teardown)
240
+ @test_runner_chooser.test_teardown_callback = method(:handle_teardown)
241
+ @horizontal_frame.addWidget(@test_runner_chooser)
242
+
243
+ # Executing Test Case Status
244
+ @executing_status = Qt::HBoxLayout.new
245
+ @executing_test_case_label = Qt::Label.new('Executing Test Case:')
246
+ @executing_status.addWidget(@executing_test_case_label)
247
+ @test_status = Qt::LineEdit.new
248
+ @test_status.setReadOnly(true)
249
+ @executing_status.addWidget(@test_status)
250
+ @pass_label = Qt::Label.new('Pass:')
251
+ @executing_status.addWidget(@pass_label)
252
+ @pass_count = Qt::LineEdit.new
253
+ @pass_count.setFixedWidth(40)
254
+ @pass_count.setReadOnly(true)
255
+ @pass_count.setAlignment(Qt::AlignHCenter)
256
+ @pass_count.setColors(Cosmos::GREEN, Cosmos::WHITE)
257
+ @executing_status.addWidget(@pass_count)
258
+ @skip_label = Qt::Label.new('Skip:')
259
+ @executing_status.addWidget(@skip_label)
260
+ @skip_count = Qt::LineEdit.new
261
+ @skip_count.setFixedWidth(40)
262
+ @skip_count.setReadOnly(true)
263
+ @skip_count.setAlignment(Qt::AlignHCenter)
264
+ @skip_count.setColors(Cosmos::YELLOW, Cosmos::WHITE)
265
+ @executing_status.addWidget(@skip_count)
266
+ @fail_label = Qt::Label.new('Fail:')
267
+ @executing_status.addWidget(@fail_label)
268
+ @fail_count = Qt::LineEdit.new
269
+ @fail_count.setFixedWidth(40)
270
+ @fail_count.setReadOnly(true)
271
+ @fail_count.setAlignment(Qt::AlignHCenter)
272
+ @fail_count.setColors(Cosmos::RED, Cosmos::WHITE)
273
+ @executing_status.addWidget(@fail_count)
274
+ @progress_bar = Qt::ProgressBar.new
275
+ @progress_bar.setFixedWidth(200)
276
+ @progress_bar.setMinimum(0)
277
+ @progress_bar.setMaximum(100)
278
+ @executing_status.addWidget(@progress_bar)
279
+ @frame.addLayout(@executing_status)
280
+
281
+ # Separator before ScriptRunnerFrame
282
+ @sep3 = Qt::Frame.new(@central_widget)
283
+ @sep3.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)
284
+ @frame.addWidget(@sep3)
285
+
286
+ @script_runner_frame = ScriptRunnerFrame.new(self)
287
+ @script_runner_frame.setContentsMargins(0,0,0,0)
288
+ @script_runner_frame.stop_callback = method(:handle_stop)
289
+ @script_runner_frame.allow_start = false
290
+ ScriptRunnerFrame.pause_on_error = true
291
+ @script_runner_frame.continue_after_error = true
292
+ @script_runner_frame.error_callback = method(:handle_error)
293
+ Test.abort_on_exception = false
294
+ @frame.addWidget(@script_runner_frame)
295
+
296
+ setCentralWidget(@central_widget)
297
+
298
+ # Display a blank message to force the statusBar to show
299
+ statusBar.showMessage("")
300
+ end
301
+
302
+ def status_timeout
303
+ pass_count = TestStatus.instance.pass_count
304
+ skip_count = TestStatus.instance.skip_count
305
+ fail_count = TestStatus.instance.fail_count
306
+ @test_status.text = TestStatus.instance.status
307
+ @pass_count.text = pass_count.to_s
308
+ @skip_count.text = skip_count.to_s
309
+ @fail_count.text = fail_count.to_s
310
+ if TestStatus.instance.status != ''
311
+ run_count = pass_count + skip_count + fail_count
312
+ total_count = TestStatus.instance.total
313
+ mod_run_count = run_count % total_count
314
+ progress = ((mod_run_count.to_f / total_count) * 100.0).to_i
315
+ @progress_bar.setValue(progress)
316
+ else
317
+ @progress_bar.setValue(0)
318
+ end
319
+ end
320
+
321
+ def self.results_writer
322
+ @@results_writer
323
+ end
324
+
325
+ def self.exec_test(result_string, test_suite_class, test_class = nil, test_case = nil)
326
+ @@started_success = false
327
+ @@test_suites.each do |test_suite|
328
+ if test_suite.class == test_suite_class
329
+ @@started_success = @@results_writer.collect_metadata(@@instance)
330
+ if @@started_success
331
+ @@results_writer.start(result_string, test_suite_class, test_class, test_case, @@settings)
332
+ loop do
333
+ yield(test_suite)
334
+ break if not @@settings['Loop Testing'] or (TestStatus.instance.fail_count > 0 and @@settings['Break Loop after Error'])
335
+ end
336
+ end
337
+ break
338
+ end
339
+ end
340
+ end
341
+
342
+ def self.start(test_suite_class, test_class = nil, test_case = nil)
343
+ result = []
344
+ exec_test('', test_suite_class, test_class, test_case) do |test_suite|
345
+ if test_case
346
+ result = test_suite.run_test_case(test_class, test_case)
347
+ @@results_writer.process_result(result)
348
+ raise StopScript if (result.exceptions and Test.abort_on_exception) or result.stopped
349
+ elsif test_class
350
+ test_suite.run_test(test_class) { |current_result| @@results_writer.process_result(current_result); raise StopScript if current_result.stopped }
351
+ else
352
+ test_suite.run { |current_result| @@results_writer.process_result(current_result); raise StopScript if current_result.stopped }
353
+ end
354
+ end
355
+ end
356
+
357
+ def self.start_setup(test_suite_class, test_class = nil)
358
+ exec_test('Manual Setup', test_suite_class, test_class) do |test_suite|
359
+ if test_class
360
+ result = test_suite.run_test_setup(test_class)
361
+ else
362
+ result = test_suite.run_setup
363
+ end
364
+ if result
365
+ @@results_writer.process_result(result)
366
+ raise StopScript if result.stopped
367
+ end
368
+ end
369
+ end
370
+
371
+ def self.start_teardown(test_suite_class, test_class = nil)
372
+ exec_test('Manual Teardown', test_suite_class, test_class) do |test_suite|
373
+ if test_class
374
+ result = test_suite.run_test_teardown(test_class)
375
+ else
376
+ result = test_suite.run_teardown
377
+ end
378
+ if result
379
+ @@results_writer.process_result(result)
380
+ raise StopScript if result.stopped
381
+ end
382
+ end
383
+ end
384
+
385
+ def continue_without_pausing_on_errors?
386
+ if !@pause_on_error.isChecked()
387
+ msg = ""
388
+ if @continue_test_case_after_error.isChecked() and @abort_testing_after_error.isChecked()
389
+ msg = "the currently executing test case will run to completion before aborting"
390
+ elsif !@continue_test_case_after_error.isChecked() and @abort_testing_after_error.isChecked()
391
+ msg = "all testing will be aborted on an error"
392
+ elsif @continue_test_case_after_error.isChecked() and !@abort_testing_after_error.isChecked()
393
+ msg = "all testing will run to completion"
394
+ else
395
+ msg = "the next test case will start executing"
396
+ end
397
+
398
+ if Qt::MessageBox.warning(self, "Warning", "If an error occurs, testing will not pause and #{msg}. Continue?", Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::Yes) == Qt::MessageBox::No
399
+ return false
400
+ end
401
+ end
402
+ true
403
+ end
404
+
405
+ def continue_loop_testing?
406
+ if @loop_testing.isChecked()
407
+ msg = ""
408
+ if @break_loop_after_error.isChecked()
409
+ msg = "unless an error occurs"
410
+ else
411
+ msg = "until explicitly stopped"
412
+ end
413
+
414
+ if Qt::MessageBox.warning(self, "Warning", "Loop testing is enabled. Tests will run forever #{msg}. Continue?", Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::Yes) == Qt::MessageBox::No
415
+ return false
416
+ end
417
+ end
418
+ true
419
+ end
420
+
421
+ ###########################################
422
+ # Callbacks
423
+ ###########################################
424
+
425
+ def generic_handler(test_suite, test = nil, test_case = nil)
426
+ return unless continue_without_pausing_on_errors?
427
+ return unless continue_loop_testing?()
428
+
429
+ # TODO: This can take a while depending on the number of tests and their
430
+ # complexity. Consider making a progress bar for this.
431
+ require_utilities()
432
+ handle_check_buttons()
433
+ @script_runner_frame.stop_message_log
434
+ yield
435
+ @script_runner_frame.run
436
+ end
437
+
438
+ def handle_start(test_suite, test = nil, test_case = nil)
439
+ generic_handler(test_suite, test, test_case) do
440
+ if test_case
441
+ @script_runner_frame.set_text("TestRunner.start(#{test_suite}, #{test}, '#{test_case}')", "#{test_suite}_#{test}_#{test_case}")
442
+ elsif test
443
+ @script_runner_frame.set_text("TestRunner.start(#{test_suite}, #{test})", "#{test_suite}_#{test}")
444
+ else
445
+ @script_runner_frame.set_text("TestRunner.start(#{test_suite})", test_suite)
446
+ end
447
+ end
448
+ end
449
+
450
+ def handle_setup(test_suite, test = nil)
451
+ generic_handler(test_suite, test) do
452
+ if test
453
+ @script_runner_frame.set_text("TestRunner.start_setup(#{test_suite}, #{test})", "#{test_suite}_#{test}_setup")
454
+ else
455
+ @script_runner_frame.set_text("TestRunner.start_setup(#{test_suite})", "#{test_suite}_setup")
456
+ end
457
+ end
458
+ end
459
+
460
+ def handle_teardown(test_suite, test = nil)
461
+ generic_handler(test_suite, test) do
462
+ if test
463
+ @script_runner_frame.set_text("TestRunner.start_teardown(#{test_suite}, #{test})", "#{test_suite}_#{test}_teardown")
464
+ else
465
+ @script_runner_frame.set_text("TestRunner.start_teardown(#{test_suite})", "#{test_suite}_teardown")
466
+ end
467
+ end
468
+ end
469
+
470
+ def handle_check_buttons
471
+ if @pause_on_error.isChecked()
472
+ ScriptRunnerFrame.pause_on_error = true
473
+ else
474
+ ScriptRunnerFrame.pause_on_error = false
475
+ end
476
+
477
+ if @continue_test_case_after_error.isChecked()
478
+ @script_runner_frame.continue_after_error = true
479
+ else
480
+ @script_runner_frame.continue_after_error = false
481
+ end
482
+
483
+ if @abort_testing_after_error.isChecked()
484
+ Test.abort_on_exception = true
485
+ else
486
+ Test.abort_on_exception = false
487
+ end
488
+
489
+ @@settings['Pause on Error'] = @pause_on_error.isChecked()
490
+ @@settings['Continue Test Case after Error'] = @continue_test_case_after_error.isChecked()
491
+ @@settings['Abort Testing after Error'] = @abort_testing_after_error.isChecked()
492
+ @@settings['Manual'] = @manual.isChecked()
493
+ @@settings['Loop Testing'] = @loop_testing.isChecked()
494
+ @@settings['Break Loop after Error'] = @break_loop_after_error.isChecked()
495
+
496
+ disable_while_running()
497
+ end
498
+
499
+ def handle_stop(script_runner_frame)
500
+ if @@started_success
501
+ @@results_writer.complete
502
+ if @@results_writer.data_package
503
+ ProgressDialog.execute(self, 'Data Package Creation Progress', 600, 300) do |progress_dialog|
504
+ @@results_writer.create_data_package(progress_dialog)
505
+ end
506
+ end
507
+ end
508
+ enable_while_stopped()
509
+ show_results() if @@started_success
510
+ end
511
+
512
+ def handle_error(script_runner_frame)
513
+ if @continue_test_case_after_error.isChecked()
514
+ script_runner_frame.enable_retry()
515
+ else
516
+ script_runner_frame.disable_retry()
517
+ end
518
+ end
519
+
520
+ def disable_while_running
521
+ TestStatus.instance.status = ''
522
+ TestStatus.instance.pass_count = 0
523
+ TestStatus.instance.skip_count = 0
524
+ TestStatus.instance.fail_count = 0
525
+ @manual.setEnabled(false)
526
+ @pause_on_error.setEnabled(false)
527
+ @continue_test_case_after_error.setEnabled(false)
528
+ @abort_testing_after_error.setEnabled(false)
529
+ @loop_testing.setEnabled(false)
530
+ @break_loop_after_error.setEnabled(false)
531
+ @test_runner_chooser.setEnabled(false)
532
+ @show_last.setEnabled(false)
533
+ @select.setEnabled(false)
534
+ @test_results_log_message.setEnabled(true)
535
+ @script_log_message.setEnabled(true)
536
+ @show_call_stack.setEnabled(true)
537
+ end
538
+
539
+ def enable_while_stopped
540
+ @manual.setEnabled(true)
541
+ @pause_on_error.setEnabled(true)
542
+ @continue_test_case_after_error.setEnabled(true)
543
+ @abort_testing_after_error.setEnabled(true)
544
+ @loop_testing.setEnabled(true)
545
+ @break_loop_after_error.setEnabled(true) if @loop_testing.isChecked()
546
+ @test_runner_chooser.setEnabled(true)
547
+ @show_last.setEnabled(true)
548
+ @select.setEnabled(true)
549
+ @test_results_log_message.setEnabled(false)
550
+ @script_log_message.setEnabled(false)
551
+ @show_call_stack.setEnabled(false)
552
+ TestStatus.instance.status = ''
553
+ end
554
+
555
+ def closeEvent(event)
556
+ if @script_runner_frame.prompt_if_running_on_close()
557
+ shutdown_cmd_tlm()
558
+ @script_runner_frame.stop_message_log
559
+ super(event)
560
+ else
561
+ event.ignore()
562
+ end
563
+ end
564
+
565
+ def on_test_results_log_message
566
+ message = get_scriptrunner_log_message('Test Results Text Entry', 'Enter text to log to the test results file')
567
+ if message
568
+ Cosmos::Test.puts('User logged: ' + message.to_s)
569
+ @script_runner_frame.handle_output_io
570
+ end
571
+ end
572
+
573
+ def on_script_log_message
574
+ message = get_scriptrunner_log_message()
575
+ if message
576
+ @script_runner_frame.scriptrunner_puts 'User logged: ' + message.to_s
577
+ @script_runner_frame.handle_output_io
578
+ end
579
+ end
580
+
581
+ def on_script_call_stack
582
+ trace = @script_runner_frame.current_backtrace
583
+ ScrollTextDialog.new(self, 'Call Stack', trace.join("\n"))
584
+ end
585
+
586
+ def on_script_toggle_debug
587
+ @script_runner_frame.toggle_debug
588
+ end
589
+
590
+ def on_script_toggle_disconnect
591
+ @server_config_file = @script_runner_frame.toggle_disconnect(@server_config_file)
592
+ end
593
+
594
+ include ScriptAudit # script_audit()
595
+
596
+ def require_utilities
597
+ ScriptRunnerFrame.instance = @script_runner_frame
598
+ build = false
599
+ @utilities.each do |utility|
600
+ if require_utility(utility)
601
+ build = true
602
+ end
603
+ end
604
+ if build
605
+ build_test_suites()
606
+ end
607
+ ScriptRunnerFrame.instance = nil
608
+ end
609
+
610
+ # Show Dialog box with textfield containing results
611
+ def show_results
612
+ if @@results_writer.filename
613
+ results_text = File.read(@@results_writer.filename)
614
+
615
+ dialog = Qt::Dialog.new(self) do |box|
616
+ box.setWindowTitle('Results')
617
+ box.resize(600, 600)
618
+ text_field = Qt::PlainTextEdit.new
619
+ text_field.setReadOnly(true)
620
+ orig_font = text_field.font
621
+ text_field.setFont(Cosmos.getFont(orig_font.family, orig_font.point_size+2))
622
+ text_field.setWordWrapMode(Qt::TextOption::NoWrap)
623
+ state = :NORMAL
624
+ results_text.each_line do |line|
625
+ state = :NORMAL if line[0..0] != ' ' and line.strip.length != 0
626
+ if line =~ /:PASS/
627
+ text_field.appendText(line, Cosmos::GREEN)
628
+ state = :PASS
629
+ elsif line =~ /:SKIP/
630
+ text_field.appendText(line, Cosmos::YELLOW)
631
+ state = :SKIP
632
+ elsif line =~ /:FAIL/
633
+ text_field.appendText(line, Cosmos::RED)
634
+ state = :FAIL
635
+ else
636
+ case state
637
+ when :NORMAL
638
+ text_field.appendText(line)
639
+ when :PASS
640
+ text_field.appendText(line, Cosmos::GREEN)
641
+ when :SKIP
642
+ text_field.appendText(line, Cosmos::YELLOW)
643
+ when :FAIL
644
+ text_field.appendText(line, Cosmos::RED)
645
+ end
646
+ end
647
+ end
648
+
649
+ vframe = Qt::VBoxLayout.new
650
+ vframe.addWidget(text_field)
651
+
652
+ # Separator Between checkboxes
653
+ sep = Qt::Frame.new(box)
654
+ sep.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
655
+ vframe.addWidget(sep)
656
+
657
+ ok = Qt::PushButton.new('OK')
658
+ ok.setDefault(true)
659
+ ok.connect(SIGNAL('clicked(bool)')) { box.accept }
660
+ vframe.addWidget(ok)
661
+ box.setLayout(vframe)
662
+ end
663
+ dialog.exec
664
+ dialog.dispose
665
+ end
666
+ end
667
+
668
+ def create_node(yard_doc, name, tree)
669
+ node = Qt::TreeWidgetItem.new([name])
670
+ node.setCheckState(0, Qt::Unchecked)
671
+ yield node
672
+ description = yard_doc.nil? ? "" : yard_doc.docstring
673
+ description = UNASSIGNED_SUITE_DESCRIPTION if name == "UnassignedTestSuite"
674
+ desc_label = Qt::Label.new(description.gsub(/\n/,' '))
675
+ desc_label.setMinimumHeight(desc_label.fontMetrics.height * 2)
676
+ desc_label.setWordWrap(true)
677
+ tree.setItemWidget(node, 1, desc_label)
678
+ return node
679
+ end
680
+
681
+ # Show Dialog box with tree of tests to allow the user to select
682
+ # a subset of tests. This also shows the Test Descriptions.
683
+ def show_select
684
+ dialog = Qt::Dialog.new(self) do |box|
685
+ box.setWindowTitle('Test Selections')
686
+ box.resize(650, 600)
687
+ @procedure_dirs.each do |dir|
688
+ # Set the logging level to ERROR to avoid output if one of the
689
+ # scripts we are parsing has syntax errors
690
+ YARD.parse(File.join(dir, '**', '*.rb'), [], YARD::Logger::ERROR)
691
+ end
692
+
693
+ tree = Qt::TreeWidget.new
694
+ tree.setColumnCount(2)
695
+ tree.setHeaderLabels(["Name", "Description"])
696
+ tree.connect(SIGNAL('itemClicked(QTreeWidgetItem*, int)')) do |widget, column|
697
+ tree.topLevelItems do |suite_node|
698
+ if suite_node != widget.topLevel
699
+ suite_node.setCheckStateAll(Qt::Unchecked)
700
+ end
701
+ end
702
+ end
703
+
704
+ orig_font = nil
705
+ @@test_suites.each do |suite|
706
+ next if suite.name == "Cosmos::CustomTestSuite"
707
+ doc = YARD::Registry.resolve(nil, suite.name)
708
+ suite_node = create_node(doc, suite.name, tree) do |node|
709
+ orig_font = node.font(0)
710
+ new_font = Cosmos.getFont(orig_font.family,
711
+ orig_font.point_size+5,
712
+ Qt::Font::Bold)
713
+ node.setFont(0, new_font)
714
+ tree.addTopLevelItem(node)
715
+ end
716
+
717
+ if suite.respond_to? :setup
718
+ doc = YARD::Registry.resolve(P(suite.name.to_s), "#setup", true)
719
+ create_node(doc, "setup", tree) do |node|
720
+ font = Cosmos.getFont(orig_font.family,
721
+ orig_font.point_size,
722
+ Qt::Font::Normal,
723
+ true) # italic
724
+ node.setFont(0, font)
725
+ suite_node.addChild(node)
726
+ end
727
+ end
728
+
729
+ suite.tests.each do |test_class, test|
730
+ doc = YARD::Registry.resolve(nil, test.name)
731
+ test_node = create_node(doc, test.name, tree) do |node|
732
+ font = Cosmos.getFont(orig_font.family,
733
+ orig_font.point_size + 2,
734
+ Qt::Font::Bold)
735
+ node.setFont(0, font)
736
+ suite_node.addChild(node)
737
+ node.setExpanded(true)
738
+ end
739
+
740
+ if test.respond_to? :setup
741
+ doc = YARD::Registry.resolve(P(test_class.to_s), "#setup", true)
742
+ create_node(doc, "setup", tree) do |node|
743
+ font = Cosmos.getFont(orig_font.family,
744
+ orig_font.point_size,
745
+ Qt::Font::Normal,
746
+ true) # italic
747
+ node.setFont(0, font)
748
+ test_node.addChild(node)
749
+ end
750
+ end
751
+
752
+ test_class.test_cases.each do |tc|
753
+ doc = YARD::Registry.resolve(P(test_class.to_s), "##{tc.to_s}", true)
754
+ create_node(doc, tc.to_s, tree) do |node|
755
+ test_node.addChild(node)
756
+ end
757
+ end
758
+
759
+ if test.respond_to? :teardown
760
+ doc = YARD::Registry.resolve(P(test_class.to_s), "#teardown", true)
761
+ create_node(doc, "teardown", tree) do |node|
762
+ font = Cosmos.getFont(orig_font.family,
763
+ orig_font.point_size,
764
+ Qt::Font::Normal,
765
+ true) # italic
766
+ node.setFont(0, font)
767
+ test_node.addChild(node)
768
+ end
769
+ end
770
+ end # suite.tests.each
771
+
772
+ if suite.respond_to? :teardown
773
+ doc = YARD::Registry.resolve(P(suite.name.to_s), "#teardown", true)
774
+ create_node(doc, "teardown", tree) do |node|
775
+ font = Cosmos.getFont(orig_font.family,
776
+ orig_font.point_size,
777
+ Qt::Font::Normal,
778
+ true) # italic
779
+ node.setFont(0, font)
780
+ suite_node.addChild(node)
781
+ end
782
+ end
783
+ end
784
+
785
+ tree.resizeColumnToContents(0)
786
+ dialog_layout = Qt::VBoxLayout.new
787
+ text = "Select test cases to be run in a newly created 'CustomTestSuite'. "\
788
+ "Note that tests can only be added from a single existing Test Suite. " \
789
+ "Thus clicking on something in another Test Suite deselects anything " \
790
+ "currently selected."
791
+ instructions = Qt::Label.new(text)
792
+ instructions.setWordWrap(true)
793
+ dialog_layout.addWidget(instructions)
794
+ dialog_layout.addWidget(tree)
795
+
796
+ # Separator Between checkboxes
797
+ sep = Qt::Frame.new(box)
798
+ sep.setFrameStyle(Qt::Frame::VLine | Qt::Frame::Sunken)
799
+ dialog_layout.addWidget(sep)
800
+
801
+ button_box = Qt::DialogButtonBox.new(Qt::DialogButtonBox::Ok |
802
+ Qt::DialogButtonBox::Cancel)
803
+ connect(button_box, SIGNAL('rejected()'), box, SLOT('reject()'))
804
+ connect(button_box, SIGNAL('accepted()')) do
805
+ Cosmos.module_eval("class CustomTestSuite < TestSuite; end")
806
+ tree.topLevelItems do |suite_node|
807
+ next if suite_node.checkState == Qt::Unchecked
808
+ cur_suite = OpenStruct.new(:setup=>false, :teardown=>false, :tests=>{})
809
+ suite = CustomTestSuite.new
810
+ begin
811
+ # Remove any previously defined suite setup methods
812
+ CustomTestSuite.send(:remove_method, :setup)
813
+ rescue NameError
814
+ # NameError is raised if no setup method was defined
815
+ end
816
+ begin
817
+ # Remove any previously defined suite teardown methods
818
+ CustomTestSuite.send(:remove_method, :teardown)
819
+ rescue NameError
820
+ # NameError is raised if no teardown method was defined
821
+ end
822
+
823
+ suite_node.children do |test_node|
824
+ if test_node.checkState == Qt::Checked
825
+ if test_node.text == 'setup'
826
+ cur_suite.setup = true
827
+ # Find the suite instance among the test suites
828
+ inst = @@test_suites.detect {|my_suite| my_suite.class.to_s == suite_node.text}
829
+ # Create a lambda which will call that one setup method
830
+ body = lambda { inst.setup }
831
+ CustomTestSuite.send(:define_method, :setup, &body)
832
+ end
833
+ if test_node.text == 'teardown'
834
+ cur_suite.teardown = true
835
+ # Find the suite instance among the test suites
836
+ inst = @@test_suites.detect {|my_suite| my_suite.class.to_s == suite_node.text}
837
+ # Create a lambda which will call that one teardown method
838
+ body = lambda { inst.teardown}
839
+ CustomTestSuite.send(:define_method, :teardown, &body)
840
+ end
841
+ end
842
+
843
+ test_node.children do |test_case|
844
+ next if test_case.checkState == Qt::Unchecked
845
+ node = cur_suite.tests[test_node.text] ||=
846
+ OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
847
+
848
+ case test_case.text
849
+ when 'setup'
850
+ suite.add_test_setup(test_node.text)
851
+ node.setup = true
852
+ when 'teardown'
853
+ suite.add_test_teardown(test_node.text)
854
+ node.teardown = true
855
+ else
856
+ suite.add_test_case(test_node.text, test_case.text)
857
+ node.cases << test_case.text
858
+ end
859
+ end
860
+ end
861
+ @@suites["CustomTestSuite"] = cur_suite
862
+ @@test_suites = @@test_suites.select {|my_suite| my_suite.class != CustomTestSuite}
863
+ @@test_suites << suite
864
+ end
865
+ Qt.execute_in_main_thread(true) do
866
+ @test_runner_chooser.test_suites = @@suites
867
+ @test_runner_chooser.select_suite("CustomTestSuite")
868
+ end
869
+ box.accept
870
+ end
871
+ dialog_layout.addWidget(button_box)
872
+ box.setLayout(dialog_layout)
873
+ end
874
+ dialog.raise
875
+ dialog.exec
876
+ dialog.dispose
877
+ end
878
+
879
+ def process_config(filename)
880
+ ScriptRunnerFrame.instance = @script_runner_frame
881
+
882
+ # Remember all the requires that fail and warn the user
883
+ require_errors = []
884
+
885
+ # Ensure the file exists
886
+ raise "Configuration File: #{filename} does not exist" unless test(?f, filename)
887
+ parser = ConfigParser.new
888
+ parser.parse_file(filename) do |keyword, params|
889
+ case keyword
890
+ when 'REQUIRE_UTILITY'
891
+ parser.verify_num_parameters(1, 1, "REQUIRE_UTILITY <filename>")
892
+ begin
893
+ require_utility params[0]
894
+ @utilities << params[0]
895
+ rescue Exception => err
896
+ require_errors << "<b>#{params[0]}</b>:\n#{err.formatted}\n"
897
+ end
898
+
899
+ when 'RESULTS_WRITER'
900
+ data_package = @@results_writer.data_package
901
+ metadata = @@results_writer.metadata
902
+ parser.verify_num_parameters(1, nil, "RESULTS_WRITER <filename> <class specific options>")
903
+ results_class = Cosmos.require_class(params[0])
904
+ if params[1]
905
+ @@results_writer = results_class.new(*params[1..-1])
906
+ else
907
+ @@results_writer = results_class.new
908
+ end
909
+ @@results_writer.data_package = data_package
910
+ @@results_writer.metadata = metadata
911
+
912
+ when 'ALLOW_DEBUG'
913
+ parser.verify_num_parameters(0, 0, "ALLOW_DEBUG")
914
+ Qt.execute_in_main_thread(true) { @toggle_debug.setEnabled(true) }
915
+
916
+ when 'PAUSE_ON_ERROR'
917
+ parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
918
+ Qt.execute_in_main_thread(true) do
919
+ @pause_on_error.setChecked(ConfigParser.handle_true_false(params[0]))
920
+ end
921
+
922
+ when 'CONTINUE_TEST_CASE_AFTER_ERROR'
923
+ parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
924
+ Qt.execute_in_main_thread(true) { @continue_test_case_after_error.setChecked(ConfigParser.handle_true_false(params[0])) }
925
+
926
+ when 'ABORT_TESTING_AFTER_ERROR'
927
+ parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
928
+ Qt.execute_in_main_thread(true) { @abort_testing_after_error.setChecked(ConfigParser.handle_true_false(params[0])) }
929
+
930
+ when 'MANUAL'
931
+ parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
932
+ Qt.execute_in_main_thread(true) do
933
+ @manual.setChecked(ConfigParser.handle_true_false(params[0]))
934
+ if @manual.isChecked()
935
+ $manual = true
936
+ else
937
+ $manual = false
938
+ end
939
+ end
940
+
941
+ when 'LOOP_TESTING'
942
+ parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
943
+ Qt.execute_in_main_thread(true) do
944
+ @loop_testing.setChecked(ConfigParser.handle_true_false(params[0]))
945
+ if @loop_testing.isChecked()
946
+ $loop_testing = true
947
+ @break_loop_after_error.setEnabled(true)
948
+ else
949
+ $loop_testing = false
950
+ @break_loop_after_error.setEnabled(false)
951
+ end
952
+ end
953
+
954
+ when 'BREAK_LOOP_AFTER_ERROR'
955
+ parser.verify_num_parameters(1, 1, "#{keyword} <TRUE or FALSE>")
956
+ Qt.execute_in_main_thread(true) { @break_loop_after_error.setChecked(ConfigParser.handle_true_false(params[0])) }
957
+
958
+ when 'IGNORE_TEST'
959
+ parser.verify_num_parameters(1, 1, "#{keyword} <Test Class Name (case sensitive)>")
960
+ @ignore_tests << params[0]
961
+
962
+ when 'IGNORE_TEST_SUITE'
963
+ parser.verify_num_parameters(1, 1, "#{keyword} <Test Suite Class Name (case sensitive)>")
964
+ @ignore_test_suites << params[0]
965
+
966
+ when 'LINE_DELAY'
967
+ parser.verify_num_parameters(1, 1, "#{keyword} <Line Delay in Seconds>")
968
+ ScriptRunnerFrame.line_delay = params[0].to_f
969
+
970
+ when 'MONITOR_LIMITS'
971
+ parser.verify_num_parameters(0, 0, keyword)
972
+ ScriptRunnerFrame.monitor_limits = true
973
+
974
+ when 'PAUSE_ON_RED'
975
+ parser.verify_num_parameters(0, 0, keyword)
976
+ ScriptRunnerFrame.monitor_limits = true
977
+ ScriptRunnerFrame.pause_on_red = true
978
+
979
+ when 'CREATE_DATA_PACKAGE'
980
+ parser.verify_num_parameters(0, 0, keyword)
981
+ @@results_writer.data_package = true
982
+
983
+ when 'AUTO_CYCLE_LOGS'
984
+ parser.verify_num_parameters(0, 0, keyword)
985
+ @@results_writer.auto_cycle_logs = true
986
+
987
+ # TODO: Deprecate COLLECT_META_DATA
988
+ when 'COLLECT_METADATA', 'COLLECT_META_DATA'
989
+ parser.verify_num_parameters(2, 2, "#{keyword} <Metadata Target Name> <Metadata Packet Name>")
990
+ System.telemetry.packet(params[0], params[1])
991
+ @@results_writer.metadata = [params[0], params[1]]
992
+
993
+ else
994
+ raise "Unhandled keyword: #{keyword}" if keyword
995
+ end
996
+ end
997
+
998
+ # Warn the user about all the requires that failed
999
+ unless require_errors.empty?
1000
+ Qt.execute_in_main_thread(true) do
1001
+ message = "While loading the Test Runner configuration file: #{filename}."
1002
+ message << "\n\nThe following errors occurred:\n#{require_errors.join("\n")}" unless require_errors.empty?
1003
+ ScrollTextDialog.new(self, "TestRunner Errors", message)
1004
+ end
1005
+ end
1006
+
1007
+ # Build Test objects
1008
+ build_test_suites()
1009
+
1010
+ ScriptRunnerFrame.instance = nil
1011
+ end
1012
+
1013
+ def build_test_suites
1014
+ ScriptRunnerFrame.instance.use_instrumentation = false
1015
+
1016
+ ignored_test_classes = []
1017
+ ignored_test_suite_classes = []
1018
+
1019
+ @ignore_tests.each do |test_name|
1020
+ begin
1021
+ klass = Object.const_get(test_name)
1022
+ ignored_test_classes << klass if klass
1023
+ rescue
1024
+ end
1025
+ end
1026
+
1027
+ @ignore_test_suites.each do |test_suite_name|
1028
+ begin
1029
+ klass = Object.const_get(test_suite_name)
1030
+ ignored_test_suite_classes << klass if klass
1031
+ rescue
1032
+ end
1033
+ end
1034
+
1035
+ # Build list of TestSuites and Tests
1036
+ @@test_suites = []
1037
+ tests = []
1038
+ ObjectSpace.each_object(Class) do |object|
1039
+ if (object.ancestors.include?(TestSuite) &&
1040
+ object != TestSuite &&
1041
+ !ignored_test_suite_classes.include?(object))
1042
+ @@test_suites << object.new
1043
+ end
1044
+ if (object.ancestors.include?(Test) &&
1045
+ object != Test &&
1046
+ !ignored_test_classes.include?(object))
1047
+ tests << object
1048
+ end
1049
+ end
1050
+ # Raise error if no test suites or tests
1051
+ if @@test_suites.empty? || tests.empty?
1052
+ msg = "No TestSuites or no Test classes found"
1053
+ if !ignored_test_suite_classes.empty?
1054
+ msg += "\n\nThe following TestSuites were found but ignored:\n#{ignored_test_suite_classes.join(", ")}"
1055
+ end
1056
+ if !ignored_test_classes.empty?
1057
+ msg += "\n\nThe following Tests were found but ignored:\n#{ignored_test_classes.join(", ")}"
1058
+ end
1059
+ Qt.execute_in_main_thread(true) do
1060
+ Qt::MessageBox.critical(self, 'Error', msg)
1061
+ end
1062
+ exit 1
1063
+ end
1064
+
1065
+ # Create TestSuite for unassigned Tests
1066
+ @@test_suites.sort!
1067
+ @@test_suites.each do |test_suite|
1068
+ tests_to_delete = []
1069
+ tests.each { |test| tests_to_delete << test if test_suite.tests[test] }
1070
+ tests_to_delete.each { |test| tests.delete(test) }
1071
+ end
1072
+ if tests.empty?
1073
+ @@test_suites = @@test_suites.select {|suite| suite.class != UnassignedTestSuite}
1074
+ else
1075
+ uts = @@test_suites.select {|suite| suite.class == UnassignedTestSuite}[0]
1076
+ tests.each { |test| uts.add_test(test) }
1077
+ end
1078
+
1079
+ ScriptRunnerFrame.instance.use_instrumentation = true
1080
+ @@test_suites.each do |suite|
1081
+ cur_suite = OpenStruct.new(:setup=>false, :teardown=>false, :tests=>{})
1082
+ cur_suite.setup = true if suite.class.method_defined?(:setup)
1083
+ cur_suite.teardown = true if suite.class.method_defined?(:teardown)
1084
+
1085
+ suite.plans.each do |test_type, test_class, test_case|
1086
+ case test_type
1087
+ when :TEST
1088
+ cur_suite.tests[test_class.name] ||=
1089
+ OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1090
+ cur_suite.tests[test_class.name].cases.concat(test_class.test_cases)
1091
+ cur_suite.tests[test_class.name].cases.uniq!
1092
+ cur_suite.tests[test_class.name].cases.sort!
1093
+ cur_suite.tests[test_class.name].setup = true if test_class.method_defined?(:setup)
1094
+ cur_suite.tests[test_class.name].teardown = true if test_class.method_defined?(:teardown)
1095
+ when :TEST_CASE
1096
+ cur_suite.tests[test_class.name] ||=
1097
+ OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1098
+ # Explicitly check for this method and raise an error if it does not exist
1099
+ if test_class.method_defined?(test_case.intern)
1100
+ cur_suite.tests[test_class.name].cases << test_case
1101
+ cur_suite.tests[test_class.name].cases.uniq!
1102
+ cur_suite.tests[test_class.name].cases.sort!
1103
+ else
1104
+ raise "#{test_class} does not have a #{test_case} method defined."
1105
+ end
1106
+ cur_suite.tests[test_class.name].setup = true if test_class.method_defined?(:setup)
1107
+ cur_suite.tests[test_class.name].teardown = true if test_class.method_defined?(:teardown)
1108
+ when :TEST_SETUP
1109
+ cur_suite.tests[test_class.name] ||=
1110
+ OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1111
+ # Explicitly check for the setup method and raise an error if it does not exist
1112
+ if test_class.method_defined?(:setup)
1113
+ cur_suite.tests[test_class.name].setup = true
1114
+ else
1115
+ raise "#{test_class} does not have a setup method defined."
1116
+ end
1117
+ when :TEST_TEARDOWN
1118
+ cur_suite.tests[test_class.name] ||=
1119
+ OpenStruct.new(:setup=>false, :teardown=>false, :cases=>[])
1120
+ # Explicitly check for the teardown method and raise an error if it does not exist
1121
+ if test_class.method_defined?(:teardown)
1122
+ cur_suite.tests[test_class.name].teardown = true
1123
+ else
1124
+ raise "#{test_class} does not have a teardown method defined."
1125
+ end
1126
+ end
1127
+ end
1128
+ @@suites[suite.name.split('::')[-1]] = cur_suite
1129
+ end
1130
+ Qt.execute_in_main_thread(true) { @test_runner_chooser.test_suites = @@suites }
1131
+ end
1132
+
1133
+ def self.run(option_parser = nil, options = nil)
1134
+ Cosmos.catch_fatal_exception do
1135
+ unless option_parser and options
1136
+ option_parser, options = create_default_options()
1137
+ options.width = 800
1138
+ options.height = 700
1139
+ options.title = "Test Runner"
1140
+ options.auto_size = false
1141
+ options.config_file = File.join(Cosmos::USERPATH, 'config', 'tools', 'test_runner', 'test_runner.txt')
1142
+ options.server_config_file = CmdTlmServer::DEFAULT_CONFIG_FILE
1143
+ option_parser.separator "Test Runner Specific Options:"
1144
+ option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
1145
+ options.config_file = File.join(Cosmos::USERPATH, 'config', 'tools', 'test_runner', arg)
1146
+ end
1147
+ option_parser.on("-s", "--server FILE", "Use the specified server configuration file for disconnect mode") do |arg|
1148
+ options.server_config_file = arg
1149
+ end
1150
+ end
1151
+
1152
+ super(option_parser, options)
1153
+ end
1154
+ end
1155
+ end # class TestRunner
1156
+
1157
+ end # module Cosmos