• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aspectran / aspectran / #4057

11 Feb 2025 06:00AM CUT coverage: 35.269% (+1.9%) from 33.377%
#4057

push

github

topframe
Update

13 of 42 new or added lines in 7 files covered. (30.95%)

4 existing lines in 3 files now uncovered.

14247 of 40395 relevant lines covered (35.27%)

0.35 hits per line

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

66.94
/utils/src/main/java/com/aspectran/utils/apon/AponWriter.java
1
/*
2
 * Copyright (c) 2008-2025 The Aspectran Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.aspectran.utils.apon;
17

18
import com.aspectran.utils.Assert;
19
import com.aspectran.utils.StringUtils;
20
import com.aspectran.utils.StringifyContext;
21
import com.aspectran.utils.annotation.jsr305.NonNull;
22
import com.aspectran.utils.annotation.jsr305.Nullable;
23

24
import java.io.File;
25
import java.io.FileWriter;
26
import java.io.Flushable;
27
import java.io.IOException;
28
import java.io.StringWriter;
29
import java.io.Writer;
30
import java.util.List;
31

32
import static com.aspectran.utils.apon.AponFormat.COMMENT_LINE_START;
33
import static com.aspectran.utils.apon.AponFormat.CURLY_BRACKET_CLOSE;
34
import static com.aspectran.utils.apon.AponFormat.CURLY_BRACKET_OPEN;
35
import static com.aspectran.utils.apon.AponFormat.DEFAULT_INDENT_STRING;
36
import static com.aspectran.utils.apon.AponFormat.DOUBLE_QUOTE_CHAR;
37
import static com.aspectran.utils.apon.AponFormat.ESCAPE_CHAR;
38
import static com.aspectran.utils.apon.AponFormat.NAME_VALUE_SEPARATOR;
39
import static com.aspectran.utils.apon.AponFormat.NEW_LINE;
40
import static com.aspectran.utils.apon.AponFormat.NEW_LINE_CHAR;
41
import static com.aspectran.utils.apon.AponFormat.NULL;
42
import static com.aspectran.utils.apon.AponFormat.ROUND_BRACKET_CLOSE;
43
import static com.aspectran.utils.apon.AponFormat.ROUND_BRACKET_OPEN;
44
import static com.aspectran.utils.apon.AponFormat.SINGLE_QUOTE_CHAR;
45
import static com.aspectran.utils.apon.AponFormat.SPACE;
46
import static com.aspectran.utils.apon.AponFormat.SPACE_CHAR;
47
import static com.aspectran.utils.apon.AponFormat.SQUARE_BRACKET_CLOSE;
48
import static com.aspectran.utils.apon.AponFormat.SQUARE_BRACKET_OPEN;
49
import static com.aspectran.utils.apon.AponFormat.SYSTEM_NEW_LINE;
50
import static com.aspectran.utils.apon.AponFormat.TEXT_LINE_START;
51

52
/**
53
 * Writes an APON object to an output source.
54
 * <p>By default, the indentation string is "  " (two blanks)</p>
55
 */
56
public class AponWriter implements Flushable {
57

58
    private final Writer writer;
59

60
    private boolean prettyPrint = true;
1✔
61

62
    private String indentString = DEFAULT_INDENT_STRING;
1✔
63

64
    private boolean nullWritable = true;
1✔
65

66
    private boolean valueTypeHintEnabled;
67

68
    private boolean autoFlush;
69

70
    private int indentDepth;
71

72
    /**
73
     * Instantiates a new AponWriter.
74
     * Pretty printing is enabled by default, and the indent string is
75
     * set to "  " (two spaces).
76
     */
77
    public AponWriter() {
78
        this(new StringWriter());
1✔
79
    }
1✔
80

81
    /**
82
     * Instantiates a new AponWriter.
83
     * Pretty printing is enabled by default, and the indent string is
84
     * set to "  " (two spaces).
85
     * @param file a File object to write to
86
     * @throws IOException if an I/O error occurs
87
     */
88
    public AponWriter(File file) throws IOException {
89
        this(new FileWriter(file));
1✔
90
    }
1✔
91

92
    /**
93
     * Instantiates a new AponWriter.
94
     * Pretty printing is enabled by default, and the indent string is
95
     * set to "  " (two spaces).
96
     * @param writer the character-output stream
97
     */
98
    public AponWriter(Writer writer) {
1✔
99
        Assert.notNull(writer, "writer must not be null");
1✔
100
        this.writer = writer;
1✔
101
    }
1✔
102

103
    public void setStringifyContext(StringifyContext stringifyContext) {
104
        if (stringifyContext != null) {
×
NEW
105
            if (stringifyContext.hasPrettyPrint()) {
×
NEW
106
                setPrettyPrint(stringifyContext.isPrettyPrint());
×
107
            }
108
            if (stringifyContext.hasIndentSize()) {
×
NEW
109
                setIndentString(stringifyContext.getIndentString());
×
110
            }
111
            if (stringifyContext.hasNullWritable()) {
×
NEW
112
                setNullWritable(stringifyContext.isNullWritable());
×
113
            }
114
        }
115
    }
×
116

117
    @SuppressWarnings("unchecked")
118
    public <T extends AponWriter> T apply(StringifyContext stringifyContext) {
119
        setStringifyContext(stringifyContext);
×
120
        return (T)this;
×
121
    }
122

123
    public void setPrettyPrint(boolean prettyPrint) {
124
        this.prettyPrint = prettyPrint;
×
125
        if (prettyPrint) {
×
NEW
126
            if (indentString == null) {
×
NEW
127
                indentString = DEFAULT_INDENT_STRING;
×
128
            }
129
        } else {
NEW
130
            indentString = null;
×
131
        }
132
    }
×
133

134
    @SuppressWarnings("unchecked")
135
    public <T extends AponWriter> T prettyPrint(boolean prettyPrint) {
136
        setPrettyPrint(prettyPrint);
×
137
        return (T)this;
×
138
    }
139

140
    public void setIndentString(String indentString) {
141
        this.indentString = indentString;
1✔
142
    }
1✔
143

144
    @SuppressWarnings("unchecked")
145
    public <T extends AponWriter> T indentString(String indentString) {
146
        setIndentString(indentString);
1✔
147
        return (T)this;
1✔
148
    }
149

150
    public void setNullWritable(boolean nullWritable) {
151
        this.nullWritable = nullWritable;
1✔
152
    }
1✔
153

154
    @SuppressWarnings("unchecked")
155
    public <T extends AponWriter> T nullWritable(boolean nullWritable) {
156
        setNullWritable(nullWritable);
1✔
157
        return (T)this;
1✔
158
    }
159

160
    public void setEnableValueTypeHints(boolean valueTypeHintEnabled) {
161
        this.valueTypeHintEnabled = valueTypeHintEnabled;
×
162
    }
×
163

164
    /**
165
     * Sets whether write a type hint for values.
166
     * @param valueTypeHintEnabled true, write a type hint for values
167
     */
168
    @SuppressWarnings("unchecked")
169
    public <T extends AponWriter> T enableValueTypeHints(boolean valueTypeHintEnabled) {
170
        setEnableValueTypeHints(valueTypeHintEnabled);
×
171
        return (T)this;
×
172
    }
173

174
    public void setAutoFlush(boolean autoFlush) {
175
        this.autoFlush = autoFlush;
×
176
    }
×
177

178
    @SuppressWarnings("unchecked")
179
    public <T extends AponWriter> T autoFlush(boolean autoFlush) {
180
        setAutoFlush(autoFlush);
×
181
        return (T)this;
×
182
    }
183

184
    /**
185
     * Write a Parameters object to the character-output stream.
186
     * @param parameters the Parameters object to be converted
187
     * @throws IOException if an I/O error occurs
188
     */
189
    @SuppressWarnings("unchecked")
190
    public <T extends AponWriter> T write(Parameters parameters) throws IOException {
191
        Assert.notNull(parameters, "parameters must not be null");
1✔
192
        if (parameters instanceof ArrayParameters arrayParameters) {
1✔
193
            for (Parameters ps : arrayParameters.getParametersList()) {
1✔
194
                beginBlock();
1✔
195
                for (Parameter pv : ps.getParameterValues()) {
1✔
196
                    if (nullWritable || pv.isAssigned()) {
1✔
197
                        write(pv);
1✔
198
                    }
199
                }
1✔
200
                endBlock();
1✔
201
            }
1✔
202
        } else {
203
            for (Parameter pv : parameters.getParameterValues()) {
1✔
204
                if (nullWritable || pv.isAssigned()) {
1✔
205
                    write(pv);
1✔
206
                }
207
            }
1✔
208
        }
209
        return (T)this;
1✔
210
    }
211

212
    /**
213
     * Write a Parameter object to the character-output stream.
214
     * @param parameter the Parameter object to be converted
215
     * @throws IOException if an I/O error occurs
216
     */
217
    @SuppressWarnings("unchecked")
218
    public <T extends AponWriter> T write(Parameter parameter) throws IOException {
219
        Assert.notNull(parameter, "parameter must not be null");
1✔
220
        if (parameter.getValueType() == ValueType.PARAMETERS) {
1✔
221
            if (parameter.isArray()) {
1✔
222
                List<Parameters> list = parameter.getValueAsParametersList();
1✔
223
                if (list != null) {
1✔
224
                    if (parameter.isBracketed()) {
1✔
225
                        writeName(parameter);
1✔
226
                        beginArray();
1✔
227
                        for (Parameters ps : list) {
1✔
228
                            indent();
1✔
229
                            beginBlock();
1✔
230
                            if (ps != null) {
1✔
231
                                write(ps);
1✔
232
                            }
233
                            endBlock();
1✔
234
                        }
1✔
235
                        endArray();
1✔
236
                    } else {
237
                        for (Parameters ps : list) {
1✔
238
                            if (ps != null) {
1✔
239
                                writeName(parameter, ps.getActualName());
1✔
240
                                beginBlock();
1✔
241
                                write(ps);
1✔
242
                                endBlock();
1✔
243
                            }
244
                        }
1✔
245
                    }
246
                }
247
            } else {
1✔
248
                Parameters ps = parameter.getValueAsParameters();
1✔
249
                if (nullWritable || ps != null) {
1✔
250
                    writeName(parameter, (ps != null ? ps.getActualName() : null));
1✔
251
                    beginBlock();
1✔
252
                    if (ps != null) {
1✔
253
                        write(ps);
1✔
254
                    }
255
                    endBlock();
1✔
256
                }
257
            }
1✔
258
        } else if (parameter.getValueType() == ValueType.VARIABLE) {
1✔
259
            if (parameter.isArray()) {
×
260
                List<?> list = parameter.getValueList();
×
261
                if (list != null) {
×
262
                    if (parameter.isBracketed()) {
×
263
                        writeName(parameter);
×
264
                        beginArray();
×
265
                        for (Object value : list) {
×
266
                            indent();
×
267
                            if (value instanceof Parameters) {
×
268
                                write((Parameters)value);
×
269
                            } else if (value != null) {
×
270
                                writeString(value.toString());
×
271
                            } else {
272
                                writeNull();
×
273
                            }
274
                        }
×
275
                        endArray();
×
276
                    } else {
277
                        for (Object value : list) {
×
278
                            writeName(parameter);
×
279
                            if (value instanceof Parameters) {
×
280
                                write((Parameters)value);
×
281
                            } else if (value != null) {
×
282
                                writeString(value.toString());
×
283
                            } else {
284
                                writeNull();
×
285
                            }
286
                        }
×
287
                    }
288
                }
289
            } else {
×
290
                Object value = parameter.getValue();
×
291
                if (nullWritable || value != null) {
×
292
                    writeName(parameter);
×
293
                    if (value instanceof Parameters) {
×
294
                        write((Parameters)value);
×
295
                    } else if (value != null) {
×
296
                        writeString(value.toString());
×
297
                    } else {
298
                        writeNull();
×
299
                    }
300
                }
301
            }
×
302
        } else if (parameter.getValueType() == ValueType.STRING) {
1✔
303
            if (parameter.isArray()) {
1✔
304
                List<String> list = parameter.getValueAsStringList();
1✔
305
                if (list != null) {
1✔
306
                    if (parameter.isBracketed()) {
1✔
307
                        writeName(parameter);
1✔
308
                        beginArray();
1✔
309
                        for (String value : list) {
1✔
310
                            indent();
1✔
311
                            writeString(value);
1✔
312
                        }
1✔
313
                        endArray();
1✔
314
                    } else {
315
                        for (String value : list) {
×
316
                            if (nullWritable || value != null) {
×
317
                                writeName(parameter);
×
318
                                writeString(value);
×
319
                            }
320
                        }
×
321
                    }
322
                }
323
            } else {
1✔
324
                String value = parameter.getValueAsString();
1✔
325
                if (nullWritable || value != null) {
1✔
326
                    writeName(parameter);
1✔
327
                    writeString(value);
1✔
328
                }
329
            }
1✔
330
        } else if (parameter.getValueType() == ValueType.TEXT) {
1✔
331
            if (parameter.isArray()) {
1✔
332
                List<String> list = parameter.getValueAsStringList();
1✔
333
                if (list != null) {
1✔
334
                    if (parameter.isBracketed()) {
1✔
335
                        writeName(parameter);
1✔
336
                        beginArray();
1✔
337
                        for (String text : list) {
1✔
338
                            indent();
1✔
339
                            beginText();
1✔
340
                            writeText(text);
1✔
341
                            endText();
1✔
342
                        }
1✔
343
                        endArray();
1✔
344
                    } else {
345
                        for (String text : list) {
×
346
                            if (nullWritable || text != null) {
×
347
                                writeName(parameter);
×
348
                                beginText();
×
349
                                writeText(text);
×
350
                                endText();
×
351
                            }
352
                        }
×
353
                    }
354
                }
355
            } else {
1✔
356
                String text = parameter.getValueAsString();
1✔
357
                if (text != null) {
1✔
358
                    writeName(parameter);
1✔
359
                    beginText();
1✔
360
                    writeText(text);
1✔
361
                    endText();
1✔
362
                } else if (nullWritable) {
1✔
363
                    writeName(parameter);
1✔
364
                    writeNull();
1✔
365
                }
366
            }
1✔
367
        } else {
368
            if (parameter.isArray()) {
1✔
369
                List<?> list = parameter.getValueList();
1✔
370
                if (list != null) {
1✔
371
                    if (parameter.isBracketed()) {
1✔
372
                        writeName(parameter);
1✔
373
                        beginArray();
1✔
374
                        for (Object value : list) {
1✔
375
                            indent();
1✔
376
                            write(value);
1✔
377
                        }
1✔
378
                        endArray();
1✔
379
                    } else {
380
                        for (Object value : list) {
×
381
                            if (nullWritable || value != null) {
×
382
                                writeName(parameter);
×
383
                                write(value);
×
384
                            }
385
                        }
×
386
                    }
387
                }
388
            } else {
1✔
389
                if (nullWritable || parameter.getValue() != null) {
1✔
390
                    writeName(parameter);
1✔
391
                    write(parameter.getValue());
1✔
392
                }
393
            }
394
        }
395
        return (T)this;
1✔
396
    }
397

398
    /**
399
     * Writes a comment to the character-output stream.
400
     * @param message the comment to write to a character-output stream
401
     * @throws IOException if an I/O error occurs
402
     */
403
    @SuppressWarnings("unchecked")
404
    public <T extends AponWriter> T comment(String message) throws IOException {
405
        if (message != null) {
×
406
            if (message.indexOf(NEW_LINE_CHAR) != -1) {
×
407
                String line;
408
                int start = 0;
×
409
                while ((line = readLine(message, start)) != null) {
×
410
                    writer.write(COMMENT_LINE_START);
×
411
                    writer.write(SPACE_CHAR);
×
412
                    writer.write(line);
×
413
                    newLine();
×
414

415
                    start += line.length();
×
416
                    start = skipNewLineChar(message, start);
×
417
                    if (start == -1) {
×
418
                        break;
×
419
                    }
420
                }
421
                if (start != -1) {
×
422
                    writer.write(COMMENT_LINE_START);
×
423
                    newLine();
×
424
                }
425
            } else {
×
426
                writer.write(COMMENT_LINE_START);
×
427
                writer.write(SPACE_CHAR);
×
428
                writer.write(message);
×
429
                newLine();
×
430
            }
431
        }
432
        return (T)this;
×
433
    }
434

435
    private void writeName(Parameter parameter) throws IOException {
436
        writeName(parameter, null);
1✔
437
    }
1✔
438

439
    private void writeName(Parameter parameter, String actualName) throws IOException {
440
        indent();
1✔
441
        writer.write(actualName != null ? actualName : parameter.getName());
1✔
442
        if (valueTypeHintEnabled || parameter.isValueTypeHinted()) {
1✔
443
            writer.write(ROUND_BRACKET_OPEN);
1✔
444
            writer.write(parameter.getValueType().toString());
1✔
445
            writer.write(ROUND_BRACKET_CLOSE);
1✔
446
        }
447
        writer.write(NAME_VALUE_SEPARATOR);
1✔
448
        if (prettyPrint) {
1✔
449
            writer.write(SPACE_CHAR);
1✔
450
        }
451
    }
1✔
452

453
    private void writeString(String value) throws IOException {
454
        if (value == null) {
1✔
455
            writeNull();
1✔
456
            return;
1✔
457
        }
458
        if (value.isEmpty()) {
1✔
459
            writer.write(DOUBLE_QUOTE_CHAR);
×
460
            writer.write(DOUBLE_QUOTE_CHAR);
×
461
            newLine();
×
462
            return;
×
463
        }
464
        if (value.indexOf(DOUBLE_QUOTE_CHAR) >= 0 ||
1✔
465
                value.indexOf(SINGLE_QUOTE_CHAR) >= 0 ||
1✔
466
                value.startsWith(SPACE) ||
1✔
467
                value.endsWith(SPACE) ||
1✔
468
                value.contains(NEW_LINE)) {
1✔
469
            writer.write(DOUBLE_QUOTE_CHAR);
1✔
470
            writer.write(escape(value));
1✔
471
            writer.write(DOUBLE_QUOTE_CHAR);
1✔
472
        } else {
473
            writer.write(value);
1✔
474
        }
475
        newLine();
1✔
476
    }
1✔
477

478
    private void writeText(String text) throws IOException {
479
        String line;
480
        int start = 0;
1✔
481
        while ((line = readLine(text, start)) != null) {
1✔
482
            indent();
1✔
483
            writer.write(TEXT_LINE_START);
1✔
484
            writer.write(line);
1✔
485
            newLine();
1✔
486

487
            start += line.length();
1✔
488
            start = skipNewLineChar(text, start);
1✔
489
            if (start == -1) {
1✔
490
                break;
1✔
491
            }
492
        }
493
        if (start != -1) {
1✔
494
            indent();
×
495
            writer.write(TEXT_LINE_START);
×
496
            newLine();
×
497
        }
498
    }
1✔
499

500
    private void write(Object value) throws IOException {
501
        if (value != null) {
1✔
502
            writer.write(value.toString());
1✔
503
            newLine();
1✔
504
        } else {
505
            writeNull();
1✔
506
        }
507
    }
1✔
508

509
    private void writeNull() throws IOException {
510
        writer.write(NULL);
1✔
511
        newLine();
1✔
512
    }
1✔
513

514
    private void beginBlock() throws IOException {
515
        writer.write(CURLY_BRACKET_OPEN);
1✔
516
        newLine();
1✔
517
        increaseIndent();
1✔
518
    }
1✔
519

520
    private void endBlock() throws IOException {
521
        decreaseIndent();
1✔
522
        indent();
1✔
523
        writer.write(CURLY_BRACKET_CLOSE);
1✔
524
        newLine();
1✔
525
    }
1✔
526

527
    private void beginArray() throws IOException {
528
        writer.write(SQUARE_BRACKET_OPEN);
1✔
529
        newLine();
1✔
530
        increaseIndent();
1✔
531
    }
1✔
532

533
    private void endArray() throws IOException {
534
        decreaseIndent();
1✔
535
        indent();
1✔
536
        writer.write(SQUARE_BRACKET_CLOSE);
1✔
537
        newLine();
1✔
538
    }
1✔
539

540
    private void beginText() throws IOException {
541
        writer.write(ROUND_BRACKET_OPEN);
1✔
542
        newLine();
1✔
543
        increaseIndent();
1✔
544
    }
1✔
545

546
    private void endText() throws IOException {
547
        decreaseIndent();
1✔
548
        indent();
1✔
549
        writer.write(ROUND_BRACKET_CLOSE);
1✔
550
        newLine();
1✔
551
    }
1✔
552

553
    private void newLine() throws IOException {
554
        writer.write(SYSTEM_NEW_LINE);
1✔
555
        if (autoFlush) {
1✔
556
            flush();
×
557
        }
558
    }
1✔
559

560
    private void indent() throws IOException {
561
        if (indentString != null && !indentString.isEmpty()) {
1✔
562
            for (int i = 0; i < indentDepth; i++) {
1✔
563
                writer.write(indentString);
1✔
564
            }
565
        }
566
    }
1✔
567

568
    private void increaseIndent() {
569
        if (indentString != null && !indentString.isEmpty()) {
1✔
570
            indentDepth++;
1✔
571
        }
572
    }
1✔
573

574
    private void decreaseIndent() {
575
        if (indentString != null && !indentString.isEmpty()) {
1✔
576
            indentDepth--;
1✔
577
        }
578
    }
1✔
579

580
    @Nullable
581
    private String readLine(@NonNull String value, int start) {
582
        if (start >= value.length()) {
1✔
583
            return null;
×
584
        }
585
        int end = start;
1✔
586
        for (; end < value.length(); end++) {
1✔
587
            char c = value.charAt(end);
1✔
588
            if (c == '\n' || c == '\r') {
1✔
589
                break;
×
590
            }
591
        }
592
        return (end > start ? value.substring(start, end) : StringUtils.EMPTY);
1✔
593
    }
594

595
    private int skipNewLineChar(@NonNull String value, int start) {
596
        int end = start;
1✔
597
        boolean cr = false;
1✔
598
        boolean lf = false;
1✔
599
        for (; end < value.length(); end++) {
1✔
600
            char c = value.charAt(end);
1✔
601
            if (c != '\n' && c != '\r') {
1✔
602
                break;
1✔
603
            }
604
            if ((lf && c == '\n') || (cr && c == '\r')) {
1✔
605
                break;
×
606
            }
607
            if (c == '\n') {
1✔
608
                lf = true;
1✔
609
            }
610
            if (c == '\r') {
1✔
611
                cr = true;
×
612
            }
613
        }
614
        return (end > start ? end : -1);
1✔
615
    }
616

617
    @Override
618
    public void flush() throws IOException {
619
        writer.flush();
×
620
    }
×
621

622
    public void close() throws IOException {
623
        writer.close();
1✔
624
    }
1✔
625

626
    @Override
627
    public String toString() {
628
        return writer.toString();
1✔
629
    }
630

631
    public static String escape(String str) {
632
        if (str == null) {
1✔
633
            return null;
×
634
        }
635

636
        int len = str.length();
1✔
637
        if (len == 0) {
1✔
638
            return str;
×
639
        }
640

641
        StringBuilder sb = new StringBuilder(len);
1✔
642
        char c;
643
        String t;
644
        for (int pos = 0; pos < len; pos++) {
1✔
645
            c = str.charAt(pos);
1✔
646
            switch (c) {
1✔
647
                case ESCAPE_CHAR:
648
                case DOUBLE_QUOTE_CHAR:
649
                    sb.append('\\');
1✔
650
                    sb.append(c);
1✔
651
                    break;
1✔
652
                case '\b':
653
                    sb.append("\\b");
×
654
                    break;
×
655
                case '\t':
656
                    sb.append("\\t");
×
657
                    break;
×
658
                case '\n':
659
                    sb.append("\\n");
1✔
660
                    break;
1✔
661
                case '\f':
662
                    sb.append("\\f");
×
663
                    break;
×
664
                case '\r':
665
                    sb.append("\\r");
×
666
                    break;
×
667
                default:
668
                    if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
1✔
669
                        t = "000" + Integer.toHexString(c);
×
670
                        sb.append("\\u").append(t.substring(t.length() - 4));
×
671
                    } else {
672
                        sb.append(c);
1✔
673
                    }
674
            }
675
        }
676
        return sb.toString();
1✔
677
    }
678

679
}
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

© 2025 Coveralls, Inc