# frozen_string_literal: true describe Diaspora::MessageRenderer do def message(text, opts={}) Diaspora::MessageRenderer.new(text, opts) end describe '#title' do context 'when :length is passed in parameters' do it 'returns string of size less or equal to :length' do string_size = 12 title = message("## This is a really, really, really long title\n Post content").title(length: string_size) expect(title.size).to be <= string_size end end context 'when :length is not passed in parameters' do context 'with a Markdown header of less than 200 characters on first line' do it 'returns atx style header' do expect(message("## My title\n Post content...").title).to eq "My title" expect(message("## My title ##\n Post content...").title).to eq "My title" end it 'returns setext style header' do expect(message("My title \n======\n Post content...").title).to eq "My title" end it 'returns header without markdown' do expect(message("## **[My title](http://diasporafoundation.org)**\n Post content...").title).to eq "My title (http://diasporafoundation.org)" end end context "without a Markdown header of less than 200 characters on first line" do it "truncates posts to the 70 first characters" do text = "Chillwave heirloom small batch semiotics, brunch cliche yr gluten-free whatever bitters selfies." expect(message(text).title).to eq "Chillwave heirloom small batch semiotics, brunch cliche yr gluten-f..." end end end end describe '#html' do it 'escapes the message' do xss = " " expect(message(xss).html).to_not include xss end it 'is html_safe' do expect(message("hey guys").html).to be_html_safe end it 'should leave HTML entities intact' do entities = '& ß ' ' "' expect(message(entities).html).to eq entities end it 'normalizes' do expect( message("\u202a#\u200eUSA\u202c").markdownified ).to eq %(

#USA

\n) end context 'with mentions' do it 'makes hovercard links for mentioned people' do expect( message( "@{Bob; #{bob.person.diaspora_handle}}", mentioned_people: [bob.person] ).html ).to include 'hovercard' end it 'makes plaintext out of mentions of people not in the posts aspects' do expect( message("@{Bob; #{bob.person.diaspora_handle}}").html ).to_not include 'href' end context 'linking all mentions' do it 'makes plain links for people not in the post aspects' do message = message("@{Bob; #{bob.person.diaspora_handle}}", link_all_mentions: true).html expect(message).to_not include 'hovercard' expect(message).to include '/u/bob' end it "makes no hovercards if they're disabled" do message = message( "@{Bob; #{bob.person.diaspora_handle}}", mentioned_people: [bob.person], disable_hovercards: true ).html expect(message).to_not include 'hovercard' expect(message).to include '/u/bob' end end end context "with diaspora:// links" do it "replaces diaspora:// links with pod-local links" do target = FactoryGirl.create(:status_message) expect( message("Have a look at diaspora://#{target.diaspora_handle}/post/#{target.guid}.").html ).to match(/Have a look at #{AppConfig.url_to("/posts/#{target.guid}")}./) end it "doesn't touch invalid diaspora:// links" do text = "You can create diaspora://author/type/guid links!" expect(message(text).html).to match(/#{text}/) end it "ignores a diaspora:// links with a unknown guid" do text = "Try this: `diaspora://unknown@localhost:3000/post/thislookslikeavalidguid123456789`" expect(message(text).html).to match(/#{text}/) end it "ignores a diaspora:// links with an invalid entity type" do target = FactoryGirl.create(:status_message) text = "Try this: `diaspora://#{target.diaspora_handle}/posts/#{target.guid}`" expect(message(text).html).to match(/#{text}/) end end end describe "#markdownified" do describe "not doing something dumb" do it "strips out script tags" do expect( message("").markdownified ).to eq "

alert('XSS is evil')

\n" end it 'strips onClick handlers from links' do expect( message('[XSS](http://joindiaspora.com/" onClick="$\(\'a\'\).remove\(\))').markdownified ).to_not match(/ onClick/i) end end it 'does not barf if message is nil' do expect(message(nil).markdownified).to eq '' end it 'autolinks standard url links' do expect( message("http://joindiaspora.com/").markdownified ).to include 'href="http://joindiaspora.com/"' end it "normalizes" do { "\u202a#\u200eUSA\u202c" => "

#USA

\n", "ള്‍" => "

ള്‍

\n" }.each do |input, output| expect(message(input).markdownified).to eq output end end context 'when formatting status messages' do it "should leave tags intact" do expect( message("I love #markdown").markdownified ).to match %r{#markdown} end it 'should leave multi-underscore tags intact' do expect( message("Here is a #multi_word tag").markdownified ).to match %r{Here is a #multi_word tag} expect( message("Here is a #multi_word_tag yo").markdownified ).to match %r{Here is a #multi_word_tag yo} end it "should leave mentions intact" do expect( message("Hey @{Bob; #{bob.diaspora_handle}}!", mentioned_people: [bob.person]).markdownified ).to match(/hovercard/) end it "should leave mentions intact for real diaspora handles" do new_person = FactoryGirl.create(:person, diaspora_handle: 'maxwell@joindiaspora.com') expect( message( "Hey @{maxwell@joindiaspora.com; #{new_person.diaspora_handle}}!", mentioned_people: [new_person] ).markdownified ).to match(/hovercard/) end it 'should process text with both a hashtag and a link' do expect( message("Test #tag?\nhttps://joindiaspora.com\n").markdownified ).to eq %{

Test #tag?
\nhttps://joindiaspora.com

\n} end it 'should process text with a header' do expect(message("# I love markdown").markdownified).to match "I love markdown" end it 'should leave HTML entities intact' do entities = '& ß ' ' "' expect(message(entities).markdownified).to eq "

#{entities}

\n" end context "with diaspora:// links" do it "replaces diaspora:// links with pod-local links" do target1 = FactoryGirl.create(:status_message) target2 = FactoryGirl.create(:status_message) text = "Have a look at [this post](diaspora://#{target1.diaspora_handle}/post/#{target1.guid}) and " \ "this one too diaspora://#{target2.diaspora_handle}/post/#{target2.guid}." rendered = message(text).markdownified expect(rendered).to match(%r{at this post and}) expect(rendered).to match(/this one too #{AppConfig.url_to("/posts/#{target2.guid}")}./) end it "doesn't touch invalid diaspora:// links" do text = "You can create diaspora://author/type/guid links!" expect(message(text).markdownified).to match(/#{text}/) end end end end describe "#plain_text_without_markdown" do it 'does not remove markdown in links' do text = "some text and here comes http://exampe.org/foo_bar_baz a link" expect(message(text).plain_text_without_markdown).to eq text end it 'does not destroy hashtag that starts a line' do text = "#hashtag message" expect(message(text).plain_text_without_markdown).to eq text end context "with mention" do it "contains the name of the mentioned person" do msg = message("@{#{alice.diaspora_handle}} is cool", mentioned_people: alice.person) expect(msg.plain_text_without_markdown).to eq "@#{alice.name} is cool" end it "uses the name from mention when the mention contains a name" do msg = message("@{Alice; #{alice.diaspora_handle}} is cool", mentioned_people: alice.person) expect(msg.plain_text_without_markdown).to eq "@Alice is cool" end it "uses the diaspora ID when the person cannot be found" do msg = message("@{#{alice.diaspora_handle}} is cool", mentioned_people: []) expect(msg.plain_text_without_markdown).to eq "@#{alice.diaspora_handle} is cool" end end context "with diaspora:// links" do it "replaces diaspora:// links with pod-local links" do target1 = FactoryGirl.create(:status_message) target2 = FactoryGirl.create(:status_message) text = "Have a look at [this post](diaspora://#{target1.diaspora_handle}/post/#{target1.guid}) and " \ "this one too diaspora://#{target2.diaspora_handle}/post/#{target2.guid}." rendered = message(text).plain_text_without_markdown expect(rendered).to match(/look at this post \(#{AppConfig.url_to("/posts/#{target1.guid}")}\) and/) expect(rendered).to match(/this one too #{AppConfig.url_to("/posts/#{target2.guid}")}./) end it "doesn't touch invalid diaspora:// links" do text = "You can create diaspora://author/type/guid links!" expect(message(text).plain_text_without_markdown).to match(/#{text}/) end end end describe "#urls" do it "extracts the urls from the raw message" do text = "[Perdu](http://perdu.com/) and [DuckDuckGo](https://duckduckgo.com/) can help you" expect(message(text).urls).to eql ["http://perdu.com/", "https://duckduckgo.com/"] end it "extracts urls from continous markdown correctly" do text = "[![Image](https://www.antifainfoblatt.de/sites/default/files/public/styles/front_full/public/jockpalfreeman.png?itok=OPjHKpmt)](https://www.antifainfoblatt.de/artikel/%E2%80%9Eschlie%C3%9Flich-waren-es-zu-viele%E2%80%9C)" expect(message(text).urls).to eq ["https://www.antifainfoblatt.de/sites/default/files/public/styles/front_full/public/jockpalfreeman.png?itok=OPjHKpmt", "https://www.antifainfoblatt.de/artikel/%E2%80%9Eschlie%C3%9Flich-waren-es-zu-viele%E2%80%9C"] end it "encodes extracted urls" do url = "http://www.example.com/url/with/umlauts/ä/index.html" expect(message(url).urls).to eq ["http://www.example.com/url/with/umlauts/%C3%A4/index.html"] end it "not double encodes an already encoded url" do encoded_url = "http://www.example.com/url/with/umlauts/%C3%A4/index.html" expect(message(encoded_url).urls).to eq [encoded_url] end it "parses IDN correctly" do url = "http://www.hören.at/" expect(message(url).urls).to eq ["http://www.xn--hren-5qa.at/"] end end describe "#plain_text_for_json" do it "normalizes" do { "\u202a#\u200eUSA\u202c" => "#USA", "ള്‍" => "ള്‍" }.each do |input, output| expect(message(input).plain_text_for_json).to eq output end end context "with diaspora:// links" do it "replaces diaspora:// links with pod-local links" do target1 = FactoryGirl.create(:status_message) target2 = FactoryGirl.create(:status_message) text = "Have a look at [this post](diaspora://#{target1.diaspora_handle}/post/#{target1.guid}) and " \ "this one too diaspora://#{target2.diaspora_handle}/post/#{target2.guid}." rendered = message(text).plain_text_for_json expect(rendered).to match(/look at \[this post\]\(#{AppConfig.url_to("/posts/#{target1.guid}")}\) and/) expect(rendered).to match(/this one too #{AppConfig.url_to("/posts/#{target2.guid}")}./) end it "doesn't touch invalid diaspora:// links" do text = "You can create diaspora://author/type/guid links!" expect(message(text).plain_text_for_json).to match(/#{text}/) end end end end