<commit_before>require 'uri'
require 'email_spec/deliveries'

module EmailSpec

  module Helpers
    include Deliveries

    A_TAG_BEGIN_REGEX = %r{<a[^>]*href=['"]?([^'"]*)['"]?[^>]*>(?:(?!</a>).)*?}
    A_TAG_END_REGEX = %r{(?:(?!</a>).)*?</a>}

    def visit_in_email(link_text, address = '')
      if address.nil? || address.empty?
        email = current_email
      else
        email = find_email!(address)
      end
      visit(parse_email_for_link(email, link_text))
    end

    def click_email_link_matching(regex, email = current_email)
      url = links_in_email(email).detect { |link| link =~ regex }
      raise "No link found matching #{regex.inspect} in #{email.default_part_body}" unless url
      visit request_uri(url)
    end

    def click_first_link_in_email(email = current_email)
      link = links_in_email(email).first
      visit request_uri(link)
    end

    def open_email(address, opts={})
      set_current_email(find_email!(address, opts))
    end

    alias_method :open_email_for, :open_email

    def open_last_email
      set_current_email(last_email_sent)
    end

    def open_last_email_for(address)
      set_current_email(mailbox_for(address).last)
    end

    def current_email(address=nil)
      address = convert_address(address)
      email = address ? email_spec_hash[:current_emails][address] : email_spec_hash[:current_email]
      exception_class = if defined?(RSpec)
        RSpec::Expectations::ExpectationNotMetError
      else
        StandardError
      end
      raise exception_class, "Expected an open email but none was found. Did you forget to call open_email?" unless email
      email
    end

    def current_email_attachments(address=nil)
      current_email(address).attachments || Array.new
    end

    def unread_emails_for(address)
      read_message_ids = read_emails_for(address).map(&:message_id)
      mailbox_for(address).reject { |m| read_message_ids.include?(m.message_id) }
    end

    def read_emails_for(address)
      email_spec_hash[:read_emails][convert_address(address)] ||= []
    end

    # Should be able to accept String or Regexp options.
    def find_email(address, opts={})
      address = convert_address(address)
      if opts[:with_subject]
        expected_subject = (opts[:with_subject].is_a?(String) ? Regexp.escape(opts[:with_subject]) : opts[:with_subject])
        mailbox_for(address).find { |m| m.subject =~ Regexp.new(expected_subject) }
      elsif opts[:with_text]
        expected_text = (opts[:with_text].is_a?(String) ? Regexp.escape(opts[:with_text]) : opts[:with_text])
        mailbox_for(address).find { |m| m.default_part_body =~ Regexp.new(expected_text) }
      elsif opts[:from]
        mailbox_for(address).find { |m| m.from.include? opts[:from] }
      else
        mailbox_for(address).first
      end
    end

    def links_in_email(email)
      links = URI::Parser.new.extract(email.default_part_body.to_s, ['http', 'https'])
      links.map{|url| HTMLEntities.new.decode(url) }.uniq
    end

    private

    def email_spec_hash
      @email_spec_hash ||= {:read_emails => {}, :unread_emails => {}, :current_emails => {}, :current_email => nil}
    end

    def find_email!(address, opts={})
      email = find_email(address, opts)
      if current_email_address.nil?
        raise EmailSpec::NoEmailAddressProvided, "No email address has been provided. Make sure current_email_address is returning something."
      elsif email.nil?
        error = "#{opts.keys.first.to_s.gsub("_", " ").downcase unless opts.empty?} #{('"' + opts.values.first.to_s + '"') unless opts.empty?}"
        raise EmailSpec::CouldNotFindEmailError, "Could not find email #{error} in the mailbox for #{current_email_address}. \n Found the following emails:\n\n #{all_emails.to_s}"
       end
      email
    end

    def set_current_email(email)
      return unless email
      [email.to, email.cc, email.bcc].compact.flatten.each do |to|
        read_emails_for(to) << email
        email_spec_hash[:current_emails][to] = email
      end<commit_msg>Suppress `warning: mismatched indentations at 'end' with 'if' at 100`<commit_after>require 'uri'
require 'email_spec/deliveries'

module EmailSpec

  module Helpers
    include Deliveries

    A_TAG_BEGIN_REGEX = %r{<a[^>]*href=['"]?([^'"]*)['"]?[^>]*>(?:(?!</a>).)*?}
    A_TAG_END_REGEX = %r{(?:(?!</a>).)*?</a>}

    def visit_in_email(link_text, address = '')
      if address.nil? || address.empty?
        email = current_email
      else
        email = find_email!(address)
      end
      visit(parse_email_for_link(email, link_text))
    end

    def click_email_link_matching(regex, email = current_email)
      url = links_in_email(email).detect { |link| link =~ regex }
      raise "No link found matching #{regex.inspect} in #{email.default_part_body}" unless url
      visit request_uri(url)
    end

    def click_first_link_in_email(email = current_email)
      link = links_in_email(email).first
      visit request_uri(link)
    end

    def open_email(address, opts={})
      set_current_email(find_email!(address, opts))
    end

    alias_method :open_email_for, :open_email

    def open_last_email
      set_current_email(last_email_sent)
    end

    def open_last_email_for(address)
      set_current_email(mailbox_for(address).last)
    end

    def current_email(address=nil)
      address = convert_address(address)
      email = address ? email_spec_hash[:current_emails][address] : email_spec_hash[:current_email]
      exception_class = if defined?(RSpec)
        RSpec::Expectations::ExpectationNotMetError
      else
        StandardError
      end
      raise exception_class, "Expected an open email but none was found. Did you forget to call open_email?" unless email
      email
    end

    def current_email_attachments(address=nil)
      current_email(address).attachments || Array.new
    end

    def unread_emails_for(address)
      read_message_ids = read_emails_for(address).map(&:message_id)
      mailbox_for(address).reject { |m| read_message_ids.include?(m.message_id) }
    end

    def read_emails_for(address)
      email_spec_hash[:read_emails][convert_address(address)] ||= []
    end

    # Should be able to accept String or Regexp options.
    def find_email(address, opts={})
      address = convert_address(address)
      if opts[:with_subject]
        expected_subject = (opts[:with_subject].is_a?(String) ? Regexp.escape(opts[:with_subject]) : opts[:with_subject])
        mailbox_for(address).find { |m| m.subject =~ Regexp.new(expected_subject) }
      elsif opts[:with_text]
        expected_text = (opts[:with_text].is_a?(String) ? Regexp.escape(opts[:with_text]) : opts[:with_text])
        mailbox_for(address).find { |m| m.default_part_body =~ Regexp.new(expected_text) }
      elsif opts[:from]
        mailbox_for(address).find { |m| m.from.include? opts[:from] }
      else
        mailbox_for(address).first
      end
    end

    def links_in_email(email)
      links = URI::Parser.new.extract(email.default_part_body.to_s, ['http', 'https'])
      links.map{|url| HTMLEntities.new.decode(url) }.uniq
    end

    private

    def email_spec_hash
      @email_spec_hash ||= {:read_emails => {}, :unread_emails => {}, :current_emails => {}, :current_email => nil}
    end

    def find_email!(address, opts={})
      email = find_email(address, opts)
      if current_email_address.nil?
        raise EmailSpec::NoEmailAddressProvided, "No email address has been provided. Make sure current_email_address is returning something."
      elsif email.nil?
        error = "#{opts.keys.first.to_s.gsub("_", " ").downcase unless opts.empty?} #{('"' + opts.values.first.to_s + '"') unless opts.empty?}"
        raise EmailSpec::CouldNotFindEmailError, "Could not find email #{error} in the mailbox for #{current_email_address}. \n Found the following emails:\n\n #{all_emails.to_s}"
      end
      email
    end

    def set_current_email(email)
      return unless email
      [email.to, email.cc, email.bcc].compact.flatten.each do |to|
        read_emails_for(to) << email
        email_spec_hash[:current_emails][to] = email
      end
{'fraction_non_alphanumeric': 0.12296187323770995, 'fraction_numerical': 0.0003677822728944465, 'mean_word_length': 3.4652435686918444, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1276519', 'n_tokens_mistral': 2682, 'n_tokens_neox': 2631, 'n_words': 528}