001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of 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,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.common.util;
017
018import static org.hamcrest.core.Is.is;
019import static org.junit.Assert.assertArrayEquals;
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertThat;
022import static org.hamcrest.CoreMatchers.containsString;
023import java.io.ByteArrayInputStream;
024import java.io.ByteArrayOutputStream;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.PrintStream;
028import java.io.Reader;
029import java.io.StringReader;
030import java.util.List;
031import org.junit.Test;
032import org.modeshape.common.FixFor;
033
034public class StringUtilTest {
035
036    public void compareSeparatedLines( Object... lines ) {
037        ByteArrayOutputStream content = new ByteArrayOutputStream();
038        PrintStream stream = new PrintStream(content);
039        for (Object line : lines) {
040            stream.println(line);
041        }
042        List<String> actualLines = StringUtil.splitLines(content.toString());
043        assertArrayEquals(lines, actualLines.toArray());
044    }
045
046    @Test
047    public void splitLinesShouldWorkCorrectly() {
048        compareSeparatedLines("Line 1", "Line 2", "Line 3", "Line 4");
049    }
050
051    @Test( expected = IllegalArgumentException.class )
052    public void createStringShouldFailIfNoPatternSupplied() {
053        StringUtil.createString(null, (Object[])null);
054    }
055
056    @Test
057    public void createStringShouldAllowNoParametersSupplied() {
058        assertThat(StringUtil.createString("test", (Object[])null), is("test"));
059    }
060
061    @Test
062    public void createStringShouldCreateStringFromPattern() {
063        String pattern = "This {0} is {1} should {2} not {3} last {4}";
064        assertEquals("This one is two should three not four last five", StringUtil.createString(pattern,
065                                                                                                "one",
066                                                                                                "two",
067                                                                                                "three",
068                                                                                                "four",
069                                                                                                "five"));
070    }
071
072    @Test( expected = IllegalArgumentException.class )
073    public void createStringShouldFailIfTooFewArgumentsSupplied() {
074        String pattern = "This {0} is {1} should {2} not {3} last {4}";
075        try {
076            StringUtil.createString(pattern, "one", "two", "three", "four");
077        } catch (IllegalArgumentException err) {
078            System.err.println(err);
079            throw err;
080        }
081    }
082
083    @Test( expected = IllegalArgumentException.class )
084    public void createStringShouldFailIfTooManyArgumentsSupplied() {
085        String pattern = "This {0} is {1} should {2} not {3} last {4}";
086        try {
087            StringUtil.createString(pattern, "one", "two", "three", "four", "five", "six");
088        } catch (IllegalArgumentException err) {
089            System.err.println(err);
090            throw err;
091        }
092    }
093
094    @Test
095    public void createStringExceptionMessageShouldbeGrammaticallyCorrect() {
096        String pattern = "One = {0}";
097        try {
098            StringUtil.createString(pattern);
099        } catch (IllegalArgumentException err) {
100            assertThat(err.getMessage().startsWith("0 parameters supplied, but 1 parameter required"), is(true));
101        }
102        pattern = "One";
103        try {
104            StringUtil.createString(pattern, "one");
105        } catch (IllegalArgumentException err) {
106            assertThat(err.getMessage().startsWith("1 parameter supplied, but 0 parameters required"), is(true));
107        }
108        pattern = "One = {0}, Two = {1}";
109        try {
110            StringUtil.createString(pattern);
111        } catch (IllegalArgumentException err) {
112            assertThat(err.getMessage().startsWith("0 parameters supplied, but 2 parameters required"), is(true));
113        }
114    }
115
116    @Test
117    public void setLengthShouldTruncateStringsThatAreTooLong() {
118        assertEquals("This is the st", StringUtil.setLength("This is the string", 14, ' '));
119    }
120
121    @Test
122    @FixFor( "MODE-2322" )
123    public void shouldSupportPrimitiveArrays() {
124        String text = StringUtil.createString("Error converting \"{2}\" from {0} to a {1}",
125                                              byte[].class.getSimpleName(),
126                                              "BinaryValue",
127                                              new byte[] {-1});
128        assertEquals("Error converting \"[-1]\" from byte[] to a BinaryValue", text);
129    }
130
131    @Test
132    public void setLengthShouldAppendCharacterForStringsThatAreTooShort() {
133        assertEquals("This      ", StringUtil.setLength("This", 10, ' '));
134    }
135
136    @Test
137    public void setLengthShouldNotRemoveLeadingWhitespace() {
138        assertEquals(" This     ", StringUtil.setLength(" This", 10, ' '));
139        assertEquals("\tThis     ", StringUtil.setLength("\tThis", 10, ' '));
140    }
141
142    @Test
143    public void setLengthShouldAppendCharacterForEmptyStrings() {
144        assertEquals("          ", StringUtil.setLength("", 10, ' '));
145    }
146
147    @Test
148    public void setLengthShouldAppendCharacterForNullStrings() {
149        assertEquals("          ", StringUtil.setLength(null, 10, ' '));
150    }
151
152    @Test
153    public void setLengthShouldReturnStringsThatAreTheDesiredLength() {
154        assertEquals("This is the string", StringUtil.setLength("This is the string", 18, ' '));
155    }
156
157    @Test
158    public void justifyLeftShouldTruncateStringsThatAreTooLong() {
159        assertEquals("This is the st", StringUtil.justifyLeft("This is the string", 14, ' '));
160    }
161
162    @Test
163    public void justifyLeftShouldAppendCharacterForStringsThatAreTooShort() {
164        assertEquals("This      ", StringUtil.justifyLeft("This", 10, ' '));
165    }
166
167    @Test
168    public void justifyLeftShouldRemoveLeadingWhitespace() {
169        assertEquals("This      ", StringUtil.justifyLeft(" This", 10, ' '));
170        assertEquals("This      ", StringUtil.justifyLeft("\tThis", 10, ' '));
171    }
172
173    @Test
174    public void justifyLeftShouldAppendCharacterForEmptyStrings() {
175        assertEquals("          ", StringUtil.justifyLeft("", 10, ' '));
176    }
177
178    @Test
179    public void justifyLeftShouldAppendCharacterForNullStrings() {
180        assertEquals("          ", StringUtil.justifyLeft(null, 10, ' '));
181    }
182
183    @Test
184    public void justifyLeftShouldReturnStringsThatAreTheDesiredLength() {
185        assertEquals("This is the string", StringUtil.justifyLeft("This is the string", 18, ' '));
186    }
187
188    @Test
189    public void justifyRightShouldTruncateStringsThatAreTooLong() {
190        assertEquals(" is the string", StringUtil.justifyRight("This is the string", 14, ' '));
191    }
192
193    @Test
194    public void justifyRightShouldPrependCharacterForStringsThatAreTooShort() {
195        assertEquals("      This", StringUtil.justifyRight("This", 10, ' '));
196    }
197
198    @Test
199    public void justifyRightShouldPrependCharacterForEmptyStrings() {
200        assertEquals("          ", StringUtil.justifyRight("", 10, ' '));
201    }
202
203    @Test
204    public void justifyRightShouldPrependCharacterForNullStrings() {
205        assertEquals("          ", StringUtil.justifyRight(null, 10, ' '));
206    }
207
208    @Test
209    public void justifyRightShouldReturnStringsThatAreTheDesiredLength() {
210        assertEquals("This is the string", StringUtil.justifyRight("This is the string", 18, ' '));
211    }
212
213    @Test
214    public void justifyCenterShouldTruncateStringsThatAreTooLong() {
215        assertEquals("This is the st", StringUtil.justifyCenter("This is the string", 14, ' '));
216    }
217
218    @Test
219    public void justifyCenterShouldPrependAndAppendSameNumberOfCharacterForStringsThatAreTooShortButOfAnEvenLength() {
220        assertEquals("   This   ", StringUtil.justifyCenter("This", 10, ' '));
221    }
222
223    @Test
224    public void justifyCenterShouldPrependOneMoreCharacterThanAppendingForStringsThatAreTooShortButOfAnOddLength() {
225        assertEquals("   Thing  ", StringUtil.justifyCenter("Thing", 10, ' '));
226    }
227
228    @Test
229    public void justifyCenterShouldPrependCharacterForEmptyStrings() {
230        assertEquals("          ", StringUtil.justifyCenter("", 10, ' '));
231    }
232
233    @Test
234    public void justifyCenterShouldPrependCharacterForNullStrings() {
235        assertEquals("          ", StringUtil.justifyCenter(null, 10, ' '));
236    }
237
238    @Test
239    public void justifyCenterShouldReturnStringsThatAreTheDesiredLength() {
240        assertEquals("This is the string", StringUtil.justifyCenter("This is the string", 18, ' '));
241    }
242
243    @Test
244    public void truncateShouldReturnEmptyStringIfNullReferenceIsSupplied() {
245        assertThat(StringUtil.truncate(null, 0), is(""));
246        assertThat(StringUtil.truncate(null, 1), is(""));
247        assertThat(StringUtil.truncate(null, 100), is(""));
248    }
249
250    @Test( expected = IllegalArgumentException.class )
251    public void truncateShouldNotAllowNegativeLength() {
252        StringUtil.truncate("some string", -1);
253    }
254
255    @Test
256    public void truncateShouldReturnEmptyStringForMaximumLengthOfZero() {
257        String str = "This is the string with some text";
258        assertThat(StringUtil.truncate(str, 0), is(""));
259        assertThat(StringUtil.truncate("", 0), is(""));
260        assertThat(StringUtil.truncate(str, 0, "123"), is(""));
261        assertThat(StringUtil.truncate("", 0, "123"), is(""));
262    }
263
264    @Test
265    public void truncateShouldNotTruncateStringShorterThanMaximumLength() {
266        String str = "This is the string with some text";
267        assertThat(StringUtil.truncate(str, str.length() + 2), is(str));
268        assertThat(StringUtil.truncate(str, str.length() + 2, null), is(str));
269        assertThat(StringUtil.truncate(str, str.length() + 2, "really long suffix"), is(str));
270    }
271
272    @Test
273    public void truncateShouldNotTruncateStringWithLengthEqualToMaximumLength() {
274        String str = "This is the string with some text";
275        assertThat(StringUtil.truncate(str, str.length()), is(str));
276        assertThat(StringUtil.truncate(str, str.length(), null), is(str));
277        assertThat(StringUtil.truncate(str, str.length(), "really long suffix"), is(str));
278    }
279
280    @Test
281    public void truncateShouldProperlyTruncateStringWithLengthGreaterThanMaximumLength() {
282        String str = "This is the string";
283        assertThat(StringUtil.truncate(str, str.length() - 1), is("This is the st..."));
284        assertThat(StringUtil.truncate(str, str.length() - 1, null), is("This is the st..."));
285        assertThat(StringUtil.truncate(str, str.length() - 1, "X"), is("This is the striX"));
286    }
287
288    @Test
289    public void truncateShouldProperlyTruncateStringWithLengthGreaterThanMaximumLengthAndMaximumLengthLongerThanPrefixLength() {
290        String str = "This is the string";
291        assertThat(StringUtil.truncate(str, 2), is(".."));
292        assertThat(StringUtil.truncate(str, 2, null), is(".."));
293        assertThat(StringUtil.truncate(str, 1, "XX"), is("X"));
294    }
295
296    @Test
297    public void readShouldReturnEmptyStringForNullInputStream() throws Exception {
298        assertThat(StringUtil.read((InputStream)null), is(""));
299    }
300
301    @Test
302    public void readShouldReturnEmptyStringForNullReader() throws Exception {
303        assertThat(StringUtil.read((Reader)null), is(""));
304    }
305
306    @Test
307    public void readShouldReadInputStreamCorrectlyAndShouldCloseStream() throws Exception {
308        // Read content shorter than buffer size ...
309        String content = "This is the way to grandma's house.";
310        InputStream stream = new ByteArrayInputStream(content.getBytes());
311        InputStreamWrapper wrapper = new InputStreamWrapper(stream);
312        assertThat(wrapper.isClosed(), is(false));
313        assertThat(StringUtil.read(wrapper), is(content));
314        assertThat(wrapper.isClosed(), is(true));
315
316        // Read content longer than buffer size ...
317        for (int i = 0; i != 10; ++i) {
318            content += content; // note this doubles each time!
319        }
320        stream = new ByteArrayInputStream(content.getBytes());
321        wrapper = new InputStreamWrapper(stream);
322        assertThat(wrapper.isClosed(), is(false));
323        assertThat(StringUtil.read(wrapper), is(content));
324        assertThat(wrapper.isClosed(), is(true));
325    }
326
327    @Test
328    public void readShouldReadReaderCorrectlyAndShouldCloseStream() throws Exception {
329        // Read content shorter than buffer size ...
330        String content = "This is the way to grandma's house.";
331        Reader reader = new StringReader(content);
332        ReaderWrapper wrapper = new ReaderWrapper(reader);
333        assertThat(wrapper.isClosed(), is(false));
334        assertThat(StringUtil.read(wrapper), is(content));
335        assertThat(wrapper.isClosed(), is(true));
336
337        // Read content longer than buffer size ...
338        for (int i = 0; i != 10; ++i) {
339            content += content; // note this doubles each time!
340        }
341        reader = new StringReader(content);
342        wrapper = new ReaderWrapper(reader);
343        assertThat(wrapper.isClosed(), is(false));
344        assertThat(StringUtil.read(wrapper), is(content));
345        assertThat(wrapper.isClosed(), is(true));
346    }
347
348    @Test
349    public void getStackTraceShouldReturnStackTrace() {
350        String msg = "This is the message for a test exception";
351        Throwable t = new IllegalArgumentException(msg);
352        String trace = StringUtil.getStackTrace(t);
353        assertThat(trace, containsString(msg));
354        assertThat(trace, containsString(this.getClass().getName()));
355    }
356
357    @Test( expected = IllegalArgumentException.class )
358    public void normalizeShouldFailIfTextNull() {
359        StringUtil.normalize(null);
360    }
361
362    @Test
363    public void normalizeShouldRemoveLeadingTrailingWhitespace() {
364        assertThat(StringUtil.normalize(" \t\n test this \t"), is("test this"));
365    }
366
367    @Test
368    public void normalizeShouldReduceInternalWhitespace() {
369        assertThat(StringUtil.normalize("test \t\n\r this"), is("test this"));
370    }
371
372    @Test
373    public void normalizeShouldReturnEqualStringIfNothingToNormalize() {
374        assertThat(StringUtil.normalize("test this"), is("test this"));
375    }
376
377    protected class InputStreamWrapper extends InputStream {
378
379        private boolean closed = false;
380        private final InputStream stream;
381
382        protected InputStreamWrapper( InputStream stream ) {
383            this.stream = stream;
384        }
385
386        public boolean isClosed() {
387            return closed;
388        }
389
390        @Override
391        public int read() throws IOException {
392            return stream.read();
393        }
394
395        @Override
396        public void close() throws IOException {
397            stream.close();
398            this.closed = true;
399        }
400
401    }
402
403    protected class ReaderWrapper extends Reader {
404
405        private boolean closed = false;
406        private final Reader reader;
407
408        protected ReaderWrapper( Reader reader ) {
409            this.reader = reader;
410        }
411
412        public boolean isClosed() {
413            return closed;
414        }
415
416        @Override
417        public void close() throws IOException {
418            reader.close();
419            this.closed = true;
420        }
421
422        @Override
423        public int read( char[] cbuf,
424                         int off,
425                         int len ) throws IOException {
426            return reader.read(cbuf, off, len);
427        }
428    }
429
430}