001    /*
002     * $Id: IOTester.java,v 1.7 2014/05/04 18:34:33 oboehm Exp $
003     *
004     * Copyright (c) 2011 by Oliver Boehm
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     *
018     * (c)reated 30.03.2011 by oliver (ob@oasd.de)
019     */
020    
021    package patterntesting.runtime.junit;
022    
023    import java.io.*;
024    import java.nio.charset.Charset;
025    import java.util.regex.Pattern;
026    
027    import org.junit.Assert;
028    import org.slf4j.*;
029    
030    import patterntesting.annotation.check.runtime.MayReturnNull;
031    import patterntesting.runtime.io.LineReader;
032    
033    /**
034     * With the IOTester you can assert if two files have equals content or
035     * if two directories have the same structure with equal files.
036     * <br/>
037     * Note: This test is not yet tested with binary files.
038     *
039     * @author oliver
040     * @since 1.1 (30.03.2011)
041     */
042    public final class IOTester {
043    
044        private static final Logger log = LoggerFactory.getLogger(IOTester.class);
045    
046        /** Utility class - no need to instantiate it. */
047        private IOTester() {}
048    
049        /**
050         * Asserts that the content of two InputStream are equal.
051         * If they are not equals the first different line or byte will be shown.
052         *
053         * @param in1 the first InputStream
054         * @param in2 the second InputStream
055         * @throws AssertionError if the check fails
056         */
057        public static void assertContentEquals(final InputStream in1, final InputStream in2)
058                throws AssertionError {
059            assertContentEquals(new InputStreamReader(in1), new InputStreamReader(in2));
060        }
061    
062        /**
063         * Asserts that the content of two InputStream are equal.
064         * If they are not equals the first different line or byte will be shown.
065         *
066         * @param in1 the first InputStream
067         * @param in2 the second InputStream
068         * @param encoding the encoding
069         * @throws AssertionError if the check fails
070         */
071        public static void assertContentEquals(final InputStream in1, final InputStream in2,
072                final Charset encoding) throws AssertionError {
073            assertContentEquals(in1, in2, Charset.defaultCharset());
074        }
075    
076        /**
077         * Asserts that the content of two InputStream are equal.
078         * If they are not equals the first different line or byte will be shown.
079         *
080         * @param in1 the first InputStream
081         * @param in2 the second InputStream
082         * @param from the line number from which the comparison is started
083         *            (starting with 1)
084         * @param to the last line number where the comparison ends.
085         * @throws AssertionError if the check fails
086         */
087        public static void assertContentEquals(final InputStream in1, final InputStream in2,
088                final int from, final int to) throws AssertionError {
089            assertContentEquals(in1, in2, Charset.defaultCharset(), from, to);
090        }
091    
092        /**
093         * Asserts that the content of two InputStream are equal.
094         * If they are not equals the first different line or byte will be shown.
095         *
096         * @param in1 the first InputStream
097         * @param in2 the second InputStream
098         * @param encoding the encoding
099         * @param from the line number from which the comparison is started
100         * (starting with 1)
101         * @param to the last line number where the comparison ends.
102         * @throws AssertionError if the check fails
103         */
104        public static void assertContentEquals(final InputStream in1, final InputStream in2,
105                final Charset encoding, final int from, final int to) throws AssertionError {
106            assertContentEquals(new InputStreamReader(in1, encoding), new InputStreamReader(in2,
107                    encoding), from, to);
108        }
109    
110        /**
111         * Asserts that the content of two Readers are equal.
112         * If they are not equals the first different line or byte will be shown.
113         *
114         * @param in1 the first InputStream
115         * @param in2 the second InputStream
116         * @param ignores the lines matching this pattern will be ignored
117         * @throws AssertionError if the check fails
118         */
119        public static void assertContentEquals(final InputStream in1, final InputStream in2,
120                final Pattern... ignores) throws AssertionError {
121            assertContentEquals(in1, in2, Charset.defaultCharset(), ignores);
122        }
123    
124        /**
125         * Asserts that the content of two Readers are equal.
126         * If they are not equals the first different line or byte will be shown.
127         *
128         * @param in1 the first InputStream
129         * @param in2 the second InputStream
130         * @param encoding the encoding
131         * @param ignores the lines matching this pattern will be ignored
132         * @throws AssertionError if the check fails
133         */
134        public static void assertContentEquals(final InputStream in1, final InputStream in2,
135                final Charset encoding, final Pattern... ignores) throws AssertionError {
136            assertContentEquals(new InputStreamReader(in1, encoding), new InputStreamReader(in2,
137                    encoding), ignores);
138        }
139    
140        /**
141         * Asserts that the content of two Readers are equal.
142         * If they are not equals the first different line or byte will be shown.
143         *
144         * @param r1 the first Reader
145         * @param r2 the second Reader
146         * @throws AssertionError if the check fails
147         */
148        // TODO: shold work also for binary files
149        public static void assertContentEquals(final Reader r1, final Reader r2) throws AssertionError {
150            assertContentEquals(new BufferedReader(r1), new BufferedReader(r2));
151        }
152    
153        /**
154         * Asserts that the content of two Readers are equal.
155         * If they are not equals the first different line or byte will be shown.
156         *
157         * @param r1 the first Reader
158         * @param r2 the second Reader
159         * @param from the line number from which the comparison is started
160         *            (starting with 1)
161         * @param to the last line number where the comparison ends.
162         * @throws AssertionError if the check fails
163         */
164        public static void assertContentEquals(final Reader r1, final Reader r2, final int from,
165                final int to) throws AssertionError {
166            assertContentEquals(new LineReader(r1), new LineReader(r2), from, to);
167        }
168    
169        /**
170         * Asserts that the content of two Readers are equal.
171         * If they are not equals the first different line or byte will be shown.
172         *
173         * @param r1 the first Reader
174         * @param r2 the second Reader
175         * @param ignores the lines matching this pattern will be ignored
176         * @throws AssertionError if the check fails
177         */
178        public static void assertContentEquals(final Reader r1, final Reader r2,
179                final Pattern... ignores) throws AssertionError {
180            assertContentEquals(new LineReader(r1), new LineReader(r2), ignores);
181        }
182    
183        /**
184         * Asserts that the content of two Readers are equal.
185         * If they are not equals the first different line or byte will be shown.
186         *
187         * @param r1 the first Reader
188         * @param r2 the second Reader
189         * @throws AssertionError if the check fails
190         */
191        public static void assertContentEquals(final BufferedReader r1, final BufferedReader r2)
192                throws AssertionError {
193            assertContentEquals(r1, r2, 1, Integer.MAX_VALUE);
194        }
195    
196        /**
197         * Asserts that the content of two Readers are equal.
198         * If they are not equals the first different line or byte will be shown.
199         *
200         * @param r1 the first Reader
201         * @param r2 the second Reader
202         * @param from the line number from which the comparison is started
203         *            (starting with 1)
204         * @param to the last line number where the comparison ends.
205         * @throws AssertionError if the check fails
206         */
207        public static void assertContentEquals(final LineReader r1, final LineReader r2,
208                final int from, final int to) throws AssertionError {
209            try {
210                r1.skipLines(from - 1);
211                r2.skipLines(from - 1);
212                for (int lineNo = from; lineNo <= to; lineNo++) {
213                    String line1 = r1.readLine();
214                    String line2 = r2.readLine();
215                    if ((line1 == null) && (line2 == null)) {
216                        return;
217                    }
218                    Assert.assertEquals("line " + lineNo + " -", line1, line2);
219                }
220            } catch (IOException ioe) {
221                throw new AssertionError(ioe);
222            }
223        }
224    
225        /**
226         * Asserts that the content of two Readers are equal.
227         * If they are not equals the first different line or byte will be shown.
228         *
229         * @param r1 the first Reader
230         * @param r2 the second Reader
231         * @param ignores the lines matching this pattern will be ignored
232         * @throws AssertionError if the check fails
233         */
234        public static void assertContentEquals(final LineReader r1, final LineReader r2,
235                final Pattern... ignores) throws AssertionError {
236            try {
237                for (;;) {
238                    String line1 = nextLine(r1, ignores);
239                    String line2 = nextLine(r2, ignores);
240                    if ((line1 == null) && (line2 == null)) {
241                        return;
242                    }
243                    if (r1.getLineNumber() == r2.getLineNumber()) {
244                        Assert.assertEquals("line " + r1.getLineNumber() + " -", line1, line2);
245                    } else {
246                        Assert.assertEquals("line " + r1.getLineNumber() + "/"  + r2.getLineNumber() + " -", line1, line2);
247                    }
248                }
249            } catch (IOException ioe) {
250                throw new AssertionError(ioe);
251            }
252        }
253    
254        @MayReturnNull
255        private static String nextLine(final BufferedReader reader, final Pattern... ignores) throws IOException {
256            for (String line = reader.readLine(); line != null; line = reader.readLine()) {
257                if (matches(line, ignores)) {
258                    log.trace("\"{}\" maches {} and is ignored.", line, ignores);
259                } else {
260                    return line;
261                }
262            }
263            return null;
264        }
265    
266        private static boolean matches(final String line, final Pattern[] ignores) {
267            for (int i = 0; i < ignores.length; i++) {
268                if (ignores[i].matcher(line).matches()) {
269                    return true;
270                }
271            }
272            return false;
273        }
274    
275    }
276