diaspora/spec/models/status_message_spec.rb
Jonne Haß 8280556a47 Introduce message renderer
This new class replaces all existing server side message
rendering helpers and is the new global entry point for such
needs. All models with relevant fields now expose an instance
of MessageRenderer for those. MessageRenderer acts as
gateway between the existing processing solutions for markdown,
mentions and tags and provides a very flexible interface for
all output needs. This makes the API to obtain a message
in a certain format clear. As a result of centralizing the
processing a lot of duplication is eliminated. Centralizing
the message processing also makes it clear where to change
its behaviour, add new representations and what options
are already available.
2014-03-15 17:16:17 +01:00

414 lines
13 KiB
Ruby

# Copyright (c) 2010-2011, Diaspora Inc. This file is
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
require 'spec_helper'
describe StatusMessage do
include PeopleHelper
before do
@user = alice
@aspect = @user.aspects.first
end
describe 'scopes' do
describe '.where_person_is_mentioned' do
it 'returns status messages where the given person is mentioned' do
@bo = bob.person
@test_string = "@{Daniel; #{@bo.diaspora_handle}} can mention people like Raph"
FactoryGirl.create(:status_message, :text => @test_string )
FactoryGirl.create(:status_message, :text => @test_string )
FactoryGirl.create(:status_message)
StatusMessage.where_person_is_mentioned(@bo).count.should == 2
end
end
context "tag_streams" do
before do
@sm1 = FactoryGirl.create(:status_message, :text => "#hashtag" , :public => true)
@sm2 = FactoryGirl.create(:status_message, :text => "#hashtag" )
@sm3 = FactoryGirl.create(:status_message, :text => "hashtags are #awesome", :public => true )
@sm4 = FactoryGirl.create(:status_message, :text => "hashtags are #awesome" )
@tag_id = ActsAsTaggableOn::Tag.where(:name => "hashtag").first.id
end
describe '.tag_steam' do
it 'returns status messages tagged with the tag' do
tag_stream = StatusMessage.send(:tag_stream, [@tag_id])
tag_stream.should include @sm1
tag_stream.should include @sm2
end
end
describe '.public_tag_stream' do
it 'returns public status messages tagged with the tag' do
StatusMessage.public_tag_stream([@tag_id]).should == [@sm1]
end
end
describe '.user_tag_stream' do
it 'returns tag stream thats owned or visibile by' do
StatusMessage.should_receive(:owned_or_visible_by_user).with(bob).and_return(StatusMessage)
StatusMessage.should_receive(:tag_stream).with([@tag_id])
StatusMessage.user_tag_stream(bob, [@tag_id])
end
end
end
end
describe ".guids_for_author" do
it 'returns an array of the status_message guids' do
sm1 = FactoryGirl.create(:status_message, :author => alice.person)
sm2 = FactoryGirl.create(:status_message, :author => bob.person)
guids = StatusMessage.guids_for_author(alice.person)
guids.should == [sm1.guid]
end
end
describe '.before_create' do
it 'calls build_tags' do
status = FactoryGirl.build(:status_message)
status.should_receive(:build_tags)
status.save
end
it 'calls filter_mentions' do
status = FactoryGirl.build(:status_message)
status.should_receive(:filter_mentions)
status.save
end
end
describe '.after_create' do
it 'calls create_mentions' do
status = FactoryGirl.build(:status_message, text: "text @{Test; #{alice.diaspora_handle}}")
status.should_receive(:create_mentions).and_call_original
status.save
end
end
describe '#diaspora_handle=' do
it 'sets #author' do
person = FactoryGirl.create(:person)
post = FactoryGirl.build(:status_message, :author => @user.person)
post.diaspora_handle = person.diaspora_handle
post.author.should == person
end
end
context "emptyness" do
it "needs either a message or at least one photo" do
n = @user.build_post(:status_message, :text => nil)
n.should_not be_valid
n.text = ""
n.should_not be_valid
n.text = "wales"
n.should be_valid
n.text = nil
photo = @user.build_post(:photo, :user_file => uploaded_photo, :to => @aspect.id)
photo.save!
n.photos << photo
n.should be_valid
n.errors.full_messages.should == []
end
it "doesn't check for content when author is remote (federation...)" do
p = FactoryGirl.build(:status_message, text: nil)
p.should be_valid
end
end
it 'should be postable through the user' do
message = "Users do things"
status = @user.post(:status_message, :text => message, :to => @aspect.id)
db_status = StatusMessage.find(status.id)
db_status.text.should == message
end
it 'should require status messages not be more than 65535 characters long' do
message = 'a' * (65535+1)
status_message = FactoryGirl.build(:status_message, :text => message)
status_message.should_not be_valid
end
describe 'mentions' do
before do
@people = [alice, bob, eve].map{|u| u.person}
@test_string = <<-STR
@{Raphael; #{@people[0].diaspora_handle}} can mention people like Raphael @{Ilya; #{@people[1].diaspora_handle}}
can mention people like Raphaellike Raphael @{Daniel; #{@people[2].diaspora_handle}} can mention people like Raph
STR
@sm = FactoryGirl.create(:status_message, :text => @test_string )
end
describe '#create_mentions' do
it 'creates a mention for everyone mentioned in the message' do
Diaspora::Mentionable.should_receive(:people_from_string).and_return(@people)
@sm.mentions.delete_all
@sm.create_mentions
@sm.mentions(true).map{|m| m.person}.to_set.should == @people.to_set
end
it 'does not barf if it gets called twice' do
@sm.create_mentions
expect{
@sm.create_mentions
}.to_not raise_error
end
end
describe '#mentioned_people' do
it 'calls create_mentions if there are no mentions in the db' do
@sm.mentions.delete_all
@sm.should_receive(:create_mentions)
@sm.mentioned_people
end
it 'returns the mentioned people' do
@sm.mentions.delete_all
@sm.mentioned_people.to_set.should == @people.to_set
end
it 'does not call create_mentions if there are mentions in the db' do
@sm.should_not_receive(:create_mentions)
@sm.mentioned_people
end
end
describe "#mentions?" do
it 'returns true if the person was mentioned' do
@sm.mentions?(@people[0]).should be_true
end
it 'returns false if the person was not mentioned' do
@sm.mentions?(FactoryGirl.build(:person)).should be_false
end
end
describe "#notify_person" do
it 'notifies the person mentioned' do
Notification.should_receive(:notify).with(alice, anything, anything)
@sm.notify_person(alice.person)
end
end
describe "#filter_mentions" do
it 'calls Diaspora::Mentionable#filter_for_aspects' do
msg = FactoryGirl.build(:status_message_in_aspect)
msg_txt = msg.raw_message
author_usr = msg.author.owner
aspect_id = author_usr.aspects.first.id
Diaspora::Mentionable.should_receive(:filter_for_aspects)
.with(msg_txt, author_usr, aspect_id)
msg.send(:filter_mentions)
end
it "doesn't do anything when public" do
msg = FactoryGirl.build(:status_message, public: true)
Diaspora::Mentionable.should_not_receive(:filter_for_aspects)
msg.send(:filter_mentions)
end
end
end
describe "#nsfw" do
it 'returns MatchObject (true) if the post contains #nsfw (however capitalised)' do
status = FactoryGirl.build(:status_message, :text => "This message is #nSFw")
status.nsfw.should be_true
end
it 'returns nil (false) if the post does not contain #nsfw' do
status = FactoryGirl.build(:status_message, :text => "This message is #sFW")
status.nsfw.should be_false
end
end
describe 'tags' do
before do
@object = FactoryGirl.build(:status_message)
end
it_should_behave_like 'it is taggable'
it 'associates different-case tags to the same tag entry' do
assert_equal ActsAsTaggableOn.force_lowercase, true
msg_lc = FactoryGirl.build(:status_message, :text => '#newhere')
msg_uc = FactoryGirl.build(:status_message, :text => '#NewHere')
msg_cp = FactoryGirl.build(:status_message, :text => '#NEWHERE')
msg_lc.save; msg_uc.save; msg_cp.save
tag_array = msg_lc.tags
expect(msg_uc.tags).to match_array(tag_array)
expect(msg_cp.tags).to match_array(tag_array)
end
end
describe "XML" do
before do
@message = FactoryGirl.build(:status_message, :text => "I hate WALRUSES!", :author => @user.person)
@xml = @message.to_xml.to_s
end
it 'serializes the escaped, unprocessed message' do
text = "[url](http://example.org)<script> alert('xss should be federated');</script>"
@message.text = text
@message.to_xml.to_s.should include Builder::XChar.encode(text)
end
it 'serializes the message' do
@xml.should include "<raw_message>I hate WALRUSES!</raw_message>"
end
it 'serializes the author address' do
@xml.should include(@user.person.diaspora_handle)
end
describe '.from_xml' do
before do
@marshalled = StatusMessage.from_xml(@xml)
end
it 'marshals the message' do
@marshalled.text.should == "I hate WALRUSES!"
end
it 'marshals the guid' do
@marshalled.guid.should == @message.guid
end
it 'marshals the author' do
@marshalled.author.should == @message.author
end
it 'marshals the diaspora_handle' do
@marshalled.diaspora_handle.should == @message.diaspora_handle
end
end
context 'with some photos' do
before do
@message.photos << FactoryGirl.build(:photo)
@message.photos << FactoryGirl.build(:photo)
@xml = @message.to_xml.to_s
end
it 'serializes the photos' do
@xml.should include "photo"
@xml.should include @message.photos.first.remote_photo_path
end
describe '.from_xml' do
before do
@marshalled = StatusMessage.from_xml(@xml)
end
it 'marshals the photos' do
@marshalled.photos.size.should == 2
end
end
end
context 'with a location' do
before do
@message.location = Location.new(coordinates: "1, 2").tap(&:save)
@xml = @message.to_xml.to_s
end
it 'serializes the location' do
@xml.should include "location"
@xml.should include "lat"
@xml.should include "lng"
end
describe ".from_xml" do
before do
@marshalled = StatusMessage.from_xml(@xml)
end
it 'marshals the location' do
@marshalled.location.should be_present
end
end
end
end
describe '#after_dispatch' do
before do
@photos = [alice.build_post(:photo, :pending => true, :user_file=> File.open(photo_fixture_name)),
alice.build_post(:photo, :pending => true, :user_file=> File.open(photo_fixture_name))]
@photos.each(&:save!)
@status_message = alice.build_post(:status_message, :text => "the best pebble.")
@status_message.photos << @photos
@status_message.save!
alice.add_to_streams(@status_message, alice.aspects)
end
it 'sets pending to false on any attached photos' do
@status_message.after_dispatch(alice)
@photos.all?{|p| p.reload.pending}.should be_false
end
it 'dispatches any attached photos' do
alice.should_receive(:dispatch_post).twice
@status_message.after_dispatch(alice)
end
end
describe 'oembed' do
before do
@youtube_url = "https://www.youtube.com/watch?v=3PtFwlKfvHI"
@message_text = "#{@youtube_url} is so cool. so is this link -> https://joindiaspora.com"
end
it 'should queue a GatherOembedData if it includes a link' do
sm = FactoryGirl.build(:status_message, :text => @message_text)
Workers::GatherOEmbedData.should_receive(:perform_async).with(instance_of(Fixnum), instance_of(String))
sm.save
end
describe '#contains_oembed_url_in_text?' do
it 'returns the oembed urls found in the raw message' do
sm = FactoryGirl.build(:status_message, :text => @message_text)
sm.contains_oembed_url_in_text?.should_not be_nil
sm.oembed_url.should == @youtube_url
end
end
end
describe 'opengraph' do
before do
@ninegag_url = "http://9gag.com/gag/a1AMW16"
@youtube_url = "https://www.youtube.com/watch?v=3PtFwlKfvHI"
@message_text = "#{@ninegag_url} is so cool. so is this link -> https://joindiaspora.com"
@oemessage_text = "#{@youtube_url} is so cool. so is this link -> https://joindiaspora.com"
end
it 'should queue a GatherOpenGraphData if it includes a link' do
sm = FactoryGirl.build(:status_message, :text => @message_text)
Workers::GatherOpenGraphData.should_receive(:perform_async).with(instance_of(Fixnum), instance_of(String))
sm.save
end
describe '#contains_open_graph_url_in_text?' do
it 'returns the opengraph urls found in the raw message' do
sm = FactoryGirl.build(:status_message, :text => @message_text)
sm.contains_open_graph_url_in_text?.should_not be_nil
sm.open_graph_url.should == @ninegag_url
end
it 'returns nil if the link is from trusted oembed provider' do
sm = FactoryGirl.build(:status_message, :text => @oemessage_text)
sm.contains_open_graph_url_in_text?.should be_nil
sm.open_graph_url.should be_nil
end
end
end
end