    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    }