80 kiapi::board::commands::BoardDesignRulesResponse* aOut, wxString* aError =
nullptr )
82 kiapi::board::commands::GetBoardDesignRules request;
83 *request.mutable_board() = aDocument;
85 kiapi::common::ApiResponse response;
95 if( response.status().status() != kiapi::common::AS_OK )
98 *aError = response.status().error_message();
103 if( !response.message().UnpackTo( aOut ) )
106 *aError = wxS(
"Failed to unpack BoardDesignRulesResponse" );
116 kiapi::board::commands::CustomRulesResponse* aOut, wxString* aError =
nullptr )
118 kiapi::board::commands::GetCustomDesignRules request;
119 *request.mutable_board() = aDocument;
121 kiapi::common::ApiResponse response;
131 if( response.status().status() != kiapi::common::AS_OK )
134 *aError = response.status().error_message();
139 if( !response.message().UnpackTo( aOut ) )
142 *aError = wxS(
"Failed to unpack CustomRulesResponse" );
164 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
166 kiapi::common::types::DocumentSpecifier document;
168 wxFileName boardPath( testDataDir, wxS(
"api_kitchen_sink.kicad_pcb" ) );
170 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
171 "OpenDocument failed: " + Client().LastError() );
173 BOOST_REQUIRE( document.type() == kiapi::common::types::DOCTYPE_PCB );
174 BOOST_REQUIRE( boardPath.GetFullName().Matches( document.board_filename() ) );
176 int footprintCount = 0;
178 BOOST_REQUIRE_MESSAGE( Client().GetItemsCount( document, kiapi::common::types::KOT_PCB_FOOTPRINT, &footprintCount ),
179 "GetItems failed: " + Client().LastError() );
181 BOOST_CHECK_GT( footprintCount, 0 );
189 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
191 kiapi::common::types::DocumentSpecifier document;
194 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
195 "OpenDocument failed: " + Client().LastError() );
199 BOOST_REQUIRE_MESSAGE( Client().GetFirstFootprint( document, &footprint ),
200 "GetFirstFootprint failed: " + Client().LastError() );
205 kiapi::common::commands::DeleteItems request;
206 *request.mutable_header()->mutable_document() = document;
209 kiapi::common::ApiResponse response;
211 BOOST_REQUIRE_MESSAGE( Client().SendCommand( request, &response ),
212 "DeleteItems failed: " + Client().LastError() );
213 BOOST_REQUIRE_EQUAL( response.status().status(), kiapi::common::AS_OK );
215 kiapi::common::commands::DeleteItemsResponse deleteResponse;
217 BOOST_REQUIRE( response.message().UnpackTo( &deleteResponse ) );
218 BOOST_REQUIRE_EQUAL( deleteResponse.deleted_items_size(), 1 );
220 kiapi::common::commands::ItemDeletionStatus::IDS_IMMUTABLE );
224 BOOST_REQUIRE_MESSAGE( Client().GetFirstFootprint( document, &after ),
225 "GetFirstFootprint after delete failed: " + Client().LastError() );
236 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
239 wxFileName boardPathA( testDataDir, wxS(
"api_kitchen_sink.kicad_pcb" ) );
240 wxFileName boardPathB( testDataDir, wxS(
"padstacks.kicad_pcb" ) );
242 kiapi::common::types::DocumentSpecifier documentA;
244 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPathA.GetFullPath(), &documentA ),
245 "OpenDocument for first board failed: " + Client().LastError() );
249 BOOST_REQUIRE_MESSAGE( Client().GetFirstFootprint( documentA, &footprintA ),
250 "GetFirstFootprint for first board failed: " + Client().LastError() );
253 kiapi::common::ApiStatusCode closeStatusA = kiapi::common::AS_UNKNOWN;
255 BOOST_REQUIRE_MESSAGE( Client().CloseDocument( &documentA, &closeStatusA ),
256 "CloseDocument for first board failed: " + Client().LastError() );
259 kiapi::common::types::DocumentSpecifier documentB;
261 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPathB.GetFullPath(), &documentB ),
262 "OpenDocument for second board failed: " + Client().LastError() );
266 BOOST_REQUIRE_MESSAGE( Client().GetFirstFootprint( documentB, &footprintB ),
267 "GetFirstFootprint for second board failed: " + Client().LastError() );
269 BOOST_CHECK_NE( footprintA.
Similarity( footprintB ), 1.0 );
271 kiapi::common::ApiStatusCode closeStatus = kiapi::common::AS_UNKNOWN;
273 BOOST_REQUIRE_MESSAGE( Client().CloseDocument( &documentB, &closeStatus ),
274 "CloseDocument failed: " + Client().LastError() );
277 BOOST_REQUIRE_MESSAGE( Client().CloseDocument(
nullptr, &closeStatus ),
278 "CloseDocument after already closed failed: " + Client().LastError() );
285 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
287 kiapi::common::types::DocumentSpecifier document;
290 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
291 "OpenDocument failed: " + Client().LastError() );
293 kiapi::board::commands::BoardDesignRulesResponse rulesResponse;
297 "GetBoardDesignRules failed: " + error );
299 BOOST_CHECK_GE( rulesResponse.rules().constraints().min_clearance().value_nm(), 0 );
300 BOOST_CHECK_GE( rulesResponse.rules().constraints().min_track_width().value_nm(), 0 );
301 BOOST_CHECK( rulesResponse.custom_rules_status() == kiapi::board::commands::CRS_VALID );
307 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
312 BOOST_REQUIRE_MESSAGE( fixtureCopy.
Create( ©Error ), copyError );
314 kiapi::common::types::DocumentSpecifier document;
316 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( fixtureCopy.
BoardPath(), &document ),
317 "OpenDocument failed: " + Client().LastError() );
319 kiapi::board::commands::BoardDesignRulesResponse getResponse;
322 "Initial GetBoardDesignRules failed: " + copyError );
324 int newWidth = getResponse.rules().constraints().min_track_width().value_nm() + 1000;
326 kiapi::board::commands::SetBoardDesignRules setRequest;
327 *setRequest.mutable_board() = document;
328 *setRequest.mutable_rules()->mutable_constraints() = getResponse.rules().constraints();
329 setRequest.mutable_rules()->mutable_constraints()->mutable_min_track_width()->set_value_nm( newWidth );
331 kiapi::common::ApiResponse setApiResponse;
333 BOOST_REQUIRE_MESSAGE( Client().SendCommand( setRequest, &setApiResponse ),
334 "SetBoardDesignRules failed to send: " + Client().LastError() );
335 BOOST_REQUIRE( setApiResponse.status().status() == kiapi::common::AS_OK );
337 kiapi::board::commands::BoardDesignRulesResponse setResponse;
338 BOOST_REQUIRE( setApiResponse.message().UnpackTo( &setResponse ) );
340 BOOST_CHECK_EQUAL( setResponse.rules().constraints().min_track_width().value_nm(), newWidth );
342 kiapi::board::commands::BoardDesignRulesResponse verifyResponse;
345 "Verification GetBoardDesignRules failed: " + copyError );
347 BOOST_CHECK_EQUAL( verifyResponse.rules().constraints().min_track_width().value_nm(), newWidth );
353 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
358 BOOST_REQUIRE_MESSAGE( fixtureCopy.
Create( ©Error ), copyError );
360 kiapi::common::types::DocumentSpecifier document;
362 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( fixtureCopy.
BoardPath(), &document ),
363 "OpenDocument failed: " + Client().LastError() );
365 kiapi::board::commands::BoardDesignRulesResponse getResponse;
368 "Initial GetBoardDesignRules failed: " + copyError );
370 kiapi::board::commands::SetBoardDesignRules setRequest;
371 *setRequest.mutable_board() = document;
372 *setRequest.mutable_rules()->mutable_constraints() = getResponse.rules().constraints();
373 setRequest.mutable_rules()->mutable_constraints()->mutable_min_track_width()->set_value_nm( 1000000000 );
375 kiapi::common::ApiResponse response;
377 BOOST_REQUIRE_MESSAGE( Client().SendCommand( setRequest, &response ),
378 "SetBoardDesignRules failed to send: " + Client().LastError() );
380 BOOST_CHECK( response.status().status() == kiapi::common::AS_BAD_REQUEST );
381 BOOST_CHECK( !response.status().error_message().empty() );
387 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
392 BOOST_REQUIRE_MESSAGE( fixtureCopy.
Create( ©Error ), copyError );
394 kiapi::common::types::DocumentSpecifier document;
396 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( fixtureCopy.
BoardPath(), &document ),
397 "OpenDocument failed: " + Client().LastError() );
399 kiapi::board::commands::BoardDesignRulesResponse getResponse;
401 "Initial GetBoardDesignRules failed: " + copyError );
403 auto applySeverityAndVerify = [&]( kiapi::common::types::RuleSeverity aSeverity )
405 kiapi::board::commands::SetBoardDesignRules setRequest;
406 *setRequest.mutable_board() = document;
408 kiapi::board::DrcSeveritySetting* setting = setRequest.mutable_rules()->add_severities();
409 setting->set_rule_type( kiapi::board::DrcErrorType::DRCET_UNCONNECTED_ITEMS );
410 setting->set_severity( aSeverity );
412 kiapi::common::ApiResponse setApiResponse;
413 BOOST_REQUIRE_MESSAGE( Client().SendCommand( setRequest, &setApiResponse ),
414 "SetBoardDesignRules failed to send: " + Client().LastError() );
415 BOOST_REQUIRE( setApiResponse.status().status() == kiapi::common::AS_OK );
417 kiapi::board::commands::BoardDesignRulesResponse verifyResponse;
419 "Verification GetBoardDesignRules failed: " + copyError );
423 for(
const kiapi::board::DrcSeveritySetting& severity : verifyResponse.rules().severities() )
425 if( severity.rule_type() == kiapi::board::DrcErrorType::DRCET_UNCONNECTED_ITEMS )
428 BOOST_CHECK( severity.severity() == aSeverity );
433 BOOST_CHECK( found );
436 applySeverityAndVerify( kiapi::common::types::RS_IGNORE );
437 applySeverityAndVerify( kiapi::common::types::RS_ERROR );
443 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
445 kiapi::common::types::DocumentSpecifier document;
448 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
449 "OpenDocument failed: " + Client().LastError() );
451 kiapi::board::commands::CustomRulesResponse response;
455 "GetCustomDesignRules failed: " + error );
457 BOOST_CHECK( response.status() == kiapi::board::commands::CRS_VALID );
458 BOOST_CHECK_GT( response.rules_size(), 0 );
460 bool foundFixtureRule =
false;
462 for(
const kiapi::board::CustomRule& rule : response.rules() )
464 if( rule.name() ==
"myrule" )
466 foundFixtureRule =
true;
474 BOOST_CHECK( foundFixtureRule );
480 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
485 BOOST_REQUIRE_MESSAGE( fixtureCopy.
Create( ©Error ), copyError );
487 kiapi::common::types::DocumentSpecifier document;
489 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( fixtureCopy.
BoardPath(), &document ),
490 "OpenDocument failed: " + Client().LastError() );
492 kiapi::board::commands::CustomRulesResponse response;
496 "GetCustomDesignRules failed: " + error );
498 BOOST_CHECK( response.status() == kiapi::board::commands::CRS_VALID );
499 BOOST_CHECK_GT( response.rules_size(), 0 );
501 kiapi::board::commands::SetCustomDesignRules setRequest;
502 *setRequest.mutable_board() = document;
504 setRequest.mutable_rules()->CopyFrom( response.rules() );
506 kiapi::board::CustomRule* rule = setRequest.add_rules();
507 rule->set_name(
"api_roundtrip_rule" );
508 rule->set_condition(
"A.NetClass == 'HV'" );
509 rule->set_layer_mode( kiapi::board::CRLM_OUTER );
510 rule->set_severity( kiapi::common::types::RS_WARNING );
512 kiapi::board::CustomRuleConstraint* annular = rule->add_constraints();
513 annular->set_type( kiapi::board::CRCT_TRACK_WIDTH );
514 annular->mutable_numeric()->set_min( 3000000 );
515 annular->mutable_numeric()->set_opt( 4000000 );
516 annular->mutable_numeric()->set_max( 5000000 );
518 kiapi::board::CustomRuleConstraint* disallow = rule->add_constraints();
519 disallow->set_type( kiapi::board::CRCT_DISALLOW );
520 disallow->mutable_disallow()->add_types( kiapi::board::CRDT_BLIND_VIAS );
522 kiapi::common::ApiResponse setApiResponse;
524 BOOST_REQUIRE_MESSAGE( Client().SendCommand( setRequest, &setApiResponse ),
525 "SetCustomDesignRules failed to send: " + Client().LastError() );
526 BOOST_REQUIRE( setApiResponse.status().status() == kiapi::common::AS_OK );
528 kiapi::board::commands::CustomRulesResponse setResponse;
529 BOOST_REQUIRE( setApiResponse.message().UnpackTo( &setResponse ) );
531 int num_rules = setResponse.rules_size();
532 BOOST_CHECK( setResponse.status() == kiapi::board::commands::CRS_VALID );
534 BOOST_CHECK_EQUAL( setResponse.rules( num_rules - 1 ).name(),
"api_roundtrip_rule" );
540 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
544 kiapi::common::types::DocumentSpecifier projectDoc;
546 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( testDataDir + wxS(
"basic_test.kicad_pro" ),
547 kiapi::common::types::DOCTYPE_PROJECT, &projectDoc ),
548 "OpenDocument for project failed: " + Client().LastError() );
550 BOOST_REQUIRE( projectDoc.type() == kiapi::common::types::DOCTYPE_PROJECT );
552 kiapi::common::types::DocumentSpecifier boardDoc;
554 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( testDataDir + wxS(
"basic_test.kicad_pcb" ),
555 kiapi::common::types::DOCTYPE_PCB, &boardDoc ),
556 "OpenDocument for board failed: " + Client().LastError() );
558 BOOST_REQUIRE( boardDoc.type() == kiapi::common::types::DOCTYPE_PCB );
561 int footprintCount = 0;
562 BOOST_REQUIRE_MESSAGE( Client().GetItemsCount( boardDoc, kiapi::common::types::KOT_PCB_FOOTPRINT, &footprintCount ),
563 "GetItems for board failed: " + Client().LastError() );
564 BOOST_CHECK_GT( footprintCount, 0 );
566 kiapi::common::types::DocumentSpecifier schDoc;
568 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( testDataDir + wxS(
"basic_test.kicad_sch" ),
569 kiapi::common::types::DOCTYPE_SCHEMATIC, &schDoc ),
570 "OpenDocument for schematic failed: " + Client().LastError() );
572 BOOST_REQUIRE( schDoc.type() == kiapi::common::types::DOCTYPE_SCHEMATIC );
576 BOOST_REQUIRE_MESSAGE( Client().GetItemsCount( boardDoc, kiapi::common::types::KOT_PCB_FOOTPRINT, &footprintCount ),
577 "GetItems for board after opening schematic failed: " + Client().LastError() );
578 BOOST_CHECK_GT( footprintCount, 0 );
583 kiapi::common::types::DocumentSpecifier otherBoardDoc;
585 BOOST_REQUIRE_MESSAGE(
586 !Client().OpenDocument( otherDataDir + wxS(
"api_kitchen_sink.kicad_pcb" ),
587 kiapi::common::types::DOCTYPE_PCB, &otherBoardDoc ),
588 "OpenDocument for a different-project board should have failed" );
590 BOOST_CHECK( Client().LastError().Contains( wxS(
"already open" ) ) );
596 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
599 [&]( kiapi::common::types::DocumentType aType,
const wxString& aExpectedExt )
604 wxFileName fileWithExt( tempDir.
ChildPathStr(
"new_doc" + aExpectedExt ) );
605 wxFileName projectWithExt( tempDir.
ChildPathStr(
"new_doc.kicad_pro" ) );
607 kiapi::common::types::DocumentSpecifier document;
609 BOOST_REQUIRE_MESSAGE( Client().CreateDocument( tempFn, aType, &document ),
610 "CreateDocument failed: " + Client().LastError() );
612 BOOST_CHECK( document.type() == aType );
613 BOOST_CHECK( document.project().name() == projectWithExt.GetName() );
614 BOOST_CHECK( document.project().path() == projectWithExt.GetPath(
true ) );
616 kiapi::common::ApiResponse response;
617 kiapi::common::commands::GetDocumentModifiedState state;
618 state.mutable_document()->CopyFrom( document );
619 BOOST_CHECK( Client().SendCommand( state, &response ) );
622 BOOST_CHECK( !wxFileName( fileWithExt ).FileExists() );
623 BOOST_CHECK( !wxFileName( projectWithExt ).FileExists() );
625 kiapi::common::commands::SaveDocument
save;
626 save.mutable_document()->CopyFrom( document );
627 BOOST_CHECK( Client().SendCommand(
save, &response ) );
629 BOOST_CHECK( wxFileName( fileWithExt ).FileExists() );
630 BOOST_CHECK( wxFileName( projectWithExt ).FileExists() );
633 std::map<kiapi::common::types::DocumentType, wxString> cases = {
634 { kiapi::common::types::DOCTYPE_PCB, wxS(
".kicad_pcb" )},
635 { kiapi::common::types::DOCTYPE_SCHEMATIC, wxS(
".kicad_sch" ) }
638 for(
const auto& [docType, ext] : cases )
642 test( docType, ext );
650 using namespace kiapi::common::commands;
652 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
655 [&]( kiapi::common::types::DocumentType aType,
const wxString& aExistingPath )
658 wxString docFileName = tempDir.
ChildPathStr(
"new_doc" );
660 kiapi::common::types::DocumentSpecifier existingDoc;
662 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( aExistingPath, aType, &existingDoc ),
663 "OpenDocument failed: " + Client().LastError() );
665 SetPageSettings modify;
666 modify.mutable_document()->CopyFrom( existingDoc );
667 modify.mutable_page_settings()->set_orientation( kiapi::common::types::PO_PORTRAIT );
668 kiapi::common::ApiResponse response;
669 BOOST_CHECK( Client().SendCommand( modify, &response ) );
671 GetDocumentModifiedState stateQuery;
672 stateQuery.mutable_document()->CopyFrom( existingDoc );
673 BOOST_CHECK( Client().SendCommand( stateQuery, &response ) );
674 GetDocumentModifiedStateResponse state;
675 BOOST_CHECK( response.message().UnpackTo( &state ) );
676 BOOST_CHECK( state.state() == DocumentModifiedState::DMS_MODIFIED );
678 kiapi::common::types::DocumentSpecifier newDoc;
680 BOOST_REQUIRE( !Client().CreateDocument( docFileName, aType, &newDoc ) );
682 BOOST_CHECK( Client().LastError().Contains( wxS(
"save or revert" ) ) );
684 kiapi::common::commands::RevertDocument revert;
685 revert.mutable_document()->CopyFrom( existingDoc );
686 BOOST_CHECK( Client().SendCommand( revert, &response ) );
688 BOOST_REQUIRE( Client().CreateDocument( docFileName, aType, &newDoc ) );
690 BOOST_CHECK( Client().CloseAllDocuments() );
693 std::map<kiapi::common::types::DocumentType, wxString> cases = {
694 { kiapi::common::types::DOCTYPE_PCB,
696 { kiapi::common::types::DOCTYPE_SCHEMATIC,
700 for(
const auto& [docType,
path] : cases )
BOOST_CHECK_EQUAL(result, "25.4")