require "spec_helper"

RSpec.describe ActiveRemote::Serializers::Protobuf::Fields do
  describe ".from_attributes" do
    let(:ready_value) { {records: [{name: "Cool Post", errors: [{message: "Boom!"}]}]} }
    let(:value) { {records: {name: "Cool Post", errors: {message: "Boom!"}}} }

    it "gets protobuf-ready fields from attributes" do
      expect(described_class.from_attributes(Generic::Remote::Posts, value)).to eq ready_value
    end
  end
end

RSpec.describe ActiveRemote::Serializers::Protobuf::Field do
  describe ".from_attribute" do
    context "when field is a repeated message" do
      let(:field) { Generic::Remote::Posts.get_field(:records) }

      context "and the value is not an array" do
        let(:ready_value) { [{name: "Cool Post", errors: [{message: "Boom!"}]}] }
        let(:value) { {name: "Cool Post", errors: {message: "Boom!"}} }

        it "gets protobuf-ready fields from the value" do
          expect(described_class.from_attribute(field, value)).to eq ready_value
        end
      end
    end

    context "when field is a message" do
      let(:field) { Generic::Remote::Post.get_field(:category) }

      context "and value is a hash" do
        let(:ready_value) { {name: "Film", errors: [{message: "Boom!"}]} }
        let(:value) { {name: "Film", errors: {message: "Boom!"}} }

        it "gets protobuf-ready fields from the value" do
          expect(described_class.from_attribute(field, value)).to eq ready_value
        end
      end
    end

    context "when field is repeated" do
      let(:field) { Generic::Remote::PostRequest.get_field(:name) }

      context "and the value is not an array" do
        let(:ready_value) { ["Cool Post"] }
        let(:value) { "Cool Post" }

        it "gets protobuf-ready fields from the value" do
          expect(described_class.from_attribute(field, value)).to eq ready_value
        end
      end
    end

    # TODO: Find a better way to write this. It works for now, but it's not
    # very clear and is hard to track down since failures don't include a
    # description.
    #
    # TODO: Consider adding specific specs for typecasting dates to integers
    # or strings since that's what prompted the re-introduction of the
    # typecasting.
    #
    context "when typecasting fields" do
      let(:string_value) { double(:string, to_s: "") }

      def typecasts(field, conversion)
        field = Serializer.get_field(field, true)
        expect(described_class.from_attribute(field, conversion.first[0])).to eq conversion.first[1]
      end

      it { typecasts(:bool_field, "0" => false) }
      it { typecasts(:bytes_field, string_value => "") }
      it { typecasts(:double_field, 0 => 0.0) }
      it { typecasts(:fixed32_field, "0" => 0) }
      it { typecasts(:fixed64_field, "0" => 0) }
      it { typecasts(:float_field, 0 => 0.0) }
      it { typecasts(:int32_field, "0" => 0) }
      it { typecasts(:int64_field, "0" => 0) }
      it { typecasts(:sfixed32_field, "0" => 0) }
      it { typecasts(:sfixed64_field, "0" => 0) }
      it { typecasts(:sint32_field, "0" => 0) }
      it { typecasts(:sint64_field, "0" => 0) }
      it { typecasts(:string_field, string_value => "") }
      it { typecasts(:uint32_field, "0" => 0) }
      it { typecasts(:uint64_field, "0" => 0) }
      it { typecasts(:enum_field, 0 => 0) }
    end
  end
end
