• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Build has been canceled!

moosetechnology / VerveineJ / 24243378737

10 Apr 2026 12:40PM UTC coverage: 52.119% (+0.2%) from 51.947%
24243378737

Pull #206

github

web-flow
Merge 4c12de030 into 239038a6f
Pull Request #206: Array support

1980 of 3988 branches covered (49.65%)

Branch coverage included in aggregate %.

76 of 107 new or added lines in 5 files covered. (71.03%)

176 existing lines in 3 files now uncovered.

4403 of 8259 relevant lines covered (53.31%)

2.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/app/src/main/java/fr/inria/verveine/extractor/java/VerveineJOptions.java
1
package fr.inria.verveine.extractor.java;
2

3
import org.eclipse.jdt.core.JavaCore;
4
import org.eclipse.jdt.core.dom.ASTParser;
5

6
import java.io.*;
7
import java.nio.charset.Charset;
8
import java.util.*;
9
import java.util.regex.Pattern;
10

11
public class VerveineJOptions {
12

13
        /**
14
         * Possible options for SourceAnchors: no source anchor, only entities [default], entities and associations
15
         */
16
        public enum AnchorOptions {
3✔
17
                none, entity, assoc;
18✔
18

19
                public static AnchorOptions getValue(String option) {
20
                        switch (option) {
8!
21
                                case "default":
22
                                case "entity":
23
                                        return entity;
2✔
24
                                case "assoc":
25
                                        return assoc;
2✔
26
                                case "none":
27
                                        return none;
×
28
                                default:
29
                                        return null;
×
30
                        }
31
                }
32
        }
33

34

35
        /**
36
         * Name (without extension) of the default file where to put the MSE model
37
         * <p>
38
         * By default, the extension is provided by the output format
39
         */
40
        public final static String OUTPUT_FILE = "output";
41

42
        /**
43
         * Default encodings of the java files to read
44
         */
45
        private static final String DEFAULT_FILE_ENCODING = "UTF-8";
46

47
        /**
48
         * Option for MSE output format
49
         */
50
        public final static String MSE_OUTPUT_FORMAT = "MSE";
51

52
        /**
53
         * Option for JSON output format
54
         */
55
        public final static String JSON_OUTPUT_FORMAT = "JSON";
56

57
        public static final String DEFAULT_CODE_VERSION = JavaCore.VERSION_9;
58

59
        /**
60
         * List of java version option from java 1.1 to java 23 argument
61
         */
62
        private static final Map<String, String> VERSION_MAP = new HashMap<>();
4✔
63

64
        /**
65
         * Init list of java version option
66
         */
67
        static {
68
                // Olds versions of Java can be written 1.x or x
69
                // While newer version can only be written x
70
                for (String version : JavaCore.getAllVersions()) {
10✔
71
                        if (version.contains(".")) {
4✔
72
                                String shortV = version.substring(2);
4✔
73

74
                                VERSION_MAP.put("-" + version, version);
6✔
75
                                VERSION_MAP.put("-" + shortV, version);
6✔
76
                        } else {
1✔
77
                                VERSION_MAP.put("-" + version, version);
6✔
78
                        }
79
                }
1✔
80
        }
1✔
81

82
        /**
83
         * Whether to output all local variables (even those with primitive type) or not (default is not).<br>
84
         * Note: allLocals => not classSummary
85
         */
86
        protected boolean allLocals;
87

88
        /**
89
         * Option: The version of Java expected by the parser
90
         */
91
        protected String codeVers;
92

93
        /**
94
         * Option: Whether to put SourceAnchors in the entities and/or associations
95
         */
96
        protected AnchorOptions anchors;
97

98
        /**
99
         * The arguments that were passed to the parser
100
         * Needed to relativize the source file names
101
         */
102
        protected Collection<String> argPath;
103
        protected Collection<String> argFiles;
104
        protected String[] classPathOptions;
105

106
        /**
107
         * pathnames to exclude from parsing.<br>
108
         * Accepts globbing expressions
109
         */
110
        protected Collection<String> excludePaths;
111

112
        /**
113
         * collection of matchers of file name to process excluding expr (see
114
         */
115
        protected Collection<Pattern> excludeMatchers;
116

117
        /**
118
         * File encoding to use to read java files
119
         */
120
        protected String fileEncoding = DEFAULT_FILE_ENCODING;
3✔
121

122
        /**
123
         * Name of the file where to put the MSE model.
124
         * Defaults to {@link #OUTPUT_FILE}
125
         */
126
        protected String outputFileName;
127

128
        /**
129
         * Format for saving the model in file: MSE or JSON
130
         */
131
        public String outputFormat;
132

133
        /**
134
         * Whether parsing is incremental
135
         * <p>
136
         * Incremental means an entire project is parsed by parts, verveineJ saving and reloading the model
137
         * respectively at the end of an execution and at the satrt of the next one
138
         */
139
        protected boolean incrementalParsing;
140

141
        /**
142
         * If possible, should I use a prettyPrinter
143
         */
144
        protected boolean prettyPrint = false;
3✔
145

146
        /**
147
         * with additional tracing for debugging
148
         */
149
        protected boolean debugging;
150

151
        /**
152
         * Text of comments exported in the model instead of using source anchor
153
         */
154
        protected boolean commentText;
155

156
        /**
157
         * Am I parsing a JDK?
158
         */
159
        protected boolean parsingJdk = false;
3✔
160
        
161
        /**
162
         * Path to system library for JDT to use 
163
         * (for Java version <= 8 <=> path to rt.jar)
164
         * (for Java version > 8 <=> path to jrt-fs.jar? have not try so to verify in practice)
165
         */
166
        protected String pathToSystemLibrary;
167
        
168

169
        /**
170
         * Option: Whether to put SourceAnchors in the entities and/or associations
171
         */
172
        private boolean isStrict = false;
3✔
173

174
        public VerveineJOptions() {
2✔
175
                this.allLocals = false;
3✔
176
                this.codeVers = null;
3✔
177
                this.commentText = false;
3✔
178
                this.incrementalParsing = false;
3✔
179
                this.outputFileName = null;
3✔
180
                this.outputFormat = null; //We need to know if the user sets this option manually. After parsing options, this will be set to the default format if it is still null.
3✔
181
                this.debugging = false;
3✔
182
        }
1✔
183

184
        public void setOptions( String[] args) {
185
                classPathOptions = new String[] {};
4✔
186
                argPath = new ArrayList<String>();
5✔
187
                argFiles = new ArrayList<String>();
5✔
188
                excludePaths = new ArrayList<String>();
5✔
189

190
                int i = 0;
2✔
191
                while (i < args.length && args[i].trim().startsWith("-")) {
11✔
192
                        try {
193
                                i += setOption(args, i);
7✔
194
                        } catch (IllegalArgumentException e) {
1✔
195
                                System.err.println(e.getMessage());
4✔
196
                                usage();
2✔
197
                                throw e;
2✔
198
                        }
1✔
199
                }
200

201
                if (JSON_OUTPUT_FORMAT.equalsIgnoreCase(outputFormat) && (incrementalParsing) ) {
8!
202
                        IllegalArgumentException illegalArgumentException = new IllegalArgumentException("-i option requires mse format.");
5✔
203
                        System.err.println(illegalArgumentException.getMessage());
4✔
204
                        usage();
2✔
205
                        throw illegalArgumentException;
2✔
206
                }
207

208
                if (outputFormat == null) {
3✔
209
                        if (incrementalParsing) {
3✔
210
                                outputFormat = MSE_OUTPUT_FORMAT;
4✔
211
                        } else {
212
                                outputFormat= JSON_OUTPUT_FORMAT;
3✔
213
                        }
214
                }
215

216
                if (outputFileName == null) {
3✔
217
                        outputFileName = VerveineJOptions.OUTPUT_FILE + "." + outputFormat.toLowerCase();
6✔
218
                }
219
                if (codeVers == null) {
3✔
220
                        codeVers = DEFAULT_CODE_VERSION;
3✔
221
                }
222
                if (anchors == null) {
3✔
223
                        anchors = VerveineJOptions.AnchorOptions.getValue("default");
4✔
224
                }
225

226
                while (i < args.length) {
4✔
227
                        String arg = args[i++].trim();
6✔
228
                        if (arg.endsWith(".java") && new File(arg).isFile()) {
10!
229
                                argFiles.add(arg);
6✔
230
                        } else {
231
                                argPath.add(arg);
5✔
232
                        }
233
                }
1✔
234
        }
1✔
235

236
        /**
237
         * treats 1 argument or more starting at position <code>i</code> in the array of arguments <code>args</code>
238
         * @param args TODO
239
         * @param i TODO
240
         * @return The number of argument(s) treated
241
         */
242
        protected int setOption( String[] args, int i) throws IllegalArgumentException {
243
                String arg = args[i].trim();
5✔
244
                int argumentsTreated = 1;
2✔
245

246
                if (arg.equals("-h")) {
4!
UNCOV
247
                        usage();
×
UNCOV
248
                        System.exit(0);
×
249
                }
250
                else if (VERSION_MAP.containsKey(arg)) {
4✔
251
                        setCodeVersion(arg);
4✔
252
                } else if (arg.equals("-alllocals")) {
4✔
253
                        allLocals = true;
4✔
254
                } else if (arg.equals("-prettyPrint")) {
4!
UNCOV
255
                        prettyPrint = true;
×
256
                } else if ((arg.charAt(0) == '-') && (arg.endsWith("cp"))) {
9!
257
                        classPathOptions = setOptionClassPath(classPathOptions, args, i);
8✔
258
                        argumentsTreated++;
2✔
259
                } else if (arg.equals("-encoding")) {
4✔
260
                        setOptionEncoding(args, i);
4✔
261
                        argumentsTreated++;
2✔
262
                } else if (arg.equals("-anchor")) {
4✔
263
                        setOptionAnchor(args, i);
4✔
264
                        argumentsTreated++;
2✔
265
                } else if (arg.equals("-commenttext")) {
4✔
266
                        commentText = true;//
4✔
267
                } else if (arg.equals("-format")) {
4✔
268
                        setOptionFormat(args, i);
4✔
269
                        argumentsTreated++;
2✔
270
                } else if (arg.equals("-excludepath")) {
4✔
271
                        if (i < args.length) {
4!
272
                                excludePaths.add(args[i + 1]);
9✔
273
                                argumentsTreated++;
2✔
274
                        } else {
UNCOV
275
                                throw new IllegalArgumentException("-excludepath requires a globbing expression");
×
276
                        }
277
                } else if (arg.equals("-o")) {
4✔
278
                        if (i < args.length) {
4!
279
                                outputFileName = args[i+1].trim();
8✔
280
                                argumentsTreated++;
2✔
281
                        } else {
UNCOV
282
                                throw new IllegalArgumentException("-o requires a filename");
×
283
                        }
284
                } else if (arg.equals("-sysLibPath")) {
4!
UNCOV
285
                        if (i < args.length) {
×
UNCOV
286
                                pathToSystemLibrary = args[i+1].trim();
×
UNCOV
287
                                argumentsTreated++;
×
288
                        } else {
UNCOV
289
                                throw new IllegalArgumentException("-sysLibPath requires a filename");
×
290
                        }
291
                } else if (arg.equals("-i")) {
4✔
292
                        incrementalParsing = true;
4✔
293

294
                }
295
                else if (arg.equals("-jdkMode")) {
4✔
296
                        parsingJdk = true;
4✔
297
                }
298
                else if (arg.equals("-strict")) {
4!
299
                        isStrict = true;
4✔
300
                }
UNCOV
301
                else if (arg.equals("-debugging")) {
×
302
                        debugging = true;
×
303
                } else {
UNCOV
304
                        throw new IllegalArgumentException("** Unrecognized option: " + arg);
×
305
                }
306

307
                return argumentsTreated;
2✔
308
        }
309

310
        /**
311
         * Computes the path of all included jars
312
         */
313
        protected String[] setOptionClassPath( String[] classPath, String[] args, int i) throws IllegalArgumentException {
314
                if (args[i].equals("-autocp")) {
6!
UNCOV
315
                        if (i+1 < args.length) {
×
UNCOV
316
                                return addToClassPath(classPath, collectAllJars(args[i+1]) );
×
317
                        } else {
UNCOV
318
                                throw new IllegalArgumentException("-autocp requires a root folder");
×
319
                        }
320
                }
321
                else if (args[i].equals("-filecp")) {
6!
UNCOV
322
                        if (i+1 < args.length) {
×
UNCOV
323
                                return addToClassPath(classPath, readAllJars(args[i+1]));
×
324
                        } else {
UNCOV
325
                                throw new IllegalArgumentException("-filecp requires a filename");
×
326
                        }
327
                }
328
                else if (args[i].equals("-cp")) {
6!
329
                        if (i+1 < args.length) {
6!
330
                                return addToClassPath(classPath,  Arrays.asList(args[i+1].split(System.getProperty("path.separator"))));
13✔
331
                        }
332
                        else {
UNCOV
333
                                throw new IllegalArgumentException("-cp requires a classPath");
×
334
                        }
335
                }
UNCOV
336
                return classPath;
×
337
        }
338

339
        protected void setOptionEncoding(String[] args, int i) {
340
                if (i+1 < args.length) {
6✔
341
                        this.fileEncoding = args[i + 1].trim();
8✔
342
                        if (Charset.availableCharsets().get(this.fileEncoding) == null) {
5✔
343
                                throw new IllegalArgumentException("Unknown file encoding: -encoding " + this.fileEncoding);
7✔
344
                        }
345
                } else {
346
                        throw new IllegalArgumentException("-encoding requires an encoding name (eg. " + DEFAULT_FILE_ENCODING + ")");
5✔
347
                }
348
        }
1✔
349

350
        protected void setOptionAnchor(String[] args, int i) {
351
                if (i+1 < args.length) {
6!
352
                        String anchor = args[i + 1].trim();
7✔
353
                        anchors = VerveineJOptions.AnchorOptions.getValue(anchor);
4✔
354
                        if (anchors == null) {
3!
355
                                throw new IllegalArgumentException("unknown option to -anchor: " + anchor);
×
356
                        }
357
                } else {
1✔
358
                        throw new IllegalArgumentException("-anchor requires an option (none|default|assoc)");
×
359
                }
360
        }
1✔
361

362
        protected void setOptionFormat(String[] args, int i) {
363
                if (i+1 < args.length) {
6!
364
                        this.outputFormat = args[i + 1].trim();
8✔
365
                        if ((! this.outputFormat.equalsIgnoreCase(MSE_OUTPUT_FORMAT)) && (! this.outputFormat.equalsIgnoreCase(JSON_OUTPUT_FORMAT))) {
10!
UNCOV
366
                                throw new IllegalArgumentException("unknown option to -format: " + outputFormat);
×
367
                        }
368
                } else {
UNCOV
369
                        throw new IllegalArgumentException("-format requires an option (mse|json)");
×
370
                }
371
        }
1✔
372

373
        protected List<String> collectAllJars(String sDir) {
UNCOV
374
                File[] faFiles = new File(sDir).listFiles();
×
UNCOV
375
                List<String> tmpPath = new ArrayList<String>();
×
UNCOV
376
                for (File file : faFiles) {
×
UNCOV
377
                        if (file.getName().endsWith("jar")) {
×
UNCOV
378
                                tmpPath.add(file.getAbsolutePath());
×
379
                        }
UNCOV
380
                        if (file.isDirectory()) {
×
381
                                tmpPath.addAll(collectAllJars(file.getAbsolutePath()));
×
382
                        }
383
                }
384
                return tmpPath;
×
385
        }
386

387
        protected String[] addToClassPath(String[] classPath, List<String> tmpPath) {
388
                int oldlength = classPath.length;
3✔
389
                int newlength = oldlength + tmpPath.size();
5✔
390
                classPath = Arrays.copyOf(classPath, newlength);
5✔
391
                for (int p = oldlength; p < newlength; p++) {
7✔
392
                        classPath[p] = tmpPath.get(p - oldlength);
9✔
393
                }
394
                return classPath;
2✔
395
        }
396

397
        /** Reads all jar in classpath from a file, one per line
398
         * @param filename of the file containing the jars of the classpath
399
         * @return the collection of jar paths
400
         */
401
        protected List<String> readAllJars(String filename) {
UNCOV
402
                List<String> tmpPath = new ArrayList<String>();
×
403
                try {
UNCOV
404
                        BufferedReader fcp = new BufferedReader(new FileReader(filename));
×
UNCOV
405
                        String jarname = fcp.readLine();
×
UNCOV
406
                        while (jarname != null) {
×
UNCOV
407
                                tmpPath.add(jarname);
×
UNCOV
408
                                jarname = fcp.readLine();
×
409
                        }
UNCOV
410
                        fcp.close();
×
UNCOV
411
                } catch (FileNotFoundException e) {
×
UNCOV
412
                        System.err.println("** Error classpath file " + filename + " not found");
×
UNCOV
413
                        e.printStackTrace();
×
UNCOV
414
                } catch (IOException e) {
×
UNCOV
415
                        System.err.println("** Error reading classpath file: " + filename);
×
UNCOV
416
                        e.printStackTrace();
×
UNCOV
417
                }
×
UNCOV
418
                return tmpPath;
×
419
        }
420

421
        protected void usage() {
422
                System.err.println("Usage: VerveineJ [-h] [-i] [-o <output-file-name>] [-prettyPrint] [-summary] [-alllocals] [-anchor (none|default|assoc)] [-cp CLASSPATH | -autocp DIR] [-1.1 | -1 | -1.2 | -2 | ... | -1.7 | -7] <files-to-parse> | <dirs-to-parse>");
3✔
423
                System.err.println("      [-h] prints this message");
3✔
424
                System.err.println("      [-i] toggles incremental parsing on (can parse a project in parts that are added to the output file)");
3✔
425
                System.err.println("      [-o <output-file-name>] specifies the name of the output file (default:" + OUTPUT_FILE + ")");
3✔
426
                System.err.println("      [-format (mse|json)] specifies the output format (default:" + MSE_OUTPUT_FORMAT + ")");
3✔
427
                System.err.println("      [-prettyPrint] toggles the usage of the json pretty printer");
3✔
428
                System.err.println("      [-summary] toggles summarization of information at the level of classes.");
3✔
429
                System.err.println("                 Summarizing at the level of classes does not produce Methods, Attributes, Accesses, and Invocations");
3✔
430
                System.err.println("                 Everything is represented as references between classes: e.g. \"A.m1() invokes B.m2()\" is uplifted to \"A references B\"");
3✔
431
                System.err.println("      [-alllocals] Forces outputing all local variables, even those with primitive type (incompatible with \"-summary\")");
3✔
432
                System.err.println("      [-encoding <file-encoding-name>] File encoding to use for reading the source code default: " + DEFAULT_FILE_ENCODING);
3✔
433
                System.err.println("      [-anchor (none|entity|default|assoc)] options for source anchor information:\n" +
3✔
434
                                "                                     - no entity\n" +
435
                                "                                     - only named entities [default]\n" +
436
                                "                                     - named entities+associations (i.e. accesses, invocations, references)");
437
                System.err.println("      [-commenttext] comments text in the model instead of as a source anchor");
3✔
438
                System.err.println("      [-cp CLASSPATH] classpath where to look for stubs");
3✔
439
                System.err.println("      [-autocp DIR] gather all jars in DIR and put them in the classpath");
3✔
440
                System.err.println("      [-filecp FILE] gather all jars listed in FILE (absolute paths) and put them in the classpath");
3✔
441
                System.err.println("      [-excludepath GLOBBINGEXPR] A globbing expression of file path to exclude from parsing");
3✔
442
                System.err.println("      [-1.1 | -1 | -1.2 | -2 | ... | -1.9 | -9 | -10 | -11 | ... ] specifies version of Java");
3✔
443
                System.err.println("      [-jdkMode] option to ABSOLUTELY set if you are making a model of a JDK");
3✔
444
                System.err.println("      [-sysLibPath <path-to-runtime-jar>] path to the system library for JDT to resolve native Java binding in the parsed code");
3✔
445
                System.err.println("                                                                                By default, JDT will collect the library used to execute VVJ (unless the option -jdkMode is active).");
3✔
446
                System.err.println("      <files-to-parse>|<dirs-to-parse> list of source files to parse or directories to search for source files");
3✔
447
        }
1✔
448

449
        protected void setCodeVersion(String arg) {
450
                if (codeVers != null) {
3!
UNCOV
451
                        System.err.println("Trying to set twice code versions: " + codeVers + " and " + arg);
×
UNCOV
452
                        usage();
×
UNCOV
453
                        throw new IllegalArgumentException();
×
454
                } else if(VERSION_MAP.containsKey(arg)){
4!
455
                        codeVers = VERSION_MAP.get(arg);
6✔
456
                }
457

458
        }
1✔
459

460
        public String getOutputFileName() {
461
                return this.outputFileName;
3✔
462
        }
463

464
        public void configureJDTParser(ASTParser jdtParser) {
465
                // If I am parsing a JDK or providing the system library,
466
                // JDT must not fetch the VM's running libraries (=JRE used by VerveineJ at runtime)
467
                boolean includeRunningVMBootclasspath = !(parsingJdk || pathToSystemLibrary != null);
10!
468
                
469
                if (pathToSystemLibrary != null) {
3!
UNCOV
470
                        List<String> deps = new ArrayList<String>();
×
UNCOV
471
                        deps.add(pathToSystemLibrary);
×
UNCOV
472
                        classPathOptions = addToClassPath(classPathOptions, deps);
×
473
                }
474
                
475
                String[] sourcePathEntries = argPath.toArray(new String[0]);
7✔
476
                
477
                jdtParser.setEnvironment(classPathOptions, /*sourcepathEntries*/sourcePathEntries, /*encodings*/null, includeRunningVMBootclasspath);
7✔
478
                jdtParser.setResolveBindings(true);
3✔
479
                /**
480
                 *  Incremental parsing should not activate Binding recovery because using this option with incremental parsing
481
                 * will result in lot of stubs in the model that would have been resolved later
482
                 * */
483
                if (!incrementalParsing) {
3✔
484
                        jdtParser.setBindingsRecovery(true);
3✔
485
                }
486
                jdtParser.setKind(ASTParser.K_COMPILATION_UNIT);
3✔
487

488
                Map<String, String> javaCoreOptions = JavaCore.getOptions();
2✔
489

490
                javaCoreOptions.put(JavaCore.COMPILER_COMPLIANCE, codeVers);
6✔
491
                javaCoreOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, codeVers);
6✔
492
                javaCoreOptions.put(JavaCore.COMPILER_SOURCE, codeVers);
6✔
493

494
    // Not absolutely sure it is necessary
495
                        if (pathToSystemLibrary != null)
3!
496
                                javaCoreOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.DISABLED);
×
497
    
498
                jdtParser.setCompilerOptions(javaCoreOptions);
3✔
499

500
        }
1✔
501

502

503
        /**
504
         * Creates a regexp matcher form a globbing expression<br>
505
         * Glob to Regexp algorithm from <a href="https://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns">https://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns</a>
506
         */
507
        protected Pattern createMatcher(String expr) {
508
                expr = expr.trim();
3✔
509
                int strLen = expr.length();
3✔
510
                StringBuilder sb = new StringBuilder(strLen);
5✔
511
                sb.append('^');
4✔
512
                if (! expr.startsWith("/")) {
4!
513
                        // not absolute path, start with ".*"
514
                        if (! expr.startsWith("*")) {
4!
UNCOV
515
                                sb.append(".*");
×
516
                        }
517
                }
518
                boolean escaping = false;
2✔
519
                int inCurlies = 0;
2✔
520
                for (char currentChar : expr.toCharArray()) {
17✔
521
                        switch (currentChar) {
2!
522
                                case '*':
523
                                        if (escaping)
2!
524
                                                sb.append("\\*");
×
525
                                        else
526
                                                sb.append(".*");
4✔
527
                                        escaping = false;
2✔
528
                                        break;
1✔
529
                                case '?':
530
                                        if (escaping)
×
531
                                                sb.append("\\?");
×
532
                                        else
UNCOV
533
                                                sb.append('.');
×
534
                                        escaping = false;
×
535
                                        break;
×
536
                                case '.':
537
                                case '(':
538
                                case ')':
539
                                case '+':
540
                                case '|':
541
                                case '^':
542
                                case '$':
543
                                case '@':
544
                                case '%':
545
                                        sb.append('\\');
×
UNCOV
546
                                        sb.append(currentChar);
×
547
                                        escaping = false;
×
548
                                        break;
×
549
                                case '\\':
UNCOV
550
                                        if (escaping) {
×
UNCOV
551
                                                sb.append("\\\\");
×
UNCOV
552
                                                escaping = false;
×
553
                                        }
554
                                        else
UNCOV
555
                                                escaping = true;
×
556
                                        break;
×
557
                                case '{':
UNCOV
558
                                        if (escaping) {
×
UNCOV
559
                                                sb.append("\\{");
×
560
                                        }
561
                                        else {
UNCOV
562
                                                sb.append('(');
×
UNCOV
563
                                                inCurlies++;
×
564
                                        }
UNCOV
565
                                        escaping = false;
×
UNCOV
566
                                        break;
×
567
                                case '}':
UNCOV
568
                                        if (inCurlies > 0 && !escaping) {
×
UNCOV
569
                                                sb.append(')');
×
UNCOV
570
                                                inCurlies--;
×
571
                                        }
UNCOV
572
                                        else if (escaping)
×
UNCOV
573
                                                sb.append("\\}");
×
574
                                        else
UNCOV
575
                                                sb.append("}");
×
UNCOV
576
                                        escaping = false;
×
UNCOV
577
                                        break;
×
578
                                case ',':
UNCOV
579
                                        if (inCurlies > 0 && !escaping) {
×
UNCOV
580
                                                sb.append('|');
×
581
                                        }
UNCOV
582
                                        else if (escaping)
×
UNCOV
583
                                                sb.append("\\,");
×
584
                                        else
UNCOV
585
                                                sb.append(",");
×
UNCOV
586
                                        break;
×
587
                                default:
588
                                        escaping = false;
2✔
589
                                        sb.append(currentChar);
4✔
590
                        }
591
                }
592

593
                if (! expr.endsWith("*")) {
4!
UNCOV
594
                        sb.append(".*$");
×
595
                }
596
                else {
597
                        sb.append('$');
4✔
598
                }
599
                return Pattern.compile(sb.toString());
4✔
600
        }
601

602
        protected void collectJavaFiles(Collection<String> paths, Collection<String> files) {
603
                excludeMatchers = new ArrayList<>(excludePaths.size());
8✔
604
                for (String expr : excludePaths) {
11✔
605
                        excludeMatchers.add(createMatcher(expr));
7✔
606
                }
1✔
607
                for (String p : paths) {
10✔
608
                        collectJavaFiles(new File(p), files);
7✔
609
                }
1✔
610
        }
1✔
611

612
        protected void collectJavaFiles(File f, Collection<String> files) {
613
                for (Pattern filter : excludeMatchers) {
11✔
614
                        String absolutePath = f.getAbsolutePath();
3✔
615
                        if (filter.matcher(absolutePath).matches()) {
5✔
616
                                System.out.println("Excluded file: " + absolutePath);
4✔
617
                                return;
1✔
618
                        }
619
                }
1✔
620
                if (f.isFile() && f.getName().endsWith(".java")) {
8✔
621
                        files.add(f.getAbsolutePath());
6✔
622
                } else if (f.isDirectory()) {
3✔
623
                        for (File child : f.listFiles()) {
17✔
624
                                collectJavaFiles(child, files);
4✔
625
                        }
626
                }
627
        }
1✔
628

629
        protected String[] sourceFilesToParse() {
630
                ArrayList<String> sourceFiles = new ArrayList<String>();
4✔
631

632
                sourceFiles.addAll(argFiles);
5✔
633
                collectJavaFiles(argPath, sourceFiles);
5✔
634

635
                return sourceFiles.toArray( new String[sourceFiles.size()] );
7✔
636
        }
637

638

639
        public boolean withAnchors() {
640
                return anchors != AnchorOptions.none;
7!
641
        }
642

643
        public boolean withAnchors(AnchorOptions anchorOption) {
644
                return anchors == anchorOption;
8✔
645
        }
646

647
        public boolean withLocals() {
648
                return allLocals;
3✔
649
        }
650

651
        public boolean withDebug() {
UNCOV
652
                return debugging;
×
653
        }
654

655
        public boolean commentsAsText() {
656
                return commentText;
3✔
657
        }
658

659
        public boolean isParsingJdk() {
UNCOV
660
                return parsingJdk;
×
661
        }
662

663
        public String getFileEncoding() {
664
                return fileEncoding;
3✔
665
        }
666
        
667
        public boolean isStrict() {
668
                return isStrict;
3✔
669
        }
670

671
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc