require "spec_helper" require "cooked_post_processor" describe CookedPostProcessor do context ".post_process" do let(:post) { build(:post) } let(:cpp) { CookedPostProcessor.new(post) } let(:post_process) { sequence("post_process") } it "post process in sequence" do cpp.expects(:keep_reverse_index_up_to_date).in_sequence(post_process) cpp.expects(:post_process_images).in_sequence(post_process) cpp.expects(:post_process_oneboxes).in_sequence(post_process) cpp.expects(:optimize_urls).in_sequence(post_process) cpp.expects(:pull_hotlinked_images).in_sequence(post_process) cpp.post_process end end context ".keep_reverse_index_up_to_date" do let(:post) { build(:post_with_uploads, id: 123) } let(:cpp) { CookedPostProcessor.new(post) } it "finds all the uploads in the post" do Upload.expects(:get_from_url).with("/uploads/default/2/2345678901234567.jpg") Upload.expects(:get_from_url).with("/uploads/default/1/1234567890123456.jpg") cpp.keep_reverse_index_up_to_date end it "cleans the reverse index up for the current post" do PostUpload.expects(:delete_all).with(post_id: post.id) cpp.keep_reverse_index_up_to_date end end context ".post_process_images" do context "with image_sizes" do let(:post) { build(:post_with_image_url) } let(:cpp) { CookedPostProcessor.new(post, image_sizes: {"http://foo.bar/image.png" => {"width" => 111, "height" => 222}}) } it "adds the width from the image sizes provided" do cpp.post_process_images cpp.html.should =~ /width=\"111\"/ cpp.should be_dirty end end context "with unsized images" do let(:post) { build(:post_with_unsized_images) } let(:cpp) { CookedPostProcessor.new(post) } it "adds the width and height to images that don't have them" do FastImage.expects(:size).returns([123, 456]) cpp.post_process_images cpp.html.should =~ /width="123" height="456"/ cpp.should be_dirty end end context "with large images" do let(:upload) { Fabricate(:upload) } let(:post) { build(:post_with_large_image) } let(:cpp) { CookedPostProcessor.new(post) } before do SiteSetting.stubs(:max_image_height).returns(2000) SiteSetting.stubs(:create_thumbnails?).returns(true) Upload.expects(:get_from_url).returns(upload) FastImage.stubs(:size).returns([1000, 2000]) # optimized_image FileUtils.stubs(:mkdir_p) File.stubs(:open) ImageSorcery.any_instance.expects(:convert).returns(true) end it "generates overlay information" do cpp.post_process_images cpp.html.should match_html '
' cpp.should be_dirty end end context "topic image" do let(:topic) { build(:topic, id: 1) } let(:post) { Fabricate(:post_with_uploaded_image, topic: topic) } let(:cpp) { CookedPostProcessor.new(post) } it "adds a topic image if there's one in the post" do FastImage.stubs(:size) post.topic.image_url.should be_nil cpp.post_process_images post.topic.reload post.topic.image_url.should be_present end end end context ".extract_images" do let(:post) { build(:post_with_images_in_quote_and_onebox) } let(:cpp) { CookedPostProcessor.new(post) } it "does not extract images inside oneboxes or quotes" do cpp.extract_images.length.should == 0 end end context ".get_size_from_image_sizes" do let(:post) { build(:post) } let(:cpp) { CookedPostProcessor.new(post) } it "returns the size" do image_sizes = { "http://my.discourse.org/image.png" => { "width" => 111, "height" => 222 } } cpp.get_size_from_image_sizes("/image.png", image_sizes).should == [111, 222] end end context ".get_size" do let(:post) { build(:post) } let(:cpp) { CookedPostProcessor.new(post) } it "ensures urls are absolute" do cpp.expects(:is_valid_image_url?).with("http://test.localhost/relative/url/image.png") cpp.get_size("/relative/url/image.png") end it "ensures urls have a default scheme" do cpp.expects(:is_valid_image_url?).with("http://schemaless.url/image.jpg") cpp.get_size("//schemaless.url/image.jpg") end it "caches the results" do SiteSetting.stubs(:crawl_images?).returns(true) FastImage.expects(:size).returns([200, 400]) cpp.get_size("http://foo.bar/image3.png") cpp.get_size("http://foo.bar/image3.png").should == [200, 400] end context "when crawl_images is disabled" do before { SiteSetting.stubs(:crawl_images?).returns(false) } it "doesn't call FastImage" do FastImage.expects(:size).never cpp.get_size("http://foo.bar/image1.png").should == nil end it "is always allowed to crawl our own images" do store = stub store.expects(:has_been_uploaded?).returns(true) Discourse.expects(:store).returns(store) FastImage.expects(:size).returns([100, 200]) cpp.get_size("http://foo.bar/image2.png").should == [100, 200] end end end context ".is_valid_image_url?" do let(:post) { build(:post) } let(:cpp) { CookedPostProcessor.new(post) } it "validates HTTP(s) urls" do cpp.is_valid_image_url?("http://domain.com").should == true cpp.is_valid_image_url?("https://domain.com").should == true end it "doesn't validate other urls" do cpp.is_valid_image_url?("ftp://domain.com").should == false cpp.is_valid_image_url?("ftps://domain.com").should == false cpp.is_valid_image_url?("/tmp/image.png").should == false cpp.is_valid_image_url?("//domain.com").should == false end it "doesn't throw an exception with a bad URI" do cpp.is_valid_image_url?("http://do