# frozen_string_literal: true

require "gir_ffi_test_helper"

describe GirFFI::Builders::StructBuilder do
  describe "#layout_specification" do
    it "returns the correct layout for Regress::TestStructA" do
      info = get_introspection_data "Regress", "TestStructA"
      builder = GirFFI::Builders::StructBuilder.new info
      _(builder.layout_specification).must_equal [:some_int, :int32, 0,
                                                  :some_int8, :int8, 4,
                                                  :some_double, :double, 8,
                                                  :some_enum, Regress::TestEnum, 16]
    end

    describe "for a struct with a simple layout" do
      before do
        @field = Object.new

        @struct = Object.new
        allow(@struct).to receive(:namespace).and_return "Foo"
        allow(@struct).to receive(:safe_name).and_return "Bar"
        allow(@struct).to receive(:fields).and_return [@field]

        @builder = GirFFI::Builders::StructBuilder.new @struct
      end

      it "creates the correct layout specification" do
        expect(@field).to receive(:layout_specification).and_return [:bar, :int32, 0]
        spec = @builder.layout_specification
        assert_equal [:bar, :int32, 0], spec
      end
    end

    describe "for a struct with a layout with a complex type" do
      it "does not flatten the complex type specification" do
        expect(simplefield = Object.new).to receive(:layout_specification).and_return [:bar, :foo, 0]
        expect(complexfield = Object.new).to receive(:layout_specification).and_return [:baz, [:qux, 2], 0]
        expect(struct = Object.new).to receive(:fields).and_return [simplefield, complexfield]

        allow(struct).to receive(:safe_name).and_return "Bar"
        allow(struct).to receive(:namespace).and_return "Foo"

        builder = GirFFI::Builders::StructBuilder.new struct
        spec = builder.layout_specification
        assert_equal [:bar, :foo, 0, :baz, [:qux, 2], 0], spec
      end
    end
  end

  describe "#superclass" do
    it "returns StructBase for a normal struct" do
      info = get_introspection_data "Regress", "TestStructA"
      builder = GirFFI::Builders::StructBuilder.new info
      _(builder.superclass).must_equal GirFFI::StructBase
    end

    it "returns BoxedBase for a boxed type" do
      info = get_introspection_data "Regress", "TestSimpleBoxedB"
      builder = GirFFI::Builders::StructBuilder.new info
      _(builder.superclass).must_equal GirFFI::BoxedBase
    end

    it "returns the GObject parent class for a type class" do
      info = get_introspection_data "GIMarshallingTests", "SubSubObjectClass"
      builder = GirFFI::Builders::StructBuilder.new info
      _(builder.superclass).must_equal GIMarshallingTests::SubObjectClass
    end

    it "returns ObjectClass for InitiallyUnownedClass" do
      info = get_introspection_data "GObject", "InitiallyUnownedClass"
      builder = GirFFI::Builders::StructBuilder.new info
      _(builder.superclass).must_equal GObject::ObjectClass
    end
  end

  describe "#setup_class" do
    before do
      save_module :Regress
    end

    it "stubs the structs methods" do
      info = get_introspection_data "Regress", "TestStructA"
      builder = GirFFI::Builders::StructBuilder.new info
      builder.setup_class
      assert_defines_instance_method Regress::TestStructA, :clone
    end

    after do
      restore_module :Regress
    end
  end
end
