blob: 6f5882f1cd49e28d6f8b1037cd6b587acea1d801 [file] [log] [blame]
/*
* Copyright (c) 2016 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.matchers.text;
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.Map;
import static java.lang.String.valueOf;
/**
* Prints a Java object value in a way humans can read it neatly.
* Inspired on hamcrest. Used for printing arguments in verification errors.
*/
public class ValuePrinter {
private ValuePrinter(){}
/**
* Prints given value so that it is neatly readable by humans.
* Handles explosive toString() implementations.
*/
public static String print(final Object value) {
if (value == null) {
return "null";
}
if (value instanceof String) {
return '"' + value.toString() + '"';
}
if (value instanceof Character) {
return printChar((Character) value);
}
if (value instanceof Long) {
return value + "L";
}
if (value instanceof Double) {
return value + "d";
}
if (value instanceof Float) {
return value + "f";
}
if (value instanceof Short) {
return "(short) " + value;
}
if (value instanceof Byte) {
return String.format("(byte) 0x%02X", (Byte) value);
}
if (value instanceof Map) {
return printMap((Map<?, ?>) value);
}
if (value.getClass().isArray()) {
return printValues("[", ", ", "]", new Iterator<Object>() {
private int currentIndex = 0;
public boolean hasNext() {
return currentIndex < Array.getLength(value);
}
public Object next() {
return Array.get(value, currentIndex++);
}
public void remove() {
throw new UnsupportedOperationException("cannot remove items from an array");
}
});
}
if (value instanceof FormattedText) {
return (((FormattedText) value).getText());
}
return descriptionOf(value);
}
private static String printMap(Map<?,?> map) {
StringBuilder result = new StringBuilder();
Iterator<? extends Map.Entry<?, ?>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<?, ?> entry = iterator.next();
result.append(print(entry.getKey())).append(" = ").append(print(entry.getValue()));
if (iterator.hasNext()) {
result.append(", ");
}
}
return "{" + result.toString() + "}";
}
/**
* Print values in a nice format, e.g. (1, 2, 3)
*
* @param start the beginning of the values, e.g. "("
* @param separator the separator of values, e.g. ", "
* @param end the end of the values, e.g. ")"
* @param values the values to print
*
* @return neatly formatted value list
*/
public static String printValues(String start, String separator, String end, Iterator<?> values) {
if(start == null){
start = "(";
}
if (separator == null){
separator = ",";
}
if (end == null){
end = ")";
}
StringBuilder sb = new StringBuilder(start);
while(values.hasNext()) {
sb.append(print(values.next()));
if (values.hasNext()) {
sb.append(separator);
}
}
return sb.append(end).toString();
}
private static String printChar(char value) {
StringBuilder sb = new StringBuilder();
sb.append('\'');
switch (value) {
case '"':
sb.append("\\\"");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
default:
sb.append(value);
}
sb.append('\'');
return sb.toString();
}
private static String descriptionOf(Object value) {
try {
return valueOf(value);
}
catch (Exception e) {
return value.getClass().getName() + "@" + Integer.toHexString(value.hashCode());
}
}
}