# frozen_string_literal: true

require 'spec_helper'

module RailsBestPractices
  module Reviews
    describe UseQueryAttributeReview do
      let(:runner) do
        Core::Runner.new(
          prepares: [Prepares::ModelPrepare.new, Prepares::SchemaPrepare.new], reviews: described_class.new
        )
      end

      before do
        content = <<-EOF
        class User < ActiveRecord::Base
          has_many :projects
          belongs_to :location
          has_one :phone

          belongs_to :category, class_name: 'IssueCategory', foreign_key: 'category_id'
        end
        EOF
        runner.prepare('app/models/user.rb', content)

        content = <<-EOF
        ActiveRecord::Schema.define(version: 20110216150853) do
          create_table "users", force => true do |t|
            t.string :login
            t.integer :age
          end
        end
        EOF
        runner.prepare('db/schema.rb', content)
      end

      it 'uses query attribute by blank call' do
        content = <<-EOF
        <% if @user.login.blank? %>
          <%= link_to 'login', new_session_path %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'uses query attribute by blank call with if in one line' do
        content = <<-EOF
        <%= link_to 'login', new_session_path if @user.login.blank? %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it "uses query attribute by blank call with '? :'" do
        content = <<-EOF
        <%= @user.login.blank? ? link_to('login', new_session_path) : '' %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'uses query attribute by comparing empty string' do
        content = <<-EOF
        <% if @user.login == "" %>
          <%= link_to 'login', new_session_path %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'uses query attribute by nil call' do
        content = <<-EOF
        <% if @user.login.nil? %>
          <%= link_to 'login', new_session_path %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'uses query attribute by present call' do
        content = <<-EOF
        <% if @user.login.present? %>
          <%= @user.login %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'uses query attribute within and conditions' do
        content = <<-EOF
        <% if @user.active? && @user.login.present? %>
          <%= @user.login %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'uses query attribute within or conditions' do
        content = <<-EOF
        <% if @user.active? or @user.login != "" %>
          <%= @user.login %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(1)
        expect(runner.errors[0].to_s).to eq('app/views/users/show.html.erb:1 - use query attribute (@user.login?)')
      end

      it 'does not use query attribute' do
        content = <<-EOF
        <% if @user.login? %>
          <%= @user.login %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(0)
      end

      it 'does not use query attribute for number' do
        content = <<-EOF
        <% unless @user.age.blank? %>
          <%= @user.age %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(0)
      end

      it 'does not review for pluralize attribute' do
        content = <<-EOF
        <% if @user.roles.blank? %>
          <%= @user.login %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(0)
      end

      it 'does not review non model class' do
        content = <<-EOF
        <% if @person.login.present? %>
          <%= @person.login %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(0)
      end

      context 'association' do
        it 'does not review belongs_to association' do
          content = <<-EOF
          <% if @user.location.present? %>
            <%= @user.location.name %>
          <% end %>
          EOF
          runner.review('app/views/users/show.html.erb', content)
          expect(runner.errors.size).to eq(0)
        end

        it 'does not review belongs_to category' do
          content = <<-EOF
          <% if @user.category.present? %>
            <%= @user.category.name %>
          <% end %>
          EOF
          runner.review('app/views/users/show.html.erb', content)
          expect(runner.errors.size).to eq(0)
        end

        it 'does not review has_one association' do
          content = <<-EOF
          <% if @user.phone.present? %>
            <%= @user.phone.number %>
          <% end %>
          EOF
          runner.review('app/views/users/show.html.erb', content)
          expect(runner.errors.size).to eq(0)
        end

        it 'does not review has_many association' do
          content = <<-EOF
          <% if @user.projects.present? %>
            <%= @user.projects.first.name %>
          <% end %>
          EOF
          runner.review('app/views/users/show.html.erb', content)
          expect(runner.errors.size).to eq(0)
        end
      end

      it 'does not review for class method' do
        content = <<-EOF
        <% if User.name.present? %>
          <%= User.name %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(0)
      end

      it 'does not review for non attribute call' do
        content = <<-EOF
        if @user.login(false).nil?
          puts @user.login(false)
        end
        EOF
        runner.review('app/models/users_controller.rb', content)
        expect(runner.errors.size).to eq(0)
      end

      it 'does not raise error for common conditional statement' do
        content = <<-EOF
        if voteable.is_a? Answer
          puts voteable.title
        end
        EOF
        expect { runner.review('app/models/users_controller.rb', content) }.not_to raise_error
      end

      it 'does not check ignored files' do
        runner =
          Core::Runner.new(
            prepares: [Prepares::ModelPrepare.new, Prepares::SchemaPrepare.new],
            reviews: described_class.new(ignored_files: %r{users/show})
          )
        content = <<-EOF
        <% if @user.login.blank? %>
          <%= link_to 'login', new_session_path %>
        <% end %>
        EOF
        runner.review('app/views/users/show.html.erb', content)
        expect(runner.errors.size).to eq(0)
      end
    end
  end
end
