breakout_parser 0.0.23 → 0.0.31

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