# frozen_string_literal: true
# rubocop:todo all

require "spec_helper"
require_relative './has_one_models'

describe Mongoid::Association::Referenced::HasOne do

  before do
    class OwnerObject; include Mongoid::Document; end
    class BelongingObject; include Mongoid::Document; end
  end

  after do
    Object.send(:remove_const, :BelongingObject)
    Object.send(:remove_const, :OwnerObject)
  end

  let(:has_one_class) do
    OwnerObject
  end

  let(:name) do
    :belonging_object
  end

  let(:association) do
    has_one_class.has_one name, options
  end

  let(:options) do
    { }
  end

  describe '#relation_complements' do

    let(:expected_complements) do
      [
          Mongoid::Association::Referenced::BelongsTo,
      ]
    end

    it 'returns the relation complements' do
      expect(association.relation_complements).to eq(expected_complements)
    end
  end

  describe '#setup!' do

    it 'sets up a getter for the relation' do
      expect(Mongoid::Association::Accessors).to receive(:define_getter!).with(association)
      association.setup!
    end

    it 'sets up a setter for the relation' do
      expect(Mongoid::Association::Accessors).to receive(:define_setter!).with(association)
      association.setup!
    end

    it 'sets up an existence check for the relation' do
      expect(Mongoid::Association::Accessors).to receive(:define_existence_check!).with(association)
      association.setup!
    end

    it 'sets up the builder for the relation' do
      expect(Mongoid::Association::Builders).to receive(:define_builder!).with(association)
      association.setup!
    end

    it 'sets up the creator for the relation' do
      expect(Mongoid::Association::Builders).to receive(:define_creator!).with(association)
      association.setup!
    end

    context 'autosave' do

      context 'when the :autosave option is true' do

        let(:options) do
          {
              autosave: true
          }
        end

        let(:association) do
          # Note that it is necessary to create the association directly, otherwise the
          # setup! method will be called by the :has_one macro
          described_class.new(has_one_class, name, options)
        end

        it 'sets up autosave' do
          expect(Mongoid::Association::Referenced::AutoSave).to receive(:define_autosave!).with(association)
          association.setup!
        end
      end

      context 'when the :autosave option is false' do

        let(:options) do
          {
              autosave: false
          }
        end

        it 'does not set up autosave' do
          expect(Mongoid::Association::Referenced::AutoSave).not_to receive(:define_autosave!)
          association.setup!
        end
      end

      context 'when the :autosave option is not provided' do

        let(:association) do
          # Note that it is necessary to create the association directly, otherwise the
          # setup! method will be called by the :has_one macro
          described_class.new(has_one_class, name, options)
        end

        it 'does not set up autosave' do
          expect(Mongoid::Association::Referenced::AutoSave).not_to receive(:define_autosave!)
          association.setup!
        end
      end
    end

    context 'when the :validate option is true' do

      let(:options) do
        {
            validate: true
        }
      end

      let(:association) do
        # Note that it is necessary to create the association directly, otherwise the
        # setup! method will be called by the :has_one macro
        described_class.new(has_one_class, name, options)
      end

      it 'sets up validation' do
        expect(has_one_class).to receive(:validates_associated).with(name).and_call_original
        association.setup!
      end
    end

    context 'when the :validate option is false' do

      let(:options) do
        {
            validate: false
        }
      end

      it 'does not set up validation' do
        expect(has_one_class).not_to receive(:validates_associated)
        association.setup!
      end
    end

    context 'when the :validate option is not provided' do

      let(:association) do
        # Note that it is necessary to create the association directly, otherwise the
        # setup! method will be called by the :embeds_one macro
        described_class.new(has_one_class, name, options)
      end

      it 'sets up the validation because it uses the validation default (true)' do
        expect(has_one_class).to receive(:validates_associated).with(name).and_call_original
        association.setup!
      end
    end

    context 'polymorphic' do

      context 'when the as option is provided' do


        let(:options) do
          {
              as: :containable
          }
        end

        before do
          association
        end

        it 'set the polymorphic attribute on the owner class' do
          expect(has_one_class.polymorphic).to be(true)
        end
      end

      context 'when the as option is not provided' do

        it 'does not set the polymorphic attribute on the owner class' do
          expect(has_one_class.polymorphic).to be(false)
        end
      end
    end

    context 'dependent' do

      context 'when the dependent option is provided' do

        context 'when the dependent option is :delete_all' do

          let(:options) do
            {
                dependent: :delete_all
            }
          end

          let(:association) do
            # Note that it is necessary to create the association directly, otherwise the
            # setup! method will be called by the :belongs_to macro
            described_class.new(has_one_class, name, options)
          end

          it 'sets up the dependency' do
            expect(Mongoid::Association::Depending).to receive(:define_dependency!)
            association.setup!
          end
        end

        context 'when the dependent option is :destroy' do

          let(:options) do
            {
                dependent: :destroy
            }
          end

          let(:association) do
            # Note that it is necessary to create the association directly, otherwise the
            # setup! method will be called by the :belongs_to macro
            described_class.new(has_one_class, name, options)
          end

          it 'sets up the dependency' do
            expect(Mongoid::Association::Depending).to receive(:define_dependency!)
            association.setup!
          end
        end

        context 'when the dependent option is :nullify' do

          let(:options) do
            {
                dependent: :nullify
            }
          end

          let(:association) do
            # Note that it is necessary to create the association directly, otherwise the
            # setup! method will be called by the :belongs_to macro
            described_class.new(has_one_class, name, options)
          end

          it 'sets up the dependency' do
            expect(Mongoid::Association::Depending).to receive(:define_dependency!)
            association.setup!
          end
        end

        context 'when the dependent option is :restrict_with_exception' do

          let(:options) do
            {
                dependent: :restrict_with_exception
            }
          end

          let(:association) do
            # Note that it is necessary to create the association directly, otherwise the
            # setup! method will be called by the :belongs_to macro
            described_class.new(has_one_class, name, options)
          end

          it 'sets up the dependency' do
            expect(Mongoid::Association::Depending).to receive(:define_dependency!)
            association.setup!
          end
        end

        context 'when the dependent option is :restrict_with_error' do

          let(:options) do
            {
                dependent: :restrict_with_error
            }
          end

          let(:association) do
            # Note that it is necessary to create the association directly, otherwise the
            # setup! method will be called by the :belongs_to macro
            described_class.new(has_one_class, name, options)
          end

          it 'sets up the dependency' do
            expect(Mongoid::Association::Depending).to receive(:define_dependency!)
            association.setup!
          end
        end
      end

      context 'when the dependent option is not provided' do

        it 'does not set up the dependency' do
          expect(Mongoid::Association::Depending).not_to receive(:define_dependency!)
          association.setup!
        end
      end
    end
  end

  describe '#type' do

    context 'when polymorphic' do

      let(:options) do
        { as: :containable }
      end

      it 'returns the as attribute followed by "_type"' do
        expect(association.type).to eq("#{options[:as]}_type")
      end
    end

    context 'when not polymorphic' do

      it 'returns nil' do
        expect(association.type).to be_nil
      end
    end
  end

  describe '#inverse_type' do

    context 'when polymorphic' do

      let(:options) do
        { as: :containable }
      end

      it 'returns nil' do
        expect(association.inverse_type).to be_nil
      end
    end

    context 'when not polymorphic' do

      it 'returns nil' do
        expect(association.inverse_type).to be_nil
      end
    end
  end

  describe '#inverse_type_setter' do

    context 'when polymorphic' do

      let(:options) do
        { as: :containable }
      end

      it 'returns nil' do
        expect(association.inverse_type).to be_nil
      end
    end

    context 'when not polymorphic' do

      it 'returns nil' do
        expect(association.inverse_type).to be_nil
      end
    end
  end

  describe '#foreign_key' do

    context 'when options has foreign_key specified' do

      let(:options) do
        { foreign_key: :other_object_id }
      end

      it 'raises returns the foreign key as a String' do
        expect(association.foreign_key).to eq(options[:foreign_key].to_s)
      end
    end

    context 'when options does not have foreign_key specified' do

      it 'returns the default foreign key, the name of the inverse followed by "_id"' do
        expect(association.foreign_key).to eq("#{association.inverse}_id")
      end
    end
  end

  describe '#embedded?' do

    it 'returns false' do
      expect(association.embedded?).to be(false)
    end
  end

  describe '#primary_key' do

    context 'when the :primary_key option is specified' do

      let(:options) do
        {
            primary_key: 'guid'
        }
      end

      it 'returns the primary_key' do
        expect(association.primary_key).to eq(options[:primary_key])
      end
    end

    context 'when the :primary_key option is not specified' do

      it 'returns the primary_key default' do
        expect(association.primary_key).to eq(Mongoid::Association::Relatable::PRIMARY_KEY_DEFAULT)
      end
    end
  end

  describe '#indexed?' do

    it 'returns false' do
      expect(association.indexed?).to be(false)
    end
  end

  describe '#relation' do

    it 'returns Mongoid::Association::Referenced::HasOne::Proxy' do
      expect(association.relation).to be(Mongoid::Association::Referenced::HasOne::Proxy)
    end
  end

  describe '#validation_default' do

    it 'returns true' do
      expect(association.validation_default).to be(true)
    end
  end

  describe '#name' do

    it 'returns the name of the relation' do
      expect(association.name).to be(name)
    end
  end

  describe '#options' do

    it 'returns the options' do
      expect(association.options).to be(options)
    end
  end

  describe '#merge!' do

  end

  describe '#store_as' do
    it 'returns nil' do
      expect(association.store_as).to be_nil
    end
  end

  describe '#touchable?' do

    it 'return false' do
      expect(association.send(:touchable?)).to be(false)
    end
  end

  describe '#order' do

    it 'returns nil' do
      expect(association.order).to be_nil
    end
  end

  describe '#scope' do

    context 'when scope is specified in the options' do

      let(:options) do
        { scope: -> { unscoped.where(foo: :bar) } }
      end

      it 'returns a Criteria Queryable Key' do
        expect(association.scope).to be_a(Proc)
      end
    end

    context 'when scope is not specified in the options' do

      it 'returns nil' do
        expect(association.scope).to be_nil
      end
    end
  end

  describe '#as' do

    context 'when :as is specified in the options' do

      let(:options) do
        {
            as: :containable
        }
      end

      it 'returns the :as option' do
        expect(association.as).to eq(options[:as])
      end
    end

    context 'when :as is not specified in the options' do

      it 'returns nil' do
        expect(association.as).to be_nil
      end
    end
  end

  describe '#polymorphic?' do

    context 'when :as is specified in the options' do

      let(:options) do
        {
            as: :containable
        }
      end

      it 'returns true' do
        expect(association.polymorphic?).to be(true)
      end

    end

    context 'when :as is not specified in the options' do

      it 'returns false' do
        expect(association.polymorphic?).to be(false)
      end
    end
  end

  describe '#type_setter' do

    context 'when polymorphic' do

      let(:options) do
        { as: :containable }
      end

      it 'returns the type followed by = as a String' do
        expect(association.type_setter).to eq("containable_type=")
      end
    end

    context 'when not polymorphic' do

      it 'returns nil' do
        expect(association.type).to be_nil
      end
    end
  end

  describe '#dependent' do

    context 'when the dependent option is provided' do

      context 'when the dependent option is :delete_all' do

        let(:options) do
          {
              dependent: :delete_all
          }
        end

        it 'returns :delete_all' do
          expect(association.dependent).to eq(:delete_all)
        end
      end

      context 'when the dependent option is :destroy' do

        let(:options) do
          {
              dependent: :destroy
          }
        end

        it 'returns :destroy' do
          expect(association.dependent).to eq(:destroy)
        end
      end

      context 'when the dependent option is :nullify' do

        let(:options) do
          {
              dependent: :nullify
          }
        end

        it 'returns :nullify' do
          expect(association.dependent).to eq(:nullify)
        end
      end

      context 'when the dependent option is :restrict_with_exception' do

        let(:options) do
          {
              dependent: :restrict_with_exception
          }
        end

        it 'returns :restrict_with_exception' do
          expect(association.dependent).to eq(:restrict_with_exception)
        end
      end

      context 'when the dependent option is :restrict_with_error' do

        let(:options) do
          {
              dependent: :restrict_with_error
          }
        end

        it 'returns :restrict_with_error' do
          expect(association.dependent).to eq(:restrict_with_error)
        end
      end
    end

    context 'when the dependent option is not provided' do

      it 'returns nil' do
        expect(association.dependent).to be_nil
      end
    end
  end

  describe '#inverse_type' do

    it 'returns nil' do
      expect(association.inverse_type).to be_nil
    end
  end

  describe '#bindable?' do

    it 'returns false' do
      expect(association.bindable?(Person.new)).to be(false)
    end
  end

  describe '#inverses' do

    context 'when polymorphic' do

      before do
        BelongingObject.belongs_to :containable, polymorphic: true
      end

      let(:options) do
        {
            as: :containable
        }
      end

      context 'when another object is passed to the method' do

        let(:instance_of_other_class) do
          BelongingObject.new
        end

        context 'when the relation class has only one relation whose class matches the owning class' do

          it 'returns the :as attribute of this association' do
            expect(association.inverses(instance_of_other_class)).to match_array([ :containable ])
          end
        end

        context 'when :inverse_of is specified' do

          before do
            options.merge!(inverse_of: :inverse_name)
          end

          it 'returns the :inverse_of value' do
            expect(association.inverses(instance_of_other_class)).to eq([ :inverse_name ])
          end
        end

        context 'when inverse_of is not specified' do

          it 'returns the :as attribute of this association' do
            expect(association.inverses(instance_of_other_class)).to match_array([ :containable ])
          end
        end
      end

      context 'when another object is not passed to the method' do

        context 'when inverse_of is specified' do

          before do
            options.merge!(inverse_of: :inverse_name)
          end

          it 'returns the :inverse_of value' do
            expect(association.inverses).to eq([ :inverse_name ])
          end
        end

        context 'when inverse_of is not specified' do

          it 'returns the :as attribute' do
            expect(association.inverses).to eq([ :containable ])
          end
        end
      end
    end

    context 'when not polymorphic' do

      before do
        BelongingObject.belongs_to :owner_object
      end

      context 'when inverse_of is specified' do

        before do
          options.merge!(inverse_of: :inverse_name)
        end

        it 'returns the :inverse_of value' do
          expect(association.inverses).to eq([ :inverse_name ])
        end
      end

      context 'when inverse_of is not specified' do

        it 'uses the inverse class to find the inverse name' do
          expect(association.inverses).to eq([ :owner_object ])
        end
      end

      context 'when :cyclic is specified' do

        it 'returns the cyclic inverse name' do

        end
      end
    end
  end

  describe '#inverse' do

    context 'when polymorphic' do

      before do
        BelongingObject.belongs_to :containable, polymorphic: true
      end

      let(:options) do
        {
            as: :containable
        }
      end

      context 'when another object is passed to the method' do

        let(:instance_of_other_class) do
          BelongingObject.new
        end

        context 'when the relation class has only one relation whose class matches the owning class' do

          it 'returns the :as attribute of this association' do
            expect(association.inverse(instance_of_other_class)).to eq(:containable)
          end
        end

        context 'when :inverse_of is specified' do

          before do
            options.merge!(inverse_of: :inverse_name)
          end

          it 'returns the :inverse_of value' do
            expect(association.inverse(instance_of_other_class)).to eq(:inverse_name)
          end
        end

        context 'when inverse_of is not specified' do

          it 'returns the :as attribute of this association' do
            expect(association.inverse(instance_of_other_class)).to eq(:containable)
          end
        end
      end

      context 'when another object is not passed to the method' do

        context 'when inverse_of is specified' do

          before do
            options.merge!(inverse_of: :inverse_name)
          end

          it 'returns the :inverse_of value' do
            expect(association.inverse).to eq(:inverse_name)
          end
        end

        context 'when inverse_of is not specified' do

          it 'returns the :as attribute' do
            expect(association.inverse).to eq(:containable)
          end
        end
      end
    end

    context 'when not polymorphic' do

      before do
        BelongingObject.belongs_to :owner_object
      end

      context 'when inverse_of is specified' do

        before do
          options.merge!(inverse_of: :inverse_name)
        end

        it 'returns the :inverse_of value' do
          expect(association.inverse).to eq(:inverse_name)
        end
      end

      context 'when inverse_of is not specified' do

        it 'uses the inverse class to find the inverse name' do
          expect(association.inverse).to eq(:owner_object)
        end
      end

      context 'when :cyclic is specified' do

        it 'returns the cyclic inverse name' do

        end
      end
    end
  end

  describe '#inverse_association' do

  end

  describe '#autosave' do

    context 'when the autosave option is specified' do

      context 'when the autosave option is true' do

        let(:options) do
          {
            autosave: true
          }
        end

        it 'returns true' do
          expect(association.autosave).to be(true)
        end
      end

      context 'when the autosave option is false' do

        let(:options) do
          {
              autosave: false
          }
        end

        it 'returns false' do
          expect(association.autosave).to be(false)
        end
      end
    end

    context 'when the autosave option is not specified' do

      it 'returns false' do
        expect(association.autosave).to be(false)
      end
    end
  end

  describe '#relation_class_name' do

    context 'when the classes are defined in a module' do

      let(:define_classes) do
        module HasOneAssociationClassName
          class OwnedClass
            include Mongoid::Document

            belongs_to :owner_class
          end

          class OwnerClass
            include Mongoid::Document

            has_one :owned_class
          end
        end
      end

      it 'returns the inferred unqualified class name' do
        define_classes

        expect(
            HasOneAssociationClassName::OwnedClass.relations['owner_class'].relation_class_name
        ).to eq('OwnerClass')
      end
    end

    context 'when the :class_name option is specified' do

      let(:options) do
        { class_name: 'OtherBelongingObject' }
      end

      it 'returns the class name option' do
        expect(association.relation_class_name).to eq('OtherBelongingObject')
      end

      context 'when the class is namespaced' do
        let(:association) do
          HomNs::PrefixedParent.relations['child']
        end

        it 'returns unqualified class name as given in the :class_name option' do
          expect(association.relation_class_name).to eq('PrefixedChild')
        end
      end
    end

    context 'when the class_name option is not specified' do

      it 'uses the name of the relation to deduce the class name' do
        expect(association.relation_class_name).to eq('BelongingObject')
      end
    end

    context "when the class is not defined" do
      let(:name) do
        :undefined_class
      end

      it 'does not trigger autoloading' do
        expect(association.relation_class_name).to eq('UndefinedClass')
      end
    end
  end

  describe '#relation_class' do

    context 'when the :class_name option is specified' do

      let!(:_class) do
        class OtherBelongingObject; end
        OtherBelongingObject
      end

      let(:options) do
        { class_name: 'OtherBelongingObject' }
      end

      it 'returns the class name option' do
        expect(association.relation_class).to eq(_class)
      end

      context 'when the class is namespaced' do
        let(:association) do
          HomNs::PrefixedParent.relations['child']
        end

        it 'returns resolved class instance' do
          expect(association.relation_class).to eq(HomNs::PrefixedChild)
        end
      end
    end

    context 'when the class_name option is not specified' do

      it 'uses the name of the relation to deduce the class name' do
        expect(association.relation_class).to eq(BelongingObject)
      end
    end
  end

  describe '#klass' do
    it 'is the target class' do
      expect(association.klass).to eq(BelongingObject)
    end
  end

  describe '#inverse_class_name' do

    it 'returns the name of the owner class' do
      expect(association.inverse_class_name).to eq('OwnerObject')
    end

    context 'polymorphic association' do
      let(:association) do
        has_one_class.has_one :belonging_object, as: :bar
      end

      it 'returns the name of the owner class' do
        expect(association.inverse_class_name).to eq(OwnerObject.name)
      end
    end
  end

  describe '#inverse_class' do

    it 'returns the owner class' do
      expect(association.inverse_class).to be(OwnerObject)
    end

    context 'polymorphic association' do
      let(:association) do
        has_one_class.has_one :belonging_object, as: :bar
      end

      it 'returns the owner class' do
        expect(association.inverse_class).to be(OwnerObject)
      end
    end
  end

  describe '#inverse_of' do

    context 'when :inverse_of is specified in the options' do

      let(:options) do
        { inverse_of: :a_belonging_object }
      end

      it 'returns the inverse_of value' do
        expect(association.inverse_of).to eq(options[:inverse_of])
      end
    end

    context 'when :inverse_of is not specified in the options' do

      it 'returns nil' do
        expect(association.inverse_of).to be_nil
      end
    end
  end

  describe '#key' do

    it 'returns the primary key' do
      expect(association.key).to eq(association.primary_key)
    end
  end

  describe '#setter' do

    it 'returns a string of the name followed by =' do
      expect(association.setter).to eq("#{name}=")
    end
  end

  describe '#validate?' do

    context 'when :validate is specified in the options' do

      context 'when validate is true' do

        let(:options) do
          { validate: true }
        end

        it 'returns true' do
          expect(association.send(:validate?)).to be(true)
        end
      end

      context 'when validate is false' do

        let(:options) do
          { validate: false }
        end

        it 'returns false' do
          expect(association.send(:validate?)).to be(false)
        end
      end
    end

    context 'when :validate is not specified in the options' do

      it 'returns the validation_default' do
        expect(association.send(:validate?)).to eq(association.validation_default)
      end
    end
  end

  describe '#autobuilding?' do

    context 'when :autobuild is specified in the options' do

      context 'when autobuild is true' do

        let(:options) do
          { autobuild: true }
        end

        it 'returns true' do
          expect(association.autobuilding?).to be(true)
        end
      end

      context 'when autobuild is false' do

        let(:options) do
          { autobuild: false }
        end

        it 'returns true' do
          expect(association.autobuilding?).to be(false)
        end
      end
    end

    context 'when :validate is not specified in the options' do

      it 'returns false' do
        expect(association.autobuilding?).to be(false)
      end
    end
  end

  describe '#forced_nil_inverse?' do

    it 'returns false' do
      expect(association.forced_nil_inverse?).to be(false)
    end
  end

  describe '#stores_foreign_key?' do

    it 'returns false' do
      expect(association.stores_foreign_key?).to be(false)
    end
  end

  describe '#inverse_setter' do

    context 'when an inverse can be determined' do

      before do
        BelongingObject.belongs_to :owner_object
      end

      it 'returns the name of the inverse followed by =' do
        expect(association.inverse_setter).to eq('owner_object=')
      end
    end

    context 'when an inverse cannot be determined' do

      it 'returns nil' do
        expect(association.inverse_setter).to be_nil
      end
    end
  end

  describe '#extension' do

    context 'when a block is passed' do

      let(:association) do
        has_one_class.embeds_one name, options do; end
      end

      it 'defines an extension module' do
        expect(association.extension).to be_a(Module)
      end

      it 'returns the extension' do
        expect(association.extension).to eq(
          "#{has_one_class.name}::#{has_one_class.name}#{name.to_s.camelize}RelationExtension".constantize)
      end
    end

    context 'when an :extension is not specified in the options' do

      it 'returns false' do
        expect(association.extension).to be_nil
      end
    end
  end

  describe '#foreign_key_setter' do

    it 'returns the foreign key followed by "="' do
      expect(association.foreign_key_setter).to eq("#{association.foreign_key}=")
    end
  end

  describe '#destructive?' do

    context 'when the dependent option is provided' do

      context 'when the dependent option is :delete_all' do

        let(:options) do
          {
              dependent: :delete_all
          }
        end

        it 'returns true' do
          expect(association.destructive?).to be(true)
        end
      end

      context 'when the dependent option is :destroy' do

        let(:options) do
          {
              dependent: :destroy
          }
        end

        it 'returns true' do
          expect(association.destructive?).to be(true)
        end
      end

      context 'when the dependent option is :nullify' do

        let(:options) do
          {
              dependent: :nullify
          }
        end

        it 'returns false' do
          expect(association.destructive?).to be(false)
        end
      end

      context 'when the dependent option is :restrict_with_exception' do

        let(:options) do
          {
              dependent: :restrict_with_exception
          }
        end

        it 'returns false' do
          expect(association.destructive?).to be(false)
        end
      end

      context 'when the dependent option is :restrict_with_error' do

        let(:options) do
          {
              dependent: :restrict_with_error
          }
        end

        it 'returns false' do
          expect(association.destructive?).to be(false)
        end
      end
    end

    context 'when the dependent option is not provided' do

      it 'returns false' do
        expect(association.destructive?).to be(false)
      end
    end
  end

  context 'when the classes are defined in a module' do

    let(:define_classes) do
      module HasOneAssociationModuleDefinitions
        class OwnedClass
          include Mongoid::Document

          belongs_to :owner_class
        end

        class OwnerClass
          include Mongoid::Document

          has_one :owned_class
        end
      end
    end

    let(:owner) do
      HasOneAssociationModuleDefinitions::OwnerClass.create!
    end

    let(:owned) do
      define_classes
      HasOneAssociationModuleDefinitions::OwnedClass.create!(owner_class: owner)
    end

    it 'successfully creates the owned document' do
      expect { owned }.not_to raise_error
    end
  end

  describe '#nested_builder' do

    it 'returns an instance of Association::Nested::One' do
      expect(association.nested_builder({}, {})).to be_a(Mongoid::Association::Nested::One)
    end
  end

  describe '#path' do

    it 'returns an instance of Mongoid::Atomic::Paths::Root' do
      expect(association.path(double( :_parent => true))).to be_a(Mongoid::Atomic::Paths::Root)
    end
  end

  describe '#foreign_key_check' do

    it 'returns the nil' do
      expect(association.foreign_key_check).to be_nil
    end
  end

  describe '#create_relation' do

    let(:owner) do
      OwnerObject.new
    end

    let(:target) do
      BelongingObject.new
    end

    before do
      association
      BelongingObject.belongs_to :owner_object
    end

    it 'returns an the target (EmbeddedObject)' do
      expect(Mongoid::Association::Referenced::HasOne::Proxy).to receive(:new).and_call_original
      expect(association.create_relation(owner, target)).to be_a(BelongingObject)
    end
  end
end
