44bool textFilesMatch(
const wxString& aGoldenPath,
const wxString& aGeneratedPath,
int aSkipLines )
46 std::ifstream goldenStream( aGoldenPath.ToStdString() );
47 std::ifstream generatedStream( aGeneratedPath.ToStdString() );
49 if( !goldenStream.is_open() )
55 if( !generatedStream.is_open() )
61 std::string goldenLine, generatedLine;
63 for(
int i = 0; i < aSkipLines; ++i )
65 std::getline( goldenStream, goldenLine );
66 std::getline( generatedStream, generatedLine );
69 int lineNum = aSkipLines + 1;
71 while( std::getline( goldenStream, goldenLine ) )
73 if( !std::getline( generatedStream, generatedLine ) )
79 if( goldenLine != generatedLine )
82 <<
" golden: " << goldenLine <<
"\n"
83 <<
" generated: " << generatedLine );
90 if( std::getline( generatedStream, generatedLine ) )
143 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
145 wxString testDataDir =
148 wxFileName boardPath( testDataDir, wxS(
"ZoneFill-4.0.7.kicad_pcb" ) );
150 kiapi::common::types::DocumentSpecifier document;
152 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
153 "OpenDocument failed: " + Client().LastError() );
157 wxFileName outputPath( tempDir.
ChildPathStr(
"plot.svg" ) );
159 kiapi::board::jobs::RunBoardJobExportSvg request;
160 *request.mutable_job_settings()->mutable_document() = document;
161 request.mutable_job_settings()->set_output_path( outputPath.GetFullPath().ToUTF8().data() );
163 request.mutable_plot_settings()->add_layers( kiapi::board::types::BL_F_Cu );
164 request.mutable_plot_settings()->set_black_and_white(
true );
165 request.mutable_plot_settings()->set_plot_drawing_sheet(
false );
166 request.mutable_plot_settings()->set_drill_marks( kiapi::board::jobs::PDM_FULL );
167 request.set_page_mode( kiapi::board::jobs::BJPM_EACH_LAYER_OWN_FILE );
168 request.set_precision( 4 );
170 kiapi::common::types::RunJobResponse response;
171 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
"RunJob failed: " + Client().LastError() );
173 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
174 "Job failed: " + wxString::FromUTF8( response.message() ) );
176 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"Job returned no output paths" );
178 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
179 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
"Generated SVG does not exist: " + generatedPath );
185 BOOST_REQUIRE_MESSAGE( !svg.empty(),
"Generated SVG is empty or unreadable: " + generatedPath );
186 BOOST_CHECK( svg.find(
"<svg" ) != std::string::npos );
187 BOOST_CHECK( svg.find(
"</svg>" ) != std::string::npos );
190 BOOST_CHECK( svg.find(
"width=\"297.0022mm\" height=\"210.0072mm\"" ) != std::string::npos );
193 BOOST_REQUIRE_MESSAGE( !colours.empty(),
"Plot declares no colours at all" );
195 for(
const std::string& colour : colours )
197 BOOST_CHECK_MESSAGE( colour ==
"#000000" || colour ==
"#FFFFFF",
198 "black_and_white was requested but the plot contains " + colour );
241 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
245 wxFileName schPath( testDataDir, wxS(
"basic_test.kicad_sch" ) );
247 kiapi::common::types::DocumentSpecifier document;
249 BOOST_REQUIRE_MESSAGE(
250 Client().OpenDocument( schPath.GetFullPath(), kiapi::common::types::DOCTYPE_SCHEMATIC, &document ),
251 "OpenDocument failed: " + Client().LastError() );
255 wxString outputDir = tempDir.
CreateChildDirStr(
"all" ) + wxFileName::GetPathSeparator();
258 kiapi::schematic::jobs::RunSchematicJobExportPng request;
259 *request.mutable_job_settings()->mutable_document() = document;
260 request.mutable_job_settings()->set_output_path( outputDir.ToUTF8().data() );
261 request.mutable_plot_settings()->set_sheet_mode( kiapi::schematic::jobs::SJSM_ALL_SHEETS );
262 request.mutable_plot_settings()->set_black_and_white(
true );
263 request.set_dpi( 150 );
265 kiapi::common::types::RunJobResponse response;
266 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
267 "RunJob failed: " + Client().LastError() );
269 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
270 "Job failed: " + wxString::FromUTF8( response.message() ) );
271 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"Job returned no output paths" );
273 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
274 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
275 "Generated PNG does not exist: " + generatedPath );
278 uint32_t width = 0, height = 0;
279 BOOST_REQUIRE_MESSAGE(
pngDimensions( generatedPath, width, height ),
280 "Generated file is not a valid PNG: " + generatedPath );
281 BOOST_CHECK_MESSAGE( width >= 1750 && width <= 1758,
282 "Unexpected PNG width " << width <<
" for 150dpi A4 landscape" );
283 BOOST_CHECK_MESSAGE( height >= 1236 && height <= 1244,
284 "Unexpected PNG height " << height <<
" for 150dpi A4 landscape" );
288 wxFileName singlePath( tempDir.
ChildPathStr(
"single.png" ) );
291 kiapi::schematic::jobs::RunSchematicJobExportPng request;
292 *request.mutable_job_settings()->mutable_document() = document;
293 request.mutable_job_settings()->set_output_path( singlePath.GetFullPath().ToUTF8().data() );
294 request.mutable_plot_settings()->set_sheet_mode( kiapi::schematic::jobs::SJSM_SINGLE_SHEET );
295 request.mutable_plot_settings()->set_black_and_white(
true );
296 request.set_dpi( 300 );
298 kiapi::common::types::RunJobResponse response;
299 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
300 "Single-sheet RunJob failed: " + Client().LastError() );
302 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
303 "Single-sheet job failed: " + wxString::FromUTF8( response.message() ) );
304 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
305 "Single-sheet job returned no output paths" );
307 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
308 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
309 "Generated PNG does not exist: " + generatedPath );
312 uint32_t width = 0, height = 0;
313 BOOST_REQUIRE_MESSAGE(
pngDimensions( generatedPath, width, height ),
314 "Generated file is not a valid PNG: " + generatedPath );
315 BOOST_CHECK_MESSAGE( width >= 3500 && width <= 3516,
316 "Unexpected PNG width " << width <<
" for 300dpi A4 landscape" );
319 BOOST_CHECK_MESSAGE( generatedPath == singlePath.GetFullPath(),
320 "Single-sheet output path not honored: " + generatedPath );
325 kiapi::schematic::jobs::RunSchematicJobExportPng request;
326 *request.mutable_job_settings()->mutable_document() = document;
327 request.mutable_job_settings()->set_output_path( outputDir.ToUTF8().data() );
328 request.mutable_plot_settings()->set_sheet_mode( kiapi::schematic::jobs::SJSM_ALL_SHEETS );
329 request.set_dpi( 10 );
331 kiapi::common::types::RunJobResponse response;
332 BOOST_CHECK_MESSAGE( !Client().RunJob( request, &response ),
333 "Out-of-range dpi was not rejected" );
338 wxString defaultDir = tempDir.
CreateChildDirStr(
"default" ) + wxFileName::GetPathSeparator();
340 kiapi::schematic::jobs::RunSchematicJobExportPng request;
341 *request.mutable_job_settings()->mutable_document() = document;
342 request.mutable_job_settings()->set_output_path( defaultDir.ToUTF8().data() );
343 request.mutable_plot_settings()->set_sheet_mode( kiapi::schematic::jobs::SJSM_ALL_SHEETS );
345 kiapi::common::types::RunJobResponse response;
346 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
347 "Default-dpi RunJob failed: " + Client().LastError() );
348 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
349 "Default-dpi job failed: " + wxString::FromUTF8( response.message() ) );
350 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
351 "Default-dpi job returned no output paths" );
353 uint32_t width = 0, height = 0;
354 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
355 BOOST_REQUIRE_MESSAGE(
pngDimensions( generatedPath, width, height ),
356 "Generated file is not a valid PNG: " + generatedPath );
357 BOOST_CHECK_MESSAGE( width >= 3500 && width <= 3516,
358 "Default dpi should be 300; got width " << width );
365 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
369 wxFileName boardPath( testDataDir, wxS(
"basic_test.kicad_pcb" ) );
371 kiapi::common::types::DocumentSpecifier document;
373 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
374 "OpenDocument failed: " + Client().LastError() );
377 wxString outputDir = tempDir.
CreateChildDirStr(
"drill" ) + wxFileName::GetPathSeparator();
379 kiapi::board::jobs::RunBoardJobExportDrill request;
380 *request.mutable_job_settings()->mutable_document() = document;
381 request.mutable_job_settings()->set_output_path( outputDir.ToUTF8().data() );
382 request.set_format( kiapi::board::jobs::DF_EXCELLON );
384 kiapi::common::types::RunJobResponse response;
385 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
"RunJob failed: " + Client().LastError() );
387 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
388 "Job failed: " + wxString::FromUTF8( response.message() ) );
390 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"Job returned no output paths" );
391 wxString generatedDrillPath;
393 for(
int i = 0; i < response.output_path_size(); ++i )
395 wxString outputPath = wxString::FromUTF8( response.output_path( i ) );
397 if( outputPath.EndsWith( wxS(
".drl" ) ) )
399 generatedDrillPath = outputPath;
404 BOOST_REQUIRE_MESSAGE( !generatedDrillPath.IsEmpty(),
"No .drl file found in job output" );
405 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedDrillPath ),
406 "Generated drill file does not exist: " + generatedDrillPath );
408 wxString goldenPath = testDataDir + wxS(
"basic_test_excellon_inches.drl" );
409 BOOST_CHECK_MESSAGE(
textFilesMatch( goldenPath, generatedDrillPath, 5 ),
410 "Drill output does not match golden file" );
416 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
418 wxString testDataDir =
421 wxFileName boardPath( testDataDir, wxS(
"ZoneFill-4.0.7.kicad_pcb" ) );
423 kiapi::common::types::DocumentSpecifier document;
425 BOOST_REQUIRE_MESSAGE( Client().OpenDocument( boardPath.GetFullPath(), &document ),
426 "OpenDocument failed: " + Client().LastError() );
432 wxString outputDir = tempDir.
CreateChildDirStr(
"multi" ) + wxFileName::GetPathSeparator();
434 kiapi::board::jobs::RunBoardJobExportPng request;
435 *request.mutable_job_settings()->mutable_document() = document;
436 request.mutable_job_settings()->set_output_path( outputDir.ToUTF8().data() );
437 request.mutable_plot_settings()->add_layers( kiapi::board::types::BL_F_Cu );
438 request.mutable_plot_settings()->set_black_and_white(
true );
439 request.set_page_mode( kiapi::board::jobs::BJPM_EACH_LAYER_OWN_FILE );
440 request.set_dpi( 150 );
442 kiapi::common::types::RunJobResponse response;
443 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
444 "RunJob failed: " + Client().LastError() );
446 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
447 "Job failed: " + wxString::FromUTF8( response.message() ) );
448 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"Job returned no output paths" );
450 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
451 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
452 "Generated PNG does not exist: " + generatedPath );
454 uint32_t width = 0, height = 0;
455 BOOST_REQUIRE_MESSAGE(
pngDimensions( generatedPath, width, height ),
456 "Generated file is not a valid PNG: " + generatedPath );
457 BOOST_CHECK_MESSAGE( width >= 1750 && width <= 1758,
458 "Unexpected PNG width " << width <<
" for 150dpi A4 landscape" );
463 wxFileName outputPath( tempDir.
ChildPathStr(
"single.png" ) );
465 kiapi::board::jobs::RunBoardJobExportPng request;
466 *request.mutable_job_settings()->mutable_document() = document;
467 request.mutable_job_settings()->set_output_path( outputPath.GetFullPath().ToUTF8().data() );
468 request.mutable_plot_settings()->add_layers( kiapi::board::types::BL_F_Cu );
469 request.mutable_plot_settings()->add_layers( kiapi::board::types::BL_F_SilkS );
470 request.mutable_plot_settings()->set_black_and_white(
true );
471 request.set_page_mode( kiapi::board::jobs::BJPM_ALL_LAYERS_ONE_PAGE );
472 request.set_dpi( 300 );
474 kiapi::common::types::RunJobResponse response;
475 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
476 "Single-mode RunJob failed: " + Client().LastError() );
478 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
479 "Single-mode job failed: " + wxString::FromUTF8( response.message() ) );
480 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
481 "Single-mode job returned no output paths" );
483 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
484 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
485 "Generated PNG does not exist: " + generatedPath );
486 BOOST_CHECK_MESSAGE( generatedPath == outputPath.GetFullPath(),
487 "Single-mode output path not honored: " + generatedPath );
489 uint32_t width = 0, height = 0;
490 BOOST_REQUIRE_MESSAGE(
pngDimensions( generatedPath, width, height ),
491 "Generated file is not a valid PNG: " + generatedPath );
492 BOOST_CHECK_MESSAGE( width >= 3500 && width <= 3516,
493 "Unexpected PNG width " << width <<
" for 300dpi A4 landscape" );
500 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
504 wxFileName schPath( testDataDir, wxS(
"basic_test.kicad_sch" ) );
506 kiapi::common::types::DocumentSpecifier document;
508 BOOST_REQUIRE_MESSAGE(
509 Client().OpenDocument( schPath.GetFullPath(), kiapi::common::types::DOCTYPE_SCHEMATIC, &document ),
510 "OpenDocument failed: " + Client().LastError() );
513 wxFileName outputPath( tempDir.
ChildPathStr(
"netlist.cadstar" ) );
515 kiapi::schematic::jobs::RunSchematicJobExportNetlist request;
516 *request.mutable_job_settings()->mutable_document() = document;
517 request.mutable_job_settings()->set_output_path( outputPath.GetFullPath().ToUTF8().data() );
518 request.set_format( kiapi::schematic::jobs::SNF_CADSTAR );
520 kiapi::common::types::RunJobResponse response;
521 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
"RunJob failed: " + Client().LastError() );
523 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
524 "Job failed: " + wxString::FromUTF8( response.message() ) );
526 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"Job returned no output paths" );
528 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
529 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
530 "Generated netlist does not exist: " + generatedPath );
533 wxString goldenPath = testDataDir + wxS(
"basic_test.netlist.cadstar" );
534 BOOST_CHECK_MESSAGE(
textFilesMatch( goldenPath, generatedPath, 3 ),
"Netlist output does not match golden file" );
540 BOOST_REQUIRE_MESSAGE( Start(), LastError() );
544 wxFileName schPath( testDataDir, wxS(
"variants.kicad_sch" ) );
546 kiapi::common::types::DocumentSpecifier document;
548 BOOST_REQUIRE_MESSAGE(
549 Client().OpenDocument( schPath.GetFullPath(), kiapi::common::types::DOCTYPE_SCHEMATIC, &document ),
550 "OpenDocument failed: " + Client().LastError() );
553 wxFileName outputPath( tempDir.
ChildPathStr(
"bom.csv" ) );
555 kiapi::schematic::jobs::RunSchematicJobExportBOM request;
556 *request.mutable_job_settings()->mutable_document() = document;
557 request.mutable_job_settings()->set_output_path( outputPath.GetFullPath().ToUTF8().data() );
558 request.set_exclude_dnp(
true );
560 request.mutable_format()->set_preset_name(
"CSV" );
562 auto* refField = request.mutable_fields()->add_fields();
563 refField->set_name(
"Reference" );
564 refField->set_label(
"Refs" );
565 refField->set_group_by(
false );
567 auto* valField = request.mutable_fields()->add_fields();
568 valField->set_name(
"Value" );
569 valField->set_label(
"Value" );
570 valField->set_group_by(
false );
572 kiapi::common::types::RunJobResponse response;
573 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
"RunJob failed: " + Client().LastError() );
575 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
576 "Job failed: " + wxString::FromUTF8( response.message() ) );
578 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"Job returned no output paths" );
580 wxString generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
581 BOOST_REQUIRE_MESSAGE( wxFileName::FileExists( generatedPath ),
"Generated BOM does not exist: " + generatedPath );
583 wxString goldenPath = testDataDir + wxS(
"variants_default.bom.csv" );
584 BOOST_CHECK_MESSAGE(
textFilesMatch( goldenPath, generatedPath, 0 ),
"BOM output does not match golden file" );
586 request.mutable_format()->clear_preset_name();
587 request.mutable_format()->set_field_delimiter(
"," );
588 request.mutable_format()->set_string_delimiter(
"\"" );
589 request.mutable_format()->set_ref_delimiter(
"," );
590 request.mutable_format()->set_ref_range_delimiter(
"" );
591 request.mutable_format()->set_include_byte_order_mark(
true );
594 BOOST_REQUIRE_MESSAGE( Client().RunJob( request, &response ),
595 "BOM job with byte order mark failed: " + Client().LastError() );
597 BOOST_REQUIRE_MESSAGE( response.status() == kiapi::common::types::JS_SUCCESS,
598 "BOM job with byte order mark failed: " + wxString::FromUTF8( response.message() ) );
599 BOOST_REQUIRE_MESSAGE( response.output_path_size() > 0,
"BOM job with byte order mark returned no output paths" );
601 generatedPath = wxString::FromUTF8( response.output_path( 0 ) );
602 std::ifstream generatedStream( generatedPath.ToStdString(), std::ios::binary );
603 std::ifstream goldenStream( goldenPath.ToStdString(), std::ios::binary );
607 std::ostringstream generatedContents;
608 std::ostringstream goldenContents;
609 generatedContents << generatedStream.rdbuf();
610 goldenContents << goldenStream.rdbuf();
612 const std::string utf8ByteOrderMark(
"\xEF\xBB\xBF", 3 );
613 const std::string bom = generatedContents.str();
614 BOOST_REQUIRE_GE( bom.size(), utf8ByteOrderMark.size() );
615 BOOST_CHECK_EQUAL( bom.substr( 0, utf8ByteOrderMark.size() ), utf8ByteOrderMark );
616 BOOST_CHECK_EQUAL( bom.substr( utf8ByteOrderMark.size() ), goldenContents.str() );
618 generatedStream.close();
619 goldenStream.close();
BOOST_CHECK_EQUAL(result, "25.4")