Skip to content
This repository was archived by the owner on Sep 11, 2022. It is now read-only.

Commit a411667

Browse files
committed
Add test module
1 parent 7a88d32 commit a411667

7 files changed

Lines changed: 480 additions & 10 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package cn.alumik.parsetree;
2+
3+
import cn.alumik.parsetree.exception.AnalysisException;
4+
import cn.alumik.parsetree.exception.ParsingException;
5+
import cn.alumik.parsetree.lexer.Lexer;
6+
import cn.alumik.parsetree.lexer.fsm.DFA;
7+
import cn.alumik.parsetree.lexer.fsm.FSMState;
8+
import cn.alumik.parsetree.lexer.fsm.NFA;
9+
import cn.alumik.parsetree.parser.Parser;
10+
import cn.alumik.parsetree.symbol.AbstractTerminalSymbol;
11+
import cn.alumik.parsetree.symbol.TerminalSymbol;
12+
import cn.alumik.parsetree.util.Config;
13+
import org.junit.After;
14+
import org.junit.Before;
15+
import org.junit.Test;
16+
17+
import java.io.ByteArrayOutputStream;
18+
import java.io.PrintStream;
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import static org.junit.Assert.assertEquals;
23+
24+
public class LexerTest {
25+
26+
private final Config mConfig = new Config("lexer.yml");
27+
28+
private final Parser mParser = new Parser(mConfig);
29+
30+
private final Lexer mLexer = new Lexer(mConfig, mParser);
31+
32+
private final ByteArrayOutputStream mOutContent = new ByteArrayOutputStream();
33+
34+
private final PrintStream mOriginalOut = System.out;
35+
36+
public LexerTest() throws ParsingException, AnalysisException {
37+
}
38+
39+
@Before
40+
public void setUpStreams() {
41+
System.setOut(new PrintStream(mOutContent));
42+
}
43+
44+
@Before
45+
public void setupLexer() {
46+
mLexer.setDfa(new DFA(makeNFA()));
47+
}
48+
49+
@After
50+
public void restoreStreams() {
51+
System.setOut(mOriginalOut);
52+
}
53+
54+
private NFA makeNFA() {
55+
final FSMState s0 = new FSMState(mLexer);
56+
final FSMState s1 = new FSMState(mLexer);
57+
final FSMState s2 = new FSMState(mLexer);
58+
final FSMState s3 = new FSMState(mLexer);
59+
final FSMState s4 = new FSMState(mLexer);
60+
final FSMState s5 = new FSMState(mLexer);
61+
final FSMState s6 = new FSMState(mLexer);
62+
final FSMState s7 = new FSMState(mLexer);
63+
final FSMState s8 = new FSMState(mLexer);
64+
final FSMState s9 = new FSMState(mLexer);
65+
66+
s0.addTransition('\0', s1);
67+
s1.addTransition('a', s2);
68+
s0.addTransition('\0', s3);
69+
s3.addTransition('a', s4);
70+
s4.addTransition('b', s5);
71+
s5.addTransition('c', s6);
72+
s0.addTransition('\0', s7);
73+
s7.addTransition('a', s8);
74+
s8.addTransition('b', s9);
75+
76+
s2.setFinal(true);
77+
s5.setFinal(true);
78+
s6.setFinal(true);
79+
s9.setFinal(true);
80+
s2.addAcceptingRule("A");
81+
s5.addAcceptingRule("AB2");
82+
s6.addAcceptingRule("ABC");
83+
s9.addAcceptingRule("AB1");
84+
85+
final NFA nfa = new NFA(s0, mLexer);
86+
nfa.addFinalState(s2);
87+
nfa.addFinalState(s5);
88+
nfa.addFinalState(s6);
89+
nfa.addFinalState(s9);
90+
return nfa;
91+
}
92+
93+
94+
@Test(expected = ParsingException.class)
95+
public void testLexWithPredefinedDFA_ExceptionFront() throws ParsingException, AnalysisException {
96+
mLexer.lex("babbebabc");
97+
}
98+
99+
@Test(expected = ParsingException.class)
100+
public void testLexWithPredefinedDFA_ExceptionBack() throws ParsingException, AnalysisException {
101+
mLexer.lex("aababcabefg");
102+
}
103+
104+
@Test
105+
public void testLexWithIgnoredSymbolsAndPredefinedDFA() throws ParsingException, AnalysisException {
106+
final List<TerminalSymbol> result = new ArrayList<>();
107+
TerminalSymbol terminalSymbol1 = new TerminalSymbol(new AbstractTerminalSymbol("AB2"));
108+
terminalSymbol1.setValue("ab");
109+
result.add(terminalSymbol1);
110+
TerminalSymbol terminalSymbol2 = new TerminalSymbol(new AbstractTerminalSymbol("ABC"));
111+
terminalSymbol2.setValue("abc");
112+
result.add(terminalSymbol2);
113+
TerminalSymbol terminalSymbol3 = new TerminalSymbol(new AbstractTerminalSymbol("AB2"));
114+
terminalSymbol3.setValue("ab");
115+
result.add(terminalSymbol3);
116+
TerminalSymbol terminalSymbol4 = new TerminalSymbol(new AbstractTerminalSymbol("AB2"));
117+
terminalSymbol4.setValue("ab");
118+
result.add(terminalSymbol4);
119+
120+
assertEquals(result, mLexer.lex("aabaabcabaab"));
121+
assertEquals(
122+
"AB2: ab\nABC: abc\nAB2: ab\nAB2: ab\n",
123+
mOutContent.toString().replace("\r", ""));
124+
}
125+
}
Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,121 @@
11
package cn.alumik.parsetree;
22

3-
import static org.junit.Assert.assertTrue;
4-
3+
import cn.alumik.parsetree.exception.AnalysisException;
4+
import cn.alumik.parsetree.exception.ParsingException;
5+
import cn.alumik.parsetree.lexer.Lexer;
6+
import cn.alumik.parsetree.parser.Parser;
7+
import cn.alumik.parsetree.symbol.AbstractNonterminalSymbol;
8+
import cn.alumik.parsetree.util.Config;
9+
import org.junit.After;
10+
import org.junit.Before;
511
import org.junit.Test;
612

7-
/**
8-
* Unit test for simple App.
9-
*/
13+
import java.io.ByteArrayOutputStream;
14+
import java.io.IOException;
15+
import java.io.PrintStream;
16+
17+
import static org.junit.Assert.assertEquals;
18+
1019
public class ParseTreeAppTest {
1120

12-
/**
13-
* Rigorous Test :-)
14-
*/
21+
private Lexer mLexer;
22+
23+
private Parser mParser;
24+
25+
private final ByteArrayOutputStream mOutContent = new ByteArrayOutputStream();
26+
27+
private final PrintStream mOriginalOut = System.out;
28+
29+
@Before
30+
public void setUpStreams() {
31+
System.setOut(new PrintStream(mOutContent));
32+
}
33+
34+
@After
35+
public void restoreStreams() {
36+
System.setOut(mOriginalOut);
37+
}
38+
39+
private void makeLexerAndParser(String configName) throws AnalysisException, ParsingException {
40+
final Config config = new Config(configName);
41+
mParser = new Parser(config);
42+
mLexer = new Lexer(config, mParser);
43+
}
44+
45+
@Test
46+
public void testInitFirstSets() throws AnalysisException, ParsingException {
47+
makeLexerAndParser("first_set.yml");
48+
49+
for (final AbstractNonterminalSymbol symbol : mParser.getGrammar().getSymbolPool().getNonterminalSymbols()) {
50+
System.out.println(symbol);
51+
System.out.println(symbol.getFirstSet());
52+
System.out.println();
53+
}
54+
55+
assertEquals("""
56+
Nonterminal symbol: A
57+
[Terminal symbol: a, Terminal symbol: b, Terminal symbol: c, Terminal symbol: d, Terminal symbol: g]
58+
59+
Nonterminal symbol: B
60+
[Terminal symbol: b, Terminal symbol: null]
61+
62+
Nonterminal symbol: C
63+
[Terminal symbol: a, Terminal symbol: c, Terminal symbol: d]
64+
65+
Nonterminal symbol: D
66+
[Terminal symbol: d, Terminal symbol: null]
67+
68+
Nonterminal symbol: _S
69+
[Terminal symbol: a, Terminal symbol: b, Terminal symbol: c, Terminal symbol: d, Terminal symbol: g]
70+
71+
Nonterminal symbol: E
72+
[Terminal symbol: c, Terminal symbol: g]
73+
74+
""",
75+
mOutContent.toString().replace("\r", ""));
76+
}
77+
78+
@Test
79+
public void testParseCpp() throws AnalysisException, ParsingException {
80+
makeLexerAndParser("cpp.yml");
81+
mLexer.lex("""
82+
int main() {
83+
int a = a + 1;
84+
cout << a << endl;
85+
return 0;
86+
}
87+
""");
88+
assertEquals("""
89+
KEYWORD: int
90+
IDENTIFIER: main
91+
LP: (
92+
RP: )
93+
LB: {
94+
KEYWORD: int
95+
IDENTIFIER: a
96+
ASSIGN_OP: =
97+
IDENTIFIER: a
98+
ADD_OP: +
99+
INTEGER: 1
100+
SEMICOLON: ;
101+
IDENTIFIER: cout
102+
LSTREAM: <<
103+
IDENTIFIER: a
104+
LSTREAM: <<
105+
IDENTIFIER: endl
106+
SEMICOLON: ;
107+
KEYWORD: return
108+
INTEGER: 0
109+
SEMICOLON: ;
110+
RB: }
111+
""",
112+
mOutContent.toString().replace("\r", ""));
113+
}
114+
15115
@Test
16-
public void shouldAnswerWithTrue() {
17-
assertTrue(true);
116+
public void watchParseCalculator() throws ParsingException, AnalysisException, IOException {
117+
makeLexerAndParser("calculator.yml");
118+
final String expr = "3*(6+(4/2)-5)+8";
119+
mParser.parse(mLexer.lex(expr)).draw("out/3_calculator.png");
18120
}
19121
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package cn.alumik.parsetree;
2+
3+
import cn.alumik.parsetree.exception.AnalysisException;
4+
import cn.alumik.parsetree.exception.ParsingException;
5+
import cn.alumik.parsetree.lexer.Lexer;
6+
import cn.alumik.parsetree.lexer.fsm.DFA;
7+
import cn.alumik.parsetree.lexer.fsm.FSMState;
8+
import cn.alumik.parsetree.lexer.fsm.NFA;
9+
import cn.alumik.parsetree.parser.Parser;
10+
import cn.alumik.parsetree.util.Config;
11+
import org.junit.Test;
12+
13+
import java.io.IOException;
14+
import java.util.AbstractMap;
15+
import java.util.LinkedHashMap;
16+
import java.util.Map;
17+
18+
import static org.junit.Assert.assertEquals;
19+
20+
public class RegexTest {
21+
22+
private final Config mConfig = new Config("lexer.yml");
23+
24+
private final Parser mParser = new Parser(mConfig);
25+
26+
private final Lexer mLexer = new Lexer(mConfig, mParser);
27+
28+
public RegexTest() throws ParsingException, AnalysisException {
29+
}
30+
31+
private NFA makeNFA1() {
32+
final FSMState s0 = new FSMState(mLexer);
33+
final FSMState s1 = new FSMState(mLexer);
34+
final FSMState s2 = new FSMState(mLexer);
35+
final FSMState s3 = new FSMState(mLexer);
36+
final FSMState s4 = new FSMState(mLexer);
37+
final FSMState s5 = new FSMState(mLexer);
38+
final FSMState s6 = new FSMState(mLexer);
39+
final FSMState s7 = new FSMState(mLexer);
40+
final FSMState s8 = new FSMState(mLexer);
41+
final FSMState s9 = new FSMState(mLexer);
42+
final FSMState s10 = new FSMState(mLexer);
43+
44+
s0.addTransition('\0', s1);
45+
s1.addTransition('\0', s5);
46+
s1.addTransition('\0', s6);
47+
s5.addTransition('a', s2);
48+
s6.addTransition('b', s3);
49+
s2.addTransition('\0', s4);
50+
s3.addTransition('\0', s4);
51+
s4.addTransition('\0', s7);
52+
s7.addTransition('a', s8);
53+
s8.addTransition('b', s9);
54+
s9.addTransition('b', s10);
55+
s0.addTransition('\0', s7);
56+
s4.addTransition('\0', s1);
57+
58+
s10.setFinal(true);
59+
s10.addAcceptingRule("(a|b)*abb");
60+
61+
final NFA nfa = new NFA(s0, mLexer);
62+
nfa.addFinalState(s10);
63+
return nfa;
64+
}
65+
66+
private NFA makeNFA2() {
67+
final FSMState s0 = new FSMState(mLexer);
68+
final FSMState s1 = new FSMState(mLexer);
69+
final FSMState s2 = new FSMState(mLexer);
70+
final FSMState s3 = new FSMState(mLexer);
71+
final FSMState s4 = new FSMState(mLexer);
72+
final FSMState s5 = new FSMState(mLexer);
73+
final FSMState s6 = new FSMState(mLexer);
74+
final FSMState s7 = new FSMState(mLexer);
75+
final FSMState s8 = new FSMState(mLexer);
76+
77+
s0.addTransition('\0', s1);
78+
s1.addTransition('a', s2);
79+
s0.addTransition('\0', s3);
80+
s3.addTransition('a', s4);
81+
s4.addTransition('b', s5);
82+
s5.addTransition('b', s6);
83+
s0.addTransition('\0', s7);
84+
s7.addTransition('a', s7);
85+
s7.addTransition('b', s8);
86+
s8.addTransition('b', s8);
87+
88+
s2.setFinal(true);
89+
s6.setFinal(true);
90+
s8.setFinal(true);
91+
s2.addAcceptingRule("a");
92+
s6.addAcceptingRule("abb");
93+
s8.addAcceptingRule("a*b+");
94+
95+
final NFA nfa = new NFA(s0, mLexer);
96+
nfa.addFinalState(s2);
97+
nfa.addFinalState(s6);
98+
nfa.addFinalState(s8);
99+
return nfa;
100+
}
101+
102+
@Test
103+
public void testMatchString() throws IOException {
104+
final Map<String, String> acceptingRules = new LinkedHashMap<>();
105+
acceptingRules.put("(a|b)*abb", "(a|b)*abb");
106+
mLexer.setAcceptingRule(acceptingRules);
107+
108+
final NFA nfa = makeNFA1();
109+
nfa.draw("out/1_nfa.png");
110+
111+
final DFA dfa = new DFA(nfa);
112+
dfa.draw("out/1_dfa.png");
113+
114+
assertEquals(new AbstractMap.SimpleEntry<>("", 1), dfa.match("abdsffgabb"));
115+
assertEquals(new AbstractMap.SimpleEntry<>("", 1), dfa.match("abab"));
116+
assertEquals(new AbstractMap.SimpleEntry<>("(a|b)*abb", 12), dfa.match("abbbababbabb"));
117+
assertEquals(new AbstractMap.SimpleEntry<>("(a|b)*abb", 3), dfa.match("abb"));
118+
assertEquals(new AbstractMap.SimpleEntry<>("(a|b)*abb", 6), dfa.match("abbabb"));
119+
assertEquals(new AbstractMap.SimpleEntry<>("(a|b)*abb", 4), dfa.match("aabbefg"));
120+
}
121+
122+
@Test
123+
public void testMergeNFA() throws IOException {
124+
final Map<String, String> acceptingRules = new LinkedHashMap<>();
125+
acceptingRules.put("a", "a");
126+
acceptingRules.put("abb", "abb");
127+
acceptingRules.put("a*b+", "a*b+");
128+
mLexer.setAcceptingRule(acceptingRules);
129+
130+
final NFA nfa = makeNFA2();
131+
nfa.draw("out/2_nfa.png");
132+
133+
final DFA dfa = new DFA(nfa);
134+
dfa.draw("out/2_dfa.png");
135+
136+
assertEquals(new AbstractMap.SimpleEntry<>("abb", 3), dfa.match("abb"));
137+
assertEquals(new AbstractMap.SimpleEntry<>("a*b+", 4), dfa.match("abbb"));
138+
assertEquals(new AbstractMap.SimpleEntry<>("a", 1), dfa.match("aefg"));
139+
assertEquals(new AbstractMap.SimpleEntry<>("", 1), dfa.match("efg"));
140+
}
141+
}

0 commit comments

Comments
 (0)