KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_bus_parsing.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
23#include <sch_connection.h>
24
25
26BOOST_AUTO_TEST_SUITE( BusParsing )
27
28
29BOOST_AUTO_TEST_CASE( ParsesFormattedVectorBus )
30{
31 wxString name;
32 std::vector<wxString> members;
33
34 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "D_{[1..2]}" ), &name, &members ) );
35 BOOST_CHECK_EQUAL( name, wxS( "D" ) );
36
37 std::vector<wxString> expected = { wxS( "D1" ), wxS( "D2" ) };
38
39 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
40}
41
42
43BOOST_AUTO_TEST_CASE( ParsesFormattedGroupWithVectorMember )
44{
45 wxString name;
46 std::vector<wxString> members;
47
48 // D_{[1..2]} keeps the subscript so recursive expansion via ParseBusVector works.
49 // ~{LATCH} preserves the overbar notation because ~{LATCH} and LATCH are different nets.
50 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "MEM{D_{[1..2]} ~{LATCH}}" ), &name, &members ) );
51 BOOST_CHECK_EQUAL( name, wxS( "MEM" ) );
52
53 std::vector<wxString> expected = { wxS( "D_{[1..2]}" ), wxS( "~{LATCH}" ) };
54
55 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
56}
57
58
59BOOST_AUTO_TEST_CASE( RejectsUnescapedSpacesInBusVector )
60{
61 wxString name;
62 std::vector<wxString> members;
63
64 // Unescaped space in bus vector prefix should fail
65 BOOST_CHECK( !NET_SETTINGS::ParseBusVector( wxS( "Data Bus[1..4]" ), &name, &members ) );
66}
67
68
69BOOST_AUTO_TEST_CASE( ParsesBackslashEscapedSpacesInBusVector )
70{
71 wxString name;
72 std::vector<wxString> members;
73
74 // Backslash-escaped space in bus vector prefix should work
75 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "Data\\ Bus[1..2]" ), &name, &members ) );
76 BOOST_CHECK_EQUAL( name, wxS( "Data Bus" ) );
77
78 std::vector<wxString> expected = { wxS( "Data Bus1" ), wxS( "Data Bus2" ) };
79
80 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
81}
82
83
84BOOST_AUTO_TEST_CASE( ParsesQuotedSpacesInBusVector )
85{
86 wxString name;
87 std::vector<wxString> members;
88
89 // Quoted string with space in bus vector prefix should work
90 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "\"Data Bus\"[1..2]" ), &name, &members ) );
91 BOOST_CHECK_EQUAL( name, wxS( "Data Bus" ) );
92
93 std::vector<wxString> expected = { wxS( "Data Bus1" ), wxS( "Data Bus2" ) };
94
95 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
96}
97
98
99BOOST_AUTO_TEST_CASE( RejectsUnescapedSpacesInBusGroupPrefix )
100{
101 wxString name;
102 std::vector<wxString> members;
103
104 // Unescaped space in bus group prefix should fail
105 BOOST_CHECK( !NET_SETTINGS::ParseBusGroup( wxS( "My Bus{NET1 NET2}" ), &name, &members ) );
106}
107
108
109BOOST_AUTO_TEST_CASE( ParsesBackslashEscapedSpacesInBusGroupPrefix )
110{
111 wxString name;
112 std::vector<wxString> members;
113
114 // Backslash-escaped space in bus group prefix should work
115 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "My\\ Bus{NET1 NET2}" ), &name, &members ) );
116 BOOST_CHECK_EQUAL( name, wxS( "My Bus" ) );
117
118 std::vector<wxString> expected = { wxS( "NET1" ), wxS( "NET2" ) };
119
120 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
121}
122
123
124BOOST_AUTO_TEST_CASE( ParsesQuotedSpacesInBusGroupPrefix )
125{
126 wxString name;
127 std::vector<wxString> members;
128
129 // Quoted string with space in bus group prefix should work
130 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "\"My Bus\"{NET1 NET2}" ), &name, &members ) );
131 BOOST_CHECK_EQUAL( name, wxS( "My Bus" ) );
132
133 std::vector<wxString> expected = { wxS( "NET1" ), wxS( "NET2" ) };
134
135 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
136}
137
138
139BOOST_AUTO_TEST_CASE( ParsesBackslashEscapedSpacesInBusGroupMembers )
140{
141 wxString name;
142 std::vector<wxString> members;
143
144 // Backslash-escaped space in bus group member name should work.
145 // Members are stored with escaped spaces so ForEachBusMember recursion works correctly.
146 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "BUS{Net\\ One Net\\ Two}" ), &name, &members ) );
147 BOOST_CHECK_EQUAL( name, wxS( "BUS" ) );
148
149 std::vector<wxString> expected = { wxS( "Net\\ One" ), wxS( "Net\\ Two" ) };
150
151 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
152}
153
154
155BOOST_AUTO_TEST_CASE( ParsesQuotedSpacesInBusGroupMembers )
156{
157 wxString name;
158 std::vector<wxString> members;
159
160 // Quoted member names with spaces should work.
161 // Members are stored with escaped spaces so ForEachBusMember recursion works correctly.
162 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "BUS{\"Net One\" \"Net Two\"}" ), &name, &members ) );
163 BOOST_CHECK_EQUAL( name, wxS( "BUS" ) );
164
165 std::vector<wxString> expected = { wxS( "Net\\ One" ), wxS( "Net\\ Two" ) };
166
167 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
168}
169
170
171BOOST_AUTO_TEST_CASE( ParsesMixedEscapingInBusGroup )
172{
173 wxString name;
174 std::vector<wxString> members;
175
176 // Mix of quoted and backslash-escaped names should work.
177 // Members are stored with escaped spaces so ForEachBusMember recursion works correctly.
178 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "BUS{\"Net One\" Net\\ Two PLAIN}" ), &name, &members ) );
179 BOOST_CHECK_EQUAL( name, wxS( "BUS" ) );
180
181 std::vector<wxString> expected = { wxS( "Net\\ One" ), wxS( "Net\\ Two" ), wxS( "PLAIN" ) };
182
183 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
184}
185
186
187BOOST_AUTO_TEST_CASE( ForEachBusMemberExpandsVectorWithSpacesInGroup )
188{
189 // Test that vector members with spaces inside bus groups are correctly expanded.
190 // This tests the fix for the bug where quoted vector members like "Data Bus"[1..2]
191 // would fail recursive parsing because the quotes were stripped without preserving
192 // space escaping.
193 std::vector<wxString> expandedMembers;
194 auto collector = [&expandedMembers]( const wxString& member )
195 {
196 expandedMembers.push_back( member );
197 };
198
199 // Quoted vector member inside a bus group
200 NET_SETTINGS::ForEachBusMember( wxS( "BUS{\"Data Bus\"[1..2] PLAIN}" ), collector );
201
202 std::vector<wxString> expected = { wxS( "Data Bus1" ), wxS( "Data Bus2" ), wxS( "PLAIN" ) };
203
204 BOOST_CHECK_EQUAL_COLLECTIONS( expandedMembers.begin(), expandedMembers.end(),
205 expected.begin(), expected.end() );
206}
207
208
209BOOST_AUTO_TEST_CASE( ForEachBusMemberExpandsEscapedVectorInGroup )
210{
211 // Test backslash-escaped vector member inside a bus group
212 std::vector<wxString> expandedMembers;
213 auto collector = [&expandedMembers]( const wxString& member )
214 {
215 expandedMembers.push_back( member );
216 };
217
218 NET_SETTINGS::ForEachBusMember( wxS( "BUS{Data\\ Bus[1..2] PLAIN}" ), collector );
219
220 std::vector<wxString> expected = { wxS( "Data Bus1" ), wxS( "Data Bus2" ), wxS( "PLAIN" ) };
221
222 BOOST_CHECK_EQUAL_COLLECTIONS( expandedMembers.begin(), expandedMembers.end(),
223 expected.begin(), expected.end() );
224}
225
226
227BOOST_AUTO_TEST_CASE( ParsesOverbarInVectorBusPrefix )
228{
229 // Overbar formatting in bus vector prefix must be preserved so expanded member
230 // net names match labels on the schematic (issue #22873, #23615).
231 wxString name;
232 std::vector<wxString> members;
233
234 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "bus_~{label}[0..2]" ), &name, &members ) );
235 BOOST_CHECK_EQUAL( name, wxS( "bus_~{label}" ) );
236
237 std::vector<wxString> expected = { wxS( "bus_~{label}0" ), wxS( "bus_~{label}1" ),
238 wxS( "bus_~{label}2" ) };
239
240 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
241}
242
243
244BOOST_AUTO_TEST_CASE( ParsesSuperscriptInVectorBusPrefix )
245{
246 // Superscript formatting in bus vector prefix must be preserved (issue #23615).
247 wxString name;
248 std::vector<wxString> members;
249
250 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "bus_^{label}[0..2]" ), &name, &members ) );
251 BOOST_CHECK_EQUAL( name, wxS( "bus_^{label}" ) );
252
253 std::vector<wxString> expected = { wxS( "bus_^{label}0" ), wxS( "bus_^{label}1" ),
254 wxS( "bus_^{label}2" ) };
255
256 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
257}
258
259
260BOOST_AUTO_TEST_CASE( ParsesSubscriptInVectorBusPrefix )
261{
262 // Subscript formatting in bus vector prefix must be preserved (issue #23615).
263 wxString name;
264 std::vector<wxString> members;
265
266 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "bus__{label}[0..2]" ), &name, &members ) );
267 BOOST_CHECK_EQUAL( name, wxS( "bus__{label}" ) );
268
269 std::vector<wxString> expected = { wxS( "bus__{label}0" ), wxS( "bus__{label}1" ),
270 wxS( "bus__{label}2" ) };
271
272 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
273}
274
275
276BOOST_AUTO_TEST_CASE( ParsesOverbarInGroupBusPrefix )
277{
278 // Overbar formatting in bus group prefix must be preserved so the net prefix
279 // matches labels on the schematic (issue #22873, #23615).
280 wxString name;
281 std::vector<wxString> members;
282
283 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "bus_~{label}{net1 net2}" ), &name, &members ) );
284 BOOST_CHECK_EQUAL( name, wxS( "bus_~{label}" ) );
285
286 std::vector<wxString> expected = { wxS( "net1" ), wxS( "net2" ) };
287
288 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
289}
290
291
292BOOST_AUTO_TEST_CASE( ParsesSuperscriptInGroupBusPrefix )
293{
294 // Superscript formatting in bus group prefix must be preserved (issue #23615).
295 wxString name;
296 std::vector<wxString> members;
297
298 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "bus_^{label}{net1 net2}" ), &name, &members ) );
299 BOOST_CHECK_EQUAL( name, wxS( "bus_^{label}" ) );
300
301 std::vector<wxString> expected = { wxS( "net1" ), wxS( "net2" ) };
302
303 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
304}
305
306
307BOOST_AUTO_TEST_CASE( ParsesSubscriptInGroupBusPrefix )
308{
309 // Subscript formatting in bus group prefix must be preserved (issue #23615).
310 wxString name;
311 std::vector<wxString> members;
312
313 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "bus__{label}{net1 net2}" ), &name, &members ) );
314 BOOST_CHECK_EQUAL( name, wxS( "bus__{label}" ) );
315
316 std::vector<wxString> expected = { wxS( "net1" ), wxS( "net2" ) };
317
318 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
319}
320
321
322BOOST_AUTO_TEST_CASE( ParsesOverbarMembersInBusGroup )
323{
324 // Regression test for issue #23521: inverted (overbar) group bus members
325 // must be preserved as-is so they match the net name on the schematic.
326 // ~{CAS} and CAS are distinct nets; stripping the overbar loses connectivity.
327 wxString name;
328 std::vector<wxString> members;
329
330 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "MEM{~{CAS} ~{RAS} ~{WE} A[2..0]}" ), &name, &members ) );
331 BOOST_CHECK_EQUAL( name, wxS( "MEM" ) );
332
333 std::vector<wxString> expected = { wxS( "~{CAS}" ), wxS( "~{RAS}" ), wxS( "~{WE}" ),
334 wxS( "A[2..0]" ) };
335
336 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
337}
338
339
340BOOST_AUTO_TEST_CASE( ForEachBusMemberExpandsOverbarMembersInGroup )
341{
342 // Verify that overbar group bus members are passed through as net names to the callback,
343 // and that subscript vector members are still correctly expanded.
344 std::vector<wxString> expandedMembers;
345 auto collector = [&expandedMembers]( const wxString& member )
346 {
347 expandedMembers.push_back( member );
348 };
349
350 NET_SETTINGS::ForEachBusMember( wxS( "MEM{~{CAS} ~{RAS} A[0..1]}" ), collector );
351
352 std::vector<wxString> expected = { wxS( "~{CAS}" ), wxS( "~{RAS}" ),
353 wxS( "A0" ), wxS( "A1" ) };
354
355 BOOST_CHECK_EQUAL_COLLECTIONS( expandedMembers.begin(), expandedMembers.end(),
356 expected.begin(), expected.end() );
357}
358
359
360BOOST_AUTO_TEST_CASE( ParsesSuperscriptInBusGroupName )
361{
362 // Regression test for issue #23615. A bus label I^{2}C{SDA SCL} must preserve
363 // the superscript marker in the group name so expanded member net names
364 // (I^{2}C.SDA, I^{2}C.SCL) match labels placed by "Unfold from Bus".
365 wxString name;
366 std::vector<wxString> members;
367
368 BOOST_CHECK( NET_SETTINGS::ParseBusGroup( wxS( "I^{2}C{SDA SCL}" ), &name, &members ) );
369 BOOST_CHECK_EQUAL( name, wxS( "I^{2}C" ) );
370
371 std::vector<wxString> expected = { wxS( "SDA" ), wxS( "SCL" ) };
372
373 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
374}
375
376
377BOOST_AUTO_TEST_CASE( ParsesSuperscriptInBusVectorName )
378{
379 // Superscript in vector bus prefix must be preserved for net name identity.
380 wxString name;
381 std::vector<wxString> members;
382
383 BOOST_CHECK( NET_SETTINGS::ParseBusVector( wxS( "I^{2}C[0..1]" ), &name, &members ) );
384 BOOST_CHECK_EQUAL( name, wxS( "I^{2}C" ) );
385
386 std::vector<wxString> expected = { wxS( "I^{2}C0" ), wxS( "I^{2}C1" ) };
387
388 BOOST_CHECK_EQUAL_COLLECTIONS( members.begin(), members.end(), expected.begin(), expected.end() );
389}
390
391
392BOOST_AUTO_TEST_CASE( ForEachBusMemberExpandsSuperscriptGroupBus )
393{
394 // End-to-end test for issue #23615. ForEachBusMember on I^{2}C{SDA SCL}
395 // must produce I^{2}C.SDA and I^{2}C.SCL as member names (with formatting).
396 std::vector<wxString> expandedMembers;
397 auto collector = [&expandedMembers]( const wxString& member )
398 {
399 expandedMembers.push_back( member );
400 };
401
402 NET_SETTINGS::ForEachBusMember( wxS( "I^{2}C{SDA SCL}" ), collector );
403
404 std::vector<wxString> expected = { wxS( "SDA" ), wxS( "SCL" ) };
405
406 BOOST_CHECK_EQUAL_COLLECTIONS( expandedMembers.begin(), expandedMembers.end(),
407 expected.begin(), expected.end() );
408}
409
410
411BOOST_AUTO_TEST_CASE( PrintBusForUIUnescapesBackslashSpaces )
412{
413 // Test that PrintBusForUI converts backslash-escaped spaces to regular spaces (issue #22872)
414
415 // Simple case with backslash-escaped space
416 BOOST_CHECK_EQUAL( SCH_CONNECTION::PrintBusForUI( wxS( "net\\ name" ) ),
417 wxS( "net name" ) );
418
419 // Bus group member with escaped space in prefix
420 BOOST_CHECK_EQUAL( SCH_CONNECTION::PrintBusForUI( wxS( "bus\\ name.net\\ 1" ) ),
421 wxS( "bus name.net 1" ) );
422
423 // Multiple escaped spaces
424 BOOST_CHECK_EQUAL( SCH_CONNECTION::PrintBusForUI( wxS( "my\\ net\\ name" ) ),
425 wxS( "my net name" ) );
426
427 // No escaped spaces (should pass through unchanged)
428 BOOST_CHECK_EQUAL( SCH_CONNECTION::PrintBusForUI( wxS( "simple_net" ) ),
429 wxS( "simple_net" ) );
430}
431
432
433BOOST_AUTO_TEST_CASE( PrintBusForUIHandlesMixedFormatting )
434{
435 // Test that PrintBusForUI handles both super/sub/overbar formatting and escaped spaces
436
437 // Overbar formatting only
439 wxS( "reset" ) );
440
441 // Both overbar and escaped space
442 BOOST_CHECK_EQUAL( SCH_CONNECTION::PrintBusForUI( wxS( "my\\ ~{signal}" ) ),
443 wxS( "my signal" ) );
444}
445
446
const char * name
static bool ParseBusGroup(const wxString &aGroup, wxString *name, std::vector< wxString > *aMemberList)
Parse a bus group label into the name and a list of components.
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parse a bus vector (e.g.
static void ForEachBusMember(const wxString &aBusPattern, const std::function< void(const wxString &)> &aFunction)
Call a function for each member of an expanded bus pattern.
static wxString PrintBusForUI(const wxString &aString)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(ParsesFormattedVectorBus)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_EQUAL(result, "25.4")