<commit_before>require 'fileutils'
require 'algoliasearch'
require 'concurrent'
require 'typhoeus'
require File.expand_path('../spec_helper', __FILE__)

module Mocha
  class Expectation
    def with_url(expected_url)
      with { |url, _| url == expected_url }
    end
  end
end

module Pod
  describe CDNSource do
    before do
      def canonical_file(relative_path)
        @remote_dir.join(relative_path)
      end

      def read_canonical_file(relative_path)
        File.read(canonical_file(relative_path))
      end

      def get_etag(relative_path)
        path = @source.repo.join(relative_path)
        etag_path = path.sub_ext(path.extname + '.etag')
        File.read(etag_path) if File.exist?(etag_path)
      end

      def all_local_files
        [@source.repo.join('**/*.yml'), @source.repo.join('**/*.txt'), @source.repo.join('**/*.json')].map(&Pathname.method(:glob)).flatten
      end

      def save_url(url)
        @url = url
        File.open(@path.join('.url'), 'w') { |f| f.write(url) }
      end

      def cleanup
        Pathname.glob(@path.join('*')).each(&:rmtree)
        @path.join('.url').delete if @path.join('.url').exist?
        ENV['NETRC'] = nil
      end

      def print_dir(tag)
        STDERR.puts tag
        STDERR.puts Pathname.glob(@path.join('*')).sort.join("\n")
      end

      def fulfilled_future(result)
        Concurrent::Promises.fulfilled_future(result)
      end

      def resolved_event
        Concurrent::Promises.resolved_event
      end

      def typhoeus_http_response_future(code, headers = {}, body = '')
        fulfilled_future(Typhoeus::Response.new(
                           :response_code => code,
                           :headers => headers,
                           :response_body => body,
        ))
      end

      def typhoeus_non_http_response_future(code)
        fulfilled_future(Typhoeus::Response.new(
                           :response_code => 0,
                           :return_code => code,
        ))
      end

      @remote_dir = fixture('mock_cdn_repo_remote')

      @path = fixture('spec-repos/test_cdn_repo_local')
      cleanup
      save_url('http://localhost:4321/')

      @source = CDNSource.new(@path)
    end

    after do
      cleanup
    end

    #-------------------------------------------------------------------------#

    describe 'In general' do
      it 'return its name' do
        @source.name.should == 'test_cdn_repo_local'
      end

      it 'return its type' do
        @source.type.should == 'CDN'
      end

      it 'works when the root URL has a trailing slash' do
        save_url('http://localhost:4321/')
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/'
      end

      it 'works when the root URL has a trailing path' do
        save_url('http://localhost:4321/trail/ing/path/')
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/trail/ing/path/'
      end

      it 'works when the root URL has no trailing slash' do
        save_url('http://localhost:4321')
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/'
      end

      it 'works when the root URL file has a newline' do
        save_url("http://localhost:4321/\n")
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/'
      end
    end

    #-------------------------------------------------------------------------#

    describe '#pods' do
      it 'returns the available Pods' do
        @source.pods.should == %w(BeaconKit SDWebImage)
      end

      it "raises if the repo doesn't exist" do
        path = fixture('spec-repos/non_existing')
        @source = CDNSource.new(path)
        @source.metadata.should.be.nil?
      end
    end

    #-------------------------------------------------------------------------#

    describe '#versions' do
      extend SpecHelper::TemporaryDirectory

      it 'returns the available versions of a Pod' do
        @source.versions('BeaconKit').map(&:to_s).should == %w(1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0)
      end

      it 'returns nil if the Pod could not be found' do
        @source.versions('Unknown_Pod').should.be.nil
      end

      it 'does not error when a Pod name need URI escaping' do
        @source.versions('СерафимиМногоꙮчитїи').map(&:to_s).should == %w(1.0.0)
        @source.specification('СерафимиМногоꙮчитїи', '1.0.0').name.should == 'СерафимиМногоꙮчитїи'
      end

      it 'uses netrc when provided' do
        save_url('http://localhost:4321/authorization')
        @source = CDNSource.new(@path)

        netrc_file = temporary_directory + '.netrc'
        File.open(netrc_file, 'w') { |f| f.write("machine localhost\nlogin user1\npassword <PASSWORD>") }

        ENV['NETRC'] = temporary_directory.to_s
        auth = nil
        CDN_MOCK_SERVER.mount_proc('/authorization') do |req, res|
          auth = req['Authorization']
          res.body = ''
        end
        @source.versions('Unknown_Pod').should.be.nil
        auth.should == 'Basic dXNlcjE6eHh4'
      end

      it 'handles redirects' do
        relative_path = 'all_pods_versions_2_0_9.txt'
        original_url = 'http://localhost:4321/' + relative_path
        redirect_url = 'http://localhost:4321/redirected/' + relative_path
        @source.expects(:download_typhoeus_impl_async).
          with_url(original_url).
          returns(typhoeus_http_response_future(301, 'location' => redirect_url))
        @source.expects(:download_typhoeus_impl_async).
          with_url(redirect_url).
          returns(typhoeus_http_response_future(200, {}, 'BeaconKit/1.0.0'))
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json').
          returns(typhoeus_http_response_future(200, {}, ''))

        @source.expects(:debug).with { |cmd| cmd.include? "CDN: #{@source.name} Relative path downloaded: all_pods_versions_2_0_9.txt, save ETag:" }
        @source.expects(:debug).with("CDN: #{@source.name} Redirecting from #{original_url} to #{redirect_url}")
        @source.expects(:debug).with { |cmd| cmd.include? "CDN: #{@source.name} Relative path downloaded: Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json, save ETag:" }
        @source.versions('BeaconKit').map(&:to_s).should == %w(1.0.0)
      end

      it 'handles responses with no headers' do
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/all_pods_versions_2_0_9.txt').
          returns(typhoeus_http_response_future(200, nil, 'BeaconKit/1.0.0'))
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json').
          returns(typhoeus_http_response_future(200, nil, '{}'))
        should.not.raise do
          @source.versions('BeaconKit')
        end
      end

      it 'raises if unexpected HTTP error' do
        @source.expects(:download_typhoeus_impl_async).
          returns(typhoeus_http_response_future(500))<commit_msg>Test for UTF-8 encoding the typhoeus response body<commit_after>require 'fileutils'
require 'algoliasearch'
require 'concurrent'
require 'typhoeus'
require File.expand_path('../spec_helper', __FILE__)

module Mocha
  class Expectation
    def with_url(expected_url)
      with { |url, _| url == expected_url }
    end
  end
end

module Pod
  describe CDNSource do
    before do
      def canonical_file(relative_path)
        @remote_dir.join(relative_path)
      end

      def read_canonical_file(relative_path)
        File.read(canonical_file(relative_path))
      end

      def get_etag(relative_path)
        path = @source.repo.join(relative_path)
        etag_path = path.sub_ext(path.extname + '.etag')
        File.read(etag_path) if File.exist?(etag_path)
      end

      def all_local_files
        [@source.repo.join('**/*.yml'), @source.repo.join('**/*.txt'), @source.repo.join('**/*.json')].map(&Pathname.method(:glob)).flatten
      end

      def save_url(url)
        @url = url
        File.open(@path.join('.url'), 'w') { |f| f.write(url) }
      end

      def cleanup
        Pathname.glob(@path.join('*')).each(&:rmtree)
        @path.join('.url').delete if @path.join('.url').exist?
        ENV['NETRC'] = nil
      end

      def print_dir(tag)
        STDERR.puts tag
        STDERR.puts Pathname.glob(@path.join('*')).sort.join("\n")
      end

      def fulfilled_future(result)
        Concurrent::Promises.fulfilled_future(result)
      end

      def resolved_event
        Concurrent::Promises.resolved_event
      end

      def typhoeus_http_response_future(code, headers = {}, body = '')
        fulfilled_future(Typhoeus::Response.new(
                           :response_code => code,
                           :headers => headers,
                           :response_body => body,
        ))
      end

      def typhoeus_non_http_response_future(code)
        fulfilled_future(Typhoeus::Response.new(
                           :response_code => 0,
                           :return_code => code,
        ))
      end

      @remote_dir = fixture('mock_cdn_repo_remote')

      @path = fixture('spec-repos/test_cdn_repo_local')
      cleanup
      save_url('http://localhost:4321/')

      @source = CDNSource.new(@path)
    end

    after do
      cleanup
    end

    #-------------------------------------------------------------------------#

    describe 'In general' do
      it 'return its name' do
        @source.name.should == 'test_cdn_repo_local'
      end

      it 'return its type' do
        @source.type.should == 'CDN'
      end

      it 'works when the root URL has a trailing slash' do
        save_url('http://localhost:4321/')
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/'
      end

      it 'works when the root URL has a trailing path' do
        save_url('http://localhost:4321/trail/ing/path/')
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/trail/ing/path/'
      end

      it 'works when the root URL has no trailing slash' do
        save_url('http://localhost:4321')
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/'
      end

      it 'works when the root URL file has a newline' do
        save_url("http://localhost:4321/\n")
        @source = CDNSource.new(@path)
        @source.url.should == 'http://localhost:4321/'
      end
    end

    #-------------------------------------------------------------------------#

    describe '#pods' do
      it 'returns the available Pods' do
        @source.pods.should == %w(BeaconKit SDWebImage)
      end

      it "raises if the repo doesn't exist" do
        path = fixture('spec-repos/non_existing')
        @source = CDNSource.new(path)
        @source.metadata.should.be.nil?
      end
    end

    #-------------------------------------------------------------------------#

    describe '#versions' do
      extend SpecHelper::TemporaryDirectory

      it 'returns the available versions of a Pod' do
        @source.versions('BeaconKit').map(&:to_s).should == %w(1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0)
      end

      it 'returns nil if the Pod could not be found' do
        @source.versions('Unknown_Pod').should.be.nil
      end

      it 'does not error when a Pod name need URI escaping' do
        @source.versions('СерафимиМногоꙮчитїи').map(&:to_s).should == %w(1.0.0)
        @source.specification('СерафимиМногоꙮчитїи', '1.0.0').name.should == 'СерафимиМногоꙮчитїи'
      end

      it 'uses netrc when provided' do
        save_url('http://localhost:4321/authorization')
        @source = CDNSource.new(@path)

        netrc_file = temporary_directory + '.netrc'
        File.open(netrc_file, 'w') { |f| f.write("machine localhost\nlogin user1\npassword <PASSWORD>") }

        ENV['NETRC'] = temporary_directory.to_s
        auth = nil
        CDN_MOCK_SERVER.mount_proc('/authorization') do |req, res|
          auth = req['Authorization']
          res.body = ''
        end
        @source.versions('Unknown_Pod').should.be.nil
        auth.should == 'Basic dXNlcjE6eHh4'
      end

      it 'handles redirects' do
        relative_path = 'all_pods_versions_2_0_9.txt'
        original_url = 'http://localhost:4321/' + relative_path
        redirect_url = 'http://localhost:4321/redirected/' + relative_path
        @source.expects(:download_typhoeus_impl_async).
          with_url(original_url).
          returns(typhoeus_http_response_future(301, 'location' => redirect_url))
        @source.expects(:download_typhoeus_impl_async).
          with_url(redirect_url).
          returns(typhoeus_http_response_future(200, {}, 'BeaconKit/1.0.0'))
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json').
          returns(typhoeus_http_response_future(200, {}, ''))

        @source.expects(:debug).with { |cmd| cmd.include? "CDN: #{@source.name} Relative path downloaded: all_pods_versions_2_0_9.txt, save ETag:" }
        @source.expects(:debug).with("CDN: #{@source.name} Redirecting from #{original_url} to #{redirect_url}")
        @source.expects(:debug).with { |cmd| cmd.include? "CDN: #{@source.name} Relative path downloaded: Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json, save ETag:" }
        @source.versions('BeaconKit').map(&:to_s).should == %w(1.0.0)
      end

      it 'handles responses with no headers' do
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/all_pods_versions_2_0_9.txt').
          returns(typhoeus_http_response_future(200, nil, 'BeaconKit/1.0.0'))
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json').
          returns(typhoeus_http_response_future(200, nil, '{}'))
        should.not.raise do
          @source.versions('BeaconKit')
        end
      end

      it 'forces UTF-8 encoding for the body' do
        mock_json_body = mock
        mock_json_body.expects(:force_encoding).with('UTF-8').at_least_once
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/all_pods_versions_2_0_9.txt').
          returns(typhoeus_http_response_future(200, nil, 'BeaconKit/1.0.0'))
        @source.expects(:download_typhoeus_impl_async).
          with_url('http://localhost:4321/Specs/2/0/9/BeaconKit/1.0.0/BeaconKit.podspec.json').
          returns(typhoeus_http_response_future(200, {}, mock_json_body))
        should.not.raise do
          @source.versions('BeaconKit')
        end
      end

      it 'raises if unexpected HTTP error' do
        @source.expects(:download_typhoeus_impl_async).
          returns(typhoeus_http_response_future(500))
{'fraction_non_alphanumeric': 0.15675819781391628, 'fraction_numerical': 0.020861103705678487, 'mean_word_length': 2.261247554879374, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5774182', 'n_tokens_mistral': 5005, 'n_tokens_neox': 4784, 'n_words': 859}