/* * Copyright (C) 2013 Square, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package retrofit2.converter.protobuf; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.InvalidProtocolBufferException; import java.io.IOException; import java.util.List; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import okio.Buffer; import okio.ByteString; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import retrofit2.Call; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.http.Body; import retrofit2.http.GET; import retrofit2.http.POST; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static retrofit2.converter.protobuf.PhoneProtos.Phone; public final class ProtoConverterFactoryTest { interface Service { @GET("/") Call<Phone> get(); @POST("/") Call<Phone> post(@Body Phone impl); @GET("/") Call<String> wrongClass(); @GET("/") Call<List<String>> wrongType(); } interface ServiceWithRegistry { @GET("/") Call<Phone> get(); } @Rule public final MockWebServer server = new MockWebServer(); private Service service; private ServiceWithRegistry serviceWithRegistry; @Before public void setUp() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(server.url("/")) .addConverterFactory(ProtoConverterFactory.create()) .build(); service = retrofit.create(Service.class); ExtensionRegistry registry = ExtensionRegistry.newInstance(); PhoneProtos.registerAllExtensions(registry); Retrofit retrofitWithRegistry = new Retrofit.Builder() .baseUrl(server.url("/")) .addConverterFactory(ProtoConverterFactory.createWithRegistry(registry)) .build(); serviceWithRegistry = retrofitWithRegistry.create(ServiceWithRegistry.class); } @Test public void serializeAndDeserialize() throws IOException, InterruptedException { ByteString encoded = ByteString.decodeBase64("Cg4oNTE5KSA4NjctNTMwOQ=="); server.enqueue(new MockResponse().setBody(new Buffer().write(encoded))); Call<Phone> call = service.post(Phone.newBuilder().setNumber("(519) 867-5309").build()); Response<Phone> response = call.execute(); Phone body = response.body(); assertThat(body.getNumber()).isEqualTo("(519) 867-5309"); RecordedRequest request = server.takeRequest(); assertThat(request.getBody().readByteString()).isEqualTo(encoded); assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-protobuf"); } @Test public void deserializeEmpty() throws IOException { server.enqueue(new MockResponse()); Call<Phone> call = service.get(); Response<Phone> response = call.execute(); Phone body = response.body(); assertThat(body.hasNumber()).isFalse(); } @Test public void deserializeUsesRegistry() throws IOException { ByteString encoded = ByteString.decodeBase64("Cg4oNTE5KSA4NjctNTMwORAB"); server.enqueue(new MockResponse().setBody(new Buffer().write(encoded))); Call<Phone> call = serviceWithRegistry.get(); Response<Phone> response = call.execute(); Phone body = response.body(); assertThat(body.getNumber()).isEqualTo("(519) 867-5309"); assertThat(body.getExtension(PhoneProtos.voicemail)).isEqualTo(true); } @Test public void deserializeWrongClass() throws IOException { ByteString encoded = ByteString.decodeBase64("Cg4oNTE5KSA4NjctNTMwOQ=="); server.enqueue(new MockResponse().setBody(new Buffer().write(encoded))); try { service.wrongClass(); fail(); } catch (IllegalArgumentException e) { assertThat(e).hasMessage("" + "Unable to create converter for class java.lang.String\n" + " for method Service.wrongClass"); assertThat(e.getCause()).hasMessage("" + "Could not locate ResponseBody converter for class java.lang.String.\n" + " Tried:\n" + " * retrofit2.BuiltInConverters\n" + " * retrofit2.converter.protobuf.ProtoConverterFactory"); } } @Test public void deserializeWrongType() throws IOException { ByteString encoded = ByteString.decodeBase64("Cg4oNTE5KSA4NjctNTMwOQ=="); server.enqueue(new MockResponse().setBody(new Buffer().write(encoded))); try { service.wrongType(); fail(); } catch (IllegalArgumentException e) { assertThat(e).hasMessage("" + "Unable to create converter for java.util.List<java.lang.String>\n" + " for method Service.wrongType"); assertThat(e.getCause()).hasMessage("" + "Could not locate ResponseBody converter for java.util.List<java.lang.String>.\n" + " Tried:\n" + " * retrofit2.BuiltInConverters\n" + " * retrofit2.converter.protobuf.ProtoConverterFactory"); } } @Test public void deserializeWrongValue() throws IOException { ByteString encoded = ByteString.decodeBase64("////"); server.enqueue(new MockResponse().setBody(new Buffer().write(encoded))); Call<?> call = service.get(); try { call.execute(); fail(); } catch (RuntimeException e) { assertThat(e.getCause()).isInstanceOf(InvalidProtocolBufferException.class) .hasMessageContaining("input ended unexpectedly"); } } }