# Copyright 2018 Twitter, Inc.
# Licensed under the Apache License, Version 2.0
# http://www.apache.org/licenses/LICENSE-2.0
# encoding: utf-8
require File.dirname(__FILE__) + '/spec_helper'
describe Twitter::TwitterText::Rewriter do
def original_text; end
def url; end
def block(*args)
if Array === @block_args
unless Array === @block_args.first
@block_args = [@block_args]
end
@block_args << args
else
@block_args = args
end
"[rewritten]"
end
describe "rewrite usernames" do #{{{
before do
@rewritten_text = Twitter::TwitterText::Rewriter.rewrite_usernames_or_lists(original_text, &method(:block))
end
context "username preceded by a space" do
def original_text; "hello @jacob"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "hello [rewritten]"
end
end
context "username at beginning of line" do
def original_text; "@jacob you're cool"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "[rewritten] you're cool"
end
end
context "username preceded by word character" do
def original_text; "meet@the beach"; end
it "should not be rewritten" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "meet@the beach"
end
end
context "username preceded by non-word character" do
def original_text; "great.@jacob"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "great.[rewritten]"
end
end
context "username containing non-word characters" do
def original_text; "@jacob&^$%^"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "[rewritten]&^$%^"
end
end
context "username over twenty characters" do
def original_text
@twenty_character_username = "zach" * 5
"@" + @twenty_character_username + "1"
end
it "should be rewritten" do
expect(@block_args).to be == ["@", @twenty_character_username, nil]
expect(@rewritten_text).to be == "[rewritten]1"
end
end
context "username followed by japanese" do
def original_text; "@jacobの"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "[rewritten]の"
end
end
context "username preceded by japanese" do
def original_text; "あ@jacob"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "あ[rewritten]"
end
end
context "username surrounded by japanese" do
def original_text; "あ@jacobの"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "あ[rewritten]の"
end
end
context "username using full-width at-sign" do
def original_text
"#{[0xFF20].pack('U')}jacob"
end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "[rewritten]"
end
end
end #}}}
describe "rewrite lists" do #{{{
before do
@rewritten_text = Twitter::TwitterText::Rewriter.rewrite_usernames_or_lists(original_text, &method(:block))
end
context "slug preceded by a space" do
def original_text; "hello @jacob/my-list"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", "/my-list"]
expect(@rewritten_text).to be == "hello [rewritten]"
end
end
context "username followed by a slash but no list" do
def original_text; "hello @jacob/ my-list"; end
it "should not be rewritten" do
expect(@block_args).to be == ["@", "jacob", nil]
expect(@rewritten_text).to be == "hello [rewritten]/ my-list"
end
end
context "empty username followed by a list" do
def original_text; "hello @/my-list"; end
it "should not be rewritten" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "hello @/my-list"
end
end
context "list slug at beginning of line" do
def original_text; "@jacob/my-list"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", "/my-list"]
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "username preceded by alpha-numeric character" do
def original_text; "meet@jacob/my-list"; end
it "should not be rewritten" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "meet@jacob/my-list"
end
end
context "username preceded by non-word character" do
def original_text; "great.@jacob/my-list"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", "/my-list"]
expect(@rewritten_text).to be == "great.[rewritten]"
end
end
context "username containing non-word characters" do
def original_text; "@jacob/my-list&^$%^"; end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", "/my-list"]
expect(@rewritten_text).to be == "[rewritten]&^$%^"
end
end
context "username over twenty characters" do
def original_text
@twentyfive_character_list = "a" * 25
"@jacob/#{@twentyfive_character_list}12345"
end
it "should be rewritten" do
expect(@block_args).to be == ["@", "jacob", "/#{@twentyfive_character_list}"]
expect(@rewritten_text).to be == "[rewritten]12345"
end
end
end #}}}
describe "rewrite hashtags" do #{{{
before do
@rewritten_text = Twitter::TwitterText::Rewriter.rewrite_hashtags(original_text, &method(:block))
end
context "with an all numeric hashtag" do
def original_text; "#123"; end
it "should not be rewritten" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "#123"
end
end
context "with a hashtag with alphanumeric characters" do
def original_text; "#ab1d"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "ab1d"]
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with a hashtag with underscores" do
def original_text; "#a_b_c_d"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "a_b_c_d"]
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with a hashtag that is preceded by a word character" do
def original_text; "ab#cd"; end
it "should not be rewritten" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "ab#cd"
end
end
context "with a hashtag that starts with a number but has word characters" do
def original_text; "#2ab"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "2ab"]
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with multiple valid hashtags" do
def original_text; "I'm frickin' awesome #ab #cd #ef"; end
it "rewrites each hashtag" do
expect(@block_args).to be == [["#", "ab"], ["#", "cd"], ["#", "ef"]]
expect(@rewritten_text).to be == "I'm frickin' awesome [rewritten] [rewritten] [rewritten]"
end
end
context "with a hashtag preceded by a ." do
def original_text; "ok, great.#abc"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "abc"]
expect(@rewritten_text).to be == "ok, great.[rewritten]"
end
end
context "with a hashtag preceded by a &" do
def original_text; "nbsp;"; end
it "should not be rewritten" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "nbsp;"
end
end
context "with a hashtag that ends in an !" do
def original_text; "#great!"; end
it "should be rewritten, but should not include the !" do
expect(@block_args).to be == ["#", "great"];
expect(@rewritten_text).to be == "[rewritten]!"
end
end
context "with a hashtag followed by Japanese" do
def original_text; "#twj_devの"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "twj_devの"];
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with a hashtag preceded by a full-width space" do
def original_text; "#{[0x3000].pack('U')}#twj_dev"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "twj_dev"];
expect(@rewritten_text).to be == " [rewritten]"
end
end
context "with a hashtag followed by a full-width space" do
def original_text; "#twj_dev#{[0x3000].pack('U')}"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "twj_dev"];
expect(@rewritten_text).to be == "[rewritten] "
end
end
context "with a hashtag using full-width hash" do
def original_text; "#{[0xFF03].pack('U')}twj_dev"; end
it "should be rewritten" do
expect(@block_args).to be == ["#", "twj_dev"];
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with a hashtag containing an accented latin character" do
def original_text
# the hashtag is #éhashtag
"##{[0x00e9].pack('U')}hashtag"
end
it "should be rewritten" do
expect(@block_args).to be == ["#", "éhashtag"];
expect(@rewritten_text).to be == "[rewritten]"
end
end
end #}}}
describe "rewrite urls" do #{{{
def url; "http://www.google.com"; end
before do
@rewritten_text = Twitter::TwitterText::Rewriter.rewrite_urls(original_text, &method(:block))
end
context "when embedded in plain text" do
def original_text; "On my search engine #{url} I found good links."; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "On my search engine [rewritten] I found good links."
end
end
context "when surrounded by Japanese;" do
def original_text; "いまなにしてる#{url}いまなにしてる"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "いまなにしてる[rewritten]いまなにしてる"
end
end
context "with a path surrounded by parentheses;" do
def original_text; "I found a neatness (#{url})"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "I found a neatness ([rewritten])"
end
context "when the URL ends with a slash;" do
def url; "http://www.google.com/"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "I found a neatness ([rewritten])"
end
end
context "when the URL has a path;" do
def url; "http://www.google.com/fsdfasdf"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "I found a neatness ([rewritten])"
end
end
end
context "when path contains parens" do
def original_text; "I found a neatness (#{url})"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "I found a neatness ([rewritten])"
end
context "wikipedia" do
def url; "http://en.wikipedia.org/wiki/Madonna_(artist)"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "I found a neatness ([rewritten])"
end
end
context "IIS session" do
def url; "http://msdn.com/S(deadbeef)/page.htm"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "I found a neatness ([rewritten])"
end
end
context "unbalanced parens" do
def url; "http://example.com/i_has_a_("; end
it "should be rewritten" do
expect(@block_args).to be == ["http://example.com/i_has_a_"];
expect(@rewritten_text).to be == "I found a neatness ([rewritten]()"
end
end
context "balanced parens with a double quote inside" do
def url; "http://foo.bar.com/foo_(\")_bar" end
it "should be rewritten" do
expect(@block_args).to be == ["http://foo.bar.com/foo_"];
expect(@rewritten_text).to be == "I found a neatness ([rewritten](\")_bar)"
end
end
context "balanced parens hiding XSS" do
def url; 'http://x.xx.com/("style="color:red"onmouseover="alert(1)' end
it "should be rewritten" do
expect(@block_args).to be == ["http://x.xx.com/"];
expect(@rewritten_text).to be == 'I found a neatness ([rewritten]("style="color:red"onmouseover="alert(1))'
end
end
end
context "when preceded by a :" do
def original_text; "Check this out @hoverbird:#{url}"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "Check this out @hoverbird:[rewritten]"
end
end
context "with a URL ending in allowed punctuation" do
it "does not consume ending punctuation" do
%w| ? ! , . : ; ] ) } = \ ' |.each do |char|
expect(Twitter::TwitterText::Rewriter.rewrite_urls("#{url}#{char}") do |url|
expect(url).to be == url
"[rewritten]"
end).to be == "[rewritten]#{char}"
end
end
end
context "with a URL preceded in forbidden characters" do
it "should be rewritten" do
%w| \ ' / ! = |.each do |char|
expect(Twitter::TwitterText::Rewriter.rewrite_urls("#{char}#{url}") do |url|
"[rewritten]" # should not be called here.
end).to be == "#{char}[rewritten]"
end
end
end
context "when embedded in a link tag" do
def original_text; "#{url}"; end
it "should be rewritten" do
expect(@block_args).to be == [url];
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with multiple URLs" do
def original_text; "http://www.links.org link at start of page, link at end http://www.foo.org"; end
it "should autolink each one" do
expect(@block_args).to be == [["http://www.links.org"], ["http://www.foo.org"]];
expect(@rewritten_text).to be == "[rewritten] link at start of page, link at end [rewritten]"
end
end
context "with multiple URLs in different formats" do
def original_text; "http://foo.com https://bar.com http://mail.foobar.org"; end
it "should autolink each one, in the proper order" do
expect(@block_args).to be == [["http://foo.com"], ["https://bar.com"], ["http://mail.foobar.org"]];
expect(@rewritten_text).to be == "[rewritten] [rewritten] [rewritten]"
end
end
context "with a URL having a long TLD" do
def original_text; "Yahoo integriert Facebook http://golem.mobi/0912/71607.html"; end
it "should autolink it" do
expect(@block_args).to be == ["http://golem.mobi/0912/71607.html"]
expect(@rewritten_text).to be == "Yahoo integriert Facebook [rewritten]"
end
end
context "with a url lacking the protocol" do
def original_text; "I like www.foobar.com dudes"; end
it "does not link at all" do
expect(@block_args).to be nil
expect(@rewritten_text).to be == "I like www.foobar.com dudes"
end
end
context "with a @ in a URL" do
context "with XSS attack" do
def original_text; 'http://x.xx.com/@"style="color:pink"onmouseover=alert(1)//'; end
it "should not allow XSS follwing @" do
expect(@block_args).to be == ["http://x.xx.com/"]
expect(@rewritten_text).to be == '[rewritten]@"style="color:pink"onmouseover=alert(1)//'
end
end
context "with a username not followed by a /" do
def original_text; "http://example.com/@foobar"; end
it "should link url" do
expect(@block_args).to be == ["http://example.com/@foobar"]
expect(@rewritten_text).to be == "[rewritten]"
end
end
context "with a username followed by a /" do
def original_text; "http://example.com/@foobar/"; end
it "should not link the username but link full url" do
expect(@block_args).to be == ["http://example.com/@foobar/"]
expect(@rewritten_text).to be == "[rewritten]"
end
end
end
end #}}}
end
# vim: foldmethod=marker