breakout_parser 0.0.23 → 0.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,13 @@
1
1
  #ifdef RUBY_VERSION
2
2
 
3
3
  #include "ruby.h"
4
+ #include "ruby_ext.h"
5
+
6
+ #ifdef RUBY_19
7
+ #include "ruby/st.h"
8
+ #else
9
+ #include "st.h"
10
+ #endif
4
11
 
5
12
  void Init_breakout_parser();
6
13
  VALUE method_parse(int, VALUE*, VALUE);
@@ -20,55 +27,78 @@ extern const char *space_name;
20
27
  extern size_t in_buf_len, bufsize, space_name_len;
21
28
 
22
29
  extern const char *site_url;
30
+ extern const char *large_files_url;
23
31
  extern size_t site_url_len;
32
+ extern size_t large_files_url_len;
33
+
34
+ extern VALUE meta_attributes;
24
35
 
25
36
  VALUE vcs_url;
26
37
 
38
+ char **temp_names, **temp_values;
39
+
27
40
  extern int parse_links_only, absolute_urls;
28
41
 
29
42
  VALUE do_parse(int argc, VALUE *argv, VALUE self) {
30
43
  VALUE s, text, r_space_name;
31
44
  char *p;
32
45
 
33
- if( argc < 2 || argc > 5 ){
34
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..5)", argc);
35
- return rb_str_new("",0); // unreachable code, but for double safety
46
+ if (argc < 2 || argc > 7) {
47
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..7)", argc);
36
48
  }
37
49
 
38
50
  text = argv[0];
39
51
  r_space_name = argv[1];
40
52
 
41
53
  site_url = NULL; site_url_len = 0;
42
- if( argc > 2 && argv[2] != Qnil && argv[2] != Qfalse ){
54
+ if (argc > 2 && RTEST(argv[2])){
43
55
  site_url = StringValueCStr(argv[2]);
44
56
  site_url_len = site_url ? strlen(site_url) : 0;
45
57
  while( site_url && site_url_len > 0 && site_url[site_url_len-1] == '/' ) {
46
58
  // skip trailing slashes
47
- site_url_len--;
59
+ site_url_len--;
48
60
  }
49
61
  }
50
62
 
51
- vcs_url = NULL;
52
- if( argc > 3 && argv[3] != Qnil && argv[3] != Qfalse ){
63
+ vcs_url = rb_str_new2("");
64
+ if (argc > 3 && RTEST(argv[3])) {
53
65
  vcs_url = argv[3];
54
66
  }
55
67
 
56
68
  absolute_urls = 0;
57
- if( argc > 4 && argv[4] != Qnil && argv[4] != Qfalse ){
69
+ if (argc > 4 && RTEST(argv[4])) {
58
70
  absolute_urls = 1;
59
71
  }
60
72
 
61
- if(!text || text == Qnil || text == Qfalse){
62
- // NULL input string
63
- return rb_str_new("",0);
73
+ large_files_url = NULL; large_files_url_len = 0;
74
+ if (argc > 5 && RTEST(argv[5])) {
75
+ large_files_url = StringValueCStr(argv[5]);
76
+ large_files_url_len = large_files_url ? strlen(large_files_url) : 0;
64
77
  }
65
78
 
66
- p = RSTRING(text)->ptr;
67
- in_buf_len = RSTRING(text)->len;
79
+ meta_attributes = rb_hash_new();
80
+ if (argc > 6 && RTEST(argv[6])) {
81
+ // More information about object types may be found in ruby.h
82
+ if (TYPE(argv[6]) != T_HASH) {
83
+ rb_raise(rb_eTypeError, "wrong type of meta attributes values; expected Hash, given %d", TYPE(argv[6]));
84
+ }
85
+
86
+ if (RHASH_SIZE(argv[6]) > 0) {
87
+ meta_attributes = argv[6];
88
+ }
89
+ }
90
+
91
+ if(!text || !(RTEST(text))){
92
+ // empty input string
93
+ return rb_str_new2("");
94
+ }
95
+
96
+ p = RSTRING_PTR(text);
97
+ in_buf_len = RSTRING_LEN(text);
68
98
 
69
99
  if(!p || in_buf_len <= 0){
70
100
  // empty input string
71
- return rb_str_new("",0);
101
+ return rb_str_new2("");
72
102
  }
73
103
 
74
104
  while( in_buf_len > 0 && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')){
@@ -84,25 +114,24 @@ VALUE do_parse(int argc, VALUE *argv, VALUE self) {
84
114
  bufsize = 1 + in_buf_len + in_buf_len/3; // reserve 30% of in_buf size
85
115
  if(bufsize<0x100) bufsize = 0x100;
86
116
 
87
- buf = ALLOC_N(char, bufsize);
117
+ buf = ALLOC_N(char, bufsize);
88
118
  bufptr = buf;
89
119
 
90
- // protect buf from GC (theoretically)
91
- rb_iv_set(self,"@obj",Data_Wrap_Struct(rb_cData,NULL,NULL,buf));
92
-
93
120
  yyparse();
94
121
  yylex_destroy();
95
- // printf("[.] yyparse() ended\n");
122
+ // printf("[.] yyparse() ended\n");
96
123
 
97
124
  // make ruby string from our char[] data
98
- s = rb_str_new(buf,bufptr-buf);
125
+ s = rb_str_new(buf, bufptr-buf);
99
126
 
100
- // cleanup
101
- rb_iv_set(self,"@obj",Qnil);
102
127
  xfree(buf);
103
128
  buf = bufptr = NULL;
104
129
  bufsize = 0;
105
130
 
131
+ #ifdef RUBY_19
132
+ s = rb_funcall(s, rb_intern("force_encoding"), 1, rb_str_new2("UTF-8")); // encode string to UTF-8
133
+ #endif
134
+
106
135
  return s;
107
136
  }
108
137
 
@@ -0,0 +1,2 @@
1
+ void yyparse();
2
+ void yylex_destroy();
@@ -0,0 +1,916 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require File.dirname(__FILE__) + '/obj_proxy'
4
+
5
+ describe 'BreakoutParser' do
6
+ def self.hex_string s
7
+ ## sexier, but not runs on ruby 1.8.6 patchlevel 383 i386-mingw32:
8
+ #s.each_byte.to_a.map{ |c| "%02x" % c }.join
9
+ r = ''
10
+ s.each_byte{ |c| r << "%02x" % c }
11
+ r
12
+ end
13
+ def hex_string s; self.class.hex_string(s); end
14
+
15
+ it 'accepts from 2 to 7 arguments' do
16
+ expect { BreakoutParser.parse }.to raise_error(ArgumentError, "wrong number of arguments (0 for 2..7)")
17
+ expect { BreakoutParser.parse('a') }.to raise_error(ArgumentError, "wrong number of arguments (1 for 2..7)")
18
+ [9, 10].each do |argc|
19
+ expect { BreakoutParser.parse(*(['a'] * (argc - 1) + [{}])) }.to raise_error(ArgumentError, "wrong number of arguments (#{argc} for 2..7)")
20
+ end
21
+ (2..6).each do |argc|
22
+ expect { BreakoutParser.parse(*(['a'] * argc)) }.to_not raise_error(ArgumentError)
23
+ end
24
+ expect { BreakoutParser.parse(*(['a'] * 6 + [{}])) }.to_not raise_error(ArgumentError)
25
+ end
26
+
27
+ it 'converts \n to <br />' do
28
+ parse("aaa\nbbb").should match(%r"aaa ?<br /> ?bbb")
29
+ end
30
+
31
+ it "parses 1M file #1" do
32
+ s = 'a' * 1024 * 1024
33
+ parse(s).size.should == s.size
34
+ end
35
+
36
+ it "parses 1M file #2" do
37
+ s = 'a' + (' ' * 1024 * 1024) + 'b'
38
+ parse(s).should == 'a b'
39
+ end
40
+
41
+ it "parses 1M file #3" do
42
+ s = 'a ' * 1024 * 512
43
+ parse(s).size.should == s.strip.size
44
+ end
45
+
46
+ it "handles nil & false text well" do
47
+ parse(false).should == ""
48
+ parse(false, :space_name => false).should == ""
49
+ parse("", :space_name => false).should == ""
50
+ parse(nil).should == ""
51
+ parse(nil, :space_name => nil).should == ""
52
+ parse("", :space_name => nil).should == ""
53
+ end
54
+
55
+ it "handles nil space_name well" do
56
+ lambda{
57
+ parse("#123", :space_name => nil)
58
+ }.should raise_error(TypeError)
59
+ end
60
+
61
+ it "handles false space_name well" do
62
+ lambda{
63
+ parse("#123", :space_name => false)
64
+ }.should raise_error(TypeError)
65
+ end
66
+
67
+ it "strips tailing spaces and newlines" do
68
+ parse("aaa ").should == "aaa"
69
+ parse("aaa\t\t\t\t\t\t").should == "aaa"
70
+ parse("aaa\r\r\r\r\r").should == "aaa"
71
+ parse("aaa\n\n\n\n\n").should == "aaa"
72
+ parse("aaa\r\n\r\n\r\n\r\n").should == "aaa"
73
+ parse("aaa\r\n\t \t \n \r \n \t \t\n\r ").should == "aaa"
74
+ end
75
+
76
+ it "strips leading spaces and newlines" do
77
+ parse(" aaa").should == "aaa"
78
+ parse("\t\t\t\t\t\taaa").should == "aaa"
79
+ parse("\r\r\r\r\raaa").should == "aaa"
80
+ parse("\n\n\n\n\naaa").should == "aaa"
81
+ parse("\r\n\r\n\r\n\r\naaa").should == "aaa"
82
+ parse("\r\n\t \t \n \r \n \t \t\n\r aaa").should == "aaa"
83
+ end
84
+
85
+ it "converts each newline to <br />" do
86
+ parse("aaa\n\nbbb").should == "aaa<br /><br />bbb"
87
+ parse("aaa\n \nbbb").should == "aaa<br /><br />bbb"
88
+ parse("aaa\n\n\nbbb").should == "aaa<br /><br /><br />bbb"
89
+ parse("aaa\n \n \nbbb").should == "aaa<br /><br /><br />bbb"
90
+ parse("aaa\r\n \r\n \r\nbbb").should == "aaa<br /><br /><br />bbb"
91
+ parse("aaa\n \n\n \nbbb").should == "aaa<br /><br /><br /><br />bbb"
92
+ parse("aaa\n \n\n\n \nbbb").should == "aaa" + "<br />"*5 + "bbb"
93
+ parse("aaa\n\n\n\n\n\n\nbbb").should == "aaa" + "<br />"*7 + "bbb"
94
+ parse("aaa\r\n\r\n\r\nbbb").should == "aaa" + "<br />"*3 + "bbb"
95
+ end
96
+
97
+ ###############################################################################
98
+
99
+ describe "@code@" do
100
+ it "only" do
101
+ parse("@smth@").should == '@smth@'
102
+ end
103
+ it "at beginning" do
104
+ parse("@smth@\nxxx").should == '@smth@<br />xxx'
105
+ end
106
+ it "in the middle of text" do
107
+ parse("xxx @smth@ yyy").should == 'xxx @smth@ yyy'
108
+ end
109
+ it "parses @multiline\\nsmth@" do
110
+ parse("@multiline\nsmth@").should == "@multiline<br />smth@"
111
+ end
112
+ it "not confuses" do
113
+ parse("look at @this code@ and mail me at xxx@yyy.com").should ==
114
+ 'look at @this code@ and mail me at <a href="mailto:xxx@yyy.com">xxx@yyy.com</a>'
115
+ end
116
+ it "w/o closing tag" do
117
+ parse("@smth").should == '@smth'
118
+ end
119
+ it "nesting1 w/o closing tags" do
120
+ parse("@smth1 @smth2").should == '@smth1 @smth2'
121
+ end
122
+ it "nesting2 w/o closing tags" do
123
+ parse("@smth1 @smth2").should == '@smth1 @smth2'
124
+ end
125
+ it "two times" do
126
+ parse("@code1@ @code2@").should == "@code1@ @code2@"
127
+ parse("@code1@ @code2@").should == "@code1@ @code2@"
128
+ parse(" @code1@ @code2@ ").should == "@code1@ @code2@"
129
+ parse(" @code1@ xxx @code2@ ").should == "@code1@ xxx @code2@"
130
+ end
131
+ end
132
+
133
+ ###############################################################################
134
+
135
+ describe "*bold*" do
136
+ it "only" do
137
+ parse("*bold*").should == '*bold*'
138
+ end
139
+ it "at beginning" do
140
+ parse("*bold*\nxxx").should == "*bold*<br />xxx"
141
+ end
142
+ it "in the middle of text" do
143
+ parse("xxx *bold* yyy").should == "xxx *bold* yyy"
144
+ end
145
+ it "parses *multiline\\nbold*" do
146
+ parse("*multiline\nbold*").should == "*multiline<br />bold*"
147
+ end
148
+ it "skips lone star inside bold block" do
149
+ parse("*aaa * bbb*").should == "*aaa * bbb*"
150
+ end
151
+ it "skips lone star" do
152
+ parse("aaa * bbb").should == 'aaa * bbb'
153
+ end
154
+ it "w/o closing tag" do
155
+ parse("*bold").should == '*bold'
156
+ end
157
+ it "nesting1 w/o closing tags" do
158
+ parse("*bold1 *bold2").should == "*bold1 *bold2"
159
+ end
160
+ it "nesting2 w/o closing tags" do
161
+ parse("*bold1 *bold2").should == "*bold1 *bold2"
162
+ end
163
+
164
+ it "not parses '*.*'" do
165
+ parse("*.*").should == "*.*"
166
+ parse(" *.* ").should == "*.*"
167
+ parse("aaa *.* bbb").should == "aaa *.* bbb"
168
+ end
169
+
170
+ it "not parses '*.something'" do
171
+ parse("*.exe").should == "*.exe"
172
+ parse(" *.exe ").should == "*.exe"
173
+ parse("aaa *.exe bbb").should == "aaa *.exe bbb"
174
+ end
175
+
176
+ end
177
+
178
+ ###############################################################################
179
+
180
+ describe "_italic_" do
181
+ it "only" do
182
+ s = "_italic_"
183
+ parse(s).should == s
184
+ end
185
+ it "at beginning" do
186
+ s = "_italic_\nxxx"
187
+ parse(s).should == s.gsub("\n","<br />")
188
+ end
189
+ it "in the middle of text" do
190
+ s = "xxx _italic_ yyy"
191
+ parse(s).should == s
192
+ end
193
+ it "parses _multiline\\nitalic_" do
194
+ s = "_multiline\nitalic_"
195
+ parse(s).should == s.gsub("\n","<br />")
196
+ end
197
+ it "skips lone underscore inside italic block" do
198
+ s = "_aaa _ bbb_"
199
+ parse(s).should == s
200
+ end
201
+ it "skips lone underscore" do
202
+ s = "aaa _ bbb"
203
+ parse(s).should == s
204
+ end
205
+ it "w/o closing tag" do
206
+ s = "_italic"
207
+ parse(s).should == s
208
+ end
209
+ it "nesting1 w/o closing tags" do
210
+ s = "_italic1 _italic2"
211
+ parse(s).should == s
212
+ end
213
+ it "nesting2 w/o closing tags" do
214
+ s = "_italic1 _italic2"
215
+ parse(s).should == s.gsub(/ +/,' ')
216
+ end
217
+ end
218
+
219
+ ###############################################################################
220
+
221
+ describe "combinations" do
222
+ it "bold in italic" do
223
+ s = "_aaa *bbb* ccc_"
224
+ parse(s).should == s
225
+ end
226
+ it "bold in italic - no closing1" do
227
+ s = "_aaa *bbb* ccc"
228
+ parse(s).should == s
229
+ end
230
+ it "bold in italic - no closing2" do
231
+ s = "_aaa *bbb ccc"
232
+ parse(s).should == s
233
+ end
234
+
235
+ it "italic in bold" do
236
+ s = "*aaa _bbb_ ccc*"
237
+ parse(s).should == s
238
+ end
239
+ it "italic in bold - no closing1" do
240
+ s = "*aaa _bbb_ ccc"
241
+ parse(s).should == s
242
+ end
243
+ it "italic in bold - no closing2" do
244
+ s = "*aaa _bbb ccc"
245
+ parse(s).should == s
246
+ end
247
+
248
+ {'ul' => '*', 'ol' => '#'}.each do |l,c|
249
+ it "raw text link inside #{l.upcase}> #1" do
250
+ s = "#{c} aaa http://www.ru"
251
+ parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a>"
252
+ end
253
+ it "raw text link inside #{l.upcase}> #2" do
254
+ s = "#{c} aaa http://www.ru\n#{c} bbb"
255
+ parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a><br />#{c} bbb"
256
+ end
257
+ it "raw text link inside #{l.upcase}> #3" do
258
+ s = "#{c} http://www.ru"
259
+ parse(s).should == "#{c} <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a>"
260
+ end
261
+ it "raw text link inside #{l.upcase}> #4" do
262
+ s = "#{c} aaa http://www.ru bbb"
263
+ parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> bbb"
264
+ end
265
+ it "two links inside #{l.upcase}>" do
266
+ s = "#{c} aaa http://www.ru http://ya.ru bbb"
267
+ parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> <a rel=\"nofollow\" href=\"http://ya.ru\">http://ya.ru</a> bbb"
268
+ end
269
+ end
270
+ end
271
+
272
+ ###############################################################################
273
+
274
+ describe "IGNORES unnumbered lists" do
275
+ it "should ignore" do
276
+ parse("* a\n* b\n* c").should == "* a<br />* b<br />* c"
277
+ end
278
+ it "two lists" do
279
+ s = "* a\n* b\n* c"
280
+ s = s + "\nxxx\n" + s
281
+ parse(s).should == "* a<br />* b<br />* c<br />xxx<br />* a<br />* b<br />* c"
282
+ end
283
+ it "in middle of text when begins with space" do
284
+ parse("hello\n * a\n * b\n * c\nworld").should ==
285
+ "hello<br />* a<br />* b<br />* c<br />world"
286
+ end
287
+ it "in middle of text" do
288
+ parse("hello\n* a\n* b\n* c\nworld").should ==
289
+ "hello<br />* a<br />* b<br />* c<br />world"
290
+ end
291
+ it "after blank line" do
292
+ parse("hello\n\n * a\n * b\n * c\nworld").should ==
293
+ "hello<br /><br />* a<br />* b<br />* c<br />world"
294
+ end
295
+ end
296
+
297
+ ###############################################################################
298
+
299
+ describe "IGNORES numbered lists" do
300
+ it "should ignore" do
301
+ parse("# a\n# b\n# c").should == "# a<br /># b<br /># c"
302
+ end
303
+ it "two lists" do
304
+ s = "# a\n# b\n# c"
305
+ s = s + "\nxxx\n" + s
306
+ parse(s).should == h(s).gsub("\n","<br />")
307
+ end
308
+ it "in middle of text when begins with space" do
309
+ parse("hello\n # a\n # b\n # c\nworld").should ==
310
+ "hello<br /># a<br /># b<br /># c<br />world"
311
+ end
312
+ it "in middle of text" do
313
+ parse("hello\n# a\n# b\n# c\nworld").should ==
314
+ "hello<br /># a<br /># b<br /># c<br />world"
315
+ end
316
+ it "after blank line" do
317
+ parse("hello\n\n # a\n # b\n # c\nworld").should ==
318
+ "hello<br /><br /># a<br /># b<br /># c<br />world"
319
+ end
320
+ end
321
+
322
+ ###############################################################################
323
+
324
+ 1.upto(5) do |lvl|
325
+ describe "H#{lvl}" do
326
+ it "at the beginning" do
327
+ s = "h#{lvl}. xxx"
328
+ parse(s).should == h(s)
329
+ end
330
+ it "after 1 line of text" do
331
+ s = "abcd\nh#{lvl}. xxx"
332
+ parse(s).should == h(s).gsub("\n","<br />")
333
+ end
334
+ it "after 2 lines of text" do
335
+ s = "abcd\ndefgh\nh#{lvl}. xxx"
336
+ parse(s).should == h(s).gsub("\n","<br />")
337
+ end
338
+ it "in middle of other words" do
339
+ s = "abcd defgh h#{lvl}. xxx yyy"
340
+ parse(s).should == h(s).gsub("\n","<br />")
341
+ end
342
+ it "in middle of other lines" do
343
+ s = "abcd defgh\nh#{lvl}. xxx\nyyy"
344
+ parse(s).should == h(s).gsub("\n","<br />")
345
+ end
346
+
347
+ it "does nothing special on spaces in id" do
348
+ s = "h#{lvl}. xxx yyy z"
349
+ parse(s).should == h(s).gsub(/ +/,' ')
350
+ end
351
+ it "does nothing special on underscores in id" do
352
+ s = "h#{lvl}. xxx___yyy_z"
353
+ parse(s).should == h(s)
354
+ end
355
+ it "does nothing special on dashes in id" do
356
+ s = "h#{lvl}. xxx---yyy-z"
357
+ parse(s).should == h(s)
358
+ end
359
+ it "does nothing special on dots in id" do
360
+ s = "h#{lvl}. xxx...yyy.z"
361
+ parse(s).should == h(s)
362
+ end
363
+
364
+ %w'Ъ ъ : ; , привет" \' ! < >'.each do |c|
365
+ it "does nothing special on \"#{c}\"" do
366
+ s = "h#{lvl}. xxx#{c}yyy"
367
+ parse(s).should == h(s)
368
+ end
369
+ end
370
+ end
371
+ end
372
+
373
+ ###############################################################################
374
+
375
+ describe "raw text links" do
376
+ describe "starting with 'http://'" do
377
+ it "at the beginning" do
378
+ parse("http://asd.ru").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>"
379
+ end
380
+ it "in middle of other words" do
381
+ parse("aaa bbb ccc http://asd.ru ddd eee fff").should ==
382
+ "aaa bbb ccc <a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a> ddd eee fff"
383
+ end
384
+ it "in new line" do
385
+ parse("aaa bbb ccc\nhttp://asd.ru\nddd eee fff").should match(
386
+ %r"aaa bbb ccc ?<br /> ?<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a> ?<br /> ?ddd eee fff"
387
+ )
388
+ end
389
+ it "escapes '&' in link _text_" do
390
+ parse("http://asd.ru/?a=1&b=2").should == "<a rel=\"nofollow\" href=\"http://asd.ru/?a=1&b=2\">http://asd.ru/?a=1&amp;b=2</a>"
391
+ end
392
+
393
+ it "parses https://" do
394
+ parse("https://asd.ru").should == "<a rel=\"nofollow\" href=\"https://asd.ru\">https://asd.ru</a>"
395
+ end
396
+
397
+ %w', .'.each do |c|
398
+ it "stops parsing on \"#{c} \"" do
399
+ parse("http://asd.ru#{c}").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c}"
400
+ parse(" http://asd.ru#{c} ").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c}"
401
+ parse(" http://asd.ru#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c} hello!"
402
+ parse("xxx http://asd.ru#{c} hello!").should == "xxx <a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c} hello!"
403
+ parse(" http://asd.ru/#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://asd.ru/\">http://asd.ru/</a>#{c} hello!"
404
+ parse(" http://aaa.com#{c} http://bbb.com").should ==
405
+ "<a rel=\"nofollow\" href=\"http://aaa.com\">http://aaa.com</a>#{c} <a rel=\"nofollow\" href=\"http://bbb.com\">http://bbb.com</a>"
406
+ end
407
+ end
408
+ end
409
+
410
+ describe "starting with 'www.'" do
411
+ it "at the beginning" do
412
+ parse("www.ru").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>"
413
+ end
414
+ it "in middle of other words" do
415
+ parse("aaa bbb ccc www.ru ddd eee fff").should ==
416
+ "aaa bbb ccc <a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a> ddd eee fff"
417
+ end
418
+ it "in new line" do
419
+ parse("aaa bbb ccc\nwww.ru\nddd eee fff").should match(
420
+ %r"aaa bbb ccc ?<br /> ?<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a> ?<br /> ?ddd eee fff"
421
+ )
422
+ end
423
+ it "escapes '&' in link _text_" do
424
+ parse("www.ru/?a=1&b=2").should == "<a rel=\"nofollow\" href=\"http://www.ru/?a=1&b=2\">www.ru/?a=1&amp;b=2</a>"
425
+ end
426
+
427
+ %w', .'.each do |c|
428
+ it "stops parsing on \"#{c} \"" do
429
+ parse("www.ru#{c}").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c}"
430
+ parse(" www.ru#{c} ").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c}"
431
+ parse(" www.ru#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c} hello!"
432
+ parse("xxx www.ru#{c} hello!").should == "xxx <a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c} hello!"
433
+ parse(" www.ru/#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://www.ru/\">www.ru/</a>#{c} hello!"
434
+ parse(" www.aaa.com#{c} www.bbb.com").should ==
435
+ "<a rel=\"nofollow\" href=\"http://www.aaa.com\">www.aaa.com</a>#{c} <a rel=\"nofollow\" href=\"http://www.bbb.com\">www.bbb.com</a>"
436
+ end
437
+ end
438
+ end
439
+
440
+ describe 'e-mails' do
441
+ it "at the beginning" do
442
+ parse("aaa@bbb.com").should == "<a href=\"mailto:aaa@bbb.com\">aaa@bbb.com</a>"
443
+ end
444
+ it "in middle of other words" do
445
+ parse("aaa bbb ccc xx@yy.cn ddd eee fff").should ==
446
+ "aaa bbb ccc <a href=\"mailto:xx@yy.cn\">xx@yy.cn</a> ddd eee fff"
447
+ end
448
+ it "in new line" do
449
+ parse("aaa bbb ccc\naa.bb@cc.dd.ee\nddd eee fff").should match(
450
+ %r"aaa bbb ccc ?<br /> ?<a href=\"mailto:aa.bb@cc.dd.ee\">aa.bb@cc.dd.ee</a> ?<br /> ?ddd eee fff"
451
+ )
452
+ end
453
+
454
+ %w', .'.each do |c|
455
+ it "stops parsing on \"#{c} \"" do
456
+ parse("a-b@c-d.efghjikl#{c}").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c}"
457
+ parse(" a-b@c-d.efghjikl#{c} ").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c}"
458
+ parse(" a-b@c-d.efghjikl#{c} hello!").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c} hello!"
459
+ parse("xxx a-b@c-d.efghjikl#{c} hello!").should == "xxx <a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c} hello!"
460
+ parse(" a-b@c-d.efghjikl#{c} hello!").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c} hello!"
461
+ parse(" www@aaa.com#{c} www@bbb.com").should ==
462
+ "<a href=\"mailto:www@aaa.com\">www@aaa.com</a>#{c} <a href=\"mailto:www@bbb.com\">www@bbb.com</a>"
463
+ end
464
+ end
465
+
466
+ it "not parses bad emails" do
467
+ s="a@b.c a@b a.b@c a.b@@c a@b@c.d a#b@c.d"
468
+ parse(s).should == s
469
+ end
470
+ end
471
+ end
472
+
473
+ ###############################################################################
474
+
475
+ describe "#ticketNum ticket links" do
476
+ it "at the beginning" do
477
+ parse("#1234").should == '<a href="/spaces/test_space/tickets/1234">#1234</a>'
478
+ end
479
+ it "in middle of other words" do
480
+ parse("aaa bbb ccc #3476 ddd eee fff").should ==
481
+ 'aaa bbb ccc <a href="/spaces/test_space/tickets/3476">#3476</a> ddd eee fff'
482
+ end
483
+ it "in new line" do
484
+ parse("aaa bbb ccc\n#1234\nddd eee fff").should match(
485
+ %r|aaa bbb ccc ?<br /> ?<a href="/spaces/test_space/tickets/1234">#1234</a> ?<br /> ?ddd eee fff|
486
+ )
487
+ end
488
+ it "ignores non-digits" do
489
+ parse("#1234d").should == '#1234d'
490
+ parse("#xxx").should == '#xxx'
491
+ end
492
+
493
+ ".,;!?:-".each_char do |c|
494
+ it "uses '#{c}' as separator" do
495
+ l = '<a href="/spaces/test_space/tickets/1234">#1234</a>'
496
+ t = "L#{c}L"
497
+ parse(t.gsub('L','#1234')).should == t.gsub('L',l)
498
+ t = "L#{c}#{c}L"
499
+ parse(t.gsub('L','#1234')).should == t.gsub('L',l)
500
+ t = "#{c}L#{c}L#{c}"
501
+ parse(t.gsub('L','#1234')).should == t.gsub('L',l)
502
+ end
503
+ end
504
+ end
505
+
506
+ ###############################################################################
507
+
508
+ [
509
+ %w'<pre><code> </code></pre>',
510
+ %w'<pre> </pre>',
511
+ %w'<notextile> </notextile>'
512
+ ].each do |ot,ct|
513
+ # ot - opening tag
514
+ # ct - closing tag
515
+
516
+ # if ot == '<notextile>'
517
+ # ote,cte = '',''
518
+ # else
519
+ ote,cte = ot,ct
520
+ # end
521
+
522
+ describe "#{ot}..#{ct}" do
523
+ it "works" do
524
+ s = <<-EOF
525
+ for ( n = 0; n < max_size && \
526
+ (c = getc( yyin )) != EOF && c != '\\n'; ++n ) \
527
+ buf[n] = (char) c; \
528
+
529
+ EOF
530
+
531
+ parse("#{ot}#{s.strip}#{ct}").should ==
532
+ h("#{ot}#{s.strip}#{ct}").gsub(/[ \t]+/,' ').gsub("\n","<br />")
533
+
534
+ s = <<-EOF
535
+ while ( 1 < 2 ) do
536
+ puts "<b>12345\\t54321</b>"
537
+ // *bold* comment
538
+ // _italic_ comment
539
+ end
540
+ ---
541
+ * aaa
542
+ * bbb
543
+ * ccc
544
+
545
+ EOF
546
+ parse("#{ot}#{s.strip}#{ct}").should ==
547
+ h("#{ote}#{s.strip}#{cte}").gsub(/[ \t]+/,' ').gsub(/\n */,"<br />")
548
+ end
549
+ it "not parses *bold*" do
550
+ s = "#{ot} *bold*#{ct}"
551
+ parse(s).should == h(s)
552
+ end
553
+ it "not parses _italic_" do
554
+ s = "#{ot} _italic_#{ct}"
555
+ parse(s).should == h(s)
556
+ end
557
+ it "not parses UL lists" do
558
+ s = "#{ot}\n * l1\n * l2\n * l3#{ct}"
559
+ parse(s).should == h(s).gsub("\n ","<br />")
560
+ end
561
+ it "not parses OL lists" do
562
+ s = "#{ot}\n # l1\n # l2\n # l3#{ct}"
563
+ parse(s).should == h(s).gsub("\n ","<br />")
564
+ end
565
+ it "not parses H1..H5" do
566
+ 1.upto(5) do |i|
567
+ s = "#{ot}\nh#{i}. zzzzzzz\n#{ct}"
568
+ parse(s).should == h(s).gsub("\n","<br />")
569
+ end
570
+ end
571
+ it "parses raw text links" do
572
+ s = "#{ot}xxx http://www.ru yyy#{ct}"
573
+ parse(s).should == "#{h(ote)}xxx <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> yyy#{h(cte)}"
574
+ s = "#{ot}http://www.ru#{ct}"
575
+ parse(s).should == "#{h(ote)}<a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a>#{h(cte)}"
576
+ end
577
+ it "keeps newlines" do
578
+ s = "#{ot}aaa\nbbb#{ct}"
579
+ parse(s).should == h(s).gsub("\n","<br />")
580
+ s = "#{ot}aaa\n\nbbb\nccc#{ct}"
581
+ parse(s).should == h(s).gsub("\n","<br />")
582
+ end
583
+
584
+ it "w/o closing tags" do
585
+ s = "#{ot}aaa"
586
+ parse(s).should == h(s)
587
+ end
588
+
589
+ it "in middle of text" do
590
+ s = "xxx #{ot}yyyy#{ct} jjj"
591
+ parse(s).should == h(s)
592
+ end
593
+
594
+ it "with 2 instances" do
595
+ s = "xxx #{ot}yyyy#{ct} <jjj> #{ot}asdkjaslkd#{ct} END"
596
+ parse(s).should == h(s)
597
+ end
598
+
599
+ it "works with unicode" do
600
+ s = "привет #{ot} жжж #{ct} пока!"
601
+ parse(s).should == h(s)
602
+
603
+ s = "#{ot}абвгдеёжзийклмнопрстуфхцчшщьыъэюя#{ct}"
604
+ parse(s).should == h(s)
605
+
606
+ s = "#{ot}АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ#{ct}"
607
+ parse(s).should == h(s)
608
+
609
+ s = "#{ot}☸☹☺☻☼☽☾☿#{ct}"
610
+ parse(s).should == h(s)
611
+ end
612
+
613
+ it "should escape lone closing tags" do
614
+ s = "#{ct}"
615
+ parse(s).should == h(s)
616
+ end
617
+
618
+ it "should skip newlines and spaces at end" do
619
+ s = "#{ot} aaa bbb ccc \n\n\n \t\n\n\n\r\n\r\n \t #{ct}"
620
+ parse(s).should == "#{h(ote)} aaa bbb ccc<br /><br /><br /><br /><br /><br /><br /><br />#{h(cte)}"
621
+ end
622
+
623
+ it "escapes html chars" do
624
+ HTML_ESCAPE.each do |k,v|
625
+ parse("#{ot}#{k}#{ct}").should == h("#{ote}#{k}#{cte}")
626
+ end
627
+ end
628
+ end
629
+ end
630
+
631
+ describe "NOT PARSES <pre><code>..</code></pre>" do
632
+ it "with no spaces between <pre> and <code>" do
633
+ s = "<pre><code>aaa</code></pre>"
634
+ parse(s).should == h(s).gsub(/ +/,' ')
635
+ end
636
+
637
+ it "with spaces between <pre> and <code>" do
638
+ s = "<pre> <code>aaa</code> </pre>"
639
+ parse(s).should == h(s).gsub(/ +/,' ')
640
+ end
641
+ it "with spaces between <pre> and <code> and inside" do
642
+ s = "<pre> <code> aaa bbb </code> </pre>"
643
+ parse(s).should == h(s).gsub(/ +/,' ')
644
+ end
645
+ end
646
+
647
+ ###############################################################################
648
+
649
+ describe "<code>..</code>" do
650
+ it "keeps <code> tags" do
651
+ s = "<code>aaa</code>"
652
+ parse(s).should == h(s)
653
+ end
654
+ it "strips heading & tailing whitespace" do
655
+ s = "<code> \r\n \t \t\r aaa \r\n\t \t\r </code>"
656
+ parse(s).should == "&lt;code&gt;<br /><br /> aaa<br /><br /> &lt;/code&gt;"
657
+ end
658
+ it "not parses *bold*" do
659
+ s = "<code>aaa *bbb* ccc</code>"
660
+ parse(s).should == h(s)
661
+ end
662
+ it "not parses _italic_" do
663
+ s = "<code>aaa _bbb_ ccc</code>"
664
+ parse(s).should == h(s)
665
+ end
666
+ it "not parses headers" do
667
+ s = "<code>aaa\nh1. bbb\nccc</code>"
668
+ parse(s).should == h(s).gsub("\n","<br />")
669
+ end
670
+ it "not parses <pre>" do
671
+ s = "<code>aaa <pre>bbb</pre> ccc</code>"
672
+ parse(s).should == h(s)
673
+ end
674
+ it "NOT closes unclosed <code>" do
675
+ s = "aaa <code>bbb"
676
+ parse(s).should == h(s)
677
+ end
678
+ it "NOT escapes '&'" do
679
+ s = "<code>aaa & bbb</code>"
680
+ parse(s).should == h(s)
681
+ end
682
+ it "parses links" do
683
+ s = "<code>aaa #1 #2 #3 http://www.ru [[wiki:jjj]] [[url:http://www.ru]] bbb</code>"
684
+ parse(s).should == "&lt;code&gt;aaa <a href=\"/spaces/test_space/tickets/1\">#1</a> <a href=\"/spaces/test_space/tickets/2\">#2</a> <a href=\"/spaces/test_space/tickets/3\">#3</a> <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> <a class=\"wiki_link\" title=\"jjj\" href=\"/spaces/test_space/wiki/jjj\">jjj</a> <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> bbb&lt;/code&gt;"
685
+ end
686
+ it "NOT works" do
687
+ s = "<code>aaa & bbb</code> xxx <code>jjj&hhh</code>"
688
+ parse(s).should == h(s)
689
+ s = "<code> aaa </code>xxx<code> jjj </code>"
690
+ parse(s).should == h(s).gsub(/ +/,' ')
691
+ end
692
+ it "NOT keeps code bold" do
693
+ s = "*aaa <code>bbb</code> ccc*"
694
+ parse(s).should == h(s)
695
+ s = "*<code>aaa</code>*"
696
+ parse(s).should == h(s)
697
+ end
698
+ it "NOT keeps code italic" do
699
+ s = "_aaa <code>bbb</code> ccc_"
700
+ parse(s).should == h(s)
701
+ s = "_<code>aaa</code>_"
702
+ parse(s).should == h(s)
703
+ end
704
+ end
705
+
706
+ ###############################################################################
707
+
708
+ describe "Assembla Links" do
709
+ a = {}
710
+ a["wiki:Name"] = '<a class="wiki_link" title="Name" href="/spaces/test_space/wiki/Name">Name</a>'
711
+ a["Name"] = '<a class="wiki_link" title="Name" href="/spaces/test_space/wiki/Name">Name</a>'
712
+ a["Name#Ref"] = '<a class="wiki_link" title="Name#Ref" href="/spaces/test_space/wiki/Name#h-Ref">Name#Ref</a>'
713
+ a["Name#h-Ref"] = '<a class="wiki_link" title="Name#h-Ref" href="/spaces/test_space/wiki/Name#h-h-Ref">Name#h-Ref</a>'
714
+ a["#Ref"] = '<a href="#h-Ref" title="#Ref" class="wiki_link">#Ref</a>'
715
+ a["#привет"] = %Q|<a href="#h-#{hex_string("привет")}" title="#привет" class="wiki_link">#привет</a>|
716
+ a["#with spc"] = %Q|<a href="#h-with__spc" title="#with spc" class="wiki_link">#with spc</a>|
717
+ a["#with__usc"] = %Q|<a href="#h-with__usc" title="#with__usc" class="wiki_link">#with__usc</a>|
718
+ a["#with--dsh"] = %Q|<a href="#h-with--dsh" title="#with--dsh" class="wiki_link">#with--dsh</a>|
719
+ a["#with!xclm"] = %Q|<a href="#h-#{hex_string("with!xclm")}" title="#with!xclm" class="wiki_link">#with!xclm</a>|
720
+ a["#with&amp"] = %Q|<a href="#h-#{hex_string("with&amp")}" title="#with&amp" class="wiki_link">#with&amp;amp</a>|
721
+
722
+ a["ticket:234"] = '<a href="/spaces/test_space/tickets/234">#234</a>'
723
+ a["revision:1f4bdab77be696efd"] =
724
+ '<a href="/code/test_space/git/changesets/1f4bdab77be696efd">revision:1f4bdab77be696efd</a>'
725
+ a["revision:12345"] =
726
+ '<a href="/code/test_space/subversion/changesets/12345">revision:12345</a>'
727
+ a["revision:567:1f4bdab77be696efd"] =
728
+ '<a href="/code/test_space/git-567/changesets/1f4bdab77be696efd">revision:1f4bdab77be696efd</a>'
729
+ a["revision:3:12345"] =
730
+ '<a href="/code/test_space/subversion-3/changesets/12345">revision:12345</a>'
731
+ a["r:2345"] = '<a href="/code/test_space/subversion/changesets/2345">revision:2345</a>'
732
+ a["r:2345ef"] = '<a href="/code/test_space/git/changesets/2345ef">revision:2345ef</a>'
733
+ a["r:10:2345"] = '<a href="/code/test_space/subversion-10/changesets/2345">revision:2345</a>'
734
+ a["r:1:2345ef"] = '<a href="/code/test_space/git-1/changesets/2345ef">revision:2345ef</a>'
735
+
736
+ a["url:http://www.ru"] = '<a rel="nofollow" href="http://www.ru">http://www.ru</a>'
737
+ a["url:https://www.ru"] = '<a rel="nofollow" href="https://www.ru">https://www.ru</a>'
738
+ a["url:www.ru"] = '<a rel="nofollow" href="http://www.ru">http://www.ru</a>'
739
+ a["url:www.ru/?a=1&b=2"] = '<a rel="nofollow" href="http://www.ru/?a=1&amp;b=2">http://www.ru/?a=1&amp;b=2</a>'
740
+ a["url:ftp://www.ru"] = '<a rel="nofollow" href="ftp://www.ru">ftp://www.ru</a>'
741
+ a["url:/spaces/x2"] = '<a rel="nofollow" href="/spaces/x2">/spaces/x2</a>'
742
+
743
+ a["file:ExistingFile.txt"] =
744
+ '<a href="/spaces/test_space/documents/download/ExistingFile.txt">file:ExistingFile.txt</a>'
745
+ a["file:cVJUz6ejWr35pEab_qKWB8"] =
746
+ '<a href="/spaces/test_space/documents/download/cVJUz6ejWr35pEab_qKWB8">file:cVJUz6ejWr35pEab_qKWB8</a>'
747
+
748
+ a.each do |k,v|
749
+ it "parses [[#{k}]]" do
750
+ parse("[[#{k}]]").should == v
751
+ end
752
+ it "parses [[#{k}|привет тест]]" do
753
+ parse("[[#{k}|привет тест]]").should == v.sub(/>.*</,">привет тест<")
754
+ end
755
+ it "parses [[#{k}|test & here]]" do
756
+ parse("[[#{k}|test & here]]").should == v.sub(/>.*</,">test &amp; here<")
757
+ end
758
+ if v['href="/'] && !k['url:']
759
+ it "parses [[#{k}]] with a site url" do
760
+ site_url = "http://www.ru"
761
+ parse("[[#{k}]]", :site_url => site_url).should ==
762
+ v.gsub('href="/',"href=\"#{site_url}/")
763
+
764
+ # with extraordinary slash
765
+ parse("[[#{k}]]", :site_url => "#{site_url}/").should ==
766
+ v.gsub('href="/',"href=\"#{site_url}/")
767
+
768
+ site_url = "http://127.0.0.1:3000"
769
+ parse("[[#{k}]]", :site_url => site_url).should ==
770
+ v.gsub('href="/',"href=\"#{site_url}/")
771
+
772
+ # with extraordinary slash
773
+ parse("[[#{k}]]", :site_url => "#{site_url}/").should ==
774
+ v.gsub('href="/',"href=\"#{site_url}/")
775
+ end
776
+ end
777
+ if v['/git/']
778
+ it "parses [[#{k}]] with custom git_url (String)" do
779
+ git_url = "http://www.ru/"
780
+ rev = k.split(':').last.tr(']','')
781
+ parse("[[#{k}]]", :git_url => git_url).should ==
782
+ v.sub('/code/test_space/git/changesets/',git_url)
783
+ end
784
+
785
+ it "parses [[#{k}]] with custom git_url (ObjProxy)" do
786
+ rev = k.split(':').last.tr(']','')
787
+ @asdfg = 'http://mmm.us'
788
+ git_url = Breakout::ObjProxy.new do
789
+ @asdfg + '/'
790
+ end
791
+ parse("[[#{k}]]", :git_url => git_url).should ==
792
+ v.sub('/code/test_space/git/changesets/',git_url)
793
+ end
794
+
795
+ it "parses [[#{k}]] with NULL git_url (ObjProxy)" do
796
+ rev = k.split(':').last.tr(']','')
797
+ git_url = Breakout::ObjProxy.new do
798
+ nil
799
+ end
800
+ parse("[[#{k}]]", :git_url => git_url).should == v
801
+ end
802
+
803
+ it "parses [[#{k}]] with FALSE git_url (ObjProxy)" do
804
+ rev = k.split(':').last.tr(']','')
805
+ git_url = Breakout::ObjProxy.new do
806
+ false
807
+ end
808
+ parse("[[#{k}]]", :git_url => git_url).should == v
809
+ end
810
+ end
811
+ end
812
+
813
+ it "should not instantiate ObjProxy's internal object if there are no git or svn links in text" do
814
+ git_url = Breakout::ObjProxy.new do
815
+ raise 'should not be raised'
816
+ end
817
+ lambda {
818
+ parse("no revision tag", :git_url => git_url).should == 'no revision tag'
819
+ }.should_not raise_error
820
+ end
821
+
822
+ describe "absolute_urls" do
823
+ # 'true' values
824
+ [true, 1, 'x'].each do |v|
825
+ it "should NOT convert relative url to absolute when absolute_urls = #{v.inspect} AND site_url is NULL" do
826
+ parse("[[url:/rel]]", :absolute_urls => v).should ==
827
+ '<a rel="nofollow" href="/rel">/rel</a>'
828
+ parse("[[url:/rel|text]]", :absolute_urls => v).should ==
829
+ '<a rel="nofollow" href="/rel">text</a>'
830
+ end
831
+ it "should convert relative url to absolute when absolute_urls = #{v.inspect}" do
832
+ parse("[[url:/rel]]", :absolute_urls => v, :site_url => 'http://www.ru').should ==
833
+ '<a rel="nofollow" href="http://www.ru/rel">/rel</a>'
834
+ parse("[[url:/rel|text]]", :absolute_urls => v, :site_url => 'http://www.ru').should ==
835
+ '<a rel="nofollow" href="http://www.ru/rel">text</a>'
836
+ end
837
+ end
838
+ # 'false' values
839
+ [false, nil].each do |v|
840
+ it "should not convert relative url to absolute when absolute_urls = #{v.inspect}" do
841
+ parse("[[url:/rel]]", :absolute_urls => v).should ==
842
+ '<a rel="nofollow" href="/rel">/rel</a>'
843
+ parse("[[url:/rel|text]]", :absolute_urls => v).should ==
844
+ '<a rel="nofollow" href="/rel">text</a>'
845
+ end
846
+ end
847
+ end
848
+
849
+ a = {}
850
+ a["image:ExistingImage.png"] =
851
+ '<img src="/spaces/test_space/documents/download/ExistingImage.png" alt="ALT" />'
852
+ a["image:cVJUz6ejWr35pEab_qKWB8"] =
853
+ '<img src="/spaces/test_space/documents/download/cVJUz6ejWr35pEab_qKWB8" alt="ALT" />'
854
+
855
+ a.each do |k,v|
856
+ it "parses [[#{k}]]" do
857
+ parse("[[#{k}]]").should == v.sub('ALT',k.sub('image:',''))
858
+ end
859
+ it "parses [[#{k}|привет тест]]" do
860
+ parse("[[#{k}|привет тест]]").should == v.sub('ALT','привет тест')
861
+ end
862
+ it "parses [[#{k}|test & here]]" do
863
+ parse("[[#{k}|test & here]]").should == v.sub('ALT','test & here')
864
+ end
865
+ end
866
+
867
+ it "ignores unknown link types" do
868
+ s = "[[zzz:xxx]]"
869
+ parse(s).should == s
870
+ s = "[[abcd:1234]]"
871
+ parse(s).should == s
872
+ s = "[[abcd::1234]] [[abcd:1234]] [[uri:ww.ru]]"
873
+ parse(s).should == s
874
+ end
875
+
876
+ it "ignores file & image links with forbidden symbols" do
877
+ s = "[[file:aaa/bbb]]"
878
+ parse(s).should == s
879
+ s = "[[file:aaa\\bbb]]"
880
+ parse(s).should == s
881
+ s = "[[file:aaa bbb]]"
882
+ parse(s).should == s
883
+
884
+ s = "[[image:aaa/bbb]]"
885
+ parse(s).should == s
886
+ s = "[[image:aaa\\bbb]]"
887
+ parse(s).should == s
888
+ s = "[[image:aaa bbb]]"
889
+ parse(s).should == s
890
+ end
891
+ end
892
+
893
+ ###############################################################################
894
+ ###############################################################################
895
+ ###############################################################################
896
+
897
+ unless defined?(HTML_ESCAPE)
898
+ HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
899
+ end
900
+
901
+ def h(s)
902
+ s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
903
+ end
904
+
905
+ def parse(s, h = {})
906
+ h[:space_name] = "test_space" unless h.key?(:space_name)
907
+ BreakoutParser.parse_links_only(s,
908
+ h[:space_name],
909
+ h[:site_url],
910
+ h[:git_url],
911
+ h[:absolute_urls],
912
+ h[:large_files_url],
913
+ h[:meta_attributes]
914
+ ).strip
915
+ end
916
+ end