001 /* 002 * Copyright 2013 Google Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package com.google.gwtmockito.fakes; 017 018 import com.google.gwt.core.client.GWT; 019 import com.google.gwt.resources.client.ClientBundle; 020 import com.google.gwt.resources.client.CssResource; 021 import com.google.gwt.resources.client.ResourceCallback; 022 import com.google.gwt.resources.client.ResourcePrototype; 023 import com.google.gwt.safehtml.shared.SafeHtml; 024 import com.google.gwt.safehtml.shared.SafeHtmlUtils; 025 import com.google.gwt.safehtml.shared.SafeUri; 026 import com.google.gwt.safehtml.shared.UriUtils; 027 028 import java.lang.reflect.InvocationHandler; 029 import java.lang.reflect.Method; 030 import java.lang.reflect.ParameterizedType; 031 import java.lang.reflect.Proxy; 032 033 /** 034 * Provides fake implementations of {@link ClientBundle}s. Any methods in the 035 * bundle returning {@link CssResource}s will GWT.create the {@link CssResource} 036 * (which by default will cause it to be generated by 037 * {@link FakeMessagesProvider}. Other types of resources will be generated to 038 * return unique values from their getText() or getSafeUri() methods. 039 * 040 * @author ekuefler@google.com (Erik Kuefler) 041 */ 042 public class FakeClientBundleProvider implements FakeProvider<ClientBundle> { 043 044 /** 045 * Returns a new instance of the given type that implements methods as 046 * described in the class description. 047 * 048 * @param type interface to be implemented by the returned type. 049 */ 050 @Override 051 public ClientBundle getFake(Class<?> type) { 052 return (ClientBundle) Proxy.newProxyInstance( 053 FakeClientBundleProvider.class.getClassLoader(), 054 new Class<?>[] {type}, 055 new InvocationHandler() { 056 @Override 057 public Object invoke(Object proxy, Method method, Object[] args) throws Exception { 058 Class<?> returnType = method.getReturnType(); 059 if (CssResource.class.isAssignableFrom(returnType)) { 060 return GWT.create(returnType); 061 } else { 062 return createFakeResource(returnType, method.getName()); 063 } 064 } 065 }); 066 } 067 068 /** 069 * Creates a fake resource class that returns its own name where possible. 070 */ 071 @SuppressWarnings("unchecked") // safe since the proxy implements type 072 private <T> T createFakeResource(Class<T> type, final String name) { 073 return (T) Proxy.newProxyInstance( 074 FakeClientBundleProvider.class.getClassLoader(), 075 new Class<?>[] {type}, 076 new InvocationHandler() { 077 @Override 078 public Object invoke(Object proxy, Method method, Object[] args) throws Exception { 079 Class<?> returnType = method.getReturnType(); 080 if (returnType == String.class) { 081 return name; 082 } else if (returnType == SafeHtml.class) { 083 return SafeHtmlUtils.fromTrustedString(name); 084 } else if (returnType == SafeUri.class) { 085 return UriUtils.fromTrustedString(name); 086 } else if (returnType == boolean.class) { 087 return false; 088 } else if (returnType == int.class) { 089 return 0; 090 } else if (method.getParameterTypes()[0] == ResourceCallback.class) { 091 // Read the underlying resource type out of the generic parameter 092 // in the method's argument 093 Class<?> resourceType = 094 (Class<?>) 095 ((ParameterizedType) args[0].getClass().getGenericInterfaces()[0]) 096 .getActualTypeArguments()[0]; 097 ((ResourceCallback<ResourcePrototype>) args[0]).onSuccess( 098 (ResourcePrototype) createFakeResource(resourceType, name)); 099 return null; 100 } else { 101 throw new IllegalArgumentException( 102 "Unexpected return type for method " + method.getName()); 103 } 104 } 105 }); 106 } 107 }