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.safehtml.shared.SafeHtml;
019    import com.google.gwt.safehtml.shared.SafeHtmlUtils;
020    import com.google.gwt.safehtml.shared.SafeUri;
021    
022    import java.lang.reflect.InvocationHandler;
023    import java.lang.reflect.Method;
024    import java.lang.reflect.Proxy;
025    import java.util.Arrays;
026    
027    /**
028     * Provides fake implementations of {@link com.google.gwt.i18n.client.Messages},
029     * {@link com.google.gwt.resources.client.CssResource}, and
030     * {@link com.google.gwt.safehtml.client.SafeHtmlTemplates}. The fake
031     * implementations implement methods by returning Strings of SafeHtml instances
032     * based on the method name and the arguments passed to it. The exact format of
033     * the message is undefined and is subject to change.
034     *
035     * @author ekuefler@google.com (Erik Kuefler)
036     */
037    public class FakeMessagesProvider<T> implements FakeProvider<T> {
038    
039      /**
040       * Returns a new instance of the given type that implements methods as
041       * described in the class description.
042       *
043       * @param type interface to be implemented by the returned type.
044       */
045      @Override
046      @SuppressWarnings("unchecked") // safe since the proxy implements type
047      public T getFake(Class<?> type) {
048        return (T) Proxy.newProxyInstance(FakeMessagesProvider.class.getClassLoader(), new Class<?>[] {type},
049            new InvocationHandler() {
050              @Override
051              public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
052                if (method.getName().equals("ensureInjected")) {
053                  return true;
054                } else if (method.getReturnType() == String.class) {
055                  return buildMessage(method, args);
056                } else if (method.getReturnType() == SafeHtml.class) {
057                  return SafeHtmlUtils.fromTrustedString(buildMessage(method, args));
058                } else {
059                  throw new IllegalArgumentException(method.getName()
060                      + " must return either String or SafeHtml");
061                }
062              }
063            });
064      }
065    
066      private String buildMessage(Method method, Object[] args) {
067        StringBuilder message = new StringBuilder(method.getName());
068        if (args == null || args.length == 0) {
069          return message.toString();
070        }
071    
072        message.append('(');
073        message.append(stringify(args[0]));
074        for (Object arg : Arrays.asList(args).subList(1, args.length)) {
075          message.append(", ").append(stringify(arg));
076        }
077        return message.append(')').toString();
078      }
079    
080      private String stringify(Object arg) {
081        if (arg == null) {
082          return "null";
083        } else if (arg instanceof SafeHtml) {
084          return ((SafeHtml) arg).asString();
085        } else if (arg instanceof SafeUri) {
086          return ((SafeUri) arg).asString();
087        } else {
088          return arg.toString();
089        }
090      }
091    }