"Fossies" - the Fresh Open Source Software Archive

Member "redmine-4.1.1/test/unit/lib/redmine/wiki_formatting/macros_test.rb" (6 Apr 2020, 16306 Bytes) of package /linux/www/redmine-4.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "macros_test.rb": 4.1.0_vs_4.1.1.

    1 # frozen_string_literal: true
    2 
    3 # Redmine - project management software
    4 # Copyright (C) 2006-2019  Jean-Philippe Lang
    5 #
    6 # This program is free software; you can redistribute it and/or
    7 # modify it under the terms of the GNU General Public License
    8 # as published by the Free Software Foundation; either version 2
    9 # of the License, or (at your option) any later version.
   10 #
   11 # This program is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with this program; if not, write to the Free Software
   18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 
   20 require File.expand_path('../../../../../test_helper', __FILE__)
   21 
   22 class Redmine::WikiFormatting::MacrosTest < Redmine::HelperTest
   23   include ApplicationHelper
   24   include ActionView::Helpers::TextHelper
   25   include ActionView::Helpers::SanitizeHelper
   26   include ERB::Util
   27   include Rails.application.routes.url_helpers
   28   extend ActionView::Helpers::SanitizeHelper::ClassMethods
   29 
   30   fixtures :projects, :roles, :enabled_modules, :users,
   31            :repositories, :changesets,
   32            :trackers, :issue_statuses, :issues,
   33            :versions, :documents,
   34            :wikis, :wiki_pages, :wiki_contents,
   35            :boards, :messages,
   36            :attachments, :enumerations
   37 
   38   def setup
   39     super
   40     @project = nil
   41   end
   42 
   43   def teardown
   44   end
   45 
   46   def test_macro_registration
   47     Redmine::WikiFormatting::Macros.register do
   48       macro :foo do |obj, args|
   49         "Foo: #{args.size} (#{args.join(',')}) (#{args.class.name})"
   50       end
   51     end
   52 
   53     assert_equal '<p>Foo: 0 () (Array)</p>', textilizable("{{foo}}")
   54     assert_equal '<p>Foo: 0 () (Array)</p>', textilizable("{{foo()}}")
   55     assert_equal '<p>Foo: 1 (arg1) (Array)</p>', textilizable("{{foo(arg1)}}")
   56     assert_equal '<p>Foo: 2 (arg1,arg2) (Array)</p>', textilizable("{{foo(arg1, arg2)}}")
   57   end
   58 
   59   def test_macro_registration_parse_args_set_to_false_should_disable_arguments_parsing
   60     Redmine::WikiFormatting::Macros.register do
   61       macro :bar, :parse_args => false do |obj, args|
   62         "Bar: (#{args}) (#{args.class.name})"
   63       end
   64     end
   65 
   66     assert_equal '<p>Bar: (args, more args) (String)</p>', textilizable("{{bar(args, more args)}}")
   67     assert_equal '<p>Bar: () (String)</p>', textilizable("{{bar}}")
   68     assert_equal '<p>Bar: () (String)</p>', textilizable("{{bar()}}")
   69   end
   70 
   71   def test_macro_registration_with_3_args_should_receive_text_argument
   72     Redmine::WikiFormatting::Macros.register do
   73       macro :baz do |obj, args, text|
   74         "Baz: (#{args.join(',')}) (#{text.class.name}) (#{text})"
   75       end
   76     end
   77 
   78     assert_equal "<p>Baz: () (NilClass) ()</p>", textilizable("{{baz}}")
   79     assert_equal "<p>Baz: () (NilClass) ()</p>", textilizable("{{baz()}}")
   80     assert_equal "<p>Baz: () (String) (line1\nline2)</p>", textilizable("{{baz()\nline1\nline2\n}}")
   81     assert_equal "<p>Baz: (arg1,arg2) (String) (line1\nline2)</p>", textilizable("{{baz(arg1, arg2)\nline1\nline2\n}}")
   82   end
   83 
   84   def test_macro_name_with_upper_case
   85     Redmine::WikiFormatting::Macros.macro(:UpperCase) {|obj, args| "Upper"}
   86 
   87     assert_equal "<p>Upper</p>", textilizable("{{UpperCase}}")
   88   end
   89 
   90   def test_multiple_macros_on_the_same_line
   91     Redmine::WikiFormatting::Macros.macro :foo do |obj, args|
   92       args.any? ? "args: #{args.join(',')}" : "no args"
   93     end
   94 
   95     assert_equal '<p>no args no args</p>', textilizable("{{foo}} {{foo}}")
   96     assert_equal '<p>args: a,b no args</p>', textilizable("{{foo(a,b)}} {{foo}}")
   97     assert_equal '<p>args: a,b args: c,d</p>', textilizable("{{foo(a,b)}} {{foo(c,d)}}")
   98     assert_equal '<p>no args args: c,d</p>', textilizable("{{foo}} {{foo(c,d)}}")
   99   end
  100 
  101   def test_macro_should_receive_the_object_as_argument_when_with_object_and_attribute
  102     issue = Issue.find(1)
  103     issue.description = "{{hello_world}}"
  104     assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(issue, :description)
  105   end
  106 
  107   def test_macro_should_receive_the_object_as_argument_when_called_with_object_option
  108     text = "{{hello_world}}"
  109     assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(text, :object => Issue.find(1))
  110   end
  111 
  112   def test_extract_macro_options_should_with_args
  113     options = extract_macro_options(["arg1", "arg2"], :foo, :size)
  114     assert_equal([["arg1", "arg2"], {}], options)
  115   end
  116 
  117   def test_extract_macro_options_should_with_options
  118     options = extract_macro_options(["foo=bar", "size=2"], :foo, :size)
  119     assert_equal([[], {:foo => "bar", :size => "2"}], options)
  120   end
  121 
  122   def test_extract_macro_options_should_with_args_and_options
  123     options = extract_macro_options(["arg1", "arg2", "foo=bar", "size=2"], :foo, :size)
  124     assert_equal([["arg1", "arg2"], {:foo => "bar", :size => "2"}], options)
  125   end
  126 
  127   def test_extract_macro_options_should_parse_options_lazily
  128     options = extract_macro_options(["params=x=1&y=2"], :params)
  129     assert_equal([[], {:params => "x=1&y=2"}], options)
  130   end
  131 
  132   def test_macro_exception_should_be_displayed
  133     Redmine::WikiFormatting::Macros.macro :exception do |obj, args|
  134       raise "My message"
  135     end
  136 
  137     text = "{{exception}}"
  138     assert_include '<div class="flash error">Error executing the <strong>exception</strong> macro (My message)</div>', textilizable(text)
  139   end
  140 
  141   def test_macro_arguments_should_not_be_parsed_by_formatters
  142     text = '{{hello_world(http://www.redmine.org, #1)}}'
  143     assert_include 'Arguments: http://www.redmine.org, #1', textilizable(text)
  144   end
  145 
  146   def test_exclamation_mark_should_not_run_macros
  147     text = "!{{hello_world}}"
  148     assert_equal '<p>{{hello_world}}</p>', textilizable(text)
  149   end
  150 
  151   def test_exclamation_mark_should_escape_macros
  152     text = "!{{hello_world(<tag>)}}"
  153     assert_equal '<p>{{hello_world(&lt;tag&gt;)}}</p>', textilizable(text)
  154   end
  155 
  156   def test_unknown_macros_should_not_be_replaced
  157     text = "{{unknown}}"
  158     assert_equal '<p>{{unknown}}</p>', textilizable(text)
  159   end
  160 
  161   def test_unknown_macros_should_parsed_as_text
  162     text = "{{unknown(*test*)}}"
  163     assert_equal '<p>{{unknown(<strong>test</strong>)}}</p>', textilizable(text)
  164   end
  165 
  166   def test_unknown_macros_should_be_escaped
  167     text = "{{unknown(<tag>)}}"
  168     assert_equal '<p>{{unknown(&lt;tag&gt;)}}</p>', textilizable(text)
  169   end
  170 
  171   def test_html_safe_macro_output_should_not_be_escaped
  172     Redmine::WikiFormatting::Macros.macro :safe_macro do |obj, args|
  173       "<tag>".html_safe
  174     end
  175     assert_equal '<p><tag></p>', textilizable("{{safe_macro}}")
  176   end
  177 
  178   def test_macro_hello_world
  179     text = "{{hello_world}}"
  180     assert textilizable(text).match(/Hello world!/)
  181   end
  182 
  183   def test_macro_hello_world_should_escape_arguments
  184     text = "{{hello_world(<tag>)}}"
  185     assert_include 'Arguments: &lt;tag&gt;', textilizable(text)
  186   end
  187 
  188   def test_macro_macro_list
  189     text = "{{macro_list}}"
  190     assert_match %r{<code>hello_world</code>}, textilizable(text)
  191   end
  192 
  193   def test_macro_include
  194     @project = Project.find(1)
  195     # include a page of the current project wiki
  196     text = "{{include(Another page)}}"
  197     assert_include 'This is a link to a ticket', textilizable(text)
  198 
  199     @project = nil
  200     # include a page of a specific project wiki
  201     text = "{{include(ecookbook:Another page)}}"
  202     assert_include 'This is a link to a ticket', textilizable(text)
  203 
  204     text = "{{include(ecookbook:)}}"
  205     assert_include 'CookBook documentation', textilizable(text)
  206 
  207     text = "{{include(unknowidentifier:somepage)}}"
  208     assert_include 'Page not found', textilizable(text)
  209   end
  210 
  211   def test_macro_collapse
  212     text = "{{collapse\n*Collapsed* block of text\n}}"
  213     with_locale 'en' do
  214       result = textilizable(text)
  215 
  216       assert_select_in result, 'div.collapsed-text'
  217       assert_select_in result, 'strong', :text => 'Collapsed'
  218       assert_select_in result, 'a.collapsible.icon-collapsed', :text => 'Show'
  219       assert_select_in result, 'a.collapsible.icon-expended', :text => 'Hide'
  220     end
  221   end
  222 
  223   def test_macro_collapse_with_one_arg
  224     text = "{{collapse(Example)\n*Collapsed* block of text\n}}"
  225     result = textilizable(text)
  226 
  227     assert_select_in result, 'div.collapsed-text'
  228     assert_select_in result, 'strong', :text => 'Collapsed'
  229     assert_select_in result, 'a.collapsible.icon-collapsed', :text => 'Example'
  230     assert_select_in result, 'a.collapsible.icon-expended', :text => 'Example'
  231   end
  232 
  233   def test_macro_collapse_with_two_args
  234     text = "{{collapse(Show example, Hide example)\n*Collapsed* block of text\n}}"
  235     result = textilizable(text)
  236 
  237     assert_select_in result, 'div.collapsed-text'
  238     assert_select_in result, 'strong', :text => 'Collapsed'
  239     assert_select_in result, 'a.collapsible.icon-collapsed', :text => 'Show example'
  240     assert_select_in result, 'a.collapsible.icon-expended', :text => 'Hide example'
  241   end
  242 
  243   def test_macro_collapse_should_not_break_toc
  244     set_language_if_valid 'en'
  245 
  246     text = <<~RAW
  247       {{toc}}
  248 
  249       h1. Title
  250 
  251       {{collapse(Show example, Hide example)
  252       h2. Heading
  253       }}"
  254     RAW
  255 
  256     expected_toc = '<ul class="toc"><li><strong>Table of contents</strong></li><li><a href="#Title">Title</a><ul><li><a href="#Heading">Heading</a></li></ul></li></ul>'
  257 
  258     assert_include expected_toc, textilizable(text).gsub(/[\r\n]/, '')
  259   end
  260 
  261   def test_macro_child_pages
  262     expected =  "<p><ul class=\"pages-hierarchy\">\n" +
  263                  "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a>\n" +
  264                  "<ul class=\"pages-hierarchy\">\n<li><a href=\"/projects/ecookbook/wiki/Child_1_1\">Child 1 1</a></li>\n</ul>\n</li>\n" +
  265                  "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" +
  266                  "</ul>\n</p>"
  267 
  268     @project = Project.find(1)
  269     # child pages of the current wiki page
  270     assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content)
  271     # child pages of another page
  272     assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content)
  273 
  274     @project = Project.find(2)
  275     assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content)
  276   end
  277 
  278   def test_macro_child_pages_with_parent_option
  279     expected =  "<p><ul class=\"pages-hierarchy\">\n" +
  280                  "<li><a href=\"/projects/ecookbook/wiki/Another_page\">Another page</a>\n" +
  281                  "<ul class=\"pages-hierarchy\">\n" +
  282                  "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a>\n" +
  283                  "<ul class=\"pages-hierarchy\">\n<li><a href=\"/projects/ecookbook/wiki/Child_1_1\">Child 1 1</a></li>\n</ul>\n</li>\n" +
  284                  "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" +
  285                  "</ul>\n</li>\n</ul>\n</p>"
  286 
  287     @project = Project.find(1)
  288     # child pages of the current wiki page
  289     assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content)
  290     # child pages of another page
  291     assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content)
  292 
  293     @project = Project.find(2)
  294     assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content)
  295   end
  296 
  297   def test_macro_child_pages_with_depth_option
  298     expected =  "<p><ul class=\"pages-hierarchy\">\n" +
  299                  "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" +
  300                  "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" +
  301                  "</ul>\n</p>"
  302 
  303     @project = Project.find(1)
  304     assert_equal expected, textilizable("{{child_pages(depth=1)}}", :object => WikiPage.find(2).content)
  305   end
  306 
  307   def test_macro_child_pages_without_wiki_page_should_fail
  308     assert_match /can be called from wiki pages only/, textilizable("{{child_pages}}")
  309   end
  310 
  311   def test_macro_thumbnail
  312     link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17/200" />'.html_safe,
  313                    "/attachments/17",
  314                    :class => "thumbnail",
  315                    :title => "testfile.PNG")
  316     assert_equal "<p>#{link}</p>",
  317                  textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14))
  318   end
  319 
  320   def test_macro_thumbnail_with_full_path
  321     link = link_to('<img alt="testfile.PNG" src="http://test.host/attachments/thumbnail/17/200" />'.html_safe,
  322                    "http://test.host/attachments/17",
  323                    :class => "thumbnail",
  324                    :title => "testfile.PNG")
  325     assert_equal "<p>#{link}</p>",
  326                  textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14), :only_path => false)
  327   end
  328 
  329   def test_macro_thumbnail_with_size
  330     link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17/400" />'.html_safe,
  331                    "/attachments/17",
  332                    :class => "thumbnail",
  333                    :title => "testfile.PNG")
  334     assert_equal "<p>#{link}</p>",
  335                  textilizable("{{thumbnail(testfile.png, size=400)}}", :object => Issue.find(14))
  336   end
  337 
  338   def test_macro_thumbnail_with_title
  339     link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17/200" />'.html_safe,
  340                    "/attachments/17",
  341                    :class => "thumbnail",
  342                    :title => "Cool image")
  343     assert_equal "<p>#{link}</p>",
  344                  textilizable("{{thumbnail(testfile.png, title=Cool image)}}", :object => Issue.find(14))
  345   end
  346 
  347   def test_macro_thumbnail_with_invalid_filename_should_fail
  348     assert_include 'test.png not found',
  349                    textilizable("{{thumbnail(test.png)}}", :object => Issue.find(14))
  350   end
  351 
  352   def test_macros_should_not_be_executed_in_pre_tags
  353     text = <<~RAW
  354       {{hello_world(foo)}}
  355 
  356       <pre>
  357       {{hello_world(pre)}}
  358       !{{hello_world(pre)}}
  359       </pre>
  360 
  361       {{hello_world(bar)}}
  362     RAW
  363     expected = <<~EXPECTED
  364       <p>Hello world! Object: NilClass, Arguments: foo and no block of text.</p>
  365 
  366       <pre>
  367       {{hello_world(pre)}}
  368       !{{hello_world(pre)}}
  369       </pre>
  370 
  371       <p>Hello world! Object: NilClass, Arguments: bar and no block of text.</p>
  372     EXPECTED
  373     assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '')
  374   end
  375 
  376   def test_macros_should_be_escaped_in_pre_tags
  377     text = "<pre>{{hello_world(<tag>)}}</pre>"
  378     assert_equal "<pre>{{hello_world(&lt;tag&gt;)}}</pre>", textilizable(text)
  379   end
  380 
  381   def test_macros_should_not_mangle_next_macros_outputs
  382     text = '{{macro(2)}} !{{macro(2)}} {{hello_world(foo)}}'
  383     assert_equal '<p>{{macro(2)}} {{macro(2)}} Hello world! Object: NilClass, Arguments: foo and no block of text.</p>', textilizable(text)
  384   end
  385 
  386   def test_macros_with_text_should_not_mangle_following_macros
  387     text = <<~RAW
  388       {{hello_world
  389       Line of text
  390       }}
  391 
  392       {{hello_world
  393       Another line of text
  394       }}
  395     RAW
  396     expected = <<~EXPECTED
  397       <p>Hello world! Object: NilClass, Called with no argument and a 12 bytes long block of text.</p>
  398       <p>Hello world! Object: NilClass, Called with no argument and a 20 bytes long block of text.</p>
  399     EXPECTED
  400     assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '')
  401   end
  402 
  403   def test_macro_should_support_phrase_modifiers
  404     text = "*{{hello_world}}*"
  405     assert_match %r|\A<p><strong>Hello world!.*</strong></p>\z|, textilizable(text)
  406   end
  407 
  408   def test_issue_macro_should_not_render_link_if_not_visible
  409     assert_equal "<p>#123</p>", textilizable('{{issue(123)}}')
  410   end
  411 
  412   def test_issue_macro_should_render_link_to_issue
  413     issue = Issue.find 1
  414     assert_equal %{<p><a class="issue tracker-1 status-1 priority-4 priority-lowest" href="/issues/1">Bug #1</a>: #{issue.subject}</p>}, textilizable("{{issue(1)}}")
  415     assert_equal %{<p>eCookbook - <a class="issue tracker-1 status-1 priority-4 priority-lowest" href="/issues/1">Bug #1</a>: #{issue.subject}</p>}, textilizable("{{issue(1, project=true)}}")
  416   end
  417 end