require 'rails_helper'

RSpec.describe Preview::ThumbnailFetcher do
  describe '.fetch' do
    it 'accepts svg thumbnails for the common safe rasterisation path' do
      page = Preview::HttpFetcher::Response.new(
          '<meta property="og:image" content="https://example.com/thumb.svg">',
          'text/html',
          'https://example.com/page')
      svg = Preview::HttpFetcher::Response.new(
          '<svg></svg>',
          'image/svg+xml',
          'https://example.com/thumb.svg')

      allow(Preview::UrlSafety).to receive(:validate) do |url|
        [URI.parse(url), ['203.0.113.10']]
      end
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/page', max_bytes: described_class::HTML_MAX_BYTES)
          .and_return(page)
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/thumb.svg')
          .and_return(svg)

      expect(described_class.fetch('https://example.com/page')).to eq('<svg></svg>')
    end

    it 'accepts allowed image content type with parameters' do
      page = Preview::HttpFetcher::Response.new(
          '<meta property="og:image" content="https://example.com/thumb.jpg">',
          'text/html',
          'https://example.com/page')
      image = Preview::HttpFetcher::Response.new(
          "\xFF\xD8\xFFjpeg-bytes".b,
          'image/jpeg; charset=binary',
          'https://example.com/thumb.jpg')

      allow(Preview::UrlSafety).to receive(:validate) do |url|
        [URI.parse(url), ['203.0.113.10']]
      end
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/page', max_bytes: described_class::HTML_MAX_BYTES)
          .and_return(page)
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/thumb.jpg')
          .and_return(image)

      expect(described_class.fetch('https://example.com/page'))
          .to eq("\xFF\xD8\xFFjpeg-bytes".b)
    end
  end

  describe '.fetch_image_response' do
    it 'rejects an unsafe input URL before HTTP fetch' do
      allow(Preview::UrlSafety).to receive(:validate)
          .and_raise(Preview::UrlSafety::UnsafeUrl, '安全でない接続先は使用できません．')
      expect(Preview::HttpFetcher).not_to receive(:fetch)

      expect {
        described_class.fetch_image_response('https://unsafe.example.com/thumb.jpg')
      }.to raise_error(Preview::UrlSafety::UnsafeUrl, '安全でない接続先は使用できません．')
    end

    it 'rejects an unsafe redirect target' do
      allow(Preview::UrlSafety).to receive(:validate)
          .and_return([URI.parse('https://example.com/thumb.jpg'), ['8.8.8.8']])
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/thumb.jpg')
          .and_raise(Preview::UrlSafety::UnsafeUrl, '安全でない接続先は使用できません．')

      expect {
        described_class.fetch_image_response('https://example.com/thumb.jpg')
      }.to raise_error(Preview::UrlSafety::UnsafeUrl, '安全でない接続先は使用できません．')
    end

    it 'rejects an oversized image response' do
      allow(Preview::UrlSafety).to receive(:validate)
          .and_return([URI.parse('https://example.com/thumb.jpg'), ['8.8.8.8']])
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/thumb.jpg')
          .and_raise(Preview::HttpFetcher::ResponseTooLarge, 'too large')

      expect {
        described_class.fetch_image_response('https://example.com/thumb.jpg')
      }.to raise_error(Preview::HttpFetcher::ResponseTooLarge)
    end

    it 'rejects a non-image content type' do
      allow(Preview::UrlSafety).to receive(:validate)
          .and_return([URI.parse('https://example.com/thumb.jpg'), ['8.8.8.8']])
      allow(Preview::HttpFetcher).to receive(:fetch)
          .with('https://example.com/thumb.jpg')
          .and_return(
              Preview::HttpFetcher::Response.new(
                  '<html></html>',
                  'text/html',
                  'https://example.com/thumb.jpg'))

      expect {
        described_class.fetch_image_response('https://example.com/thumb.jpg')
      }.to raise_error(Preview::ThumbnailFetcher::GenerationFailed)
    end
  end
end
