/** * */ package com.github.lpezet.antiope2.retrofitted; import static org.assertj.core.api.Assertions.assertThat; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Test; import rx.Observable; import com.github.lpezet.antiope2.dao.http.IHttpResponse; import com.github.lpezet.antiope2.retrofitted.Callback; import com.github.lpezet.antiope2.retrofitted.MethodInfo; import com.github.lpezet.antiope2.retrofitted.annotation.Converter; import com.github.lpezet.antiope2.retrofitted.annotation.http.Body; import com.github.lpezet.antiope2.retrofitted.annotation.http.GET; import com.github.lpezet.antiope2.retrofitted.annotation.http.POST; import com.google.gson.reflect.TypeToken; /** * @author Luc Pezet */ public class MethodInfoTest { @Test public void pathParameterParsing() throws Exception { expectParams("/"); expectParams("/foo"); expectParams("/foo/bar"); expectParams("/foo/bar/{}"); expectParams("/foo/bar/{taco}", "taco"); expectParams("/foo/bar/{t}", "t"); expectParams("/foo/bar/{!!!}/"); // Invalid parameter. expectParams("/foo/bar/{}/{taco}", "taco"); expectParams("/foo/bar/{taco}/or/{burrito}", "taco", "burrito"); expectParams("/foo/bar/{taco}/or/{taco}", "taco"); expectParams("/foo/bar/{taco-shell}", "taco-shell"); expectParams("/foo/bar/{taco_shell}", "taco_shell"); expectParams("/foo/bar/{sha256}", "sha256"); expectParams("/foo/bar/{TACO}", "TACO"); expectParams("/foo/bar/{taco}/{tAco}/{taCo}", "taco", "tAco", "taCo"); expectParams("/foo/bar/{1}"); // Invalid parameter, name cannot start with digit. } private static void expectParams(String path, String... expected) { Set<String> calculated = MethodInfo.parsePathParameters(path); assertThat(calculated).hasSize(expected.length); if (expected.length > 0) { assertThat(calculated).containsExactly(expected); } } static class Dummy { } static class MyConverter implements com.github.lpezet.antiope2.retrofitted.converter.Converter { @Override public Object deserialize(InputStream pBody, Type pType) throws IOException { // TODO Auto-generated method stub return null; } @Override public InputStream serialize(Object pBody, Type pType) { // TODO Auto-generated method stub return null; } } @Test public void methodSpecificConverter() { class Example { @Converter(MyConverter.class) @GET("/foo") String a() { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getConverter().getClass()).isEqualTo(MyConverter.class); } @Test public void concreteBodyType() { class Example { @POST("/foo") String a(@Body Dummy body) { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getRequestObjectType()).isEqualTo(Dummy.class); } @Test public void genericBodyType() { class Example { @POST("/foo") String a(@Body List<String> body) { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); Type expected = new TypeToken<List<String>>() {}.getType(); assertThat(methodInfo.getRequestObjectType()).isEqualTo(expected); } @Test public void wildcardBodyType() { class Example { @POST("/foo") String a(@Body List<? super String> body) { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); Type expected = new TypeToken<List<? super String>>() {}.getType(); assertThat(methodInfo.getRequestObjectType()).isEqualTo(expected); } @Test public void concreteCallbackTypes() { class Example { @GET("/foo") void a(ResponseCallback cb) { } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getResponseObjectType()).isEqualTo(IHttpResponse.class); } @Test public void genericCallbackTypes() { class Example { @GET("/foo") void a(Callback<IHttpResponse> cb) { } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getResponseObjectType()).isEqualTo(IHttpResponse.class); } @Test public void wildcardGenericCallbackTypes() { class Example { @GET("/foo") void a(Callback<? extends IHttpResponse> c) { } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getResponseObjectType()).isEqualTo(IHttpResponse.class); } @Test public void genericCallbackWithGenericType() { class Example { @GET("/foo") void a(Callback<List<String>> c) { } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); Type expected = new TypeToken<List<String>>() {}.getType(); assertThat(methodInfo.getResponseObjectType()).isEqualTo(expected); } // RestMethodInfo reconstructs this type from MultimapCallback<String, Set<Long>>. It contains // a little of everything: a parameterized type, a generic array, and a wildcard. private static Map<? extends String, Set<Long>[]> extendingGenericCallbackType; @Test public void extendingGenericCallback() throws Exception { class Example { @GET("/foo") void a(MultimapCallback<String, Set<Long>> callback) { } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getResponseObjectType()).isEqualTo( MethodInfoTest.class.getDeclaredField("extendingGenericCallbackType").getGenericType()); } @Test public void synchronousResponse() { class Example { @GET("/foo") IHttpResponse a() { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getResponseObjectType()).isEqualTo(IHttpResponse.class); } @Test public void synchronousGenericResponse() { class Example { @GET("/foo") List<String> a() { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); Type expected = new TypeToken<List<String>>() {}.getType(); assertThat(methodInfo.getResponseObjectType()).isEqualTo(expected); } // TODO /* * @Test public void streamingResponse() { * class Example { * @GET("/foo") @Streaming Response a() { * return null; * } * } * Method method = TestingUtils.onlyMethod(Example.class); * MethodInfo methodInfo = new MethodInfo(method); * assertThat(methodInfo.responseObjectType).isEqualTo(Response.class); * } */ @Test public void observableResponse() { class Example { @GET("/foo") Observable<IHttpResponse> a() { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); assertThat(methodInfo.getResponseObjectType()).isEqualTo(IHttpResponse.class); } @Test public void observableGenericResponse() { class Example { @GET("/foo") Observable<List<String>> a() { return null; } } Method method = TestingUtils.onlyMethod(Example.class); MethodInfo methodInfo = new MethodInfo(method); Type expected = new TypeToken<List<String>>() {}.getType(); assertThat(methodInfo.getResponseObjectType()).isEqualTo(expected); } private static interface ResponseCallback extends Callback<IHttpResponse> { } private static interface MultimapCallback<K, V> extends Callback<Map<? extends K, V[]>> { } }