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

LearnLib / automatalib / 10167589650

30 Jul 2024 06:14PM UTC coverage: 90.072% (+0.06%) from 90.009%
10167589650

push

github

mtf90
serialization/aut: use semantically correct assertEquals order

15931 of 17687 relevant lines covered (90.07%)

1.66 hits per line

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

98.31
/serialization/aut/src/main/java/net/automatalib/serialization/aut/InternalAUTParser.java
1
/* Copyright (C) 2013-2024 TU Dortmund University
2
 * This file is part of AutomataLib, http://www.automatalib.net/.
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 net.automatalib.serialization.aut;
17

18
import java.io.BufferedReader;
19
import java.io.IOException;
20
import java.io.InputStream;
21
import java.util.HashMap;
22
import java.util.HashSet;
23
import java.util.Map;
24
import java.util.Set;
25
import java.util.function.Function;
26

27
import net.automatalib.alphabet.Alphabet;
28
import net.automatalib.alphabet.impl.Alphabets;
29
import net.automatalib.automaton.fsa.impl.CompactNFA;
30
import net.automatalib.automaton.simple.SimpleAutomaton;
31
import net.automatalib.common.util.HashUtil;
32
import net.automatalib.common.util.IOUtil;
33
import net.automatalib.serialization.InputModelData;
34

35
class InternalAUTParser {
36

37
    private int initialState;
38
    private int numStates;
39
    private final Set<String> alphabetSymbols = new HashSet<>();
2✔
40
    private final Map<Integer, Map<String, Set<Integer>>> transitionMap = new HashMap<>();
2✔
41

42
    private final InputStream inputStream;
43

44
    private char[] currentLineContent;
45
    private int currentLine;
46
    private int currentPos;
47

48
    InternalAUTParser(InputStream is) {
2✔
49
        this.inputStream = is;
2✔
50
    }
2✔
51

52
    public <I> InputModelData<I, SimpleAutomaton<Integer, I>> parse(Function<String, I> inputTransformer)
53
            throws IOException {
54
        try (BufferedReader br = new BufferedReader(IOUtil.asUncompressedBufferedNonClosingUTF8Reader(inputStream))) {
2✔
55

56
            // parsing
57
            parseHeader(br);
2✔
58
            while (parseTransition(br)) {}
2✔
59

60
            // automaton construction
61
            final Map<String, I> inputMap = new HashMap<>(HashUtil.capacity(this.alphabetSymbols.size()));
2✔
62
            for (String s : this.alphabetSymbols) {
2✔
63
                inputMap.put(s, inputTransformer.apply(s));
2✔
64
            }
2✔
65
            final Alphabet<I> alphabet = Alphabets.fromCollection(inputMap.values());
2✔
66

67
            final CompactNFA<I> result = new CompactNFA<>(alphabet, numStates);
2✔
68

69
            for (int i = 0; i < numStates; i++) {
2✔
70
                result.addState();
2✔
71
            }
72

73
            for (Map.Entry<Integer, Map<String, Set<Integer>>> outgoing : transitionMap.entrySet()) {
2✔
74
                final Integer src = outgoing.getKey();
2✔
75
                for (Map.Entry<String, Set<Integer>> targets : outgoing.getValue().entrySet()) {
2✔
76
                    final String input = targets.getKey();
2✔
77
                    final Set<Integer> tgts = targets.getValue();
2✔
78
                    for (Integer tgt : tgts) {
2✔
79
                        result.addTransition(src, inputMap.get(input), tgt);
2✔
80
                    }
2✔
81
                }
2✔
82
            }
2✔
83
            result.setInitial(initialState, true);
2✔
84

85
            return new InputModelData<>(result, alphabet);
2✔
86
        }
87
    }
88

89
    private void parseHeader(BufferedReader reader) throws IOException {
90
        final String line = reader.readLine();
2✔
91

92
        if (line == null) {
2✔
93
            throw new IllegalArgumentException(buildErrorMessage("Missing description"));
×
94
        }
95

96
        currentLineContent = line.toCharArray();
2✔
97
        currentPos = 0;
2✔
98

99
        shiftToNextNonWhitespace();
2✔
100
        verifyDesAndShift();
2✔
101
        verifyLBracketAndShift();
2✔
102
        initialState = parseNumberAndShift();
2✔
103
        verifyCommaAndShift();
2✔
104
        parseNumberAndShift(); // ignore number of transitions
2✔
105
        verifyCommaAndShift();
2✔
106
        numStates = parseNumberAndShift(); // store number of states
2✔
107
        if (numStates < 1) {
2✔
108
            throw new IllegalArgumentException("Number of states must be >= 1");
2✔
109
        }
110
        verifyRBracketAndShift();
2✔
111
    }
2✔
112

113
    private boolean parseTransition(BufferedReader reader) throws IOException {
114
        final String line = reader.readLine();
2✔
115

116
        if (line == null) {
2✔
117
            return false;
2✔
118
        }
119

120
        currentLineContent = line.toCharArray();
2✔
121
        currentLine++;
2✔
122
        currentPos = 0;
2✔
123

124
        final int start;
125
        final String label;
126
        final int dest;
127

128
        shiftToNextNonWhitespace();
2✔
129
        verifyLBracketAndShift();
2✔
130
        start = parseNumberAndShift();
2✔
131
        verifyCommaAndShift();
2✔
132
        label = parseLabelAndShift();
2✔
133
        verifyCommaAndShift();
2✔
134
        dest = parseNumberAndShift();
2✔
135
        verifyRBracketAndShift();
2✔
136

137
        alphabetSymbols.add(label);
2✔
138
        transitionMap.computeIfAbsent(start, k -> new HashMap<>())
2✔
139
                     .computeIfAbsent(label, k -> new HashSet<>())
2✔
140
                     .add(dest);
2✔
141

142
        return true;
2✔
143
    }
144

145
    private void verifyDesAndShift() {
146

147
        if (currentLineContent[currentPos] != 'd' || currentLineContent[currentPos + 1] != 'e' ||
2✔
148
            currentLineContent[currentPos + 2] != 's') {
149
            throw new IllegalArgumentException(buildErrorMessage("Missing 'des' keyword"));
2✔
150
        }
151

152
        currentPos += 3;
2✔
153
        shiftToNextNonWhitespace();
2✔
154
    }
2✔
155

156
    private void verifyLBracketAndShift() {
157
        verifySymbolAndShift('(');
2✔
158
    }
2✔
159

160
    private void verifyRBracketAndShift() {
161
        verifySymbolAndShift(')');
2✔
162
    }
2✔
163

164
    private void verifyCommaAndShift() {
165
        verifySymbolAndShift(',');
2✔
166
    }
2✔
167

168
    private void verifySymbolAndShift(char symbol) {
169

170
        if (currentLineContent[currentPos] != symbol) {
2✔
171
            throw new IllegalArgumentException(buildErrorMessage("Expected: " + symbol));
2✔
172
        }
173

174
        currentPos++;
2✔
175
        shiftToNextNonWhitespace();
2✔
176
    }
2✔
177

178
    private void shiftToNextNonWhitespace() {
179
        while (currentPos < currentLineContent.length && Character.isWhitespace(currentLineContent[currentPos])) {
2✔
180
            currentPos++;
2✔
181
        }
182
    }
2✔
183

184
    private int parseNumberAndShift() {
185

186
        final StringBuilder sb = new StringBuilder();
2✔
187

188
        char sym = currentLineContent[currentPos];
2✔
189

190
        while (Character.isDigit(sym)) {
2✔
191
            sb.append(sym);
2✔
192
            currentPos++;
2✔
193
            sym = currentLineContent[currentPos];
2✔
194
        }
195

196
        if (sb.length() == 0){
2✔
197
            throw new IllegalArgumentException(buildErrorMessage("Expected a positive number"));
2✔
198
        }
199

200
        // forward pointer
201
        shiftToNextNonWhitespace();
2✔
202
        return Integer.parseInt(sb.toString());
2✔
203
    }
204

205
    private String parseLabelAndShift() {
206

207
        if (currentLineContent[currentPos] == '"') {
2✔
208
            return parseQuotedLabelAndShift();
2✔
209
        } else {
210
            return parseNormalLabelAndShift();
2✔
211
        }
212
    }
213

214
    private String parseQuotedLabelAndShift() {
215
        int openingIndex = currentPos;
2✔
216
        int closingIndex = currentLineContent.length - 1;
2✔
217

218
        // find terminating "
219
        while (currentLineContent[closingIndex--] != '"') {}
2✔
220

221
        // skip terminating " as well
222
        currentPos = closingIndex + 2;
2✔
223
        shiftToNextNonWhitespace();
2✔
224

225
        return new String(currentLineContent, openingIndex + 1, closingIndex - openingIndex);
2✔
226
    }
227

228
    private String parseNormalLabelAndShift() {
229

230
        final char firstChar = currentLineContent[currentPos];
2✔
231

232
        if (currentLineContent[currentPos] == '*') {
2✔
233
            currentPos++;
2✔
234
            shiftToNextNonWhitespace();
2✔
235
            return "*";
2✔
236
        } else if (Character.isLetter(firstChar)) {
2✔
237
            int startIdx = currentPos;
2✔
238

239
            while (isValidIdentifier()) {
2✔
240
                currentPos++;
2✔
241
            }
242

243
            int endIdx = currentPos;
2✔
244

245
            shiftToNextNonWhitespace();
2✔
246
            return new String(currentLineContent, startIdx, endIdx - startIdx);
2✔
247
        } else {
248
            throw new IllegalArgumentException(buildErrorMessage("Invalid unquoted label"));
×
249
        }
250
    }
251

252
    private boolean isValidIdentifier() {
253
        final char currentChar = currentLineContent[currentPos];
2✔
254
        return Character.isLetterOrDigit(currentChar) || currentChar == '_';
2✔
255
    }
256

257
    private String buildErrorMessage(String desc) {
258
        return "In line " + currentLine + ", col " + currentPos + ": " + desc;
2✔
259
    }
260

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