View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.utils;
18  
19  import static org.apache.juneau.commons.utils.CollectionUtils.*;
20  import static org.apache.juneau.commons.utils.Utils.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.text.*;
24  
25  import org.apache.juneau.*;
26  import org.junit.jupiter.api.*;
27  
28  /**
29   * Tests {@link StringExpressionMatcher}.
30   */
31  class StringExpressionMatcher_Test extends TestBase {
32  
33  	private static void test(String expression, String toString, String[] shouldMatch, String[] shouldNotMatch) {
34  		var m = safe(()->new StringExpressionMatcher(expression));
35  		assertEquals(toString, m.toString());
36  		for (var i : shouldMatch)
37  			if (! m.matches(i))
38  				fail("Matcher "+m+" should have matched '"+i+"' but didn't.");
39  		for (var i : shouldNotMatch)
40  			if (m.matches(i))
41  				fail("Matcher "+m+" should not have matched '"+i+"' but did.");
42  	}
43  
44  	//------------------------------------------------------------------------------------------------------------------
45  	// No operand
46  	//------------------------------------------------------------------------------------------------------------------
47  
48  	@Test void a01_noOperand() {
49  		test("", "(NEVER)", a(), a("foo", "foox", "xfoo", "fo", null));
50  		test(null, "(NEVER)", a(), a("foo", "foox", "xfoo", "fo", null));
51  		test("  ", "(NEVER)", a(), a("foo", "foox", "xfoo", "fo", null));
52  		test("()", "(NEVER)", a(), a("foo", "foox", "xfoo", "fo", null));
53  		test("(())", "(NEVER)", a(), a("foo", "foox", "xfoo", "fo", null));
54  		test("  (  (  )  )  ", "(NEVER)", a(), a("foo", "foox", "xfoo", "fo", null));
55  	}
56  
57  	//------------------------------------------------------------------------------------------------------------------
58  	// Single operand equals
59  	//------------------------------------------------------------------------------------------------------------------
60  
61  	@Test void a02_singleOperand_eq() {
62  		test("foo", "[= foo]", a("foo"), a("foox", "xfoo", "fo", null));
63  		test("  foo  ", "[= foo]", a("foo"), a("foox", "xfoo", "fo", null));
64  		test("(foo)", "[= foo]", a("foo"), a("foox", "xfoo", "fo", null));
65  		test("((foo))", "[= foo]", a("foo"), a("foox", "xfoo", "fo", null));
66  		test(" ( foo ) ", "[= foo]", a("foo"), a("foox", "xfoo", "fo", null));
67  		test("  (  (  foo  )  )  ", "[= foo]", a("foo"), a("foox", "xfoo", "fo", null));
68  	}
69  
70  	//------------------------------------------------------------------------------------------------------------------
71  	// Single operand equals
72  	//------------------------------------------------------------------------------------------------------------------
73  
74  	@Test void a03_singleOperand_pattern() {
75  		test("foo*", "[* foo.*]", a("foo", "foox"), a("xfoo", "fo", null));
76  		test("  foo*  ", "[* foo.*]", a("foo", "foox"), a("xfoo", "fo", null));
77  		test("(foo*)", "[* foo.*]", a("foo", "foox"), a("xfoo", "fo", null));
78  		test("((foo*))", "[* foo.*]", a("foo", "foox"), a("xfoo", "fo", null));
79  		test(" ( foo* ) ", "[* foo.*]", a("foo", "foox"), a("xfoo", "fo", null));
80  		test("  (  (  foo*  )  )  ", "[* foo.*]", a("foo", "foox"), a("xfoo", "fo", null));
81  	}
82  
83  	//------------------------------------------------------------------------------------------------------------------
84  	// | operator
85  	//------------------------------------------------------------------------------------------------------------------
86  
87  	@Test void a04_or_singlePipe() {
88  		test("foo|bar|baz", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
89  		test("  foo  |  bar  |  baz  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
90  		test("(foo|bar|baz)", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
91  		test("(foo)|(bar)|(baz)", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
92  		test("  (  foo  |  bar  |  baz  )  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
93  		test("((foo)|(bar)|(baz))", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
94  		test("((((foo))|((bar))|((baz))))", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
95  		test("  (  (  (  (  foo  )  )  |  (  (  bar  )  )  |  (  (  baz  )  )  )  )  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
96  	}
97  
98  	//------------------------------------------------------------------------------------------------------------------
99  	// || operator
100 	//------------------------------------------------------------------------------------------------------------------
101 
102 	@Test void a05_or_doublePipe() {
103 		test("foo||bar||baz", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
104 		test("  foo  ||  bar  ||  baz  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
105 		test("(foo||bar||baz)", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
106 		test("(foo)||(bar)||(baz)", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
107 		test("  (  foo  ||  bar  ||  baz  )  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
108 		test("((foo)||(bar)||(baz))", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
109 		test("((((foo))||((bar))||((baz))))", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
110 		test("  (  (  (  (  foo  )  )  ||  (  (  bar  )  )  ||  (  (  baz  )  )  )  )  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
111 	}
112 
113 	//------------------------------------------------------------------------------------------------------------------
114 	// , operator
115 	//------------------------------------------------------------------------------------------------------------------
116 
117 	@Test void a06_or_comma() {
118 		test("foo,bar,baz", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
119 		test("  foo  ,  bar  ,  baz  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
120 		test("(foo,bar,baz)", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
121 		test("(foo),(bar),(baz)", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
122 		test("  (  foo  ,  bar  ,  baz  )  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
123 		test("((foo),(bar),(baz))", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
124 		test("((((foo)),((bar)),((baz))))", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
125 		test("  (  (  (  (  foo  )  )  ,  (  (  bar  )  )  ,  (  (  baz  )  )  )  )  ", "(| [= foo] [= bar] [= baz])", a("foo", "bar", "baz"), a("foox", "xfoo", "fo", null));
126 	}
127 
128 	//------------------------------------------------------------------------------------------------------------------
129 	// & operator
130 	//------------------------------------------------------------------------------------------------------------------
131 
132 	@Test void a07_and_singleAmp() {
133 		test("fo*&*oo&foo", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
134 		test("  fo*  &  *oo  &  foo  ", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
135 		test("(fo*&*oo&foo)", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
136 		test("(fo*)&(*oo)&(foo)", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
137 		test("  (  fo*  &  *oo  &  foo  )  ", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
138 		test("((fo*)&(*oo)&(foo))", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
139 		test("((((fo*))&((*oo))&((foo))))", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
140 		test("  (  (  (  (  fo*  )  )  &  (  (  *oo  )  )  &  (  (  foo  )  )  )  )  ", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
141 	}
142 
143 	//------------------------------------------------------------------------------------------------------------------
144 	// && operator
145 	//------------------------------------------------------------------------------------------------------------------
146 
147 	@Test void a08_and_doubleAmp() {
148 		test("fo*&&*oo&&foo", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
149 		test("  fo*  &&  *oo  &&  foo  ", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
150 		test("(fo*&&*oo&&foo)", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
151 		test("(fo*)&&(*oo)&&(foo)", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
152 		test("  (  fo*  &&  *oo  &&  foo  )  ", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
153 		test("((fo*)&&(*oo)&&(foo))", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
154 		test("((((fo*))&&((*oo))&&((foo))))", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
155 		test("  (  (  (  (  fo*  )  )  &&  (  (  *oo  )  )  &&  (  (  foo  )  )  )  )  ", "(& [* fo.*] [* .*oo] [= foo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
156 	}
157 
158 	//------------------------------------------------------------------------------------------------------------------
159 	// | and & operators
160 	//------------------------------------------------------------------------------------------------------------------
161 
162 	@Test void a09_and_singleMixed() {
163 		test("fo*&*oo|bar", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
164 		test("bar|fo*&*oo", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
165 		test("  fo*  &  *oo  |  bar  ", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
166 		test("  bar  |  fo*  &  *oo  ", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
167 		test("(fo*&*oo|bar)", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
168 		test("(bar|fo*&*oo)", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
169 		test("(fo*)&(*oo)|(bar)", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
170 		test("(bar)|(fo*)&(*oo)", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
171 		test("  (  fo*  &  *oo  |  bar  )  ", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
172 		test("  (  bar  |  fo*  &  *oo  )  ", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
173 		test("((fo*)&(*oo)|(bar))", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
174 		test("((bar)|(fo*)&(*oo))", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
175 		test("((((fo*))&((*oo))|((bar))))", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
176 		test("((((bar))|((fo*))&((*oo))))", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
177 		test("  (  (  (  (  fo*  )  )  &  (  (  *oo  )  )  |  (  (  bar  )  )  )  )  ", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
178 		test("  (  (  (  (  bar  )  )  |  (  (  fo*  )  )  &  (  (  *oo  )  )  )  )  ", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
179 	}
180 
181 	//------------------------------------------------------------------------------------------------------------------
182 	// "||" and "&&" operators
183 	//------------------------------------------------------------------------------------------------------------------
184 
185 	@Test void a10_and_doubleMixed() {
186 		test("fo*&&*oo||bar", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
187 		test("bar||fo*&&*oo", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
188 		test("  fo*  &&  *oo  ||  bar  ", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
189 		test("  bar  ||  fo*  &&  *oo  ", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
190 		test("(fo*&&*oo||bar)", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
191 		test("(bar||fo*&&*oo)", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
192 		test("(fo*)&&(*oo)||(bar)", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
193 		test("(bar)||(fo*)&&(*oo)", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
194 		test("  (  fo*  &&  *oo  ||  bar  )  ", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
195 		test("  (  bar  ||  fo*  &&  *oo  )  ", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
196 		test("((fo*)&&(*oo)||(bar))", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
197 		test("((bar)||(fo*)&&(*oo))", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
198 		test("((((fo*))&&((*oo))||((bar))))", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
199 		test("((((bar))||((fo*))&&((*oo))))", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
200 		test("  (  (  (  (  fo*  )  )  &&  (  (  *oo  )  )  ||  (  (  bar  )  )  )  )  ", "(| (& [* fo.*] [* .*oo]) [= bar])", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
201 		test("  (  (  (  (  bar  )  )  ||  (  (  fo*  )  )  &&  (  (  *oo  )  )  )  )  ", "(| [= bar] (& [* fo.*] [* .*oo]))", a("foo", "bar"), a("foox", "xfoo", "fo", "baz", null));
202 	}
203 
204 	//------------------------------------------------------------------------------------------------------------------
205 	// | and & and () operators
206 	//------------------------------------------------------------------------------------------------------------------
207 
208 	@Test void a11_and_singleMixedParentheses() {
209 		test("fo*&(*oo|bar)", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
210 		test("(bar|fo*)&*oo", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
211 		test("  fo*  &  (  *oo  |  bar  )  ", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
212 		test("  (  bar  |  fo*  )  &  *oo  ", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
213 		test("(fo*&(*oo|bar))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
214 		test("((bar|fo*)&*oo)", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
215 		test("(fo*)&((*oo)|(bar))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
216 		test("((bar)|(fo*))&(*oo)", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
217 		test("  (  fo*  &  (  *oo  |  bar  )  )  ", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
218 		test("  (  (  bar  |  fo*  )  &  *oo  )  ", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
219 		test("((fo*)&((*oo)|(bar)))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
220 		test("(((bar)|(fo*))&(*oo))", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
221 		test("((((fo*))&(((*oo))|((bar)))))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
222 		test("(((((bar))|((fo*)))&((*oo))))", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
223 		test("  (  (  (  (  fo*  )  )  &  (  (  (  *oo  )  )  |  (  (  bar  )  )  )  )  )  ", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
224 		test("  (  (  (  (  (  bar  )  )  |  (  (  fo*  )  )  )  &  (  (  *oo  )  )  )  )  ", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
225 	}
226 
227 	//------------------------------------------------------------------------------------------------------------------
228 	// "||" and "&&" and "()" operators
229 	//------------------------------------------------------------------------------------------------------------------
230 
231 	@Test void a12_and_doubleMixedParentheses() {
232 		test("fo*&&(*oo||bar)", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
233 		test("(bar||fo*)&&*oo", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
234 		test("  fo*  &&  (  *oo  ||  bar  )  ", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
235 		test("  (  bar  ||  fo*  )  &&  *oo  ", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
236 		test("(fo*&&(*oo||bar))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
237 		test("((bar||fo*)&&*oo)", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
238 		test("(fo*)&((*oo)||(bar))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
239 		test("((bar)||(fo*))&&(*oo)", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
240 		test("  (  fo*  &&  (  *oo  ||  bar  )  )  ", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
241 		test("  (  (  bar  ||  fo*  )  &&  *oo  )  ", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
242 		test("((fo*)&&((*oo)||(bar)))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
243 		test("(((bar)||(fo*))&&(*oo))", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
244 		test("((((fo*))&&(((*oo))||((bar)))))", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
245 		test("(((((bar))||((fo*)))&&((*oo))))", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
246 		test("  (  (  (  (  fo*  )  )  &&  (  (  (  *oo  )  )  ||  (  (  bar  )  )  )  )  )  ", "(& [* fo.*] (| [* .*oo] [= bar]))", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
247 		test("  (  (  (  (  (  bar  )  )  ||  (  (  fo*  )  )  )  &&  (  (  *oo  )  )  )  )  ", "(& (| [= bar] [* fo.*]) [* .*oo])", a("foo"), a("foox", "xfoo", "fo", "bar", "baz", null));
248 	}
249 
250 	//------------------------------------------------------------------------------------------------------------------
251 	// Error conditions
252 	//------------------------------------------------------------------------------------------------------------------
253 
254 	@Test void b01_errors() {
255 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("&foo"));
256 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo bar"));
257 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("(foo"));
258 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo &"));
259 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo ||"));
260 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo ,"));
261 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo & "));
262 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo || "));
263 		assertThrows(ParseException.class, ()->new StringExpressionMatcher("foo , "));
264 	}
265 }