KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_sch_api_proto.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 * @author Jon Evans <[email protected]>
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
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21#include <import_export.h>
24
25#include <api/schematic/schematic_types.pb.h>
26#include <api/api_sch_utils.h>
27
28#include <eeschema_test_utils.h>
29
30#include <sch_bitmap.h>
31#include <sch_bus_entry.h>
32#include <sch_group.h>
33#include <sch_junction.h>
34#include <sch_label.h>
35#include <sch_line.h>
36#include <sch_no_connect.h>
37#include <sch_rule_area.h>
38#include <sch_screen.h>
39#include <sch_shape.h>
40#include <sch_sheet.h>
41#include <sch_sheet_path.h>
42#include <sch_symbol.h>
43#include <sch_table.h>
44#include <sch_text.h>
45#include <sch_textbox.h>
46#include <wx/filename.h>
47
48
49BOOST_FIXTURE_TEST_SUITE( ApiSchProto, KI_TEST::SCHEMATIC_TEST_FIXTURE )
50
52{
53 wxFileName fn( KI_TEST::GetEeschemaTestDataDir(), wxS( "api_kitchen_sink.kicad_sch" ) );
54 LoadSchematic( fn );
55 SCH_SHEET_PATH path = m_schematic->CurrentSheet();
56
57 for( SCH_ITEM* item : m_schematic->RootScreen()->Items() )
58 {
59 switch( item->Type() )
60 {
61 case SCH_JUNCTION_T:
63 static_cast<SCH_JUNCTION*>( item ),
64 []()
65 {
66 return std::make_unique<SCH_JUNCTION>();
67 } );
68 break;
69
72 static_cast<SCH_NO_CONNECT*>( item ),
73 []()
74 {
75 return std::make_unique<SCH_NO_CONNECT>();
76 } );
77 break;
78
81 static_cast<SCH_BUS_WIRE_ENTRY*>( item ),
82 []()
83 {
84 return std::make_unique<SCH_BUS_WIRE_ENTRY>();
85 } );
86 break;
87
90 static_cast<SCH_BUS_BUS_ENTRY*>( item ),
91 []()
92 {
93 return std::make_unique<SCH_BUS_BUS_ENTRY>();
94 } );
95 break;
96
97 case SCH_LINE_T:
99 static_cast<SCH_LINE*>( item ),
100 []()
101 {
102 return std::make_unique<SCH_LINE>();
103 } );
104 break;
105
106 case SCH_SHAPE_T:
108 static_cast<SCH_SHAPE*>( item ),
109 []()
110 {
111 return std::make_unique<SCH_SHAPE>();
112 } );
113 break;
114
115 case SCH_RULE_AREA_T:
117 static_cast<SCH_RULE_AREA*>( item ),
118 []()
119 {
120 return std::make_unique<SCH_RULE_AREA>();
121 } );
122 break;
123
124 case SCH_BITMAP_T:
126 static_cast<SCH_BITMAP*>( item ),
127 []()
128 {
129 return std::make_unique<SCH_BITMAP>();
130 } );
131 break;
132
133 case SCH_TEXT_T:
135 static_cast<SCH_TEXT*>( item ),
136 []()
137 {
138 return std::make_unique<SCH_TEXT>();
139 } );
140 break;
141
142 case SCH_TEXTBOX_T:
144 static_cast<SCH_TEXTBOX*>( item ),
145 []()
146 {
147 return std::make_unique<SCH_TEXTBOX>();
148 } );
149 break;
150
151 case SCH_LABEL_T:
153 static_cast<SCH_LABEL*>( item ),
154 []()
155 {
156 return std::make_unique<SCH_LABEL>();
157 } );
158 break;
159
162 static_cast<SCH_GLOBALLABEL*>( item ),
163 []()
164 {
165 return std::make_unique<SCH_GLOBALLABEL>();
166 } );
167 break;
168
169 case SCH_HIER_LABEL_T:
171 static_cast<SCH_HIERLABEL*>( item ),
172 []()
173 {
174 return std::make_unique<SCH_HIERLABEL>();
175 } );
176 break;
177
180 static_cast<SCH_DIRECTIVE_LABEL*>( item ),
181 []()
182 {
183 return std::make_unique<SCH_DIRECTIVE_LABEL>();
184 } );
185 break;
186
187 case SCH_GROUP_T:
189 static_cast<SCH_GROUP*>( item ),
190 [this]()
191 {
192 return std::make_unique<SCH_GROUP>( m_schematic->RootScreen() );
193 } );
194 break;
195
196 case SCH_SHEET_T:
198 static_cast<SCH_SHEET*>( item ),
199 [this]()
200 {
201 return std::make_unique<SCH_SHEET>( m_schematic->RootScreen() );
202 } );
203 break;
204
205 case SCH_TABLE_T:
207 static_cast<SCH_TABLE*>( item ),
208 []()
209 {
210 return std::make_unique<SCH_TABLE>();
211 } );
212 break;
213
214 case SCH_SYMBOL_T:
215 {
216 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
217
218 BOOST_TEST_CONTEXT( "symbol: " << symbol->m_Uuid.AsStdString() )
219 {
220 bool result = false;
221 kiapi::schematic::types::SchematicSymbolInstance symbolProto;
222 BOOST_REQUIRE_NO_THROW( result = PackSymbol( &symbolProto, symbol, path ) );
223 BOOST_REQUIRE_MESSAGE( result, "Serialization failed" );
224
225 std::unique_ptr<SCH_SYMBOL> output = std::make_unique<SCH_SYMBOL>();
226
227 // A symbol reaches its schematic through the screen it sits on, which is where
228 // the variant registry lives.
229 output->SetParent( m_schematic->RootScreen() );
230
231 BOOST_REQUIRE_NO_THROW( result = UnpackSymbol( output.get(), symbolProto ) );
232 BOOST_REQUIRE_MESSAGE( result, "Deserialization failed" );
233
234 BOOST_REQUIRE_NO_THROW( ApplySymbolInstance( output.get(), symbolProto, path,
235 m_schematic.get() ) );
236
237 kiapi::schematic::types::SchematicSymbolInstance outputProto;
238 BOOST_REQUIRE_NO_THROW( result = PackSymbol( &outputProto, output.get(), path ) );
239 BOOST_REQUIRE_MESSAGE( result, "Second serialization failed" );
240
241 if( !( outputProto.SerializeAsString() == symbolProto.SerializeAsString() ) )
242 {
243 BOOST_TEST_MESSAGE( "Input: " << symbolProto.Utf8DebugString() );
244 BOOST_TEST_MESSAGE( "Output: " << outputProto.Utf8DebugString() );
245 BOOST_TEST_FAIL( "Round-tripped protobuf does not match" );
246 }
247
248 if( !output->operator==( *symbol ) )
249 BOOST_TEST_FAIL( "Round-tripped object does not match" );
250 }
251
252 break;
253 }
254
255 default:
256 break;
257 }
258 }
259}
260
261
262BOOST_AUTO_TEST_CASE( PerPlacementAttributes )
263{
264 wxFileName fn( KI_TEST::GetEeschemaTestDataDir(), wxS( "api_kitchen_sink.kicad_sch" ) );
265 LoadSchematic( fn );
266 SCH_SHEET_PATH path = m_schematic->CurrentSheet();
267
268 SCH_SYMBOL* symbol = nullptr;
269
270 for( SCH_ITEM* item : m_schematic->RootScreen()->Items().OfType( SCH_SYMBOL_T ) )
271 {
272 symbol = static_cast<SCH_SYMBOL*>( item );
273 break;
274 }
275
276 BOOST_REQUIRE( symbol );
277
278 const wxString variantName( wxS( "api-variant" ) );
279 const bool baseDNP = symbol->GetDNP();
280
281 kiapi::schematic::types::SchematicSymbolInstance proto;
282 BOOST_REQUIRE( PackSymbol( &proto, symbol, path ) );
283
284 kiapi::schematic::types::SchematicSymbolVariant* variant =
285 proto.mutable_variants()->add_variants();
286 variant->set_name( variantName.ToUTF8() );
287 variant->mutable_attributes()->set_do_not_populate( !baseDNP );
288
289 ApplySymbolInstance( symbol, proto, path, m_schematic.get() );
290
291 BOOST_CHECK_EQUAL( symbol->GetDNP( &path, variantName ), !baseDNP );
292 BOOST_CHECK_EQUAL( symbol->GetDNP(), baseDNP );
293 BOOST_CHECK( m_schematic->GetVariantNames().count( variantName ) );
294
295 // An unset variant set leaves the placement's variants alone.
296 kiapi::schematic::types::SchematicSymbolInstance untouched;
297 untouched.mutable_reference_field()->mutable_text()->set_text(
298 symbol->GetRef( &path ).ToUTF8() );
299
300 ApplySymbolInstance( symbol, untouched, path, m_schematic.get() );
301
302 BOOST_CHECK_EQUAL( symbol->GetDNP( &path, variantName ), !baseDNP );
303
304 // Sending the set back without a variant removes it from this placement, while the variant
305 // itself stays registered with the schematic.
306 kiapi::schematic::types::SchematicSymbolInstance cleared;
307 BOOST_REQUIRE( PackSymbol( &cleared, symbol, path ) );
308 BOOST_REQUIRE_EQUAL( cleared.variants().variants_size(), 1 );
309 cleared.mutable_variants()->clear_variants();
310
311 ApplySymbolInstance( symbol, cleared, path, m_schematic.get() );
312
313 BOOST_CHECK_EQUAL( symbol->GetDNP( &path, variantName ), baseDNP );
314 BOOST_CHECK( m_schematic->GetVariantNames().count( variantName ) );
315}
316
317
318BOOST_AUTO_TEST_CASE( PerPlacementFieldOverride )
319{
320 wxFileName fn( KI_TEST::GetEeschemaTestDataDir(), wxS( "api_kitchen_sink.kicad_sch" ) );
321 LoadSchematic( fn );
322 SCH_SHEET_PATH path = m_schematic->CurrentSheet();
323
324 SCH_SYMBOL* symbol = nullptr;
325
326 for( SCH_ITEM* item : m_schematic->RootScreen()->Items().OfType( SCH_SYMBOL_T ) )
327 {
328 symbol = static_cast<SCH_SYMBOL*>( item );
329 break;
330 }
331
332 BOOST_REQUIRE( symbol );
333
334 const wxString variantName( wxS( "api-variant" ) );
335 const wxString fieldName = symbol->GetField( FIELD_T::VALUE )->GetName();
336 const wxString baseValue = symbol->GetFieldText( fieldName, &path );
337 const wxString overrideValue( wxS( "Override" ) );
338
339 kiapi::schematic::types::SchematicSymbolInstance proto;
340 BOOST_REQUIRE( PackSymbol( &proto, symbol, path ) );
341
342 kiapi::schematic::types::SchematicSymbolVariant* variant = proto.mutable_variants()->add_variants();
343 variant->set_name( variantName.ToUTF8() );
344 variant->mutable_attributes()->set_do_not_populate( true );
345 ( *variant->mutable_fields() )[std::string( fieldName.ToUTF8() )] = overrideValue.ToUTF8();
346
347 ApplySymbolInstance( symbol, proto, path, m_schematic.get() );
348
349 BOOST_CHECK_EQUAL( symbol->GetFieldText( fieldName, &path, variantName ), overrideValue );
350 BOOST_CHECK( symbol->GetDNP( &path, variantName ) );
351
352 kiapi::schematic::types::SchematicSymbolInstance withoutField;
353 BOOST_REQUIRE( PackSymbol( &withoutField, symbol, path ) );
354 BOOST_REQUIRE_EQUAL( withoutField.variants().variants_size(), 1 );
355
356 withoutField.mutable_variants()->mutable_variants( 0 )->clear_fields();
357
358 ApplySymbolInstance( symbol, withoutField, path, m_schematic.get() );
359
360 BOOST_CHECK_EQUAL( symbol->GetFieldText( fieldName, &path, variantName ), baseValue );
361 BOOST_CHECK( symbol->GetDNP( &path, variantName ) );
362
363 kiapi::schematic::types::SchematicSymbolInstance cleared;
364 BOOST_REQUIRE( PackSymbol( &cleared, symbol, path ) );
365 cleared.mutable_variants()->clear_variants();
366
367 ApplySymbolInstance( symbol, cleared, path, m_schematic.get() );
368
369 BOOST_CHECK( !symbol->GetDNP( &path, variantName ) );
370 BOOST_CHECK( m_schematic->GetVariantNames().count( variantName ) );
371}
372
373
374BOOST_AUTO_TEST_CASE( SheetInstanceRoundTrip )
375{
376 wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
377 fn.AppendDir( wxS( "variants" ) );
378 fn.SetName( wxS( "variants" ) );
379 fn.SetExt( wxS( "kicad_sch" ) );
380 LoadSchematic( fn );
381
382 SCH_SHEET* sheet = nullptr;
383
384 for( SCH_ITEM* item : m_schematic->RootScreen()->Items().OfType( SCH_SHEET_T ) )
385 {
386 sheet = static_cast<SCH_SHEET*>( item );
387 break;
388 }
389
390 BOOST_REQUIRE( sheet );
391
392 SCH_SHEET_PATH parentPath = m_schematic->CurrentSheet();
393
394 kiapi::schematic::types::SheetSymbol proto;
395 BOOST_REQUIRE( PackSheet( &proto, sheet, parentPath ) );
396
397 BOOST_CHECK_EQUAL( proto.page_number(), "2" );
398 BOOST_REQUIRE_EQUAL( proto.variants().variants_size(), 1 );
399
400 const kiapi::schematic::types::SheetVariant& variant = proto.variants().variants( 0 );
401 BOOST_CHECK_EQUAL( variant.name(), "Variant 1" );
402 BOOST_CHECK( variant.exclude_from_sim() );
403
404 std::unique_ptr<SCH_SHEET> output = std::make_unique<SCH_SHEET>( m_schematic->RootScreen() );
405 output->SetParent( m_schematic->RootScreen() );
406 output->SetScreen( new SCH_SCREEN( m_schematic.get() ) );
407
408 BOOST_REQUIRE( UnpackSheet( output.get(), proto ).has_value() );
409 ApplySheetInstance( output.get(), proto, parentPath, m_schematic.get() );
410
411 SCH_SHEET_PATH childPath( parentPath );
412 childPath.push_back( output.get() );
413
414 BOOST_CHECK_EQUAL( childPath.GetPageNumber(), "2" );
415 BOOST_CHECK( output->GetExcludedFromSim( &parentPath, wxS( "Variant 1" ) ) );
416
417 kiapi::schematic::types::SheetSymbol outputProto;
418 BOOST_REQUIRE( PackSheet( &outputProto, output.get(), parentPath ) );
419
420 BOOST_CHECK_EQUAL( outputProto.page_number(), proto.page_number() );
421 BOOST_REQUIRE_EQUAL( outputProto.variants().variants_size(), 1 );
422 BOOST_CHECK_EQUAL( outputProto.variants().variants( 0 ).name(), "Variant 1" );
423 BOOST_CHECK_EQUAL( outputProto.variants().variants( 0 ).exclude_from_sim(),
424 proto.variants().variants( 0 ).exclude_from_sim() );
425}
426
427
428BOOST_AUTO_TEST_CASE( SheetVariantManagement )
429{
430 wxFileName fn( KI_TEST::GetEeschemaTestDataDir(), wxS( "api_kitchen_sink.kicad_sch" ) );
431 LoadSchematic( fn );
432
433 SCH_SHEET* sheet = nullptr;
434
435 for( SCH_ITEM* item : m_schematic->RootScreen()->Items().OfType( SCH_SHEET_T ) )
436 {
437 sheet = static_cast<SCH_SHEET*>( item );
438 break;
439 }
440
441 BOOST_REQUIRE( sheet );
442
443 SCH_SHEET_PATH parentPath = m_schematic->CurrentSheet();
444 const wxString variantName( wxS( "api-sheet-variant" ) );
445 const bool baseDNP = sheet->GetDNP( &parentPath );
446
447 kiapi::schematic::types::SheetSymbol proto;
448 BOOST_REQUIRE( PackSheet( &proto, sheet, parentPath ) );
449
450 kiapi::schematic::types::SheetVariant* variant = proto.mutable_variants()->add_variants();
451 variant->set_name( variantName.ToUTF8() );
452 variant->set_dnp( !baseDNP );
453
454 ApplySheetInstance( sheet, proto, parentPath, m_schematic.get() );
455
456 BOOST_CHECK_EQUAL( sheet->GetDNP( &parentPath, variantName ), !baseDNP );
457 BOOST_CHECK_EQUAL( sheet->GetDNP( &parentPath ), baseDNP );
458 BOOST_CHECK( m_schematic->GetVariantNames().count( variantName ) );
459
460 kiapi::schematic::types::SheetSymbol untouched;
461 BOOST_REQUIRE( PackSheet( &untouched, sheet, parentPath ) );
462 untouched.clear_variants();
463
464 if( untouched.page_number().empty() )
465 untouched.set_page_number( "1" );
466
467 ApplySheetInstance( sheet, untouched, parentPath, m_schematic.get() );
468
469 BOOST_CHECK_EQUAL( sheet->GetDNP( &parentPath, variantName ), !baseDNP );
470
471 kiapi::schematic::types::SheetSymbol cleared;
472 BOOST_REQUIRE( PackSheet( &cleared, sheet, parentPath ) );
473 BOOST_REQUIRE_EQUAL( cleared.variants().variants_size(), 1 );
474 cleared.mutable_variants()->clear_variants();
475
476 ApplySheetInstance( sheet, cleared, parentPath, m_schematic.get() );
477
478 BOOST_CHECK_EQUAL( sheet->GetDNP( &parentPath, variantName ), baseDNP );
479 BOOST_CHECK( m_schematic->GetVariantNames().count( variantName ) );
480}
481
void ApplySymbolInstance(SCH_SYMBOL *aSymbol, const kiapi::schematic::types::SchematicSymbolInstance &aInput, const SCH_SHEET_PATH &aPath, SCHEMATIC *aSchematic)
Apply placement-specific data to an aSymbol at aPath: reference, unit, and the per-placement attribut...
tl::expected< bool, ApiResponseStatus > UnpackSheet(SCH_SHEET *aOutput, const kiapi::schematic::types::SheetSymbol &aInput)
Unpack the every placement data from the input.
bool PackSheet(kiapi::schematic::types::SheetSymbol *aOutput, const SCH_SHEET *aInput, const SCH_SHEET_PATH &aPath)
bool PackSymbol(kiapi::schematic::types::SchematicSymbolInstance *aOutput, const SCH_SYMBOL *aInput, const SCH_SHEET_PATH &aPath)
void ApplySheetInstance(SCH_SHEET *aSheet, const kiapi::schematic::types::SheetSymbol &aInput, const SCH_SHEET_PATH &aParentPath, SCHEMATIC *aSchematic)
Apply the placement data in a sheet message to aSheet: page number and the variants the message carri...
bool UnpackSymbol(SCH_SYMBOL *aOutput, const kiapi::schematic::types::SchematicSymbolInstance &aInput)
Unpack the geometry, the library definition, fields, and the default-variant attributes that are shar...
void testProtoFromKiCadObject(KiCadClass *aInput, Factory &&aCreateOutput)
const KIID m_Uuid
Definition eda_item.h:597
std::string AsStdString() const
Definition kiid.cpp:270
A generic fixture for loading schematics and associated settings for qa tests.
Object to handle a bitmap image that can be inserted in a schematic.
Definition sch_bitmap.h:36
Class for a bus to bus entry.
Class for a wire to bus entry.
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:48
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString GetPageNumber() const
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flags.
Schematic symbol object.
Definition sch_symbol.h:75
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) const
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
Class to handle a set of SCH_ITEMs.
static void LoadSchematic(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const wxString &aFileName)
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
@ VALUE
Field Value of part, i.e. "3.3K".
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
BOOST_AUTO_TEST_CASE(KitchenSink)
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_GROUP_T
Definition typeinfo.h:169
@ SCH_TABLE_T
Definition typeinfo.h:161
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_NO_CONNECT_T
Definition typeinfo.h:156
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:167
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_RULE_AREA_T
Definition typeinfo.h:166
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:158
@ SCH_TEXT_T
Definition typeinfo.h:147
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:157
@ SCH_BITMAP_T
Definition typeinfo.h:160
@ SCH_TEXTBOX_T
Definition typeinfo.h:148
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164
@ SCH_JUNCTION_T
Definition typeinfo.h:155