# frozen_string_literal: true

module ThinkingSphinx
  module ActiveRecord
    module Callbacks; end
  end
end

require 'active_support/core_ext/string/inflections'
require 'thinking_sphinx/callbacks'
require 'thinking_sphinx/errors'
require 'thinking_sphinx/active_record/callbacks/update_callbacks'

describe ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks do
  describe '#after_update' do
    let(:callbacks)     {
      ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks.new instance }
    let(:instance)      { double('instance', :class => klass, :id => 2) }
    let(:klass)         { double(:name => 'Article') }
    let(:configuration) { double('configuration',
      :settings => {'attribute_updates' => true},
      :indices_for_references => [index], :index_set_class => set_class) }
    let(:connection)    { double('connection', :execute => '') }
    let(:index)         { double 'index', :name => 'article_core',
      :sources => [source], :document_id_for_key => 3, :distributed? => false,
      :type => 'plain', :primary_key => :id}
    let(:source)        { double('source', :attributes => []) }
    let(:set_class)     { double(:reference_name => :article) }

    before :each do
      stub_const 'ThinkingSphinx::Configuration',
        double(:instance => configuration)
      stub_const 'ThinkingSphinx::Connection', double
      stub_const 'Riddle::Query', double(:update => 'SphinxQL')

      allow(ThinkingSphinx::Connection).to receive(:take).and_yield(connection)

      source.attributes.replace([
        double(:name => 'foo', :updateable? => true,
          :columns => [double(:__name => 'foo_column')]),
        double(:name => 'bar', :updateable? => true, :value_for => 7,
          :columns => [double(:__name => 'bar_column')]),
        double(:name => 'baz', :updateable? => false)
      ])

      allow(instance).to receive_messages(
        :changed       => ['bar_column', 'baz'],
        :bar_column    => 7,
        :saved_changes => {'bar_column' => [1, 2], 'baz' => [3, 4]}
      )
    end

    it "does not send any updates to Sphinx if updates are disabled" do
      configuration.settings['attribute_updates'] = false

      expect(connection).not_to receive(:execute)

      callbacks.after_update
    end

    it "builds an update query with only updateable attributes that have changed" do
      expect(Riddle::Query).to receive(:update).
        with('article_core', 3, { 'bar' => 7 }).and_return('SphinxQL')

      callbacks.after_update
    end

    it "sends the update query through to Sphinx" do
      expect(connection).to receive(:execute).with('SphinxQL')

      callbacks.after_update
    end

    it "doesn't care if the update fails at Sphinx's end" do
      allow(connection).to receive(:execute).
        and_raise(ThinkingSphinx::ConnectionError.new(''))

      expect { callbacks.after_update }.not_to raise_error
    end

    it 'does nothing if callbacks are suspended' do
      ThinkingSphinx::Callbacks.suspend!

      expect(connection).not_to receive(:execute)

      callbacks.after_update

      ThinkingSphinx::Callbacks.resume!
    end
  end
end
