Project

General

Profile

Defect #30371 » 0001-Remove-unnecessary-trailing-white-spaces.patch

Yuichi HARADA, 2019-01-23 07:23

View differences:

lib/redmine/wiki_formatting/textile/redcloth3.rb
71 71
#
72 72
# == Links
73 73
#
74
# To make a hypertext link, put the link text in "quotation 
74
# To make a hypertext link, put the link text in "quotation
75 75
# marks" followed immediately by a colon and the URL of the link.
76
# 
77
# Optional: text in (parentheses) following the link text, 
78
# but before the closing quotation mark, will become a Title 
76
#
77
# Optional: text in (parentheses) following the link text,
78
# but before the closing quotation mark, will become a Title
79 79
# attribute for the link, visible as a tool tip when a cursor is above it.
80
# 
80
#
81 81
# Example:
82 82
#
83 83
#  "This is a link (This is a title) ":http://www.textism.com
84
# 
84
#
85 85
# Will become:
86
# 
86
#
87 87
#  <a href="http://www.textism.com" title="This is a title">This is a link</a>
88 88
#
89 89
# == Images
90 90
#
91 91
# To insert an image, put the URL for the image inside exclamation marks.
92 92
#
93
# Optional: text that immediately follows the URL in (parentheses) will 
94
# be used as the Alt text for the image. Images on the web should always 
95
# have descriptive Alt text for the benefit of readers using non-graphical 
93
# Optional: text that immediately follows the URL in (parentheses) will
94
# be used as the Alt text for the image. Images on the web should always
95
# have descriptive Alt text for the benefit of readers using non-graphical
96 96
# browsers.
97 97
#
98
# Optional: place a colon followed by a URL immediately after the 
98
# Optional: place a colon followed by a URL immediately after the
99 99
# closing ! to make the image into a link.
100
# 
100
#
101 101
# Example:
102 102
#
103 103
#  !http://www.textism.com/common/textist.gif(Textist)!
......
116 116
#
117 117
# == Defining Acronyms
118 118
#
119
# HTML allows authors to define acronyms via the tag. The definition appears as a 
120
# tool tip when a cursor hovers over the acronym. A crucial aid to clear writing, 
119
# HTML allows authors to define acronyms via the tag. The definition appears as a
120
# tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
121 121
# this should be used at least once for each acronym in documents where they appear.
122 122
#
123
# To quickly define an acronym in Textile, place the full text in (parentheses) 
123
# To quickly define an acronym in Textile, place the full text in (parentheses)
124 124
# immediately following the acronym.
125
# 
125
#
126 126
# Example:
127 127
#
128 128
#  ACLU(American Civil Liberties Union)
......
145 145
#     (background:#ddd;color:red). |{}| | | |
146 146
#
147 147
# == Using RedCloth
148
# 
148
#
149 149
# RedCloth is simply an extension of the String class, which can handle
150 150
# Textile formatting.  Use it like a String and output HTML with its
151 151
# RedCloth#to_html method.
......
268 268
        rules = DEFAULT_RULES if rules.empty?
269 269
        # make our working copy
270 270
        text = self.dup
271
        
271

  
272 272
        @urlrefs = {}
273 273
        @shelf = []
274 274
        textile_rules = [:block_textile_table, :block_textile_lists,
275 275
                         :block_textile_prefix, :inline_textile_image, :inline_textile_link,
276 276
                         :inline_textile_code, :inline_textile_span, :glyphs_textile]
277 277
        markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
278
                          :block_markdown_bq, :block_markdown_lists, 
278
                          :block_markdown_bq, :block_markdown_lists,
279 279
                          :inline_markdown_reflink, :inline_markdown_link]
280 280
        @rules = rules.collect do |rule|
281 281
            case rule
......
289 289
        end.flatten
290 290

  
291 291
        # standard clean up
292
        incoming_entities text 
293
        clean_white_space text 
292
        incoming_entities text
293
        clean_white_space text
294 294

  
295 295
        # start processor
296 296
        @pre_list = []
......
299 299
        escape_html_tags text
300 300
        # need to do this before #hard_break and #blocks
301 301
        block_textile_quotes text unless @lite_mode
302
        hard_break text 
302
        hard_break text
303 303
        unless @lite_mode
304 304
            refs text
305 305
            blocks text
......
326 326
    #
327 327
    TEXTILE_TAGS =
328 328

  
329
        [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230], 
330
         [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249], 
331
         [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217], 
332
         [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732], 
329
        [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
330
         [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
331
         [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
332
         [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
333 333
         [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
334 334

  
335 335
        collect! do |a, b|
......
357 357

  
358 358
    # Text markup tags, don't conflict with block tags
359 359
    SIMPLE_HTML_TAGS = [
360
        'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code', 
360
        'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code',
361 361
        'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br',
362 362
        'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'
363 363
    ]
......
373 373
        ['+', 'ins', :limit],
374 374
        ['^', 'sup', :limit],
375 375
        ['~', 'sub', :limit]
376
    ] 
376
    ]
377 377
    QTAGS_JOIN = QTAGS.map {|rc, ht, rtype| Regexp::quote rc}.join('|')
378
    
378

  
379 379
    QTAGS.collect! do |rc, ht, rtype|
380 380
        rcq = Regexp::quote rc
381 381
        re =
......
395 395
                (#{C})
396 396
                (?::(\S+))?
397 397
                ([[:word:]]|[^\s\-].*?[^\s\-])
398
                #{rcq}/xm 
398
                #{rcq}/xm
399 399
            end
400 400
        [rc, ht, re, rtype]
401 401
    end
......
464 464

  
465 465
    # Parses Textile attribute lists and builds an HTML attribute string
466 466
    def pba( text_in, element = "" )
467
        
467

  
468 468
        return '' unless text_in
469 469

  
470 470
        style = []
......
485 485

  
486 486
        cls = $1 if
487 487
            text.sub!( /\(([^()]+?)\)/, '' )
488
                        
488

  
489 489
        style << "padding-left:#{ $1.length }em;" if
490 490
            text.sub!( /([(]+)/, '' )
491 491

  
......
510 510
        atts << " id=\"#{ id }\"" if id
511 511
        atts << " colspan=\"#{ colspan }\"" if colspan
512 512
        atts << " rowspan=\"#{ rowspan }\"" if rowspan
513
        
513

  
514 514
        atts
515 515
    end
516 516

  
......
525 525
    end
526 526

  
527 527
    TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m
528
    
528

  
529 529
    # Parses a Textile table block, building HTML from the result.
530
    def block_textile_table( text ) 
530
    def block_textile_table( text )
531 531
        text.gsub!( TABLE_RE ) do |matches|
532 532

  
533 533
            tatts, fullrow = $~[1..2]
......
538 538
            fullrow.each_line do |row|
539 539
                ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
540 540
                cells = []
541
                # the regexp prevents wiki links with a | from being cut as cells 
541
                # the regexp prevents wiki links with a | from being cut as cells
542 542
                row.scan(/\|(_?#{S}#{A}#{C}\. ?)?((\[\[[^|\]]*\|[^|\]]*\]\]|[^|])*?)(?=\|)/) do |modifiers, cell|
543 543
                    ctyp = 'd'
544 544
                    ctyp = 'h' if modifiers && modifiers =~ /^_/
......
547 547
                    catts = pba( modifiers, 'td' ) if modifiers
548 548

  
549 549
                    catts = shelve( catts ) if catts
550
                    cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>" 
550
                    cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
551 551
                end
552 552
                ratts = shelve( ratts ) if ratts
553 553
                rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
......
560 560
    LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m
561 561

  
562 562
    # Parses Textile lists and generates HTML
563
    def block_textile_lists( text ) 
563
    def block_textile_lists( text )
564 564
        text.gsub!( LISTS_RE ) do |match|
565 565
            lines = match.split( /\n/ )
566 566
            last_line = -1
567 567
            depth = []
568 568
            lines.each_with_index do |line, line_id|
569
                if line =~ LISTS_CONTENT_RE 
569
                if line =~ LISTS_CONTENT_RE
570 570
                    tl,atts,content = $~[1..3]
571 571
                    if depth.last
572 572
                        if depth.last.length > tl.length
......
602 602
            lines.join( "\n" )
603 603
        end
604 604
    end
605
    
605

  
606 606
    QUOTES_RE = /(^>+([^\n]*?)(\n|$))+/m
607 607
    QUOTES_CONTENT_RE = /^([> ]+)(.*)$/m
608
    
608

  
609 609
    def block_textile_quotes( text )
610 610
      text.gsub!( QUOTES_RE ) do |match|
611 611
        lines = match.split( /\n/ )
612 612
        quotes = ''
613 613
        indent = 0
614 614
        lines.each do |line|
615
          line =~ QUOTES_CONTENT_RE 
615
          line =~ QUOTES_CONTENT_RE
616 616
          bq,content = $1, $2
617 617
          l = bq.count('>')
618 618
          if l != indent
......
633 633
        @
634 634
        (?=\W)/x
635 635

  
636
    def inline_textile_code( text ) 
636
    def inline_textile_code( text )
637 637
        text.gsub!( CODE_RE ) do |m|
638 638
            before,lang,code,after = $~[1..4]
639 639
            lang = " lang=\"#{ lang }\"" if lang
......
641 641
        end
642 642
    end
643 643

  
644
    def lT( text ) 
644
    def lT( text )
645 645
        text =~ /\#$/ ? 'o' : 'u'
646 646
    end
647 647

  
......
676 676
                        end
677 677
                    end
678 678

  
679
                    block_applied = 0 
679
                    block_applied = 0
680 680
                    @rules.each do |rule_name|
681 681
                        block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) )
682 682
                    end
......
723 723

  
724 724
    BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m
725 725

  
726
    def block_textile_prefix( text ) 
726
    def block_textile_prefix( text )
727 727
        if text =~ BLOCK_RE
728 728
            tag,tagpre,num,atts,cite,content = $~[1..6]
729 729
            atts = pba( atts )
......
733 733
            if respond_to? "textile_#{ tag }", true
734 734
              replacement = method( "textile_#{ tag }" ).call( tag, atts, cite, content )
735 735
            elsif respond_to? "textile_#{ tagpre }_", true
736
              replacement = method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content )  
736
              replacement = method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content )
737 737
            end
738 738
            text.gsub!( $& ) { replacement } if replacement
739 739
        end
740 740
    end
741
    
741

  
742 742
    SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m
743 743
    def block_markdown_setext( text )
744 744
        if text =~ SETEXT_RE
......
790 790
    def block_markdown_lists( text )
791 791
    end
792 792

  
793
    def inline_textile_span( text ) 
793
    def inline_textile_span( text )
794 794
        QTAGS.each do |qtag_rc, ht, qtag_re, rtype|
795 795
            text.gsub!( qtag_re ) do |m|
796
             
796

  
797 797
                case rtype
798 798
                when :limit
799 799
                    sta,oqs,qtag,content,oqa = $~[1..6]
......
826 826
            (                          # $url
827 827
            (\/|[a-zA-Z]+:\/\/|www\.|mailto:)  # $proto
828 828
            [[:alnum:]_\/]\S+?
829
            )               
829
            )
830 830
            (\/)?                      # $slash
831 831
            ([^[:alnum:]_\=\/;\(\)]*?)         # $post
832 832
            )
833 833
            (?=<|\s|$)
834
        /x 
834
        /x
835 835
#"
836
    def inline_textile_link( text ) 
836
    def inline_textile_link( text )
837 837
        text.gsub!( LINK_RE ) do |m|
838 838
          all,pre,atts,text,title,url,proto,slash,post = $~[1..9]
839 839
          if text.include?('<br />')
......
841 841
          else
842 842
            url, url_title = check_refs( url )
843 843
            title ||= url_title
844
            
844

  
845 845
            # Idea below : an URL with unbalanced parethesis and
846 846
            # ending by ')' is put into external parenthesis
847 847
            if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) )
......
852 852
            atts = " href=\"#{ htmlesc url }#{ slash }\"#{ atts }"
853 853
            atts << " title=\"#{ htmlesc title }\"" if title
854 854
            atts = shelve( atts ) if atts
855
            
855

  
856 856
            external = (url =~ /^https?:\/\//) ? ' class="external"' : ''
857
            
857

  
858 858
            "#{ pre }<a#{ atts }#{ external }>#{ text }</a>#{ post }"
859 859
          end
860 860
        end
......
865 865
            [ ]?                # opt. space
866 866
            (?:\n[ ]*)?         # one optional newline followed by spaces
867 867
            \[(.*?)\]           # $id
868
        /x 
868
        /x
869 869

  
870
    def inline_markdown_reflink( text ) 
870
    def inline_markdown_reflink( text )
871 871
        text.gsub!( MARKDOWN_REFLINK_RE ) do |m|
872 872
            text, id = $~[1..2]
873 873

  
......
876 876
            else
877 877
                url, title = check_refs( id )
878 878
            end
879
            
879

  
880 880
            atts = " href=\"#{ url }\""
881 881
            atts << " title=\"#{ title }\"" if title
882 882
            atts = shelve( atts )
883
            
883

  
884 884
            "<a#{ atts }>#{ text }</a>"
885 885
        end
886 886
    end
......
897 897
            \3                  # matching quote
898 898
            )?                  # title is optional
899 899
            \)
900
        /x 
900
        /x
901 901

  
902
    def inline_markdown_link( text ) 
902
    def inline_markdown_link( text )
903 903
        text.gsub!( MARKDOWN_LINK_RE ) do |m|
904 904
            text, url, quote, title = $~[1..4]
905 905

  
906 906
            atts = " href=\"#{ url }\""
907 907
            atts << " title=\"#{ title }\"" if title
908 908
            atts = shelve( atts )
909
            
909

  
910 910
            "<a#{ atts }>#{ text }</a>"
911 911
        end
912 912
    end
......
920 920
        end
921 921
    end
922 922

  
923
    def refs_textile( text ) 
923
    def refs_textile( text )
924 924
        text.gsub!( TEXTILE_REFS_RE ) do |m|
925 925
            flag, url = $~[2..3]
926 926
            @urlrefs[flag.downcase] = [url, nil]
927 927
            nil
928 928
        end
929 929
    end
930
    
930

  
931 931
    def refs_markdown( text )
932 932
        text.gsub!( MARKDOWN_REFS_RE ) do |m|
933 933
            flag, url = $~[2..3]
......
937 937
        end
938 938
    end
939 939

  
940
    def check_refs( text ) 
940
    def check_refs( text )
941 941
        ret = @urlrefs[text.downcase] if text
942 942
        ret || [text, nil]
943 943
    end
......
953 953
            (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))?   # optional title
954 954
            \!                   # closing
955 955
            (?::#{ HYPERLINK })? # optional href
956
        /x 
956
        /x
957 957

  
958
    def inline_textile_image( text ) 
958
    def inline_textile_image( text )
959 959
        text.gsub!( IMAGE_RE )  do |m|
960 960
            stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
961 961
            htmlesc title
962 962
            atts = pba( atts )
963 963
            atts = " src=\"#{ htmlesc url.dup }\"#{ atts }"
964 964
            atts << " title=\"#{ title }\"" if title
965
            atts << " alt=\"#{ title }\"" 
965
            atts << " alt=\"#{ title }\""
966 966
            # size = @getimagesize($url);
967 967
            # if($size) $atts.= " $size[3]";
968 968

  
......
975 975
            out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
976 976
            out << "<img#{ shelve( atts ) } />"
977 977
            out << "</a>#{ href_a1 }#{ href_a2 }" if href
978
            
979
            if algn 
978

  
979
            if algn
980 980
                algn = h_align( algn )
981 981
                if stln == "<p>"
982 982
                    out = "<p style=\"float:#{ algn }\">#{ out }"
......
991 991
        end
992 992
    end
993 993

  
994
    def shelve( val ) 
994
    def shelve( val )
995 995
        @shelf << val
996 996
        " :redsh##{ @shelf.length }:"
997 997
    end
998
    
999
    def retrieve( text ) 
998

  
999
    def retrieve( text )
1000 1000
        text.gsub!(/ :redsh#(\d+):/) do
1001 1001
          @shelf[$1.to_i - 1] || $&
1002 1002
        end
1003 1003
    end
1004 1004

  
1005
    def incoming_entities( text ) 
1005
    def incoming_entities( text )
1006 1006
        ## turn any incoming ampersands into a dummy character for now.
1007 1007
        ## This uses a negative lookahead for alphanumerics followed by a semicolon,
1008 1008
        ## implying an incoming html entity, to be skipped
......
1010 1010
        text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
1011 1011
    end
1012 1012

  
1013
    def no_textile( text ) 
1013
    def no_textile( text )
1014 1014
        text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/,
1015 1015
            '\1<notextile>\2</notextile>\3' )
1016 1016
        text.gsub!( /^ *==([^=]+.*?)==/m,
1017 1017
            '\1<notextile>\2</notextile>\3' )
1018 1018
    end
1019 1019

  
1020
    def clean_white_space( text ) 
1020
    def clean_white_space( text )
1021 1021
        # normalize line breaks
1022 1022
        text.gsub!( /\r\n/, "\n" )
1023 1023
        text.gsub!( /\r/, "\n" )
......
1043 1043
        end
1044 1044
    end
1045 1045

  
1046
    def footnote_ref( text ) 
1046
    def footnote_ref( text )
1047 1047
        text.gsub!( /\b\[([0-9]+?)\](\s)?/,
1048 1048
            '<sup><a href="#fn\1">\1</a></sup>\2' )
1049 1049
    end
1050
    
1050

  
1051 1051
    OFFTAGS = /(code|pre|kbd|notextile)/
1052 1052
    OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }\b>)|(<#{ OFFTAGS }\b[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\b\W|\Z)/mi
1053 1053
    OFFTAG_OPEN = /<#{ OFFTAGS }/
......
1069 1069
                    elsif line =~ OFFTAG_CLOSE
1070 1070
                        codepre -= 1
1071 1071
                        codepre = 0 if codepre < 0
1072
                    end 
1072
                    end
1073 1073
                elsif codepre.zero?
1074 1074
                    glyphs_textile( line, level + 1 )
1075 1075
                else
......
1116 1116
                    end
1117 1117
                    codepre -= 1 unless codepre.zero?
1118 1118
                    used_offtags = {} if codepre.zero?
1119
                end 
1119
                end
1120 1120
                line
1121 1121
            end
1122 1122
        end
......
1130 1130
        end
1131 1131
    end
1132 1132

  
1133
    def inline( text ) 
1133
    def inline( text )
1134 1134
        [/^inline_/, /^glyphs_/].each do |meth_re|
1135 1135
            @rules.each do |rule_name|
1136 1136
                method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
......
1138 1138
        end
1139 1139
    end
1140 1140

  
1141
    def h_align( text ) 
1141
    def h_align( text )
1142 1142
        H_ALGN_VALS[text]
1143 1143
    end
1144 1144

  
1145
    def v_align( text ) 
1145
    def v_align( text )
1146 1146
        V_ALGN_VALS[text]
1147 1147
    end
1148 1148

  
......
1156 1156
        'img' => ['src', 'alt', 'title'],
1157 1157
        'br' => [],
1158 1158
        'i' => nil,
1159
        'u' => nil, 
1159
        'u' => nil,
1160 1160
        'b' => nil,
1161 1161
        'pre' => nil,
1162 1162
        'kbd' => nil,
......
1181 1181
        'h3' => nil,
1182 1182
        'h4' => nil,
1183 1183
        'h5' => nil,
1184
        'h6' => nil, 
1184
        'h6' => nil,
1185 1185
        'blockquote' => ['cite']
1186 1186
    }
1187 1187

  
......
1209 1209
            end
1210 1210
        end
1211 1211
    end
1212
    
1213
    
1212

  
1213

  
1214 1214
    ALLOWED_TAGS = %w(redpre pre code kbd notextile)
1215 1215
    def escape_html_tags(text)
1216 1216
      text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "&lt;#{$1}#{'&gt;' unless $3.blank?}" }
test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb
280 280
This is a table with trailing whitespace in one row:
281 281

  
282 282
|cell11|cell12|
283
|cell21|cell22| 
283
|cell21|cell22|
284 284
|cell31|cell32|
285 285
RAW
286 286

  
......
382 382
    expected = '<p><img src="/images/comment.png&quot;onclick=&amp;#x61;&amp;#x6c;&amp;#x65;&amp;#x72;&amp;#x74;&amp;#x28;&amp;#x27;&amp;#x58;&amp;#x53;&amp;#x53;&amp;#x27;&amp;#x29;;&amp;#x22;" alt="" /></p>'
383 383
    assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '')
384 384
  end
385
  
386
  
385

  
386

  
387 387
  STR_WITHOUT_PRE = [
388 388
  # 0
389 389
"h1. Title
......
413 413
Ut rhoncus elementum adipiscing."]
414 414

  
415 415
  TEXT_WITHOUT_PRE = STR_WITHOUT_PRE.join("\n\n").freeze
416
  
416

  
417 417
  def test_get_section_should_return_the_requested_section_and_its_hash
418 418
    assert_section_with_hash STR_WITHOUT_PRE[1], TEXT_WITHOUT_PRE, 2
419 419
    assert_section_with_hash STR_WITHOUT_PRE[2..3].join("\n\n"), TEXT_WITHOUT_PRE, 3
420 420
    assert_section_with_hash STR_WITHOUT_PRE[3], TEXT_WITHOUT_PRE, 5
421 421
    assert_section_with_hash STR_WITHOUT_PRE[4], TEXT_WITHOUT_PRE, 6
422
    
422

  
423 423
    assert_section_with_hash '', TEXT_WITHOUT_PRE, 0
424 424
    assert_section_with_hash '', TEXT_WITHOUT_PRE, 10
425 425
  end
426
  
426

  
427 427
  def test_update_section_should_update_the_requested_section
428 428
    replacement = "New text"
429
    
429

  
430 430
    assert_equal [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(2, replacement)
431 431
    assert_equal [STR_WITHOUT_PRE[0..1], replacement, STR_WITHOUT_PRE[4]].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(3, replacement)
432 432
    assert_equal [STR_WITHOUT_PRE[0..2], replacement, STR_WITHOUT_PRE[4]].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(5, replacement)
433 433
    assert_equal [STR_WITHOUT_PRE[0..3], replacement].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(6, replacement)
434
    
434

  
435 435
    assert_equal TEXT_WITHOUT_PRE, @formatter.new(TEXT_WITHOUT_PRE).update_section(0, replacement)
436 436
    assert_equal TEXT_WITHOUT_PRE, @formatter.new(TEXT_WITHOUT_PRE).update_section(10, replacement)
437 437
  end
438
  
438

  
439 439
  def test_update_section_with_hash_should_update_the_requested_section
440 440
    replacement = "New text"
441
    
441

  
442 442
    assert_equal [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].flatten.join("\n\n"),
443 443
      @formatter.new(TEXT_WITHOUT_PRE).update_section(2, replacement, Digest::MD5.hexdigest(STR_WITHOUT_PRE[1]))
444 444
  end
445
  
445

  
446 446
  def test_update_section_with_wrong_hash_should_raise_an_error
447 447
    assert_raise Redmine::WikiFormatting::StaleSectionError do
448 448
      @formatter.new(TEXT_WITHOUT_PRE).update_section(2, "New text", Digest::MD5.hexdigest("Old text"))
......
493 493
  def test_update_section_should_not_escape_pre_content_outside_section
494 494
    text = STR_WITH_PRE.join("\n\n")
495 495
    replacement = "New text"
496
    
496

  
497 497
    assert_equal [STR_WITH_PRE[0..1], "New text"].flatten.join("\n\n"),
498 498
      @formatter.new(text).update_section(3, replacement)
499 499
  end
......
508 508
h1. Heading 2
509 509

  
510 510
Content 2
511
 
511

  
512 512
h1. Heading 3
513 513

  
514 514
Content 3
515 515

  
516 516
h1. Heading 4
517
 
517

  
518 518
Content 4
519 519
STR
520 520

  
......
632 632
  def to_html(text)
633 633
    @formatter.new(text).to_html
634 634
  end
635
  
635

  
636 636
  def assert_section_with_hash(expected, text, index)
637 637
    result = @formatter.new(text).get_section(index)
638
    
638

  
639 639
    assert_kind_of Array, result
640 640
    assert_equal 2, result.size
641 641
    assert_equal expected, result.first, "section content did not match"
(2-2/3)