laser 0.7.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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