xref: /OpenGrok/opengrok-indexer/src/test/java/org/opengrok/indexer/util/CustomAssertions.java (revision d6df19e1b22784c78f567cf74c42f18e3901b900)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2017, 2019, Chris Fraire <cfraire@me.com>.
22  */
23 package org.opengrok.indexer.util;
24 
25 import java.io.ByteArrayInputStream;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.Reader;
29 import java.nio.charset.StandardCharsets;
30 import java.util.ArrayList;
31 import java.util.List;
32 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
33 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
34 import org.opengrok.indexer.analysis.JFlexSymbolMatcher;
35 import org.opengrok.indexer.analysis.JFlexTokenizer;
36 
37 import static org.junit.jupiter.api.Assertions.assertEquals;
38 import static org.junit.jupiter.api.Assertions.assertTrue;
39 import static org.opengrok.indexer.util.StreamUtils.copyStream;
40 
41 /**
42  * Represents a container for custom test assertion methods.
43  */
44 public class CustomAssertions {
45     /**
46      * non-public so as to be just a static container class.
47      */
CustomAssertions()48     protected CustomAssertions() {
49     }
50 
51     /**
52      * Asserts the specified strings have equal contents, comparing line-wise
53      * after splitting on LFs.
54      * @param messagePrefix a message prefixed to line-specific or length-
55      * specific errors
56      * @param expected the expected content
57      * @param actual the actual content
58      */
assertLinesEqual(String messagePrefix, String expected, String actual)59     public static void assertLinesEqual(String messagePrefix, String expected, String actual) {
60         String[] expecteds = expected.split("\n");
61         String[] gotten = actual.split("\n");
62         assertLinesEqual(messagePrefix, expecteds, gotten);
63     }
64 
65     /**
66      * Asserts the specified lines arrays have equal contents.
67      * @param messagePrefix a message prefixed to line-specific or length-
68      * specific errors
69      * @param expecteds the expected content of lines
70      * @param actuals the actual content of lines
71      */
assertLinesEqual(String messagePrefix, String[] expecteds, String[] actuals)72     public static void assertLinesEqual(String messagePrefix, String[] expecteds, String[] actuals) {
73 
74         List<Integer> diffLines = new ArrayList<>();
75 
76         final int SHOW_N_DIFFS = 50;
77         int ndiffs = 0;
78         int lastDiff = -2;
79         for (int i = 0; i < expecteds.length || i < actuals.length; i++) {
80             if (i >= expecteds.length || i >= actuals.length ||
81                 !expecteds[i].equals(actuals[i])) {
82 
83                 if (lastDiff + 1 != i && !diffLines.isEmpty()) {
84                     printDiffs(expecteds, actuals, diffLines);
85                     diffLines.clear();
86                 }
87                 ++ndiffs;
88                 lastDiff = i;
89                 diffLines.add(i);
90                 if (ndiffs >= SHOW_N_DIFFS) {
91                     break;
92                 }
93             }
94         }
95         if (!diffLines.isEmpty()) {
96             printDiffs(expecteds, actuals, diffLines);
97             diffLines.clear();
98         }
99 
100         assertEquals(0, ndiffs, messagePrefix + "--should have no diffs");
101         assertEquals(expecteds.length, actuals.length, messagePrefix + "--number of lines");
102     }
103 
104     /**
105      * Asserts the specified tokenizer class produces an expected stream of
106      * symbols from the specified input.
107      * @param klass the test class
108      * @param iss the input stream
109      * @param expectedTokens the expected, ordered token list
110      * @throws java.lang.Exception if an error occurs constructing a
111      * {@code klass} instance or testing the stream
112      */
assertSymbolStream(Class<? extends JFlexSymbolMatcher> klass, InputStream iss, List<String> expectedTokens)113     public static void assertSymbolStream(Class<? extends JFlexSymbolMatcher> klass, InputStream iss,
114             List<String> expectedTokens) throws Exception {
115 
116         byte[] inputCopy = copyStream(iss);
117         String input = new String(inputCopy, StandardCharsets.UTF_8);
118         JFlexTokenizer tokenizer = new JFlexTokenizer(
119             klass.getConstructor(Reader.class).newInstance(
120                     new InputStreamReader(new ByteArrayInputStream(inputCopy), StandardCharsets.UTF_8)));
121 
122         CharTermAttribute term = tokenizer.addAttribute(
123             CharTermAttribute.class);
124         OffsetAttribute offs = tokenizer.addAttribute(OffsetAttribute.class);
125 
126         int count = 0;
127         List<String> tokens = new ArrayList<>();
128         while (tokenizer.incrementToken()) {
129             String termValue = term.toString();
130             tokens.add(termValue);
131 
132             String cutValue = input.substring(offs.startOffset(),
133                 offs.endOffset());
134             assertEquals(cutValue, termValue, "cut term" + (1 + count));
135             ++count;
136         }
137 
138         count = 0;
139         for (String token : tokens) {
140             // 1-based offset to accord with line #
141             if (count >= expectedTokens.size()) {
142                 printTokens(tokens);
143                 assertTrue(count < expectedTokens.size(), "too many tokens at term" + (1 + count) + ": " + token);
144             }
145             String expected = expectedTokens.get(count);
146             if (!token.equals(expected)) {
147                 printTokens(tokens);
148                 assertEquals(expected, token, "term" + (1 + count));
149             }
150             count++;
151         }
152 
153         if (expectedTokens.size() != count) {
154             printTokens(tokens);
155             assertEquals(expectedTokens.size(), count, "wrong number of tokens");
156         }
157     }
158 
159     private static void printDiffs(String[] expecteds, String[] actuals, List<Integer> diffLines) {
160         if (diffLines.size() < 1) {
161             return;
162         }
163 
164         int ln0 = diffLines.get(0);
165         int numln = diffLines.size();
166         int loff = (Math.min(ln0, expecteds.length)) + 1;
167         int lnum = countWithin(expecteds.length, ln0, numln);
168         int roff = (Math.min(ln0, actuals.length)) + 1;
169         int rnum = countWithin(actuals.length, ln0, numln);
170 
171         System.out.format("@@ -%d,%d +%d,%d @@", loff, lnum, roff, rnum);
172         System.out.println();
173 
174         for (int i : diffLines) {
175             if (i >= expecteds.length) {
176                 break;
177             } else {
178                 System.out.print("- ");
179                 System.out.println(expecteds[i]);
180             }
181         }
182         for (int i : diffLines) {
183             if (i >= actuals.length) {
184                 break;
185             } else {
186                 System.out.print("+ ");
187                 System.out.println(actuals[i]);
188             }
189         }
190     }
191 
countWithin(int maxoffset, int ln0, int numln)192     private static int countWithin(int maxoffset, int ln0, int numln) {
193         while (numln > 0) {
194             if (ln0 + numln <= maxoffset) {
195                 return numln;
196             }
197             --numln;
198         }
199         return 0;
200     }
201 
202     /**
203      * Outputs a token list to stdout for use in a competent diffing tool
204      * to compare to e.g. samplesymbols.txt.
205      */
printTokens(List<String> tokens)206     private static void printTokens(List<String> tokens) {
207         System.out.println("BEGIN TOKENS\n=====");
208         for (String token : tokens) {
209             System.out.println(token);
210         }
211         System.out.println("=====\nEND TOKENS");
212     }
213 }
214