001 package org.hamcrest; 002 003 import static java.lang.String.valueOf; 004 005 import java.util.Arrays; 006 import java.util.Iterator; 007 008 import org.hamcrest.internal.ArrayIterator; 009 import org.hamcrest.internal.SelfDescribingValueIterator; 010 011 /** 012 * A {@link Description} that is stored as a string. 013 */ 014 public abstract class BaseDescription implements Description { 015 016 @Override 017 public Description appendText(String text) { 018 append(text); 019 return this; 020 } 021 022 @Override 023 public Description appendDescriptionOf(SelfDescribing value) { 024 value.describeTo(this); 025 return this; 026 } 027 028 @Override 029 public Description appendValue(Object value) { 030 if (value == null) { 031 append("null"); 032 } else if (value instanceof String) { 033 toJavaSyntax((String) value); 034 } else if (value instanceof Character) { 035 append('"'); 036 toJavaSyntax((Character) value); 037 append('"'); 038 } else if (value instanceof Short) { 039 append('<'); 040 append(descriptionOf(value)); 041 append("s>"); 042 } else if (value instanceof Long) { 043 append('<'); 044 append(descriptionOf(value)); 045 append("L>"); 046 } else if (value instanceof Float) { 047 append('<'); 048 append(descriptionOf(value)); 049 append("F>"); 050 } else if (value.getClass().isArray()) { 051 appendValueList("[",", ","]", new ArrayIterator(value)); 052 } else { 053 append('<'); 054 append(descriptionOf(value)); 055 append('>'); 056 } 057 return this; 058 } 059 060 private String descriptionOf(Object value) { 061 try { 062 return valueOf(value); 063 } 064 catch (Exception e) { 065 return value.getClass().getName() + "@" + Integer.toHexString(value.hashCode()); 066 } 067 } 068 069 @Override 070 public <T> Description appendValueList(String start, String separator, String end, T... values) { 071 return appendValueList(start, separator, end, Arrays.asList(values)); 072 } 073 074 @Override 075 public <T> Description appendValueList(String start, String separator, String end, Iterable<T> values) { 076 return appendValueList(start, separator, end, values.iterator()); 077 } 078 079 private <T> Description appendValueList(String start, String separator, String end, Iterator<T> values) { 080 return appendList(start, separator, end, new SelfDescribingValueIterator<T>(values)); 081 } 082 083 @Override 084 public Description appendList(String start, String separator, String end, Iterable<? extends SelfDescribing> values) { 085 return appendList(start, separator, end, values.iterator()); 086 } 087 088 private Description appendList(String start, String separator, String end, Iterator<? extends SelfDescribing> i) { 089 boolean separate = false; 090 091 append(start); 092 while (i.hasNext()) { 093 if (separate) append(separator); 094 appendDescriptionOf(i.next()); 095 separate = true; 096 } 097 append(end); 098 099 return this; 100 } 101 102 /** 103 * Append the String <var>str</var> to the description. 104 * The default implementation passes every character to {@link #append(char)}. 105 * Override in subclasses to provide an efficient implementation. 106 */ 107 protected void append(String str) { 108 for (int i = 0; i < str.length(); i++) { 109 append(str.charAt(i)); 110 } 111 } 112 113 /** 114 * Append the char <var>c</var> to the description. 115 */ 116 protected abstract void append(char c); 117 118 private void toJavaSyntax(String unformatted) { 119 append('"'); 120 for (int i = 0; i < unformatted.length(); i++) { 121 toJavaSyntax(unformatted.charAt(i)); 122 } 123 append('"'); 124 } 125 126 private void toJavaSyntax(char ch) { 127 switch (ch) { 128 case '"': 129 append("\\\""); 130 break; 131 case '\n': 132 append("\\n"); 133 break; 134 case '\r': 135 append("\\r"); 136 break; 137 case '\t': 138 append("\\t"); 139 break; 140 default: 141 append(ch); 142 } 143 } 144 }