xref: /OpenGrok/opengrok-indexer/src/test/java/org/opengrok/indexer/util/StreamUtils.java (revision 750b3115a5b8976536ee4dccce497eb97b7a4c9b)
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, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2018, 2021, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.util;
25 
26 import org.opengrok.indexer.analysis.CtagsReader;
27 import org.opengrok.indexer.analysis.Definitions;
28 import org.opengrok.indexer.analysis.StreamSource;
29 import java.io.BufferedInputStream;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayOutputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.InputStreamReader;
35 import java.io.Reader;
36 import java.nio.charset.StandardCharsets;
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 import static org.junit.jupiter.api.Assertions.assertNotNull;
41 
42 /**
43  * Represents a container for stream utility methods.
44  */
45 public class StreamUtils {
46     /**
47      * Read a stream fully to an in-memory byte array.
48      * @param iss a defined stream at the chosen starting position
49      * @return a defined instance
50      * @throws IOException if I/O fails
51      */
copyStream(InputStream iss)52     public static byte[] copyStream(InputStream iss) throws IOException {
53 
54         ByteArrayOutputStream baosExp = new ByteArrayOutputStream();
55         byte[] buffer = new byte[8192];
56         int read;
57         do {
58             read = iss.read(buffer, 0, buffer.length);
59             if (read > 0) {
60                 baosExp.write(buffer, 0, read);
61             }
62         } while (read >= 0);
63 
64         baosExp.close();
65         return baosExp.toByteArray();
66     }
67 
68     /**
69      * Read all bytes from the specified reader.
70      * @param in a required instance
71      * @return a defined instance
72      * @throws IOException thrown if I/O error occurs while reading
73      */
readToEnd(Reader in)74     public static String readToEnd(Reader in) throws IOException {
75 
76         StringBuilder result = new StringBuilder();
77         char[] buf = new char[8 * 1024];
78         int charsRead;
79         while ((charsRead = in.read(buf, 0, buf.length)) != -1) {
80             result.append(buf, 0, charsRead);
81         }
82 
83         return result.toString();
84     }
85 
readTagsFromResource(String resourceName)86     public static Definitions readTagsFromResource(String resourceName)
87             throws IOException {
88         return readTagsFromResource(resourceName, null);
89     }
90 
readTagsFromResource(String tagsResourceName, String rawResourceName)91     public static Definitions readTagsFromResource(String tagsResourceName,
92             String rawResourceName) throws IOException {
93         return readTagsFromResource(tagsResourceName, rawResourceName, 0);
94     }
95 
readTagsFromResource(String tagsResourceName, String rawResourceName, int tabSize)96     public static Definitions readTagsFromResource(String tagsResourceName,
97         String rawResourceName, int tabSize) throws IOException {
98 
99         InputStream res = StreamUtils.class.getClassLoader().
100             getResourceAsStream(tagsResourceName);
101         assertNotNull(res, tagsResourceName + " as resource");
102 
103         BufferedReader in = new BufferedReader(new InputStreamReader(
104             res, StandardCharsets.UTF_8));
105 
106         CtagsReader rdr = new CtagsReader();
107         rdr.setTabSize(tabSize);
108         if (rawResourceName != null) {
109             rdr.setSplitterSupplier(() -> {
110                 /*
111                  * This should return truly raw content, as the CtagsReader will
112                  * expand tabs according to its setting.
113                  */
114                 SourceSplitter splitter = new SourceSplitter();
115                 StreamSource src = sourceFromEmbedded(rawResourceName);
116                 try {
117                     splitter.reset(src);
118                 } catch (IOException ex) {
119                     System.err.println(ex.toString());
120                     return null;
121                 }
122                 return splitter;
123             });
124         }
125 
126         String line;
127         while ((line = in.readLine()) != null) {
128             rdr.readLine(line);
129         }
130         return rdr.getDefinitions();
131     }
132 
133     /**
134      * Gets a {@link Reader} from a specified resource name or raises an
135      * assertion error if no defined stream is available.
136      * @param resourceName a required name
137      * @return a defined instance
138      * @throws IOException thrown on I/O error
139      */
readerFromResource(String resourceName)140     public static Reader readerFromResource(String resourceName)
141             throws IOException {
142 
143         InputStream res = StreamUtils.class.getClassLoader().
144                 getResourceAsStream(resourceName);
145         assertNotNull(res, resourceName + " should be gettable");
146         return IOUtils.createBOMStrippedReader(res, StandardCharsets.UTF_8.name());
147     }
148 
149     /**
150      * Creates a {@code StreamSource} instance that reads data from an
151      * embedded resource.
152      * @param resourceName a required resource name
153      * @return a stream source that reads from {@code name}
154      */
sourceFromEmbedded(String resourceName)155     public static StreamSource sourceFromEmbedded(String resourceName) {
156         return new StreamSource() {
157             @Override
158             public InputStream getStream() {
159                 InputStream res = StreamUtils.class.getClassLoader().
160                     getResourceAsStream(resourceName);
161                 assertNotNull(res, "resource " + resourceName);
162                 return new BufferedInputStream(res);
163             }
164         };
165     }
166 
167     /**
168      * Parses symbols, one per line (trimmed), from a resource stream, but
169      * recognizing a hash character {@code '#'} as starting a line comment that
170      * is not included in a symbol.
171      * @return a defined instance
172      */
173     public static List<String> readSampleSymbols(InputStream symbolsResource) throws IOException {
174         List<String> result = new ArrayList<>();
175         try (BufferedReader rdr = new BufferedReader(new InputStreamReader(symbolsResource,
176                 StandardCharsets.UTF_8))) {
177             String line;
178             while ((line = rdr.readLine()) != null) {
179                 int hashOffset = line.indexOf('#');
180                 if (hashOffset != -1) {
181                     line = line.substring(0, hashOffset);
182                 }
183                 result.add(line.trim());
184             }
185         }
186         return result;
187     }
188 
189     // private to enforce static
190     private StreamUtils() {
191     }
192 }
193