twitter-text-kow 1.3.1.0

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.
@@ -0,0 +1,858 @@
1
+ # Copyright 2018 Twitter, Inc.
2
+ # Licensed under the Apache License, Version 2.0
3
+ # http://www.apache.org/licenses/LICENSE-2.0
4
+
5
+ # encoding: utf-8
6
+ require File.dirname(__FILE__) + '/spec_helper'
7
+
8
+ class TestAutolink
9
+ include Twitter::TwitterText::Autolink
10
+ end
11
+
12
+ describe Twitter::TwitterText::Autolink do
13
+ def original_text; end
14
+ def url; end
15
+
16
+ describe "auto_link_custom" do
17
+ before do
18
+ @autolinked_text = TestAutolink.new.auto_link(original_text) if original_text
19
+ end
20
+
21
+ describe "plain text" do
22
+ context "plain text with emoji" do
23
+ def original_text; "gotcha 👍"; end
24
+
25
+ it "should be unchanged" do
26
+ expect(@autolinked_text).to eq("gotcha 👍")
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "username autolinking" do
32
+ context "username preceded by a space" do
33
+ def original_text; "hello @jacob"; end
34
+
35
+ it "should be linked" do
36
+ expect(@autolinked_text).to link_to_screen_name('jacob')
37
+ end
38
+ end
39
+
40
+ context "username in camelCase" do
41
+ def original_text() "@jaCob iS cOoL" end
42
+
43
+ it "should be linked" do
44
+ expect(@autolinked_text).to link_to_screen_name('jaCob')
45
+ end
46
+ end
47
+
48
+ context "username at beginning of line" do
49
+ def original_text; "@jacob you're cool"; end
50
+
51
+ it "should be linked" do
52
+ expect(@autolinked_text).to link_to_screen_name('jacob')
53
+ end
54
+ end
55
+
56
+ context "username preceded by word character" do
57
+ def original_text; "meet@the beach"; end
58
+
59
+ it "should not be linked" do
60
+ expect(Nokogiri::HTML(@autolinked_text).search('a')).to be_empty
61
+ end
62
+ end
63
+
64
+ context "username preceded by non-word character" do
65
+ def original_text; "great.@jacob"; end
66
+
67
+ it "should be linked" do
68
+ expect(@autolinked_text).to link_to_screen_name('jacob')
69
+ end
70
+ end
71
+
72
+ context "username containing non-word characters" do
73
+ def original_text; "@zach&^$%^"; end
74
+
75
+ it "should not be linked" do
76
+ expect(@autolinked_text).to link_to_screen_name('zach')
77
+ end
78
+ end
79
+
80
+ context "username over twenty characters" do
81
+ def original_text
82
+ @twenty_character_username = "zach" * 5
83
+ "@" + @twenty_character_username + "1"
84
+ end
85
+
86
+ it "should not be linked" do
87
+ expect(@autolinked_text).to link_to_screen_name(@twenty_character_username)
88
+ end
89
+ end
90
+
91
+ context "username followed by japanese" do
92
+ def original_text; "@jacobの"; end
93
+
94
+ it "should be linked" do
95
+ expect(@autolinked_text).to link_to_screen_name('jacob')
96
+ end
97
+ end
98
+
99
+ context "username preceded by japanese" do
100
+ def original_text; "あ@matz"; end
101
+
102
+ it "should be linked" do
103
+ expect(@autolinked_text).to link_to_screen_name('matz')
104
+ end
105
+ end
106
+
107
+ context "username surrounded by japanese" do
108
+ def original_text; "あ@yoshimiの"; end
109
+
110
+ it "should be linked" do
111
+ expect(@autolinked_text).to link_to_screen_name('yoshimi')
112
+ end
113
+ end
114
+
115
+ context "username using full-width at-sign" do
116
+ def original_text
117
+ "#{[0xFF20].pack('U')}jacob"
118
+ end
119
+
120
+ it "should be linked" do
121
+ expect(@autolinked_text).to link_to_screen_name('jacob')
122
+ end
123
+ end
124
+ end
125
+
126
+ describe "list path autolinking" do
127
+
128
+ context "when List is not available" do
129
+ it "should not be linked" do
130
+ @autolinked_text = TestAutolink.new.auto_link_usernames_or_lists("hello @jacob/my-list", :suppress_lists => true)
131
+ expect(@autolinked_text).to_not link_to_list_path('jacob/my-list')
132
+ expect(@autolinked_text).to include('my-list')
133
+ end
134
+ end
135
+
136
+ context "slug preceded by a space" do
137
+ def original_text; "hello @jacob/my-list"; end
138
+
139
+ it "should be linked" do
140
+ expect(@autolinked_text).to link_to_list_path('jacob/my-list')
141
+ end
142
+ end
143
+
144
+ context "username followed by a slash but no list" do
145
+ def original_text; "hello @jacob/ my-list"; end
146
+
147
+ it "should NOT be linked" do
148
+ expect(@autolinked_text).to_not link_to_list_path('jacob/my-list')
149
+ expect(@autolinked_text).to link_to_screen_name('jacob')
150
+ end
151
+ end
152
+
153
+ context "empty username followed by a list" do
154
+ def original_text; "hello @/my-list"; end
155
+
156
+ it "should NOT be linked" do
157
+ expect(Nokogiri::HTML(@autolinked_text).search('a')).to be_empty
158
+ end
159
+ end
160
+
161
+ context "list slug at beginning of line" do
162
+ def original_text; "@jacob/my-list"; end
163
+
164
+ it "should be linked" do
165
+ expect(@autolinked_text).to link_to_list_path('jacob/my-list')
166
+ end
167
+ end
168
+
169
+ context "username preceded by alpha-numeric character" do
170
+ def original_text; "meet@the/beach"; end
171
+
172
+ it "should not be linked" do
173
+ expect(Nokogiri::HTML(@autolinked_text).search('a')).to be_empty
174
+ end
175
+ end
176
+
177
+ context "username preceded by non-word character" do
178
+ def original_text; "great.@jacob/my-list"; end
179
+
180
+ it "should be linked" do
181
+ @autolinked_text = TestAutolink.new.auto_link("great.@jacob/my-list")
182
+ expect(@autolinked_text).to link_to_list_path('jacob/my-list')
183
+ end
184
+ end
185
+
186
+ context "username containing non-word characters" do
187
+ def original_text; "@zach/test&^$%^"; end
188
+
189
+ it "should be linked" do
190
+ expect(@autolinked_text).to link_to_list_path('zach/test')
191
+ end
192
+ end
193
+
194
+ context "username over twenty characters" do
195
+ def original_text
196
+ @twentyfive_character_list = "jack/" + ("a" * 25)
197
+ "@#{@twentyfive_character_list}12345"
198
+ end
199
+
200
+ it "should be linked" do
201
+ expect(@autolinked_text).to link_to_list_path(@twentyfive_character_list)
202
+ end
203
+ end
204
+ end
205
+
206
+ describe "hashtag autolinking" do
207
+ context "with an all numeric hashtag" do
208
+ def original_text; "#123"; end
209
+
210
+ it "should not be linked" do
211
+ expect(@autolinked_text).to_not have_autolinked_hashtag('#123')
212
+ end
213
+ end
214
+
215
+ context "with a hashtag with alphanumeric characters" do
216
+ def original_text; "#ab1d"; end
217
+
218
+ it "should be linked" do
219
+ expect(@autolinked_text).to have_autolinked_hashtag('#ab1d')
220
+ end
221
+ end
222
+
223
+ context "with a hashtag with underscores" do
224
+ def original_text; "#a_b_c_d"; end
225
+
226
+ it "should be linked" do
227
+ expect(@autolinked_text).to have_autolinked_hashtag(original_text)
228
+ end
229
+ end
230
+
231
+ context "with a hashtag that is preceded by a word character" do
232
+ def original_text; "ab#cd"; end
233
+
234
+ it "should not be linked" do
235
+ expect(@autolinked_text).to_not have_autolinked_hashtag(original_text)
236
+ end
237
+ end
238
+
239
+ context "with a page anchor in a url" do
240
+ def original_text; "Here's my url: http://foobar.com/#home"; end
241
+
242
+ it "should not link the hashtag" do
243
+ expect(@autolinked_text).to_not have_autolinked_hashtag('#home')
244
+ end
245
+
246
+ it "should link the url" do
247
+ expect(@autolinked_text).to have_autolinked_url('http://foobar.com/#home')
248
+ end
249
+ end
250
+
251
+ context "with a hashtag that starts with a number but has word characters" do
252
+ def original_text; "#2ab"; end
253
+
254
+ it "should be linked" do
255
+ expect(@autolinked_text).to have_autolinked_hashtag(original_text)
256
+ end
257
+ end
258
+
259
+ context "with multiple valid hashtags" do
260
+ def original_text; "I'm frickin' awesome #ab #cd #ef"; end
261
+
262
+ it "links each hashtag" do
263
+ expect(@autolinked_text).to have_autolinked_hashtag('#ab')
264
+ expect(@autolinked_text).to have_autolinked_hashtag('#cd')
265
+ expect(@autolinked_text).to have_autolinked_hashtag('#ef')
266
+ end
267
+ end
268
+
269
+ context "with a hashtag preceded by a ." do
270
+ def original_text; "ok, great.#abc"; end
271
+
272
+ it "should be linked" do
273
+ expect(@autolinked_text).to have_autolinked_hashtag('#abc')
274
+ end
275
+ end
276
+
277
+ context "with a hashtag preceded by a &" do
278
+ def original_text; "&#nbsp;"; end
279
+
280
+ it "should not be linked" do
281
+ expect(@autolinked_text).to_not have_autolinked_hashtag('#nbsp;')
282
+ end
283
+ end
284
+
285
+ context "with a hashtag that ends in an !" do
286
+ def original_text; "#great!"; end
287
+
288
+ it "should be linked, but should not include the !" do
289
+ expect(@autolinked_text).to have_autolinked_hashtag('#great')
290
+ end
291
+ end
292
+
293
+ context "with a hashtag followed by Japanese" do
294
+ def original_text; "#twj_devの"; end
295
+
296
+ it "should be linked" do
297
+ expect(@autolinked_text).to have_autolinked_hashtag('#twj_devの')
298
+ end
299
+ end
300
+
301
+ context "with a hashtag preceded by a full-width space" do
302
+ def original_text; "#{[0x3000].pack('U')}#twj_dev"; end
303
+
304
+ it "should be linked" do
305
+ expect(@autolinked_text).to have_autolinked_hashtag('#twj_dev')
306
+ end
307
+ end
308
+
309
+ context "with a hashtag followed by a full-width space" do
310
+ def original_text; "#twj_dev#{[0x3000].pack('U')}"; end
311
+
312
+ it "should be linked" do
313
+ expect(@autolinked_text).to have_autolinked_hashtag('#twj_dev')
314
+ end
315
+ end
316
+
317
+ context "with a hashtag using full-width hash" do
318
+ def original_text; "#{[0xFF03].pack('U')}twj_dev"; end
319
+
320
+ it "should be linked" do
321
+ link = Nokogiri::HTML(@autolinked_text).search('a')
322
+ expect((link.inner_text.respond_to?(:force_encoding) ? link.inner_text.force_encoding("utf-8") : link.inner_text)).to be == "#{[0xFF03].pack('U')}twj_dev"
323
+ expect(link.first['href']).to be == 'https://twitter.com/search?q=%23twj_dev'
324
+ end
325
+ end
326
+
327
+ context "with a hashtag containing an accented latin character" do
328
+ def original_text
329
+ # the hashtag is #éhashtag
330
+ "##{[0x00e9].pack('U')}hashtag"
331
+ end
332
+
333
+ it "should be linked" do
334
+ expect(@autolinked_text).to be == "<a class=\"tweet-url hashtag\" href=\"https://twitter.com/search?q=%23éhashtag\" rel=\"nofollow\" title=\"#éhashtag\">#éhashtag</a>"
335
+ end
336
+ end
337
+
338
+ end
339
+
340
+ describe "URL autolinking" do
341
+ def url; "http://www.google.com"; end
342
+
343
+ context "when embedded in plain text" do
344
+ def original_text; "On my search engine #{url} I found good links."; end
345
+
346
+ it "should be linked" do
347
+ expect(@autolinked_text).to have_autolinked_url(url)
348
+ end
349
+ end
350
+
351
+ context "when surrounded by Japanese;" do
352
+ def original_text; "いまなにしてる#{url}いまなにしてる"; end
353
+
354
+ it "should be linked" do
355
+ expect(@autolinked_text).to have_autolinked_url(url)
356
+ end
357
+ end
358
+
359
+ context "with a path surrounded by parentheses;" do
360
+ def original_text; "I found a neatness (#{url})"; end
361
+
362
+ it "should be linked" do
363
+ expect(@autolinked_text).to have_autolinked_url(url)
364
+ end
365
+
366
+ context "when the URL ends with a slash;" do
367
+ def url; "http://www.google.com/"; end
368
+
369
+ it "should be linked" do
370
+ expect(@autolinked_text).to have_autolinked_url(url)
371
+ end
372
+ end
373
+
374
+ context "when the URL has a path;" do
375
+ def url; "http://www.google.com/fsdfasdf"; end
376
+
377
+ it "should be linked" do
378
+ expect(@autolinked_text).to have_autolinked_url(url)
379
+ end
380
+ end
381
+ end
382
+
383
+ context "when path contains parens" do
384
+ def original_text; "I found a neatness (#{url})"; end
385
+
386
+ it "should be linked" do
387
+ expect(@autolinked_text).to have_autolinked_url(url)
388
+ end
389
+
390
+ context "wikipedia" do
391
+ def url; "http://en.wikipedia.org/wiki/Madonna_(artist)"; end
392
+
393
+ it "should be linked" do
394
+ expect(@autolinked_text).to have_autolinked_url(url)
395
+ end
396
+ end
397
+
398
+ context "IIS session" do
399
+ def url; "http://msdn.com/S(deadbeef)/page.htm"; end
400
+
401
+ it "should be linked" do
402
+ expect(@autolinked_text).to have_autolinked_url(url)
403
+ end
404
+ end
405
+
406
+ context "unbalanced parens" do
407
+ def url; "http://example.com/i_has_a_("; end
408
+
409
+ it "should be linked" do
410
+ expect(@autolinked_text).to have_autolinked_url("http://example.com/i_has_a_")
411
+ end
412
+ end
413
+
414
+ context "balanced parens with a double quote inside" do
415
+ def url; "http://foo.com/foo_(\")_bar" end
416
+
417
+ it "should be linked" do
418
+ expect(@autolinked_text).to have_autolinked_url("http://foo.com/foo_")
419
+ end
420
+ end
421
+
422
+ context "balanced parens hiding XSS" do
423
+ def url; 'http://x.xx.com/("style="color:red"onmouseover="alert(1)' end
424
+
425
+ it "should be linked" do
426
+ expect(@autolinked_text).to have_autolinked_url("http://x.xx.com/")
427
+ end
428
+ end
429
+ end
430
+
431
+ context "when preceded by a :" do
432
+ def original_text; "Check this out @hoverbird:#{url}"; end
433
+
434
+ it "should be linked" do
435
+ expect(@autolinked_text).to have_autolinked_url(url)
436
+ end
437
+ end
438
+
439
+ context "with a URL ending in allowed punctuation" do
440
+ it "does not consume ending punctuation" do
441
+ matcher = TestAutolink.new
442
+ %w| ? ! , . : ; ] ) } = \ ' |.each do |char|
443
+ expect(matcher.auto_link("#{url}#{char}")).to have_autolinked_url(url)
444
+ end
445
+ end
446
+ end
447
+
448
+ context "with a URL preceded in forbidden characters" do
449
+ it "should be linked" do
450
+ matcher = TestAutolink.new
451
+ %w| \ ' / ! = |.each do |char|
452
+ expect(matcher.auto_link("#{char}#{url}")).to have_autolinked_url(url)
453
+ end
454
+ end
455
+ end
456
+
457
+ context "when embedded in a link tag" do
458
+ def original_text; "<link rel='true'>#{url}</link>"; end
459
+
460
+ it "should be linked" do
461
+ expect(@autolinked_text).to have_autolinked_url(url)
462
+ end
463
+ end
464
+
465
+ context "with multiple URLs" do
466
+ def original_text; "http://www.links.org link at start of page, link at end http://www.foo.org"; end
467
+
468
+ it "should autolink each one" do
469
+ expect(@autolinked_text).to have_autolinked_url('http://www.links.org')
470
+ expect(@autolinked_text).to have_autolinked_url('http://www.foo.org')
471
+ end
472
+ end
473
+
474
+ context "with multiple URLs in different formats" do
475
+ def original_text; "http://foo.com https://bar.com http://mail.foobar.org"; end
476
+
477
+ it "should autolink each one, in the proper order" do
478
+ expect(@autolinked_text).to have_autolinked_url('http://foo.com')
479
+ expect(@autolinked_text).to have_autolinked_url('https://bar.com')
480
+ expect(@autolinked_text).to have_autolinked_url('http://mail.foobar.org')
481
+ end
482
+ end
483
+
484
+ context "with a URL having a long TLD" do
485
+ def original_text; "Yahoo integriert Facebook http://golem.mobi/0912/71607.html"; end
486
+
487
+ it "should autolink it" do
488
+ expect(@autolinked_text).to have_autolinked_url('http://golem.mobi/0912/71607.html')
489
+ end
490
+ end
491
+
492
+ context "with a url lacking the protocol" do
493
+ def original_text; "I like www.foobar.com dudes"; end
494
+
495
+ it "does not link at all" do
496
+ link = Nokogiri::HTML(@autolinked_text).search('a')
497
+ expect(link).to be_empty
498
+ end
499
+ end
500
+
501
+ context "with a @ in a URL" do
502
+ context "with XSS attack" do
503
+ def original_text; 'http://x.xx.com/@"style="color:pink"onmouseover=alert(1)//'; end
504
+
505
+ it "should not allow XSS follwing @" do
506
+ expect(@autolinked_text).to have_autolinked_url('http://x.xx.com/')
507
+ end
508
+ end
509
+
510
+ context "with a username not followed by a /" do
511
+ def original_text; 'http://example.com/@foobar'; end
512
+
513
+ it "should link url" do
514
+ expect(@autolinked_text).to have_autolinked_url('http://example.com/@foobar')
515
+ end
516
+ end
517
+
518
+ context "with a username followed by a /" do
519
+ def original_text; 'http://example.com/@foobar/'; end
520
+
521
+ it "should not link the username but link full url" do
522
+ expect(@autolinked_text).to have_autolinked_url('http://example.com/@foobar/')
523
+ expect(@autolinked_text).to_not link_to_screen_name('foobar')
524
+ end
525
+ end
526
+ end
527
+
528
+ context "regex engine quirks" do
529
+ context "does not spiral out of control on repeated periods" do
530
+ def original_text; "Test a ton of periods http://example.com/path.........................................."; end
531
+
532
+ it "should autolink" do
533
+ expect(@autolinked_text).to have_autolinked_url('http://example.com/path')
534
+ end
535
+ end
536
+
537
+ context "does not spiral out of control on repeated dashes" do
538
+ def original_text; "Single char file ext http://www.bestbuy.com/site/Currie+Technologies+-+Ezip+400+Scooter/9885188.p?id=1218189013070&skuId=9885188"; end
539
+
540
+ it "should autolink" do
541
+ expect(@autolinked_text).to have_autolinked_url('http://www.bestbuy.com/site/Currie+Technologies+-+Ezip+400+Scooter/9885188.p?id=1218189013070&skuId=9885188')
542
+ end
543
+ end
544
+ end
545
+
546
+ end
547
+
548
+ describe "Autolink all" do
549
+ before do
550
+ @linker = TestAutolink.new
551
+ end
552
+
553
+ it "should allow url/hashtag overlap" do
554
+ auto_linked = @linker.auto_link("https://twitter.com/#search")
555
+ expect(auto_linked).to have_autolinked_url('https://twitter.com/#search')
556
+ end
557
+
558
+ it "should not add invalid option in HTML tags" do
559
+ auto_linked = @linker.auto_link("https://twitter.com/ is a URL, not a hashtag", :hashtag_class => 'hashtag_classname')
560
+ expect(auto_linked).to have_autolinked_url('https://twitter.com/')
561
+ expect(auto_linked).to_not include('hashtag_class')
562
+ expect(auto_linked).to_not include('hashtag_classname')
563
+ end
564
+
565
+ it "should autolink url/hashtag/mention in text with Unicode supplementary characters" do
566
+ auto_linked = @linker.auto_link("#{[0x10400].pack('U')} #hashtag #{[0x10400].pack('U')} @mention #{[0x10400].pack('U')} http://twitter.com/")
567
+ expect(auto_linked).to have_autolinked_hashtag('#hashtag')
568
+ expect(auto_linked).to link_to_screen_name('mention')
569
+ expect(auto_linked).to have_autolinked_url('http://twitter.com/')
570
+ end
571
+ end
572
+
573
+ end
574
+
575
+ describe "autolinking options" do
576
+ before do
577
+ @linker = TestAutolink.new
578
+ end
579
+
580
+ it "should show display_url when :url_entities provided" do
581
+ linked = @linker.auto_link("http://t.co/0JG5Mcq", :url_entities => [{
582
+ "url" => "http://t.co/0JG5Mcq",
583
+ "display_url" => "blog.twitter.com/2011/05/twitte…",
584
+ "expanded_url" => "http://blog.twitter.com/2011/05/twitter-for-mac-update.html",
585
+ "indices" => [
586
+ 84,
587
+ 103
588
+ ]
589
+ }])
590
+ html = Nokogiri::HTML(linked)
591
+ expect(html.search('a')).to_not be_empty
592
+ expect(html.search('a[@href="http://t.co/0JG5Mcq"]')).to_not be_empty
593
+ expect(html.search('span[@class=js-display-url]').inner_text).to be == "blog.twitter.com/2011/05/twitte"
594
+ expect(html.inner_text).to be == " http://blog.twitter.com/2011/05/twitter-for-mac-update.html …"
595
+ expect(html.search('span[@style="position:absolute;left:-9999px;"]').size).to be == 4
596
+ end
597
+
598
+ it "should accept invisible_tag_attrs option" do
599
+ linked = @linker.auto_link("http://t.co/0JG5Mcq",
600
+ {
601
+ :url_entities => [{
602
+ "url" => "http://t.co/0JG5Mcq",
603
+ "display_url" => "blog.twitter.com/2011/05/twitte…",
604
+ "expanded_url" => "http://blog.twitter.com/2011/05/twitter-for-mac-update.html",
605
+ "indices" => [
606
+ 0,
607
+ 19
608
+ ]
609
+ }],
610
+ :invisible_tag_attrs => "style='dummy;'"
611
+ })
612
+ html = Nokogiri::HTML(linked)
613
+ expect(html.search('span[@style="dummy;"]').size).to be == 4
614
+ end
615
+
616
+ it "should show display_url if available in entity" do
617
+ linked = @linker.auto_link_entities("http://t.co/0JG5Mcq",
618
+ [{
619
+ :url => "http://t.co/0JG5Mcq",
620
+ :display_url => "blog.twitter.com/2011/05/twitte…",
621
+ :expanded_url => "http://blog.twitter.com/2011/05/twitter-for-mac-update.html",
622
+ :indices => [0, 19]
623
+ }]
624
+ )
625
+ html = Nokogiri::HTML(linked)
626
+ expect(html.search('a')).to_not be_empty
627
+ expect(html.search('a[@href="http://t.co/0JG5Mcq"]')).to_not be_empty
628
+ expect(html.search('span[@class=js-display-url]').inner_text).to be == "blog.twitter.com/2011/05/twitte"
629
+ expect(html.inner_text).to be == " http://blog.twitter.com/2011/05/twitter-for-mac-update.html …"
630
+ end
631
+
632
+ it "should apply :class as a CSS class" do
633
+ linked = @linker.auto_link("http://example.com/", :class => 'myclass')
634
+ expect(linked).to have_autolinked_url('http://example.com/')
635
+ expect(linked).to match(/myclass/)
636
+ end
637
+
638
+ it "should apply :url_class only on URL" do
639
+ linked = @linker.auto_link("http://twitter.com")
640
+ expect(linked).to have_autolinked_url('http://twitter.com')
641
+ expect(expect(linked)).to_not match(/class/)
642
+
643
+ linked = @linker.auto_link("http://twitter.com", :url_class => 'testClass')
644
+ expect(linked).to have_autolinked_url('http://twitter.com')
645
+ expect(linked).to match(/class=\"testClass\"/)
646
+
647
+ linked = @linker.auto_link("#hash @tw", :url_class => 'testClass')
648
+ expect(linked).to match(/class=\"tweet-url hashtag\"/)
649
+ expect(linked).to match(/class=\"tweet-url username\"/)
650
+ expect(linked).to_not match(/class=\"testClass\"/)
651
+ end
652
+
653
+ it "should add rel=nofollow by default" do
654
+ linked = @linker.auto_link("http://example.com/")
655
+ expect(linked).to have_autolinked_url('http://example.com/')
656
+ expect(linked).to match(/nofollow/)
657
+ end
658
+
659
+ it "should include the '@' symbol in a username when passed :username_include_symbol" do
660
+ linked = @linker.auto_link("@user", :username_include_symbol => true)
661
+ expect(linked).to link_to_screen_name('user', '@user')
662
+ end
663
+
664
+ it "should include the '@' symbol in a list when passed :username_include_symbol" do
665
+ linked = @linker.auto_link("@user/list", :username_include_symbol => true)
666
+ expect(linked).to link_to_list_path('user/list', '@user/list')
667
+ end
668
+
669
+ it "should not add rel=nofollow when passed :suppress_no_follow" do
670
+ linked = @linker.auto_link("http://example.com/", :suppress_no_follow => true)
671
+ expect(linked).to have_autolinked_url('http://example.com/')
672
+ expect(linked).to_not match(/nofollow/)
673
+ end
674
+
675
+ it "should not add a target attribute by default" do
676
+ linked = @linker.auto_link("http://example.com/")
677
+ expect(linked).to have_autolinked_url('http://example.com/')
678
+ expect(linked).to_not match(/target=/)
679
+ end
680
+
681
+ it "should respect the :target option" do
682
+ linked = @linker.auto_link("http://example.com/", :target => 'mywindow')
683
+ expect(linked).to have_autolinked_url('http://example.com/')
684
+ expect(linked).to match(/target="mywindow"/)
685
+ end
686
+
687
+ it "should customize href by username_url_block option" do
688
+ linked = @linker.auto_link("@test", :username_url_block => lambda{|a| "dummy"})
689
+ expect(linked).to have_autolinked_url('dummy', 'test')
690
+ end
691
+
692
+ it "should customize href by list_url_block option" do
693
+ linked = @linker.auto_link("@test/list", :list_url_block => lambda{|a| "dummy"})
694
+ expect(linked).to have_autolinked_url('dummy', 'test/list')
695
+ end
696
+
697
+ it "should customize href by hashtag_url_block option" do
698
+ linked = @linker.auto_link("#hashtag", :hashtag_url_block => lambda{|a| "dummy"})
699
+ expect(linked).to have_autolinked_url('dummy', '#hashtag')
700
+ end
701
+
702
+ it "should customize href by cashtag_url_block option" do
703
+ linked = @linker.auto_link("$CASH", :cashtag_url_block => lambda{|a| "dummy"})
704
+ expect(linked).to have_autolinked_url('dummy', '$CASH')
705
+ end
706
+
707
+ it "should customize href by link_url_block option" do
708
+ linked = @linker.auto_link("http://example.com/", :link_url_block => lambda{|a| "dummy"})
709
+ expect(linked).to have_autolinked_url('dummy', 'http://example.com/')
710
+ end
711
+
712
+ it "should modify link attributes by link_attribute_block" do
713
+ linked = @linker.auto_link("#hash @mention",
714
+ :link_attribute_block => lambda{|entity, attributes|
715
+ attributes[:"dummy-hash-attr"] = "test" if entity[:hashtag]
716
+ }
717
+ )
718
+ expect(linked).to match(/<a[^>]+hashtag[^>]+dummy-hash-attr=\"test\"[^>]+>/)
719
+ expect(linked).to_not match(/<a[^>]+username[^>]+dummy-hash-attr=\"test\"[^>]+>/)
720
+ expect(linked).to_not match(/link_attribute_block/i)
721
+
722
+ linked = @linker.auto_link("@mention http://twitter.com/",
723
+ :link_attribute_block => lambda{|entity, attributes|
724
+ attributes["dummy-url-attr"] = entity[:url] if entity[:url]
725
+ }
726
+ )
727
+ expect(linked).to_not match(/<a[^>]+username[^>]+dummy-url-attr=\"http:\/\/twitter.com\/\"[^>]*>/)
728
+ expect(linked).to match(/<a[^>]+dummy-url-attr=\"http:\/\/twitter.com\/\"/)
729
+ end
730
+
731
+ it "should modify link text by link_text_block" do
732
+ linked = @linker.auto_link("#hash @mention",
733
+ :link_text_block => lambda{|entity, text|
734
+ entity[:hashtag] ? "#replaced" : "pre_#{text}_post"
735
+ }
736
+ )
737
+ expect(linked).to match(/<a[^>]+>#replaced<\/a>/)
738
+ expect(linked).to match(/<a[^>]+>pre_mention_post<\/a>/)
739
+
740
+ linked = @linker.auto_link("#hash @mention", {
741
+ :link_text_block => lambda{|entity, text|
742
+ "pre_#{text}_post"
743
+ },
744
+ :symbol_tag => "s", :text_with_symbol_tag => "b", :username_include_symbol => true
745
+ })
746
+ expect(linked).to match(/<a[^>]+>pre_<s>#<\/s><b>hash<\/b>_post<\/a>/)
747
+ expect(linked).to match(/<a[^>]+>pre_<s>@<\/s><b>mention<\/b>_post<\/a>/)
748
+ end
749
+
750
+ it "should apply :url_target only to auto-linked URLs" do
751
+ auto_linked = @linker.auto_link("#hashtag @mention http://test.com/", {:url_target => '_blank'})
752
+ expect(auto_linked).to have_autolinked_hashtag('#hashtag')
753
+ expect(auto_linked).to link_to_screen_name('mention')
754
+ expect(auto_linked).to have_autolinked_url('http://test.com/')
755
+ expect(auto_linked).to_not match(/<a[^>]+hashtag[^>]+target[^>]+>/)
756
+ expect(auto_linked).to_not match(/<a[^>]+username[^>]+target[^>]+>/)
757
+ expect(auto_linked).to match(/<a[^>]+test.com[^>]+target=\"_blank\"[^>]*>/)
758
+ end
759
+
760
+ it "should apply target='_blank' only to auto-linked URLs when :target_blank is set to true" do
761
+ auto_linked = @linker.auto_link("#hashtag @mention http://test.com/", {:target_blank => true})
762
+ expect(auto_linked).to have_autolinked_hashtag('#hashtag')
763
+ expect(auto_linked).to link_to_screen_name('mention')
764
+ expect(auto_linked).to have_autolinked_url('http://test.com/')
765
+ expect(auto_linked).to match(/<a[^>]+hashtag[^>]+target=\"_blank\"[^>]*>/)
766
+ expect(auto_linked).to match(/<a[^>]+username[^>]+target=\"_blank\"[^>]*>/)
767
+ expect(auto_linked).to match(/<a[^>]+test.com[^>]+target=\"_blank\"[^>]*>/)
768
+ end
769
+ end
770
+
771
+ describe "link_url_with_entity" do
772
+ before do
773
+ @linker = TestAutolink.new
774
+ end
775
+
776
+ it "should use display_url and expanded_url" do
777
+ expect(@linker.send(:link_url_with_entity,
778
+ {
779
+ :url => "http://t.co/abcde",
780
+ :display_url => "twitter.com",
781
+ :expanded_url => "http://twitter.com/"},
782
+ {:invisible_tag_attrs => "class='invisible'"}).gsub('"', "'")).to be == "<span class='tco-ellipsis'><span class='invisible'>&nbsp;</span></span><span class='invisible'>http://</span><span class='js-display-url'>twitter.com</span><span class='invisible'>/</span><span class='tco-ellipsis'><span class='invisible'>&nbsp;</span></span>";
783
+ end
784
+
785
+ it "should correctly handle display_url ending with '…'" do
786
+ expect(@linker.send(:link_url_with_entity,
787
+ {
788
+ :url => "http://t.co/abcde",
789
+ :display_url => "twitter.com…",
790
+ :expanded_url => "http://twitter.com/abcdefg"},
791
+ {:invisible_tag_attrs => "class='invisible'"}).gsub('"', "'")).to be == "<span class='tco-ellipsis'><span class='invisible'>&nbsp;</span></span><span class='invisible'>http://</span><span class='js-display-url'>twitter.com</span><span class='invisible'>/abcdefg</span><span class='tco-ellipsis'><span class='invisible'>&nbsp;</span>…</span>";
792
+ end
793
+
794
+ it "should correctly handle display_url starting with '…'" do
795
+ expect(@linker.send(:link_url_with_entity,
796
+ {
797
+ :url => "http://t.co/abcde",
798
+ :display_url => "…tter.com/abcdefg",
799
+ :expanded_url => "http://twitter.com/abcdefg"},
800
+ {:invisible_tag_attrs => "class='invisible'"}).gsub('"', "'")).to be == "<span class='tco-ellipsis'>…<span class='invisible'>&nbsp;</span></span><span class='invisible'>http://twi</span><span class='js-display-url'>tter.com/abcdefg</span><span class='invisible'></span><span class='tco-ellipsis'><span class='invisible'>&nbsp;</span></span>";
801
+ end
802
+
803
+ it "should not create spans if display_url and expanded_url are on different domains" do
804
+ expect(@linker.send(:link_url_with_entity,
805
+ {
806
+ :url => "http://t.co/abcde",
807
+ :display_url => "pic.twitter.com/xyz",
808
+ :expanded_url => "http://twitter.com/foo/statuses/123/photo/1"},
809
+ {:invisible_tag_attrs => "class='invisible'"}).gsub('"', "'")).to be == "pic.twitter.com/xyz"
810
+ end
811
+ end
812
+
813
+ describe "symbol_tag" do
814
+ before do
815
+ @linker = TestAutolink.new
816
+ end
817
+ it "should put :symbol_tag around symbol" do
818
+ expect(@linker.auto_link("@mention", {:symbol_tag => 's', :username_include_symbol=>true})).to match(/<s>@<\/s>mention/)
819
+ expect(@linker.auto_link("#hash", {:symbol_tag => 's'})).to match(/<s>#<\/s>hash/)
820
+ result = @linker.auto_link("@mention #hash $CASH", {:symbol_tag => 'b', :username_include_symbol=>true})
821
+ expect(result).to match(/<b>@<\/b>mention/)
822
+ expect(result).to match(/<b>#<\/b>hash/)
823
+ expect(result).to match(/<b>\$<\/b>CASH/)
824
+ end
825
+ it "should put :text_with_symbol_tag around text" do
826
+ result = @linker.auto_link("@mention #hash $CASH", {:text_with_symbol_tag => 'b'})
827
+ expect(result).to match(/<b>mention<\/b>/)
828
+ expect(result).to match(/<b>hash<\/b>/)
829
+ expect(result).to match(/<b>CASH<\/b>/)
830
+ end
831
+ it "should put :symbol_tag around symbol and :text_with_symbol_tag around text" do
832
+ result = @linker.auto_link("@mention #hash $CASH", {:symbol_tag => 's', :text_with_symbol_tag => 'b', :username_include_symbol=>true})
833
+ expect(result).to match(/<s>@<\/s><b>mention<\/b>/)
834
+ expect(result).to match(/<s>#<\/s><b>hash<\/b>/)
835
+ expect(result).to match(/<s>\$<\/s><b>CASH<\/b>/)
836
+ end
837
+ end
838
+
839
+ describe "html_escape" do
840
+ before do
841
+ @linker = TestAutolink.new
842
+ end
843
+ it "should escape html entities properly" do
844
+ expect(@linker.html_escape("&")).to be == "&amp;"
845
+ expect(@linker.html_escape(">")).to be == "&gt;"
846
+ expect(@linker.html_escape("<")).to be == "&lt;"
847
+ expect(@linker.html_escape("\"")).to be == "&quot;"
848
+ expect(@linker.html_escape("'")).to be == "&#39;"
849
+ expect(@linker.html_escape("&<>\"")).to be == "&amp;&lt;&gt;&quot;"
850
+ expect(@linker.html_escape("<div>")).to be == "&lt;div&gt;"
851
+ expect(@linker.html_escape("a&b")).to be == "a&amp;b"
852
+ expect(@linker.html_escape("<a href=\"https://twitter.com\" target=\"_blank\">twitter & friends</a>")).to be == "&lt;a href=&quot;https://twitter.com&quot; target=&quot;_blank&quot;&gt;twitter &amp; friends&lt;/a&gt;"
853
+ expect(@linker.html_escape("&amp;")).to be == "&amp;amp;"
854
+ expect(@linker.html_escape(nil)).to be == nil
855
+ end
856
+ end
857
+
858
+ end