laser 0.7.0.pre1

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 (319) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +14 -0
  4. data/LICENSE +661 -0
  5. data/README.md +158 -0
  6. data/Rakefile +104 -0
  7. data/VERSION +1 -0
  8. data/bin/laser +7 -0
  9. data/design_docs/goals.md +57 -0
  10. data/design_docs/object_regex.md +426 -0
  11. data/design_docs/type_annotations.md +80 -0
  12. data/ext/laser/BasicBlock.cpp +572 -0
  13. data/ext/laser/BasicBlock.h +118 -0
  14. data/ext/laser/extconf.rb +3 -0
  15. data/features/laser.feature +25 -0
  16. data/features/step_definitions/laser_steps.rb +39 -0
  17. data/features/support/env.rb +14 -0
  18. data/features/support/testdata/1_input +1 -0
  19. data/features/support/testdata/1_output +1 -0
  20. data/features/support/testdata/2_input +4 -0
  21. data/features/support/testdata/2_output +4 -0
  22. data/features/support/testdata/3_input +8 -0
  23. data/features/support/testdata/3_output +11 -0
  24. data/features/support/testdata/4_input +5 -0
  25. data/features/support/testdata/4_output +5 -0
  26. data/features/support/testdata/5_input +13 -0
  27. data/laser.gemspec +382 -0
  28. data/lib/laser.rb +98 -0
  29. data/lib/laser/analysis/annotations.rb +95 -0
  30. data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
  31. data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
  32. data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
  33. data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
  34. data/lib/laser/analysis/argument_expansion.rb +132 -0
  35. data/lib/laser/analysis/arity.rb +34 -0
  36. data/lib/laser/analysis/bindings.rb +144 -0
  37. data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
  38. data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
  39. data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
  40. data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
  41. data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
  42. data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
  43. data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
  44. data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
  45. data/lib/laser/analysis/comments.rb +35 -0
  46. data/lib/laser/analysis/control_flow.rb +28 -0
  47. data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
  48. data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
  49. data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
  50. data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
  51. data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
  52. data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
  53. data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
  54. data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
  55. data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
  56. data/lib/laser/analysis/control_flow/simulation.rb +385 -0
  57. data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
  58. data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
  59. data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
  60. data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
  61. data/lib/laser/analysis/errors.rb +131 -0
  62. data/lib/laser/analysis/laser_utils.rb +18 -0
  63. data/lib/laser/analysis/lexical_analysis.rb +172 -0
  64. data/lib/laser/analysis/method_call.rb +68 -0
  65. data/lib/laser/analysis/protocol_registry.rb +30 -0
  66. data/lib/laser/analysis/scope.rb +118 -0
  67. data/lib/laser/analysis/sexp.rb +159 -0
  68. data/lib/laser/analysis/sexp_analysis.rb +40 -0
  69. data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
  70. data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
  71. data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
  72. data/lib/laser/analysis/signature.rb +76 -0
  73. data/lib/laser/analysis/special_methods/send.rb +67 -0
  74. data/lib/laser/analysis/unused_methods.rb +21 -0
  75. data/lib/laser/analysis/visitor.rb +141 -0
  76. data/lib/laser/annotation_parser/annotations.treetop +126 -0
  77. data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
  78. data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
  79. data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
  80. data/lib/laser/annotation_parser/overload.treetop +24 -0
  81. data/lib/laser/annotation_parser/overload_parser.rb +167 -0
  82. data/lib/laser/annotation_parser/parsers.rb +6 -0
  83. data/lib/laser/annotation_parser/structural.treetop +37 -0
  84. data/lib/laser/annotation_parser/structural_parser.rb +406 -0
  85. data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
  86. data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
  87. data/lib/laser/rake/task.rb +46 -0
  88. data/lib/laser/runner.rb +189 -0
  89. data/lib/laser/scanner.rb +169 -0
  90. data/lib/laser/standard_library/_thread.rb +110 -0
  91. data/lib/laser/standard_library/abbrev.rb +103 -0
  92. data/lib/laser/standard_library/array.rb +418 -0
  93. data/lib/laser/standard_library/base64.rb +91 -0
  94. data/lib/laser/standard_library/basic_object.rb +55 -0
  95. data/lib/laser/standard_library/benchmark.rb +556 -0
  96. data/lib/laser/standard_library/bignum.rb +185 -0
  97. data/lib/laser/standard_library/cgi.rb +275 -0
  98. data/lib/laser/standard_library/cgi/cookie.rb +147 -0
  99. data/lib/laser/standard_library/cgi/core.rb +791 -0
  100. data/lib/laser/standard_library/cgi/html.rb +1021 -0
  101. data/lib/laser/standard_library/cgi/session.rb +537 -0
  102. data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
  103. data/lib/laser/standard_library/cgi/util.rb +188 -0
  104. data/lib/laser/standard_library/class_definitions.rb +333 -0
  105. data/lib/laser/standard_library/comparable.rb +125 -0
  106. data/lib/laser/standard_library/complex.rb +162 -0
  107. data/lib/laser/standard_library/enumerable.rb +178 -0
  108. data/lib/laser/standard_library/exceptions.rb +135 -0
  109. data/lib/laser/standard_library/fixnum.rb +188 -0
  110. data/lib/laser/standard_library/float.rb +180 -0
  111. data/lib/laser/standard_library/hash.rb +237 -0
  112. data/lib/laser/standard_library/integer.rb +123 -0
  113. data/lib/laser/standard_library/laser_magic.rb +7 -0
  114. data/lib/laser/standard_library/nil_false_true.rb +113 -0
  115. data/lib/laser/standard_library/numbers.rb +192 -0
  116. data/lib/laser/standard_library/proc.rb +31 -0
  117. data/lib/laser/standard_library/set.rb +1348 -0
  118. data/lib/laser/standard_library/string.rb +666 -0
  119. data/lib/laser/standard_library/stringio.rb +2 -0
  120. data/lib/laser/standard_library/symbol.rb +125 -0
  121. data/lib/laser/standard_library/tsort.rb +242 -0
  122. data/lib/laser/support/acts_as_struct.rb +66 -0
  123. data/lib/laser/support/frequency.rb +55 -0
  124. data/lib/laser/support/inheritable_attributes.rb +145 -0
  125. data/lib/laser/support/module_extensions.rb +94 -0
  126. data/lib/laser/support/placeholder_object.rb +13 -0
  127. data/lib/laser/third_party/rgl/adjacency.rb +221 -0
  128. data/lib/laser/third_party/rgl/base.rb +228 -0
  129. data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
  130. data/lib/laser/third_party/rgl/condensation.rb +47 -0
  131. data/lib/laser/third_party/rgl/connected_components.rb +138 -0
  132. data/lib/laser/third_party/rgl/control_flow.rb +170 -0
  133. data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
  134. data/lib/laser/third_party/rgl/dominators.rb +124 -0
  135. data/lib/laser/third_party/rgl/dot.rb +93 -0
  136. data/lib/laser/third_party/rgl/graphxml.rb +51 -0
  137. data/lib/laser/third_party/rgl/implicit.rb +174 -0
  138. data/lib/laser/third_party/rgl/mutable.rb +117 -0
  139. data/lib/laser/third_party/rgl/rdot.rb +445 -0
  140. data/lib/laser/third_party/rgl/topsort.rb +72 -0
  141. data/lib/laser/third_party/rgl/transitivity.rb +180 -0
  142. data/lib/laser/third_party/rgl/traversal.rb +348 -0
  143. data/lib/laser/types/types.rb +433 -0
  144. data/lib/laser/version.rb +14 -0
  145. data/lib/laser/warning.rb +149 -0
  146. data/lib/laser/warning_sets/default.yml +13 -0
  147. data/lib/laser/warnings/assignment_in_condition.rb +20 -0
  148. data/lib/laser/warnings/comment_spacing.rb +31 -0
  149. data/lib/laser/warnings/extra_blank_lines.rb +30 -0
  150. data/lib/laser/warnings/extra_whitespace.rb +16 -0
  151. data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
  152. data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
  153. data/lib/laser/warnings/line_length.rb +115 -0
  154. data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
  155. data/lib/laser/warnings/operator_spacing.rb +68 -0
  156. data/lib/laser/warnings/parens_on_declaration.rb +30 -0
  157. data/lib/laser/warnings/rescue_exception.rb +42 -0
  158. data/lib/laser/warnings/semicolon.rb +25 -0
  159. data/lib/laser/warnings/sexp_errors.rb +24 -0
  160. data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
  161. data/lib/laser/warnings/useless_double_quotes.rb +38 -0
  162. data/spec/analysis_specs/annotations_spec.rb +47 -0
  163. data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
  164. data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
  165. data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
  166. data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
  167. data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
  168. data/spec/analysis_specs/bindings_spec.rb +36 -0
  169. data/spec/analysis_specs/comment_spec.rb +93 -0
  170. data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
  171. data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
  172. data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
  173. data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
  174. data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
  175. data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
  176. data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
  177. data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
  178. data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
  179. data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
  180. data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
  181. data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
  182. data/spec/analysis_specs/error_spec.rb +30 -0
  183. data/spec/analysis_specs/laser_class_spec.rb +322 -0
  184. data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
  185. data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
  186. data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
  187. data/spec/analysis_specs/scope_spec.rb +126 -0
  188. data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
  189. data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
  190. data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
  191. data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
  192. data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
  193. data/spec/analysis_specs/sexp_spec.rb +167 -0
  194. data/spec/analysis_specs/spec_helper.rb +27 -0
  195. data/spec/analysis_specs/unused_methods_spec.rb +65 -0
  196. data/spec/analysis_specs/visitor_spec.rb +64 -0
  197. data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
  198. data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
  199. data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
  200. data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
  201. data/spec/annotation_parser_specs/spec_helper.rb +1 -0
  202. data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
  203. data/spec/laser_spec.rb +14 -0
  204. data/spec/rake_specs/spec_helper.rb +1 -0
  205. data/spec/rake_specs/task_spec.rb +67 -0
  206. data/spec/runner_spec.rb +207 -0
  207. data/spec/scanner_spec.rb +75 -0
  208. data/spec/spec_helper.rb +121 -0
  209. data/spec/standard_library/exceptions_spec.rb +19 -0
  210. data/spec/standard_library/globals_spec.rb +14 -0
  211. data/spec/standard_library/set_spec.rb +31 -0
  212. data/spec/standard_library/spec_helper.rb +1 -0
  213. data/spec/standard_library/standard_library_spec.rb +302 -0
  214. data/spec/support_specs/acts_as_struct_spec.rb +94 -0
  215. data/spec/support_specs/frequency_spec.rb +23 -0
  216. data/spec/support_specs/module_extensions_spec.rb +117 -0
  217. data/spec/support_specs/spec_helper.rb +1 -0
  218. data/spec/type_specs/spec_helper.rb +1 -0
  219. data/spec/type_specs/types_spec.rb +133 -0
  220. data/spec/warning_spec.rb +95 -0
  221. data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
  222. data/spec/warning_specs/comment_spacing_spec.rb +65 -0
  223. data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
  224. data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
  225. data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
  226. data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
  227. data/spec/warning_specs/line_length_spec.rb +173 -0
  228. data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
  229. data/spec/warning_specs/operator_spacing_spec.rb +104 -0
  230. data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
  231. data/spec/warning_specs/rescue_exception_spec.rb +105 -0
  232. data/spec/warning_specs/semicolon_spec.rb +58 -0
  233. data/spec/warning_specs/spec_helper.rb +1 -0
  234. data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
  235. data/status_reports/2010/12/2010-12-14.md +163 -0
  236. data/status_reports/2010/12/2010-12-23.md +298 -0
  237. data/status_reports/2010/12/2010-12-24.md +6 -0
  238. data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
  239. data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
  240. data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
  241. data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
  242. data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
  243. data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
  244. data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
  245. data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
  246. data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
  247. data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
  248. data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
  249. data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
  250. data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
  251. data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
  252. data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
  253. data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
  254. data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
  255. data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
  256. data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
  257. data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
  258. data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
  259. data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
  260. data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
  261. data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
  262. data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
  263. data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
  264. data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
  265. data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
  266. data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
  267. data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
  268. data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
  269. data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
  270. data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
  271. data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
  272. data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
  273. data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
  274. data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
  275. data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
  276. data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
  277. data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
  278. data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
  279. data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
  280. data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
  281. data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
  282. data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
  283. data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
  284. data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
  285. data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
  286. data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
  287. data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
  288. data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
  289. data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
  290. data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
  291. data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
  292. data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
  293. data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
  294. data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
  295. data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
  296. data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
  297. data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
  298. data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
  299. data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
  300. data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
  301. data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
  302. data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
  303. data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
  304. data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
  305. data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
  306. data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
  307. data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
  308. data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
  309. data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
  310. data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
  311. data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
  312. data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
  313. data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
  314. data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
  315. data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
  316. data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
  317. data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
  318. data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
  319. metadata +470 -0
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/dot'
3
+
4
+ class TestDot < Test::Unit::TestCase
5
+
6
+ def test_to_dot_graph
7
+ graph = RGL::DirectedAdjacencyGraph[1,2]
8
+ dot = graph.to_dot_graph.to_s
9
+ assert_match(dot, /\{[^}]*\}/) # {...}
10
+ assert_match(dot, /1\s*\[/) # node 1
11
+ assert_match(dot, /2\s*\[/) # node 2
12
+ assert_match(dot, /1\s*->\s*2/) # edge
13
+ end
14
+
15
+ def assert_match(dot, pattern)
16
+ assert(!(dot =~ pattern).nil?, "#{dot} doesn't match #{pattern}")
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/base'
3
+
4
+ include RGL::Edge
5
+
6
+ class TestEdge < Test::Unit::TestCase
7
+
8
+ def test_directed_edge
9
+ assert_raises(ArgumentError) {DirectedEdge.new}
10
+ e = DirectedEdge.new 1,2
11
+ assert_equal(1,e.source)
12
+ assert_equal(2,e.target)
13
+ assert_equal([1,2],e.to_a)
14
+ assert_equal("(1-2)",e.to_s)
15
+ assert_equal("(2-1)",e.reverse.to_s)
16
+ assert_equal([1,2],[e[0],e[1]])
17
+ assert(DirectedEdge[1,2].eql?(DirectedEdge.new(1,2)))
18
+ assert(!DirectedEdge[1,2].eql?(DirectedEdge.new(1,3)))
19
+ assert(!DirectedEdge[2,1].eql?(DirectedEdge.new(1,2)))
20
+ end
21
+
22
+ def test_undirected_edge
23
+ assert_raises(ArgumentError) {UnDirectedEdge.new}
24
+ e = UnDirectedEdge.new 1,2
25
+ assert_equal(1,e.source)
26
+ assert_equal(2,e.target)
27
+ assert_equal([1,2],e.to_a)
28
+ assert_equal("(1=2)",e.to_s)
29
+ assert(UnDirectedEdge.new(1,2).eql?(UnDirectedEdge.new(2,1)))
30
+ assert(!UnDirectedEdge.new(1,3).eql?(UnDirectedEdge.new(2,1)))
31
+ assert_equal(UnDirectedEdge.new(1,2).hash,UnDirectedEdge.new(1,2).hash)
32
+ end
33
+
34
+ end
@@ -0,0 +1,71 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/adjacency'
3
+ require_relative 'test_helper'
4
+
5
+ include RGL
6
+
7
+ class TestGraph < Test::Unit::TestCase
8
+
9
+ class NotImplementedGraph
10
+ include Graph
11
+ end
12
+
13
+ def setup
14
+ @dg1 = DirectedAdjacencyGraph.new
15
+ @edges = [[1,2],[2,3],[2,4],[4,5],[1,6],[6,4]]
16
+ @edges.each do |(src,target)|
17
+ @dg1.add_edge(src, target)
18
+ end
19
+ @loan_vertices = [7, 8, 9]
20
+ @loan_vertices.each do |vertex|
21
+ @dg1.add_vertex(vertex)
22
+ end
23
+
24
+ @dg2 = DirectedAdjacencyGraph[*@edges.flatten]
25
+ @loan_vertices.each do |vertex|
26
+ @dg2.add_vertex(vertex)
27
+ end
28
+
29
+ @ug = AdjacencyGraph.new(Array)
30
+ @ug.add_edges(*@edges)
31
+ @ug.add_vertices(*@loan_vertices)
32
+ end
33
+
34
+ def test_equality
35
+ assert_equal @dg1, @dg1
36
+ assert_equal @dg1, @dg1.dup
37
+ assert_equal @ug, @ug.dup
38
+ assert_not_equal @ug, @dg1
39
+ assert_not_equal @dg1, @ug
40
+ assert_not_equal @dg1, 42
41
+ assert_equal @dg1, @dg2
42
+ @dg1.add_vertex 42
43
+ assert_not_equal @dg1, @dg2
44
+ end
45
+
46
+ def test_to_adjacency
47
+ assert_equal @dg1, @dg1.to_adjacency
48
+ assert_equal @ug, @ug.to_adjacency
49
+ end
50
+
51
+ def test_merge
52
+ merge = DirectedAdjacencyGraph.new(Array, @dg1, @ug)
53
+ assert_equal merge.num_edges, 12
54
+ assert_equal merge.num_vertices, 9
55
+ merge = DirectedAdjacencyGraph.new(Set, @dg1, @dg1)
56
+ assert_equal merge.num_edges, 6
57
+ assert_equal merge.num_vertices, 9
58
+ end
59
+
60
+ def test_set_edgelist_class
61
+ edges = @dg1.edges
62
+ @dg1.edgelist_class=Array
63
+ assert_equal edges, @dg1.edges
64
+ end
65
+
66
+ def test_not_implemented
67
+ graph = NotImplementedGraph.new
68
+ assert_raise(NotImplementedError) { graph.each_vertex }
69
+ assert_raise(NotImplementedError) { graph.each_adjacent(nil) }
70
+ end
71
+ end
@@ -0,0 +1,57 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/graphxml'
3
+ require 'laser/third_party/rgl/adjacency'
4
+ require 'laser/third_party/rgl/topsort'
5
+ require 'laser/third_party/rgl/connected_components'
6
+ require 'laser/third_party/rgl/dot'
7
+
8
+ include RGL
9
+
10
+ class TestGraphXML < Test::Unit::TestCase
11
+ NORTH_DIR = File.expand_path(File.join(File.dirname(__FILE__), 'examples', 'north')) + '/'
12
+
13
+ def setup
14
+ @stream = File.new(File.join(NORTH_DIR, 'g.10.0.graphml'))
15
+ end
16
+
17
+ def tear_down
18
+ @stream.close
19
+ end
20
+
21
+ def test_graphxml
22
+ @dg = DirectedAdjacencyGraph.new.from_graphxml(@stream).edges.sort.join
23
+ assert_equal("(n0-n1)(n0-n2)(n0-n9)(n3-n4)(n4-n5)(n5-n7)(n8-n0)(n8-n3)(n8-n4)(n8-n5)(n8-n6)",@dg)
24
+ end
25
+
26
+ def test_north_graphs
27
+ name,nnodes,nedges = '',0,0
28
+ IO.foreach(NORTH_DIR + '/Graph.log') {
29
+ |line|
30
+ if /name:\s*(.*)\sformat: graphml\s+nodes: (\d+)\s+edges: (\d+)/ =~ line
31
+ name,nnodes,nedges = $1,$2.to_i,$3.to_i
32
+ end
33
+ if name && /directed: (\w+).*acyclic: (\w+).*connected: (\w+).*biconnected: (\w+)\s+/ =~ line
34
+ directed, acyclic, connected, biconnected = $1,$2,$3,$4
35
+ File.open(NORTH_DIR + name + '.graphml') {
36
+ |file|
37
+ print '.'; $stdout.flush
38
+ graph = (directed == 'true' ? DirectedAdjacencyGraph : AdjacencyGraph).new.from_graphxml(file)
39
+ #graph.write_to_graphic_file
40
+ assert_equal(nnodes,graph.num_vertices)
41
+ assert_equal(nedges,graph.num_edges)
42
+ assert_equal(acyclic,graph.acyclic?.to_s)
43
+
44
+ num_comp = 0
45
+ graph.to_undirected.each_connected_component {|x| num_comp += 1}
46
+ assert_equal(connected,(num_comp == 1).to_s)
47
+
48
+ # if graph.directed?
49
+ # num_comp = graph.strongly_connected_components.num_comp
50
+ # #puts num_comp
51
+ # assert_equal(biconnected, (num_comp == 1).to_s)
52
+ # end
53
+ }
54
+ end
55
+ }
56
+ end
57
+ end
@@ -0,0 +1,52 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/implicit'
3
+ require 'laser/third_party/rgl/adjacency'
4
+
5
+ include RGL
6
+
7
+ class TestImplicit < Test::Unit::TestCase
8
+ def setup
9
+ @dg = DirectedAdjacencyGraph.new
10
+ [[1,2],[2,3],[2,4],[4,5],[1,6],[6,4]].each do |(src,target)|
11
+ @dg.add_edge(src, target)
12
+ end
13
+
14
+ @cycle = ImplicitGraph.new { |g|
15
+ g.vertex_iterator { |b| 0.upto(4,&b) }
16
+ g.adjacent_iterator { |x, b| b.call((x+1)%5) }
17
+ g.directed = true
18
+ }
19
+ end
20
+
21
+ def test_empty
22
+ empty = ImplicitGraph.new
23
+ assert(empty.empty?)
24
+ assert_equal([],empty.edges)
25
+ assert_equal([],empty.vertices)
26
+ end
27
+
28
+ def test_cycle
29
+ assert(!@cycle.empty?)
30
+ assert_equal([0, 1, 2, 3, 4],@cycle.vertices.sort)
31
+ assert_equal("(0-1)(1-2)(2-3)(3-4)(4-0)",@cycle.edges.sort.join)
32
+ end
33
+
34
+ def test_vertex_filtered_graph
35
+ fg = @cycle.vertices_filtered_by {|v| v%2 == 0}
36
+ assert_equal([0, 2, 4],fg.vertices.sort)
37
+ assert_equal("(4-0)",fg.edges.sort.join)
38
+ assert(fg.directed?)
39
+
40
+ fg = @dg.vertices_filtered_by {|v| v%2 == 0}
41
+ assert_equal([2, 4, 6],fg.vertices.sort)
42
+ assert_equal("(2-4)(6-4)",fg.edges.sort.join)
43
+ assert(fg.directed?)
44
+ end
45
+
46
+ def test_edge_filtered_graph
47
+ fg = @cycle.edges_filtered_by {|u,v| u+v > 3}
48
+ assert_equal(@cycle.vertices.sort,fg.vertices.sort)
49
+ assert_equal("(2-3)(3-4)(4-0)",fg.edges.sort.join)
50
+ assert(fg.directed?)
51
+ end
52
+ end
@@ -0,0 +1,863 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/rdot'
3
+
4
+ include RGL
5
+
6
+ # Add some helper methods to TestCase
7
+ class Test::Unit::TestCase
8
+
9
+ # assert string matches regular expression
10
+ def assert_match(dot, pattern)
11
+ assert(!(dot =~ pattern).nil?, "#{dot} doesn't match #{pattern}")
12
+ end
13
+
14
+ # assert string doesn't match regular expression
15
+ def assert_no_match(dot, pattern)
16
+ assert((dot =~ pattern).nil?, "#{dot} shouldn't match #{pattern}")
17
+ end
18
+
19
+ end
20
+
21
+ # Tests for DOT::Port
22
+ class TestDotPort < Test::Unit::TestCase
23
+ def test_name
24
+ port = DOT::Port.new()
25
+ assert_equal('', port.to_s)
26
+
27
+ port = DOT::Port.new('test_name')
28
+ assert_equal('<test_name>', port.to_s)
29
+ end
30
+
31
+ def test_label
32
+ port = DOT::Port.new(nil, 'test_label')
33
+ assert_equal('test_label', port.to_s)
34
+ end
35
+
36
+ def test_name_and_label
37
+ port = DOT::Port.new('test_name', 'test_label')
38
+ assert_equal('<test_name> test_label', port.to_s)
39
+ end
40
+
41
+ def test_nested_ports
42
+ port = DOT::Port.new([DOT::Port.new(nil, 'a'), DOT::Port.new(nil, 'b')])
43
+ assert_equal('{a | b}', port.to_s)
44
+ end
45
+
46
+ def test_name_label_and_nested_ports
47
+ port = DOT::Port.new('test_name', 'test_label')
48
+ port.ports = [DOT::Port.new(nil, 'a'), DOT::Port.new(nil, 'b')]
49
+ assert_equal('{a | b}', port.to_s)
50
+ end
51
+ end
52
+
53
+ # Tests for DOT::Node
54
+ class TestDotNode < Test::Unit::TestCase
55
+
56
+ def test_no_name
57
+ node = DOT::Node.new()
58
+ dot = node.to_s
59
+ assert_nil(dot)
60
+ end
61
+
62
+ # bug 16125
63
+ def test_1prop_0comma
64
+ node = DOT::Node.new({"label"=>"the_label"})
65
+ dot = node.to_s
66
+ assert_no_match(dot, /,/)
67
+ end
68
+
69
+ def test_2prop_1comma
70
+ node = DOT::Node.new({"label"=>"the_label", "shape"=>"ellipse"})
71
+ dot = node.to_s
72
+ assert_match(dot, /\[[^,]*,[^,]*\]/)
73
+ end
74
+
75
+ def test_name_without_label
76
+ node = DOT::Node.new({"name"=>"test_name"})
77
+ dot = node.to_s
78
+ assert_no_match(dot, /label/)
79
+ end
80
+
81
+ def test_no_label
82
+ node = DOT::Node.new({"shape"=>"ellipse"})
83
+ dot = node.to_s
84
+ assert_no_match(dot, /label/)
85
+ end
86
+
87
+ def test_Mrecord_no_label_no_ports
88
+ node = DOT::Node.new({"name" => "test_name", "shape"=>"Mrecord"})
89
+ dot = node.to_s
90
+ assert_match(dot, /shape\s*=\s*Mrecord/)
91
+ assert_no_match(dot, /label/)
92
+ end
93
+
94
+ def test_Mrecord_label_no_ports
95
+ node = DOT::Node.new({"name" => "test_name", "label" => "test_label", "shape"=>"Mrecord"})
96
+ dot = node.to_s
97
+ assert_match(dot, /shape\s*=\s*Mrecord/)
98
+ assert_match(dot, /label\s*=\s*test_label/)
99
+ end
100
+
101
+ def test_Mrecord_label_with_ports
102
+ node = DOT::Node.new({"name" => "test_name", "label" => "test_label", "shape"=>"Mrecord"})
103
+ node.ports << DOT::Port.new(nil, "a")
104
+ node.ports << DOT::Port.new(nil, "b")
105
+ dot = node.to_s
106
+ assert_match(dot, /shape\s*=\s*Mrecord/)
107
+ assert_match(dot, /label\s*=\s*"a\s*|\s*b"/)
108
+ end
109
+
110
+ def test_Mrecord_no_label_with_ports
111
+ node = DOT::Node.new({"name" => "test_name", "shape"=>"Mrecord"})
112
+ node.ports << DOT::Port.new(nil, "a")
113
+ node.ports << DOT::Port.new(nil, "b")
114
+ dot = node.to_s
115
+ assert_match(dot, /shape\s*=\s*Mrecord/)
116
+ assert_match(dot, /label\s*=\s*"a\s*|\s*b"/)
117
+ end
118
+
119
+ def test_record_no_label_no_ports
120
+ node = DOT::Node.new({"name" => "test_name", "shape"=>"record"})
121
+ dot = node.to_s
122
+ assert_match(dot, /shape\s*=\s*record/)
123
+ assert_no_match(dot, /label/)
124
+ end
125
+
126
+ def test_record_label_no_ports
127
+ node = DOT::Node.new({"name" => "test_name", "label" => "test_label", "shape"=>"record"})
128
+ dot = node.to_s
129
+ assert_match(dot, /shape\s*=\s*record/)
130
+ assert_match(dot, /label\s*=\s*test_label/)
131
+ end
132
+
133
+ def test_record_label_with_ports
134
+ node = DOT::Node.new({"name" => "test_name", "label" => "test_label", "shape"=>"record"})
135
+ node.ports << DOT::Port.new(nil, "a")
136
+ node.ports << DOT::Port.new(nil, "b")
137
+ dot = node.to_s
138
+ assert_match(dot, /shape\s*=\s*record/)
139
+ assert_match(dot, /label\s*=\s*"a\s*|\s*b"/)
140
+ end
141
+
142
+ def test_record_no_label_with_ports
143
+ node = DOT::Node.new({"name" => "test_name", "shape"=>"record"})
144
+ node.ports << DOT::Port.new(nil, "a")
145
+ node.ports << DOT::Port.new(nil, "b")
146
+ dot = node.to_s
147
+ assert_match(dot, /shape\s*=\s*record/)
148
+ assert_match(dot, /label\s*=\s*"a\s*|\s*b"/)
149
+ end
150
+
151
+ def test_no_shape_no_label_no_ports
152
+ node = DOT::Node.new({"name" => "test_name"})
153
+ node.ports << DOT::Port.new(nil, "a")
154
+ node.ports << DOT::Port.new(nil, "b")
155
+ dot = node.to_s
156
+ assert_no_match(dot, /shape\s*=\s/)
157
+ assert_no_match(dot, /label\s*=\s*/)
158
+ end
159
+
160
+ def test_no_shape_no_label_with_ports
161
+ node = DOT::Node.new({"name" => "test_name"})
162
+ node.ports << DOT::Port.new(nil, "a")
163
+ node.ports << DOT::Port.new(nil, "b")
164
+ dot = node.to_s
165
+ assert_no_match(dot, /shape\s*=\s*record/)
166
+ assert_no_match(dot, /label\s*=\s*/)
167
+ end
168
+
169
+ def test_name_quoting
170
+ node = DOT::Node.new({"name" => "Name with spaces"})
171
+ dot = node.to_s
172
+ assert_match(dot, /^"Name with spaces"$/)
173
+
174
+ node = DOT::Node.new({"name" => "Name with \"quotes\""})
175
+ dot = node.to_s
176
+ assert_match(dot, /^"Name with \\"quotes\\""$/)
177
+
178
+ node = DOT::Node.new({"name" => "Name with \\backslashes\\"})
179
+ dot = node.to_s
180
+ assert_match(dot, /^"Name with \\\\backslashes\\\\"$/)
181
+
182
+ node = DOT::Node.new({"name" => "Name with\nembedded\nnewlines"})
183
+ dot = node.to_s
184
+ assert_match(dot, /\A.*"Name with\nembedded\nnewlines".*\Z/m)
185
+
186
+ node = DOT::Node.new({"name" => "Name_with_trailing_newline\n"})
187
+ dot = node.to_s
188
+ assert_match(dot, /\A.*"Name_with_trailing_newline\n".*\Z/m)
189
+
190
+ node = DOT::Node.new({"name" => "123.456"})
191
+ dot = node.to_s
192
+ assert_match(dot, /^123.456$/)
193
+
194
+ node = DOT::Node.new({"name" => ".456"})
195
+ dot = node.to_s
196
+ assert_match(dot, /^.456$/)
197
+
198
+ node = DOT::Node.new({"name" => "-.456"})
199
+ dot = node.to_s
200
+ assert_match(dot, /^-.456$/)
201
+
202
+ node = DOT::Node.new({"name" => "-456"})
203
+ dot = node.to_s
204
+ assert_match(dot, /^-456$/)
205
+
206
+ node = DOT::Node.new({"name" => "-123.456"})
207
+ dot = node.to_s
208
+ assert_match(dot, /^-123.456$/)
209
+
210
+ node = DOT::Node.new({"name" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
211
+ dot = node.to_s
212
+ assert_match(dot, /^<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>$/)
213
+ end
214
+
215
+ def test_label_quoting
216
+ node = DOT::Node.new({"name" => "test_name", "label" => "Label with spaces"})
217
+ dot = node.to_s
218
+ assert_match(dot, /label\s*=\s*"Label with spaces"/)
219
+
220
+ node = DOT::Node.new({"name" => "test_name", "label" => "Label with \"quotes\""})
221
+ dot = node.to_s
222
+ assert_match(dot, /label\s*=\s*"Label with \\"quotes\\""/)
223
+
224
+ node = DOT::Node.new({"name" => "test_name", "label" => "Label with \\backslashes\\"})
225
+ dot = node.to_s
226
+ assert_match(dot, /label\s*=\s*"Label with \\\\backslashes\\\\"/)
227
+
228
+ node = DOT::Node.new({"name" => "test_name", "label" => "Label with\nembedded\nnewlines"})
229
+ dot = node.to_s
230
+ assert_match(dot, /label\s*=\s*"Label with\\nembedded\\nnewlines"/)
231
+
232
+ node = DOT::Node.new({"name" => "test_name", "label" => "Label_with_a_trailing_newline\n"})
233
+ dot = node.to_s
234
+ assert_match(dot, /label\s*=\s*"Label_with_a_trailing_newline\\n"/)
235
+
236
+ node = DOT::Node.new({"name" => "test_name", "label" => "Left justified label\\l"})
237
+ dot = node.to_s
238
+ assert_match(dot, /label\s*=\s*"Left justified label\\l"/)
239
+
240
+ node = DOT::Node.new({"name" => "test_name", "label" => "Right justified label\\r"})
241
+ dot = node.to_s
242
+ assert_match(dot, /label\s*=\s*"Right justified label\\r"/)
243
+
244
+ node = DOT::Node.new({"name" => "test_name", "label" => "123.456"})
245
+ dot = node.to_s
246
+ assert_match(dot, /label\s*=\s*123.456/)
247
+
248
+ node = DOT::Node.new({"name" => "test_name", "label" => ".456"})
249
+ dot = node.to_s
250
+ assert_match(dot, /label\s*=\s*.456/)
251
+
252
+ node = DOT::Node.new({"name" => "test_name", "label" => "-.456"})
253
+ dot = node.to_s
254
+ assert_match(dot, /label\s*=\s*-.456/)
255
+
256
+ node = DOT::Node.new({"name" => "test_name", "label" => "-456"})
257
+ dot = node.to_s
258
+ assert_match(dot, /label\s*=\s*-456/)
259
+
260
+ node = DOT::Node.new({"name" => "test_name", "label" => "-123.456"})
261
+ dot = node.to_s
262
+ assert_match(dot, /label\s*=\s*-123.456/)
263
+
264
+ node = DOT::Node.new({"name" => "test_name", "label" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
265
+ dot = node.to_s
266
+ assert_match(dot, /label\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
267
+ end
268
+
269
+ def test_option_quoting
270
+ node = DOT::Node.new({"name" => "test_name", "comment" => "Comment with spaces"})
271
+ dot = node.to_s
272
+ assert_match(dot, /comment\s*=\s*"Comment with spaces"/)
273
+
274
+ node = DOT::Node.new({"name" => "test_name", "comment" => "Comment with \"quotes\""})
275
+ dot = node.to_s
276
+ assert_match(dot, /comment\s*=\s*"Comment with \\"quotes\\""/)
277
+
278
+ node = DOT::Node.new({"name" => "test_name", "comment" => "Comment with \\backslashes\\"})
279
+ dot = node.to_s
280
+ assert_match(dot, /comment\s*=\s*"Comment with \\\\backslashes\\\\"/)
281
+
282
+ node = DOT::Node.new({"name" => "test_name", "comment" => "123.456"})
283
+ dot = node.to_s
284
+ assert_match(dot, /comment\s*=\s*123.456/)
285
+
286
+ node = DOT::Node.new({"name" => "test_name", "comment" => ".456"})
287
+ dot = node.to_s
288
+ assert_match(dot, /comment\s*=\s*.456/)
289
+
290
+ node = DOT::Node.new({"name" => "test_name", "comment" => "-.456"})
291
+ dot = node.to_s
292
+ assert_match(dot, /comment\s*=\s*-.456/)
293
+
294
+ node = DOT::Node.new({"name" => "test_name", "comment" => "-456"})
295
+ dot = node.to_s
296
+ assert_match(dot, /comment\s*=\s*-456/)
297
+
298
+ node = DOT::Node.new({"name" => "test_name", "comment" => "-123.456"})
299
+ dot = node.to_s
300
+ assert_match(dot, /comment\s*=\s*-123.456/)
301
+
302
+ node = DOT::Node.new({"name" => "test_name", "comment" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
303
+ dot = node.to_s
304
+ assert_match(dot, /comment\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
305
+ end
306
+ end
307
+
308
+ # Tests for DOT::Edge
309
+ class TestDotEdge < Test::Unit::TestCase
310
+
311
+ def test_0prop
312
+ edge = DOT::Edge.new({'from' => 'a', 'to' => 'b'})
313
+ dot = edge.to_s
314
+ assert_equal('a -- b', dot)
315
+ end
316
+
317
+ def test_1prop_0comma
318
+ edge = DOT::Edge.new({"label"=>"the_label"})
319
+ dot = edge.to_s
320
+ assert_no_match(dot, /,/)
321
+ end
322
+
323
+ def test_2prop_1comma
324
+ edge = DOT::Edge.new({"label"=>"the_label", "weight"=>"2"})
325
+ dot = edge.to_s
326
+ assert_match(dot, /\[[^,]*,[^,]*\]/)
327
+ end
328
+
329
+ def test_no_label
330
+ edge = DOT::Edge.new({"weight"=>"2"})
331
+ dot = edge.to_s
332
+ assert_no_match(dot, /label/)
333
+ end
334
+ end
335
+
336
+ # Tests for DOT::DirectedEdge
337
+ class TestDotDirectedEdge < Test::Unit::TestCase
338
+
339
+ def test_0prop
340
+ edge = DOT::DirectedEdge.new({'from' => 'a', 'to' => 'b'})
341
+ dot = edge.to_s
342
+ assert_equal('a -> b', dot)
343
+ end
344
+
345
+ def test_1prop_0comma
346
+ edge = DOT::DirectedEdge.new({"label"=>"the_label"})
347
+ dot = edge.to_s
348
+ assert_no_match(dot, /,/)
349
+ end
350
+
351
+ def test_2prop_1comma
352
+ edge = DOT::DirectedEdge.new({"label"=>"the_label", "weight"=>"2"})
353
+ dot = edge.to_s
354
+ assert_match(dot, /\[[^,]*,[^,]*\]/)
355
+ end
356
+
357
+ def test_no_label
358
+ edge = DOT::DirectedEdge.new({"weight"=>"2"})
359
+ dot = edge.to_s
360
+ assert_no_match(dot, /label/)
361
+ end
362
+ end
363
+
364
+ # Tests for DOT::Graph
365
+ class TestDotGraph < Test::Unit::TestCase
366
+ def test_graph_statement
367
+ graph = DOT::Graph.new()
368
+ dot = graph.to_s
369
+ assert_match(dot, /^\s*graph /)
370
+ end
371
+
372
+ def test_name_quoting
373
+ node = DOT::Graph.new({"name" => "Name with spaces"})
374
+ dot = node.to_s
375
+ assert_match(dot, /^graph "Name with spaces" \{$/)
376
+
377
+ node = DOT::Graph.new({"name" => "Name with \"quotes\""})
378
+ dot = node.to_s
379
+ assert_match(dot, /^graph "Name with \\"quotes\\"" \{$/)
380
+
381
+ node = DOT::Graph.new({"name" => "Name with \\backslashes\\"})
382
+ dot = node.to_s
383
+ assert_match(dot, /^graph "Name with \\\\backslashes\\\\" \{$/)
384
+
385
+ node = DOT::Graph.new({"name" => "Name with\nembedded\nnewlines"})
386
+ dot = node.to_s
387
+ assert_match(dot, /\A.*"Name with\nembedded\nnewlines".*\Z/m)
388
+
389
+ node = DOT::Graph.new({"name" => "Name_with_trailing_newline\n"})
390
+ dot = node.to_s
391
+ assert_match(dot, /\A.*"Name_with_trailing_newline\n".*\Z/m)
392
+
393
+ node = DOT::Graph.new({"name" => "123.456"})
394
+ dot = node.to_s
395
+ assert_match(dot, /^graph 123.456 \{$/)
396
+
397
+ node = DOT::Graph.new({"name" => ".456"})
398
+ dot = node.to_s
399
+ assert_match(dot, /^graph .456 \{$/)
400
+
401
+ node = DOT::Graph.new({"name" => "-.456"})
402
+ dot = node.to_s
403
+ assert_match(dot, /^graph -.456 \{$/)
404
+
405
+ node = DOT::Graph.new({"name" => "-456"})
406
+ dot = node.to_s
407
+ assert_match(dot, /^graph -456 \{$/)
408
+
409
+ node = DOT::Graph.new({"name" => "-123.456"})
410
+ dot = node.to_s
411
+ assert_match(dot, /^graph -123.456 \{$/)
412
+
413
+ node = DOT::Graph.new({"name" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
414
+ dot = node.to_s
415
+ assert_match(dot, /^graph <html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html> \{$/)
416
+ end
417
+
418
+ def test_label_quoting
419
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Label with spaces"})
420
+ dot = node.to_s
421
+ assert_match(dot, /label\s*=\s*"Label with spaces"/)
422
+
423
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Label with \"quotes\""})
424
+ dot = node.to_s
425
+ assert_match(dot, /label\s*=\s*"Label with \\"quotes\\""/)
426
+
427
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Label with \\backslashes\\"})
428
+ dot = node.to_s
429
+ assert_match(dot, /label\s*=\s*"Label with \\\\backslashes\\\\"/)
430
+
431
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Label with\nembedded\nnewlines"})
432
+ dot = node.to_s
433
+ assert_match(dot, /label\s*=\s*"Label with\\nembedded\\nnewlines"/)
434
+
435
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Label_with_a_trailing_newline\n"})
436
+ dot = node.to_s
437
+ assert_match(dot, /label\s*=\s*"Label_with_a_trailing_newline\\n"/)
438
+
439
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Left justified label\\l"})
440
+ dot = node.to_s
441
+ assert_match(dot, /label\s*=\s*"Left justified label\\l"/)
442
+
443
+ node = DOT::Graph.new({"name" => "test_name", "label" => "Right justified label\\r"})
444
+ dot = node.to_s
445
+ assert_match(dot, /label\s*=\s*"Right justified label\\r"/)
446
+
447
+ node = DOT::Graph.new({"name" => "test_name", "label" => "123.456"})
448
+ dot = node.to_s
449
+ assert_match(dot, /label\s*=\s*123.456/)
450
+
451
+ node = DOT::Graph.new({"name" => "test_name", "label" => ".456"})
452
+ dot = node.to_s
453
+ assert_match(dot, /label\s*=\s*.456/)
454
+
455
+ node = DOT::Graph.new({"name" => "test_name", "label" => "-.456"})
456
+ dot = node.to_s
457
+ assert_match(dot, /label\s*=\s*-.456/)
458
+
459
+ node = DOT::Graph.new({"name" => "test_name", "label" => "-456"})
460
+ dot = node.to_s
461
+ assert_match(dot, /label\s*=\s*-456/)
462
+
463
+ node = DOT::Graph.new({"name" => "test_name", "label" => "-123.456"})
464
+ dot = node.to_s
465
+ assert_match(dot, /label\s*=\s*-123.456/)
466
+
467
+ node = DOT::Graph.new({"name" => "test_name", "label" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
468
+ dot = node.to_s
469
+ assert_match(dot, /label\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
470
+ end
471
+
472
+ def test_option_quoting
473
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "Comment with spaces"})
474
+ dot = node.to_s
475
+ assert_match(dot, /comment\s*=\s*"Comment with spaces"/)
476
+
477
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "Comment with \"quotes\""})
478
+ dot = node.to_s
479
+ assert_match(dot, /comment\s*=\s*"Comment with \\"quotes\\""/)
480
+
481
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "Comment with \\backslashes\\"})
482
+ dot = node.to_s
483
+ assert_match(dot, /comment\s*=\s*"Comment with \\\\backslashes\\\\"/)
484
+
485
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "123.456"})
486
+ dot = node.to_s
487
+ assert_match(dot, /comment\s*=\s*123.456/)
488
+
489
+ node = DOT::Graph.new({"name" => "test_name", "comment" => ".456"})
490
+ dot = node.to_s
491
+ assert_match(dot, /comment\s*=\s*.456/)
492
+
493
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "-.456"})
494
+ dot = node.to_s
495
+ assert_match(dot, /comment\s*=\s*-.456/)
496
+
497
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "-456"})
498
+ dot = node.to_s
499
+ assert_match(dot, /comment\s*=\s*-456/)
500
+
501
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "-123.456"})
502
+ dot = node.to_s
503
+ assert_match(dot, /comment\s*=\s*-123.456/)
504
+
505
+ node = DOT::Graph.new({"name" => "test_name", "comment" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
506
+ dot = node.to_s
507
+ assert_match(dot, /comment\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
508
+ end
509
+
510
+ def test_element_containment
511
+ node1 = DOT::Node.new('name' => 'test_node1')
512
+ node2 = DOT::Node.new('name' => 'test_node2')
513
+
514
+ graph = DOT::Graph.new('name' => 'test_graph')
515
+ assert_nil(graph.pop)
516
+ assert_equal(graph, graph.push(node1))
517
+ assert_equal(graph, graph << node2)
518
+ graph.each_element do |element|
519
+ assert([node1, node2].include?(element))
520
+ end
521
+ assert_equal(node2, graph.pop)
522
+ assert_equal(node1, graph.pop)
523
+ assert_nil(graph.pop)
524
+
525
+ graph = DOT::Graph.new('name' => 'test_graph', 'elements' => [node1])
526
+ assert_equal(node1, graph.pop)
527
+ assert_nil(graph.pop)
528
+ end
529
+ end
530
+
531
+ # Tests for DOT::Digraph
532
+ class TestDotDigraph < Test::Unit::TestCase
533
+ def test_digraph_statement
534
+ digraph = DOT::Digraph.new()
535
+ dot = digraph.to_s
536
+ assert_match(dot, /^\s*digraph /)
537
+ end
538
+
539
+ def test_name_quoting
540
+ node = DOT::Digraph.new({"name" => "Name with spaces"})
541
+ dot = node.to_s
542
+ assert_match(dot, /^digraph "Name with spaces" \{$/)
543
+
544
+ node = DOT::Digraph.new({"name" => "Name with \"quotes\""})
545
+ dot = node.to_s
546
+ assert_match(dot, /^digraph "Name with \\"quotes\\"" \{$/)
547
+
548
+ node = DOT::Digraph.new({"name" => "Name with \\backslashes\\"})
549
+ dot = node.to_s
550
+ assert_match(dot, /^digraph "Name with \\\\backslashes\\\\" \{$/)
551
+
552
+ node = DOT::Digraph.new({"name" => "Name with\nembedded\nnewlines"})
553
+ dot = node.to_s
554
+ assert_match(dot, /\A.*"Name with\nembedded\nnewlines".*\Z/m)
555
+
556
+ node = DOT::Digraph.new({"name" => "Name_with_trailing_newline\n"})
557
+ dot = node.to_s
558
+ assert_match(dot, /\A.*"Name_with_trailing_newline\n".*\Z/m)
559
+
560
+ node = DOT::Digraph.new({"name" => "123.456"})
561
+ dot = node.to_s
562
+ assert_match(dot, /^digraph 123.456 \{$/)
563
+
564
+ node = DOT::Digraph.new({"name" => ".456"})
565
+ dot = node.to_s
566
+ assert_match(dot, /^digraph .456 \{$/)
567
+
568
+ node = DOT::Digraph.new({"name" => "-.456"})
569
+ dot = node.to_s
570
+ assert_match(dot, /^digraph -.456 \{$/)
571
+
572
+ node = DOT::Digraph.new({"name" => "-456"})
573
+ dot = node.to_s
574
+ assert_match(dot, /^digraph -456 \{$/)
575
+
576
+ node = DOT::Digraph.new({"name" => "-123.456"})
577
+ dot = node.to_s
578
+ assert_match(dot, /^digraph -123.456 \{$/)
579
+
580
+ node = DOT::Digraph.new({"name" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
581
+ dot = node.to_s
582
+ assert_match(dot, /^digraph <html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html> \{$/)
583
+ end
584
+
585
+ def test_label_quoting
586
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Label with spaces"})
587
+ dot = node.to_s
588
+ assert_match(dot, /label\s*=\s*"Label with spaces"/)
589
+
590
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Label with \"quotes\""})
591
+ dot = node.to_s
592
+ assert_match(dot, /label\s*=\s*"Label with \\"quotes\\""/)
593
+
594
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Label with \\backslashes\\"})
595
+ dot = node.to_s
596
+ assert_match(dot, /label\s*=\s*"Label with \\\\backslashes\\\\"/)
597
+
598
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Label with\nembedded\nnewlines"})
599
+ dot = node.to_s
600
+ assert_match(dot, /label\s*=\s*"Label with\\nembedded\\nnewlines"/)
601
+
602
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Label_with_a_trailing_newline\n"})
603
+ dot = node.to_s
604
+ assert_match(dot, /label\s*=\s*"Label_with_a_trailing_newline\\n"/)
605
+
606
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Left justified label\\l"})
607
+ dot = node.to_s
608
+ assert_match(dot, /label\s*=\s*"Left justified label\\l"/)
609
+
610
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "Right justified label\\r"})
611
+ dot = node.to_s
612
+ assert_match(dot, /label\s*=\s*"Right justified label\\r"/)
613
+
614
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "123.456"})
615
+ dot = node.to_s
616
+ assert_match(dot, /label\s*=\s*123.456/)
617
+
618
+ node = DOT::Digraph.new({"name" => "test_name", "label" => ".456"})
619
+ dot = node.to_s
620
+ assert_match(dot, /label\s*=\s*.456/)
621
+
622
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "-.456"})
623
+ dot = node.to_s
624
+ assert_match(dot, /label\s*=\s*-.456/)
625
+
626
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "-456"})
627
+ dot = node.to_s
628
+ assert_match(dot, /label\s*=\s*-456/)
629
+
630
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "-123.456"})
631
+ dot = node.to_s
632
+ assert_match(dot, /label\s*=\s*-123.456/)
633
+
634
+ node = DOT::Digraph.new({"name" => "test_name", "label" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
635
+ dot = node.to_s
636
+ assert_match(dot, /label\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
637
+ end
638
+
639
+ def test_option_quoting
640
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "Comment with spaces"})
641
+ dot = node.to_s
642
+ assert_match(dot, /comment\s*=\s*"Comment with spaces"/)
643
+
644
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "Comment with \"quotes\""})
645
+ dot = node.to_s
646
+ assert_match(dot, /comment\s*=\s*"Comment with \\"quotes\\""/)
647
+
648
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "Comment with \\backslashes\\"})
649
+ dot = node.to_s
650
+ assert_match(dot, /comment\s*=\s*"Comment with \\\\backslashes\\\\"/)
651
+
652
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "123.456"})
653
+ dot = node.to_s
654
+ assert_match(dot, /comment\s*=\s*123.456/)
655
+
656
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => ".456"})
657
+ dot = node.to_s
658
+ assert_match(dot, /comment\s*=\s*.456/)
659
+
660
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "-.456"})
661
+ dot = node.to_s
662
+ assert_match(dot, /comment\s*=\s*-.456/)
663
+
664
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "-456"})
665
+ dot = node.to_s
666
+ assert_match(dot, /comment\s*=\s*-456/)
667
+
668
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "-123.456"})
669
+ dot = node.to_s
670
+ assert_match(dot, /comment\s*=\s*-123.456/)
671
+
672
+ node = DOT::Digraph.new({"name" => "test_name", "comment" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
673
+ dot = node.to_s
674
+ assert_match(dot, /comment\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
675
+ end
676
+
677
+ def test_element_containment
678
+ node1 = DOT::Node.new('name' => 'test_node1')
679
+ node2 = DOT::Node.new('name' => 'test_node2')
680
+
681
+ graph = DOT::Digraph.new('name' => 'test_graph')
682
+ assert_nil(graph.pop)
683
+ assert_equal(graph, graph.push(node1))
684
+ assert_equal(graph, graph << node2)
685
+ graph.each_element do |element|
686
+ assert([node1, node2].include?(element))
687
+ end
688
+ assert_equal(node2, graph.pop)
689
+ assert_equal(node1, graph.pop)
690
+ assert_nil(graph.pop)
691
+
692
+ graph = DOT::Digraph.new('name' => 'test_graph', 'elements' => [node1])
693
+ assert_equal(node1, graph.pop)
694
+ assert_nil(graph.pop)
695
+ end
696
+ end
697
+
698
+ # Tests for DOT::Subgraph
699
+ class TestDotSubgraph < Test::Unit::TestCase
700
+ def test_subgraph_statement
701
+ subgraph = DOT::Subgraph.new()
702
+ dot = subgraph.to_s
703
+ assert_match(dot, /^\s*subgraph /)
704
+ end
705
+
706
+ def test_name_quoting
707
+ node = DOT::Subgraph.new({"name" => "Name with spaces"})
708
+ dot = node.to_s
709
+ assert_match(dot, /^subgraph "Name with spaces" \{$/)
710
+
711
+ node = DOT::Subgraph.new({"name" => "Name with \"quotes\""})
712
+ dot = node.to_s
713
+ assert_match(dot, /^subgraph "Name with \\"quotes\\"" \{$/)
714
+
715
+ node = DOT::Subgraph.new({"name" => "Name with \\backslashes\\"})
716
+ dot = node.to_s
717
+ assert_match(dot, /^subgraph "Name with \\\\backslashes\\\\" \{$/)
718
+
719
+ node = DOT::Subgraph.new({"name" => "Name with\nembedded\nnewlines"})
720
+ dot = node.to_s
721
+ assert_match(dot, /\A.*"Name with\nembedded\nnewlines".*\Z/m)
722
+
723
+ node = DOT::Subgraph.new({"name" => "Name_with_trailing_newline\n"})
724
+ dot = node.to_s
725
+ assert_match(dot, /\A.*"Name_with_trailing_newline\n".*\Z/m)
726
+
727
+ node = DOT::Subgraph.new({"name" => "123.456"})
728
+ dot = node.to_s
729
+ assert_match(dot, /^subgraph 123.456 \{$/)
730
+
731
+ node = DOT::Subgraph.new({"name" => ".456"})
732
+ dot = node.to_s
733
+ assert_match(dot, /^subgraph .456 \{$/)
734
+
735
+ node = DOT::Subgraph.new({"name" => "-.456"})
736
+ dot = node.to_s
737
+ assert_match(dot, /^subgraph -.456 \{$/)
738
+
739
+ node = DOT::Subgraph.new({"name" => "-456"})
740
+ dot = node.to_s
741
+ assert_match(dot, /^subgraph -456 \{$/)
742
+
743
+ node = DOT::Subgraph.new({"name" => "-123.456"})
744
+ dot = node.to_s
745
+ assert_match(dot, /^subgraph -123.456 \{$/)
746
+
747
+ node = DOT::Subgraph.new({"name" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
748
+ dot = node.to_s
749
+ assert_match(dot, /^subgraph <html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html> \{$/)
750
+ end
751
+
752
+ def test_label_quoting
753
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Label with spaces"})
754
+ dot = node.to_s
755
+ assert_match(dot, /label\s*=\s*"Label with spaces"/)
756
+
757
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Label with \"quotes\""})
758
+ dot = node.to_s
759
+ assert_match(dot, /label\s*=\s*"Label with \\"quotes\\""/)
760
+
761
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Label with \\backslashes\\"})
762
+ dot = node.to_s
763
+ assert_match(dot, /label\s*=\s*"Label with \\\\backslashes\\\\"/)
764
+
765
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Label with\nembedded\nnewlines"})
766
+ dot = node.to_s
767
+ assert_match(dot, /label\s*=\s*"Label with\\nembedded\\nnewlines"/)
768
+
769
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Label_with_a_trailing_newline\n"})
770
+ dot = node.to_s
771
+ assert_match(dot, /label\s*=\s*"Label_with_a_trailing_newline\\n"/)
772
+
773
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Left justified label\\l"})
774
+ dot = node.to_s
775
+ assert_match(dot, /label\s*=\s*"Left justified label\\l"/)
776
+
777
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "Right justified label\\r"})
778
+ dot = node.to_s
779
+ assert_match(dot, /label\s*=\s*"Right justified label\\r"/)
780
+
781
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "123.456"})
782
+ dot = node.to_s
783
+ assert_match(dot, /label\s*=\s*123.456/)
784
+
785
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => ".456"})
786
+ dot = node.to_s
787
+ assert_match(dot, /label\s*=\s*.456/)
788
+
789
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "-.456"})
790
+ dot = node.to_s
791
+ assert_match(dot, /label\s*=\s*-.456/)
792
+
793
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "-456"})
794
+ dot = node.to_s
795
+ assert_match(dot, /label\s*=\s*-456/)
796
+
797
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "-123.456"})
798
+ dot = node.to_s
799
+ assert_match(dot, /label\s*=\s*-123.456/)
800
+
801
+ node = DOT::Subgraph.new({"name" => "test_name", "label" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
802
+ dot = node.to_s
803
+ assert_match(dot, /label\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
804
+ end
805
+
806
+ def test_option_quoting
807
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "Comment with spaces"})
808
+ dot = node.to_s
809
+ assert_match(dot, /comment\s*=\s*"Comment with spaces"/)
810
+
811
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "Comment with \"quotes\""})
812
+ dot = node.to_s
813
+ assert_match(dot, /comment\s*=\s*"Comment with \\"quotes\\""/)
814
+
815
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "Comment with \\backslashes\\"})
816
+ dot = node.to_s
817
+ assert_match(dot, /comment\s*=\s*"Comment with \\\\backslashes\\\\"/)
818
+
819
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "123.456"})
820
+ dot = node.to_s
821
+ assert_match(dot, /comment\s*=\s*123.456/)
822
+
823
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => ".456"})
824
+ dot = node.to_s
825
+ assert_match(dot, /comment\s*=\s*.456/)
826
+
827
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "-.456"})
828
+ dot = node.to_s
829
+ assert_match(dot, /comment\s*=\s*-.456/)
830
+
831
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "-456"})
832
+ dot = node.to_s
833
+ assert_match(dot, /comment\s*=\s*-456/)
834
+
835
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "-123.456"})
836
+ dot = node.to_s
837
+ assert_match(dot, /comment\s*=\s*-123.456/)
838
+
839
+ node = DOT::Subgraph.new({"name" => "test_name", "comment" => "<html><head><title>test</title></head>\n<body>text</body></html>"})
840
+ dot = node.to_s
841
+ assert_match(dot, /comment\s*=\s*<html><head><title>test<\/title><\/head>\n<body>text<\/body><\/html>/)
842
+ end
843
+
844
+ def test_element_containment
845
+ node1 = DOT::Node.new('name' => 'test_node1')
846
+ node2 = DOT::Node.new('name' => 'test_node2')
847
+
848
+ graph = DOT::Subgraph.new('name' => 'test_graph')
849
+ assert_nil(graph.pop)
850
+ assert_equal(graph, graph.push(node1))
851
+ assert_equal(graph, graph << node2)
852
+ graph.each_element do |element|
853
+ assert([node1, node2].include?(element))
854
+ end
855
+ assert_equal(node2, graph.pop)
856
+ assert_equal(node1, graph.pop)
857
+ assert_nil(graph.pop)
858
+
859
+ graph = DOT::Subgraph.new('name' => 'test_graph', 'elements' => [node1])
860
+ assert_equal(node1, graph.pop)
861
+ assert_nil(graph.pop)
862
+ end
863
+ end