PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/test/controller_test.rb

http://github.com/ruport/ruport
Ruby | 744 lines | 540 code | 173 blank | 31 comment | 4 complexity | 34ae5f1a4a25693219cd5c788a4a1623 MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/usr/bin/env ruby -w
  2. require File.join(File.expand_path(File.dirname(__FILE__)), "helpers")
  3. ###########################################################################
  4. #
  5. # NOTE:
  6. #
  7. # As it stands, we haven't found a more clever way to test the formatting
  8. # system than to just create a bunch of renderers and basic formatters for
  9. # different concepts we're trying to test. Patches and ideas welcome:
  10. #
  11. # list.rubyreports.org
  12. ############################################################################
  13. #============================================================================
  14. # These two renderers represent the two styles that can be used when defining
  15. # renderers in Ruport. The OldSchoolController approach has largely been
  16. # deprecated, but still has uses in edge cases that we need to support.
  17. #============================================================================
  18. class OldSchoolController < Ruport::Controller
  19. def run
  20. formatter do
  21. build_header
  22. build_body
  23. build_footer
  24. end
  25. end
  26. end
  27. class VanillaController < Ruport::Controller
  28. stage :header,:body,:footer
  29. end
  30. # This formatter implements some junk output so we can be sure
  31. # that the hooks are being set up right. Perhaps these could
  32. # be replaced by mock objects in the future.
  33. class DummyText < Ruport::Formatter
  34. renders :text, :for => OldSchoolController
  35. def prepare_document
  36. output << "p"
  37. end
  38. def build_header
  39. output << "header\n"
  40. end
  41. def build_body
  42. output << "body\n"
  43. end
  44. def build_footer
  45. output << "footer\n"
  46. end
  47. def finalize_document
  48. output << "f"
  49. end
  50. end
  51. # This formatter modifies the (String) data object passed to it
  52. class Destructive < Ruport::Formatter
  53. def prepare_document; end
  54. def build_header; end
  55. def build_body
  56. output << "You sent #{data}"
  57. data.replace("RUBBISH")
  58. end
  59. def build_footer; end
  60. def finalize_document; end
  61. end
  62. class VanillaBinary < Ruport::Formatter
  63. renders :bin, :for => VanillaController
  64. save_as_binary_file
  65. end
  66. class SpecialFinalize < Ruport::Formatter
  67. renders :with_finalize, :for => VanillaController
  68. def finalize
  69. output << "I has been finalized"
  70. end
  71. end
  72. class TestController < Minitest::Test
  73. def teardown
  74. Ruport::Formatter::Template.instance_variable_set(:@templates, nil)
  75. end
  76. def test_trivial
  77. actual = OldSchoolController.render(:text)
  78. assert_equal "header\nbody\nfooter\n", actual
  79. end
  80. context "when running a formatter with custom a finalize method" do
  81. should "specify_finalize_method_should_be_called" do
  82. assert_equal "I has been finalized",
  83. VanillaController.render_with_finalize
  84. end
  85. end
  86. context "when using templates" do
  87. should "specify_apply_template_should_be_called" do
  88. Ruport::Formatter::Template.create(:stub)
  89. Ruport.Table(%w[a b c]).to_csv(:template => :stub) do |r|
  90. r.formatter.expects(:apply_template)
  91. end
  92. end
  93. should "specify_undefined_template_should_throw_sensible_error" do
  94. assert_raises(Ruport::Formatter::TemplateNotDefined) do
  95. Ruport.Table(%w[a b c]).to_csv(:template => :sub)
  96. end
  97. end
  98. end
  99. context "when using default templates" do
  100. should "specify_default_template_should_be_called" do
  101. Ruport::Formatter::Template.create(:default)
  102. Ruport.Table(%w[a b c]).to_csv do |r|
  103. r.formatter.expects(:apply_template)
  104. assert r.formatter.template == Ruport::Formatter::Template[:default]
  105. end
  106. end
  107. should "specify_specific_should_override_default" do
  108. Ruport::Formatter::Template.create(:default)
  109. Ruport::Formatter::Template.create(:stub)
  110. Ruport.Table(%w[a b c]).to_csv(:template => :stub) do |r|
  111. r.formatter.expects(:apply_template)
  112. assert r.formatter.template == Ruport::Formatter::Template[:stub]
  113. end
  114. end
  115. should "specify_should_be_able_to_disable_templates" do
  116. Ruport::Formatter::Template.create(:default)
  117. Ruport.Table(%w[a b c]).to_csv(:template => false) do |r|
  118. r.formatter.expects(:apply_template).never
  119. end
  120. end
  121. end
  122. def test_using_io
  123. require "stringio"
  124. out = StringIO.new
  125. OldSchoolController.render(:text) { |r| r.io = out }
  126. out.rewind
  127. assert_equal "header\nbody\nfooter\n", out.read
  128. assert_equal "", out.read
  129. end
  130. def test_using_file
  131. f = []
  132. File.expects(:open).yields(f)
  133. OldSchoolController.render(:text, :file => "foo.text")
  134. assert_equal "header\nbody\nfooter\n", f[0]
  135. f = []
  136. File.expects(:open).with("blah","wb").yields(f)
  137. VanillaController.render(:bin, :file => "blah")
  138. end
  139. def test_using_file_via_rendering_tools
  140. f = []
  141. File.expects(:open).yields(f)
  142. Ruport.Table(%w[a b c], :data => [[1,2,3],[4,5,6]]).save_as("foo.csv")
  143. assert_equal "a,b,c\n1,2,3\n4,5,6\n", f[0]
  144. end
  145. def test_formats
  146. assert_equal( {}, Ruport::Controller.formats )
  147. assert_equal( { :text => DummyText },OldSchoolController.formats )
  148. end
  149. def test_method_missing
  150. actual = OldSchoolController.render_text
  151. assert_equal "header\nbody\nfooter\n", actual
  152. end
  153. def test_formatter
  154. # normal instance mode
  155. rend = OldSchoolController.new
  156. rend.send(:use_formatter,:text)
  157. assert_kind_of Ruport::Formatter, rend.formatter
  158. assert_kind_of DummyText, rend.formatter
  159. # render mode
  160. OldSchoolController.render_text do |r|
  161. assert_kind_of Ruport::Formatter, r.formatter
  162. assert_kind_of DummyText, r.formatter
  163. end
  164. assert_equal "body\n", rend.formatter { build_body }.output
  165. rend.formatter.clear_output
  166. assert_equal "", rend.formatter.output
  167. end
  168. def test_options_act_like_indifferent_hash
  169. opts = Ruport::Controller::Options.new
  170. opts.foo = "bar"
  171. assert_equal "bar", opts[:foo]
  172. assert_equal "bar", opts["foo"]
  173. opts["f"] = "bar"
  174. assert_equal "bar", opts[:f]
  175. assert_equal "bar", opts.f
  176. assert_equal "bar", opts["f"]
  177. opts[:apple] = "banana"
  178. assert_equal "banana", opts.apple
  179. assert_equal "banana", opts["apple"]
  180. assert_equal "banana", opts[:apple]
  181. end
  182. end
  183. class TestFormatterUsingBuild < Minitest::Test
  184. # This formatter uses the build syntax
  185. class UsesBuild < Ruport::Formatter
  186. renders :text_using_build, :for => VanillaController
  187. build :header do
  188. output << "header\n"
  189. end
  190. build :body do
  191. output << "body\n"
  192. end
  193. build :footer do
  194. output << "footer\n"
  195. end
  196. end
  197. def test_should_render_using_build_syntax
  198. assert_equal "header\nbody\nfooter\n",
  199. VanillaController.render_text_using_build
  200. VanillaController.render_text_using_build do |rend|
  201. assert rend.formatter.respond_to?(:build_header)
  202. assert rend.formatter.respond_to?(:build_body)
  203. assert rend.formatter.respond_to?(:build_footer)
  204. end
  205. end
  206. end
  207. class TestFormatterWithLayout < Minitest::Test
  208. # This formatter is meant to check out a special case in Ruport's renderer,
  209. # in which a layout method is called and yielded to when defined
  210. class WithLayout < DummyText
  211. renders :text_with_layout, :for => VanillaController
  212. def layout
  213. output << "---\n"
  214. yield
  215. output << "---\n"
  216. end
  217. end
  218. def test_layout
  219. assert_equal "---\nheader\nbody\nfooter\n---\n",
  220. VanillaController.render_text_with_layout
  221. end
  222. def test_layout_disabled
  223. assert_equal "header\nbody\nfooter\n",
  224. VanillaController.render_text_with_layout(:layout => false)
  225. end
  226. end
  227. class TestControllerWithManyHooks < Minitest::Test
  228. # This provides a way to check several hooks that controllers supports
  229. class ControllerWithManyHooks < Ruport::Controller
  230. add_format DummyText, :text
  231. add_format Destructive, :destructive
  232. prepare :document
  233. stage :header
  234. stage :body
  235. stage :footer
  236. finalize :document
  237. def setup
  238. options.apple = true
  239. end
  240. end
  241. def test_hash_options_setters
  242. ControllerWithManyHooks.render(:text, :subtitle => "foo", :subsubtitle => "bar") do |r|
  243. assert_equal "foo", r.options.subtitle
  244. assert_equal "bar", r.options.subsubtitle
  245. end
  246. end
  247. def test_data_accessors
  248. ControllerWithManyHooks.render(:text, :data => [1,2,4]) do |r|
  249. assert_equal [1,2,4], r.data
  250. end
  251. ControllerWithManyHooks.render_text(%w[a b c]) do |r|
  252. assert_equal %w[a b c], r.data
  253. end
  254. ControllerWithManyHooks.render_text(%w[a b f],:snapper => :red) do |r|
  255. assert_equal %w[a b f], r.data
  256. assert_equal :red, r.options.snapper
  257. end
  258. end
  259. def test_formatter_data_dup
  260. source = "some text"
  261. result = ControllerWithManyHooks.render(:destructive, :data => source)
  262. assert_equal("You sent some text", result)
  263. assert_equal("some text", source)
  264. end
  265. def test_stage_helper
  266. assert ControllerWithManyHooks.stages.include?('body')
  267. end
  268. def test_finalize_helper
  269. assert_equal :document, ControllerWithManyHooks.final_stage
  270. end
  271. def test_prepare_helper
  272. assert_equal :document, ControllerWithManyHooks.first_stage
  273. end
  274. def test_finalize_again
  275. assert_raises(Ruport::Controller::StageAlreadyDefinedError) {
  276. ControllerWithManyHooks.finalize :report
  277. }
  278. end
  279. def test_prepare_again
  280. assert_raises(Ruport::Controller::StageAlreadyDefinedError) {
  281. ControllerWithManyHooks.prepare :foo
  282. }
  283. end
  284. def test_renderer_using_helpers
  285. actual = ControllerWithManyHooks.render(:text)
  286. assert_equal "pheader\nbody\nfooter\nf", actual
  287. actual = ControllerWithManyHooks.render_text
  288. assert_equal "pheader\nbody\nfooter\nf", actual
  289. end
  290. def test_required_option_helper
  291. a = ControllerWithManyHooks.dup
  292. a.required_option :title
  293. a.render_text do |r|
  294. r.title = "Test Report"
  295. assert_equal "Test Report", r.options.title
  296. end
  297. end
  298. def test_without_required_option
  299. a = ControllerWithManyHooks.dup
  300. a.required_option :title
  301. assert_raises(Ruport::Controller::RequiredOptionNotSet) { a.render(:text) }
  302. end
  303. end
  304. class TestControllerWithRunHook < Minitest::Test
  305. class ControllerWithRunHook < Ruport::Controller
  306. add_format DummyText, :text
  307. required_option :foo,:bar
  308. stage :header
  309. stage :body
  310. stage :footer
  311. def run
  312. formatter.output << "|"
  313. super
  314. end
  315. end
  316. def test_renderer_with_run_hooks
  317. assert_equal "|header\nbody\nfooter\n",
  318. ControllerWithRunHook.render_text(:foo => "bar",:bar => "baz")
  319. end
  320. end
  321. class TestControllerWithHelperModule < Minitest::Test
  322. class ControllerWithHelperModule < VanillaController
  323. add_format DummyText, :stub
  324. module Helpers
  325. def say_hello
  326. "Hello Dolly"
  327. end
  328. end
  329. end
  330. def test_renderer_helper_module
  331. ControllerWithHelperModule.render_stub do |r|
  332. assert_equal "Hello Dolly", r.formatter.say_hello
  333. end
  334. end
  335. end
  336. class TestMultiPurposeFormatter < Minitest::Test
  337. # This provides a way to check the multi-format hooks for the Controller
  338. class MultiPurposeFormatter < Ruport::Formatter
  339. renders [:html,:text], :for => VanillaController
  340. def build_header
  341. a = 10
  342. text { output << "Foo: #{a}\n" }
  343. html { output << "<b>Foo: #{a}</b>\n" }
  344. end
  345. def build_body
  346. html { output << "<pre>\n" }
  347. output << options.body_text
  348. html { output << "\n</pre>\n" }
  349. end
  350. end
  351. def test_multi_purpose
  352. text = VanillaController.render_text(:body_text => "foo")
  353. assert_equal "Foo: 10\nfoo", text
  354. html = VanillaController.render_html(:body_text => "bar")
  355. assert_equal "<b>Foo: 10</b>\n<pre>\nbar\n</pre>\n",html
  356. end
  357. def test_method_missing_hack_formatter
  358. assert_equal [:html,:text], MultiPurposeFormatter.formats
  359. a = MultiPurposeFormatter.new
  360. a.format = :html
  361. visited = false
  362. a.html { visited = true }
  363. assert visited
  364. visited = false
  365. a.text { visited = true }
  366. assert !visited
  367. assert_raises(NoMethodError) do
  368. a.pdf { 'do nothing' }
  369. end
  370. end
  371. end
  372. class TestFormatterErbHelper < Minitest::Test
  373. class ErbFormatter < Ruport::Formatter
  374. renders :terb, :for => VanillaController
  375. def build_body
  376. # demonstrate local binding
  377. @foo = "bar"
  378. if options.binding
  379. output << erb("Binding Override: <%= reverse.inspect %>",
  380. :binding => options.binding)
  381. else
  382. output << erb("Default Binding: <%= @foo %>")
  383. end
  384. end
  385. end
  386. #FIXME: need to test file
  387. def test_self_bound
  388. assert_equal "Default Binding: bar", VanillaController.render_terb
  389. end
  390. def test_custom_bound
  391. a = [1,2,3]
  392. arr_binding = a.instance_eval { binding }
  393. assert_equal "Binding Override: [3, 2, 1]",
  394. VanillaController.render_terb(:binding => arr_binding)
  395. end
  396. end
  397. class TestOptionReaders < Minitest::Test
  398. class ControllerForCheckingOptionReaders < Ruport::Controller
  399. required_option :foo
  400. end
  401. class ControllerForCheckingPassivity < Ruport::Controller
  402. def foo
  403. "apples"
  404. end
  405. required_option :foo
  406. end
  407. def setup
  408. @renderer = ControllerForCheckingOptionReaders.new
  409. @renderer.formatter = Ruport::Formatter.new
  410. @passive = ControllerForCheckingPassivity.new
  411. @passive.formatter = Ruport::Formatter.new
  412. end
  413. def test_options_are_readable
  414. @renderer.foo = 5
  415. assert_equal 5, @renderer.foo
  416. end
  417. def test_methods_are_not_overridden
  418. @passive.foo = 5
  419. assert_equal "apples", @passive.foo
  420. assert_equal 5, @passive.options.foo
  421. assert_equal 5, @passive.formatter.options.foo
  422. end
  423. end
  424. class TestSetupOrdering < Minitest::Test
  425. class ControllerWithSetup < Ruport::Controller
  426. stage :bar
  427. def setup
  428. options.foo.capitalize!
  429. end
  430. end
  431. class BasicFormatter < Ruport::Formatter
  432. renders :text, :for => ControllerWithSetup
  433. def build_bar
  434. output << options.foo
  435. end
  436. end
  437. def test_render_hash_options_should_be_called_before_setup
  438. assert_equal "Hello", ControllerWithSetup.render_text(:foo => "hello")
  439. end
  440. def test_render_block_should_be_called_before_setup
  441. assert_equal "Hello",
  442. ControllerWithSetup.render_text { |r| r.options.foo = "hello" }
  443. end
  444. end
  445. class CustomFormatter < Ruport::Formatter
  446. def custom_helper
  447. output << "Custom!"
  448. end
  449. end
  450. class ControllerWithAnonymousFormatters < Ruport::Controller
  451. stage :report
  452. formatter :html do
  453. build :report do
  454. output << textile("h1. Hi there")
  455. end
  456. end
  457. formatter :csv do
  458. build :report do
  459. build_row([1,2,3])
  460. end
  461. end
  462. formatter :pdf do
  463. build :report do
  464. add_text "hello world"
  465. end
  466. end
  467. formatter :text do
  468. build :report do
  469. output << "Hello world"
  470. end
  471. end
  472. formatter :custom => CustomFormatter do
  473. build :report do
  474. output << "This is "
  475. custom_helper
  476. end
  477. end
  478. end
  479. class TestAnonymousFormatter < Minitest::Test
  480. def test_text_formatter_shortcut_is_accessible
  481. assert_equal "Hello world", ControllerWithAnonymousFormatters.render_text
  482. assert_equal "1,2,3\n", ControllerWithAnonymousFormatters.render_csv
  483. assert_equal "<h1>Hi there</h1>", ControllerWithAnonymousFormatters.render_html
  484. if RUBY_VERSION < "1.9"
  485. assert_not_nil ControllerWithAnonymousFormatters.render_pdf
  486. end
  487. end
  488. def test_custom_formatter_shortcut_is_accessible
  489. assert_equal "This is Custom!", ControllerWithAnonymousFormatters.render_custom
  490. end
  491. end
  492. # Used to ensure that problems in controller code aren't mistakenly intercepted
  493. # by Ruport.
  494. class MisbehavingController < Ruport::Controller
  495. end
  496. class MisbehavingFormatter < Ruport::Formatter
  497. renders :text, :for => MisbehavingController
  498. def initialize
  499. super
  500. raise NoMethodError
  501. end
  502. end
  503. class TestMisbehavingController < Minitest::Test
  504. def test_controller_errors_should_bubble_up
  505. assert_raises(NoMethodError) do
  506. MisbehavingController.render :text
  507. end
  508. end
  509. end
  510. class TestControllerHooks < Minitest::Test
  511. require "mocha"
  512. class DummyObject
  513. include Ruport::Controller::Hooks
  514. renders_as_table
  515. end
  516. def test_should_return_self
  517. a = DummyObject.new
  518. rend = mock("renderer")
  519. rend.expects(:data=).with(a)
  520. Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
  521. a.as(:csv)
  522. end
  523. class DummyObject2
  524. include Ruport::Controller::Hooks
  525. renders_as_table
  526. def renderable_data(_format)
  527. 1
  528. end
  529. end
  530. def test_should_return_results_of_renderable_data
  531. a = DummyObject2.new
  532. rend = mock("renderer")
  533. rend.expects(:data=).with(1)
  534. Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
  535. a.as(:csv)
  536. end
  537. class DummyObject3
  538. include Ruport::Controller::Hooks
  539. renders_as_table
  540. def renderable_data
  541. raise ArgumentError
  542. end
  543. end
  544. def test_should_not_mask_errors
  545. assert_raises(ArgumentError) { DummyObject3.new.as(:csv) }
  546. end
  547. class DummyObject4
  548. include Ruport::Controller::Hooks
  549. renders_as_table
  550. def renderable_data(format)
  551. case format
  552. when :html
  553. 1
  554. when :csv
  555. 2
  556. end
  557. end
  558. end
  559. def test_should_return_results_of_renderable_data_using_format
  560. a = DummyObject4.new
  561. rend = mock("renderer")
  562. rend.expects(:data=).with(2)
  563. Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
  564. a.as(:csv)
  565. end
  566. def test_an_unknown_format_error_should_be_raised
  567. assert_raises(Ruport::Controller::UnknownFormatError) do
  568. Ruport::Controller.render_foo
  569. end
  570. end
  571. end