KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_allegro_boards.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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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
21
22#include "allegro_block_tests.h"
23#include "allegro_test_utils.h"
24
25#include <filesystem>
26#include <fstream>
27
28#include <boost/test/data/test_case.hpp>
29
30#include <json_common.h>
31
32#include <board.h>
33#include <reporter.h>
35
38
40
51
52using namespace ALLEGRO;
53using namespace KI_TEST;
54
55
61{
62 uint8_t m_BlockType;
65 const nlohmann::json& m_BlockTestJson;
66};
67
73{
74 // The board name in the JSON registry
75 std::string m_BrdName;
76
78 std::vector<ALLEGRO_BLOCK_TEST_DESCRIPTOR> m_BlockTests;
80
82 std::vector<BOARD_EXPECTATION_TEST::DESCRIPTOR> m_ExpectationTests;
83};
84
85
94{
95 nlohmann::json m_Json;
96 std::vector<ALLEGRO_BOARD_TEST_DESCRIPTOR> m_BoardTests;
97
98 const nlohmann::json& GetBoardJson( const std::string& aBoardName ) const
99 {
100 return m_Json["boards"][aBoardName];
101 }
102};
103
104
105static std::vector<uint8_t> loadDataByUri( const std::string& aDataSource )
106{
107 // For now, we only support loading from files, but in the future we could also support
108 // loading from other sources (e.g. from compiled-in data, base64, etc.)
109
110 // Split off the protocol (e.g. "file://") if present, to get the actual path
111 std::string path, protocol;
112 const std::string sep = "://";
113
114 size_t sepPos = aDataSource.find( sep );
115 if( sepPos != std::string::npos )
116 {
117 protocol = aDataSource.substr( 0, sepPos );
118 path = aDataSource.substr( sepPos + sep.size() );
119 }
120 else
121 {
122 // No protocol
123 throw std::runtime_error( "Unsupported data source URI (missing protocol): " + aDataSource );
124 }
125
126 if( protocol == "file" )
127 {
128 // This means get it from a file in the QD data
129 return KI_TEST::LoadBinaryData( path, std::nullopt );
130 }
131
132 throw std::runtime_error( "Unsupported data source protocol: " + protocol );
133}
134
135
136ALLEGRO::FMT_VER getFormatVersionFromStr( const std::string& aFmtVerStr )
137{
138 // clang-format off
139 static const std::map<std::string, ALLEGRO::FMT_VER> fmtVerStrMap{
140 { "16.0", FMT_VER::V_160 },
141 { "16.2", FMT_VER::V_162 },
142 { "16.4", FMT_VER::V_164 },
143 { "16.5", FMT_VER::V_165 },
144 { "16.6", FMT_VER::V_166 },
145 { "17.2", FMT_VER::V_172 },
146 { "17.4", FMT_VER::V_174 },
147 { "17.5", FMT_VER::V_175 },
148 { "18.0", FMT_VER::V_180 },
149 };
150 // clang-format on
151
152 auto it = fmtVerStrMap.find( aFmtVerStr );
153 if( it != fmtVerStrMap.end() )
154 {
155 return it->second;
156 }
157
158 return FMT_VER::V_UNKNOWN;
159}
160
161
162static std::unique_ptr<HEADER_TEST_INFO> createHeaderTestEntry( const std::string& boardDir,
163 const nlohmann::json& headerTestEntry )
164{
165 std::unique_ptr<HEADER_TEST_INFO> headerTest;
166
167 if( !headerTestEntry.is_object() )
168 {
169 throw std::runtime_error( "Header test entry is not a valid JSON object" );
170 }
171
172 // Default header location
173 const std::string headerDataUri = std::string( "file://" ) + boardDir + "header.bin";
174
175 return std::make_unique<HEADER_TEST_INFO>( headerDataUri, headerTestEntry.value( "skip", false ) );
176}
177
178
179static BLOCK_TEST_INFO createBlockTestEntry( const std::string& boardDir,
180 const ALLEGRO_BLOCK_TEST_DESCRIPTOR& aBlockTestDescriptor )
181{
182 const nlohmann::json& blockTestJson = aBlockTestDescriptor.m_BlockTestJson;
183 const bool skipBlock = blockTestJson.value( "skip", false );
184
185 const uint8_t& blockType = aBlockTestDescriptor.m_BlockType;
186 const size_t& blockOffset = aBlockTestDescriptor.m_BlockOffset;
187
188 // Default block data location is a file with a name based on the block type and offset
189 wxString blockDataLoc = wxString::Format( "0x%02x_0x%08zx.bin", blockType, blockOffset );
190
191 const std::string blockDataUri = std::string( "file://" ) + boardDir + blockDataLoc.ToStdString();
192
193 const bool extraBlockTest = blockTestJson.value( "extraBlockTest", false );
194
195 return BLOCK_TEST_INFO{
196 blockType,
197 blockOffset,
198 skipBlock,
199 extraBlockTest,
200 blockDataUri,
201 };
202}
203
204
210
211
212static BOARD_TEST_INFO createBoardTestInfo( const std::string& aBrdName, const nlohmann::json& boardTestEntry )
213{
214 const ALLEGRO::FMT_VER formatVersion =
215 getFormatVersionFromStr( boardTestEntry.value( "formatVersion", "unknown" ) );
216
217 return BOARD_TEST_INFO{ aBrdName, formatVersion };
218}
219
220
222{
223public:
224 void RunHeaderTest( const std::string& aBrdName, const nlohmann::json& aBoardTestJson )
225 {
226 BOOST_TEST_CONTEXT( wxString::Format( "Testing header from board %s", aBrdName ) )
227 {
228 BOARD_TEST_INFO brdDef = createBoardTestInfo( aBrdName, aBoardTestJson );
229
230 const std::string boardDir = AllegroBoardDataDir( aBrdName );
231
232 std::unique_ptr<HEADER_TEST_INFO> headerTest = nullptr;
233
234 if( aBoardTestJson.contains( "header" ) && aBoardTestJson["header"].is_object() )
235 {
236 headerTest = createHeaderTestEntry( boardDir, aBoardTestJson["header"] );
237 }
238
239 BOOST_REQUIRE( headerTest != nullptr );
240
241 if( headerTest->m_Skip )
242 {
243 BOOST_TEST_MESSAGE( "Skipping test for this header" );
244 return;
245 }
246
247 // Read in the header data
248 std::vector<uint8_t> headerData = loadDataByUri( headerTest->m_HeaderDataSource );
249 FILE_STREAM fileStream( headerData.data(), headerData.size() );
250 HEADER_PARSER parser( fileStream );
251
252 std::unique_ptr<FILE_HEADER> header = parser.ParseHeader();
253
254 BOOST_REQUIRE( header != nullptr );
255
256 // We don't expect any known header to be in an unknown format
258
259 // Make sure the format version matches what the board is expected to be
260 if( brdDef.m_FormatVersion != FMT_VER::V_UNKNOWN )
261 {
262 BOOST_TEST( parser.GetFormatVersion() == brdDef.m_FormatVersion );
263 }
264
265 // Other header tests - validate some commonly used fields?
266
267 // The parser should have consumed all the data in the header
268 BOOST_TEST( fileStream.Position() == headerData.size() );
269 }
270 }
271
272
273 void RunBlockTest( const std::string& aBrdName, const nlohmann::json& aBoardTestJson,
274 const ALLEGRO_BLOCK_TEST_DESCRIPTOR& aBlockTest )
275 {
276 const BOARD_TEST_INFO brdDef = createBoardTestInfo( aBrdName, aBoardTestJson );
277 const BLOCK_TEST_INFO blockTest = createBlockTestEntry( AllegroBoardDataDir( aBrdName ), aBlockTest );
278
279 BOOST_TEST_CONTEXT( wxString::Format( "Testing block type %#02x at offset %#010zx from board %s",
280 blockTest.m_BlockType, blockTest.m_BlockOffset, aBrdName ) )
281 {
282 if( blockTest.m_Skip )
283 {
284 BOOST_TEST_MESSAGE( "Skipping test for this block" );
285 return;
286 }
287
288 // Read in the block data, and create a FILE_STREAM for it
289 std::vector<uint8_t> data = loadDataByUri( blockTest.m_DataSource );
290 FILE_STREAM fileStream( data.data(), data.size() );
291
292 BLOCK_PARSER parser( fileStream, brdDef.m_FormatVersion );
293
294 bool endOfObjectsMarker = false;
295 std::unique_ptr<BLOCK_BASE> block = parser.ParseBlock( endOfObjectsMarker );
296
297 // Compare the result to the expected results
298 BOOST_REQUIRE( block != nullptr );
299
300 // The parser should have consumed all the data in the block
301 BOOST_TEST( fileStream.Position() == data.size() );
302
303 // Look up and run additional ad-hoc block-level tests
304 if( blockTest.m_ExtraBlockTest )
305 {
306 KI_TEST::RunAdditionalBlockTest( aBrdName, blockTest.m_BlockOffset, *block );
307 }
308 }
309 }
310};
311
312
313static void AssertNoErrors( const CAPTURING_REPORTER& aReporter )
314{
315 if( aReporter.GetErrorCount() > 0 )
316 {
317 std::ostringstream ss;
318 ss << "Expected no errors, but found " << aReporter.GetErrorCount() << " errors:";
319
320 for( const auto& msg : aReporter.GetMessages() )
321 {
322 if( msg.severity == RPT_SEVERITY_ERROR )
323 {
324 ss << "\n " << msg.text;
325 }
326 }
327 BOOST_TEST_MESSAGE( ss.str() );
328 }
329 BOOST_TEST( aReporter.GetErrorCount() == 0 );
330}
331
332
333void RunBoardLoad( const std::string& aBrdName, const nlohmann::json& aBoardTestJson )
334{
335 BOARD* board = nullptr;
336
337 BOOST_TEST_CONTEXT( "Testing load from board: " << aBrdName )
338 {
339 if( aBoardTestJson.contains( "boardFile" ) )
340 {
341 const std::string boardFilePath =
342 KI_TEST::AllegroBoardDataDir( aBrdName ) + aBoardTestJson["boardFile"].get<std::string>();
343
344 if( !std::filesystem::exists( boardFilePath ) )
345 {
346 BOOST_FAIL( "Board file does not exist: " + boardFilePath );
347 return;
348 }
349
352
353 const bool expectLoadFailure = aBoardTestJson.value( "expectLoadFailure", false );
354
355 if( expectLoadFailure )
356 {
357 BOOST_CHECK( board == nullptr );
358 BOOST_TEST_MESSAGE( "Board load was expected to fail, and it did." );
359 return;
360 }
361 else
362 {
363 BOOST_CHECK_MESSAGE( board != nullptr, "Board load was expected to succeed, but it failed." );
364
365 // Can allow a certain number of warnings, but no errors
367
368 // Can check max warnings here if we want
369 if( reporter.GetWarningCount() > 0 )
370 {
371 std::ostringstream ss;
372 ss << aBrdName << ": " << reporter.GetWarningCount() << " warnings";
373
374 for( const auto& msg : reporter.GetMessages() )
375 {
376 if( msg.severity == RPT_SEVERITY_WARNING )
377 {
378 ss << "\n " << msg.text;
379 }
380 }
381
382 BOOST_TEST_MESSAGE( ss.str() );
383 }
384
385 KI_TEST::PrintBoardStats( board, aBrdName );
386 }
387 }
388 }
389}
390
391
392static uint8_t getByteFromHexStr( const nlohmann::json& aJsonEntry, const std::string& aFieldName )
393{
394 if( !aJsonEntry.contains( aFieldName ) )
395 {
396 throw std::runtime_error( "Block test entry is missing the '" + aFieldName + "' field" );
397 }
398
399 if( aJsonEntry[aFieldName].is_number_unsigned() )
400 {
401 const unsigned long value = aJsonEntry[aFieldName].get<unsigned long>();
402 if( value > 0xFF )
403 {
404 throw std::runtime_error( "Value is too large to fit in a byte: " + std::to_string( value ) );
405 }
406 return static_cast<uint8_t>( value );
407 }
408 else if( aJsonEntry[aFieldName].is_string() )
409 {
410 const std::string aHexStr = aJsonEntry[aFieldName];
411
412 const unsigned long value = std::stoul( aHexStr, nullptr, 0 );
413 if( value > 0xFF )
414 {
415 throw std::runtime_error( "Value is too large to fit in a byte: " + aHexStr );
416 }
417 return static_cast<uint8_t>( value );
418 }
419
420 throw std::runtime_error( "Block test entry has an invalid '" + aFieldName
421 + "' field (must be a byte value as a number or hex string)" );
422}
423
424
425static ALLEGRO_BLOCK_TEST_DESCRIPTOR createBlockTestDescriptor( const nlohmann::json& aBlockTestJson )
426{
427 const uint8_t blockType = getByteFromHexStr( aBlockTestJson, "type" );
428
429 if( !aBlockTestJson.contains( "offset" ) || !aBlockTestJson["offset"].is_string() )
430 {
431 throw std::runtime_error( "Block test entry is missing a valid 'offset' field" );
432 }
433
434 const std::string block_offset = aBlockTestJson["offset"];
435 const size_t blockOffset = std::stoul( block_offset, nullptr, 0 );
436
438 blockType,
439 blockOffset,
440 aBlockTestJson,
441 };
442}
443
444
452static std::vector<ALLEGRO_BOARD_TEST_DESCRIPTOR> getBoardTestDefinitions( const nlohmann::json& aJson )
453{
454 if( !aJson.contains( "boards" ) || !aJson["boards"].is_object() )
455 {
456 throw std::runtime_error( "Test register JSON file does not contain a valid 'boards' object." );
457 }
458
459 std::vector<ALLEGRO_BOARD_TEST_DESCRIPTOR> boardTests;
460
461 for( auto& [boardName, boardEntry] : aJson["boards"].items() )
462 {
464 .m_BrdName = boardName,
465 .m_HasHeaderTest = boardEntry.contains( "header" ),
466 .m_BlockTests = {},
467 .m_HasBoardFile = boardEntry.contains( "boardFile" ),
468 .m_ExpectationTests = {},
469 };
470
471 if( boardEntry.contains( "blocks" ) && boardEntry["blocks"].is_array() )
472 {
473 for( const auto& blockTestEntry : boardEntry["blocks"] )
474 {
475 boardTestRef.m_BlockTests.emplace_back( createBlockTestDescriptor( blockTestEntry ) );
476 }
477 }
478
479 if( boardEntry.contains( "boardExpectations" ) )
480 {
481 const auto& expectationsEntry = boardEntry["boardExpectations"];
482
483 boardTestRef.m_ExpectationTests =
485 }
486
487 boardTests.push_back( std::move( boardTestRef ) );
488 }
489
490 return boardTests;
491}
492
493
495{
496 static ALLEGRO_BLOCK_TEST_REGISTRY registry = []()
497 {
499
500 // There is currently one registry file, but we could have more, e.g. if we
501 // stored the test definitions on a per-board basis in the board data dirs
502 const std::filesystem::path testRegisterJsonPath( AllegroBoardDataDir( "" ) + "board_data_registry.json" );
503 std::ifstream jsonFileStream( testRegisterJsonPath );
504
505 reg.m_Json = nlohmann::json::parse( jsonFileStream, nullptr, true, true );
507
508 return reg;
509 }();
510
511 return registry;
512}
513
514
518static std::vector<std::string> getBoardTestLabels( const nlohmann::json& boardTestJson )
519{
520 std::vector<std::string> labels;
521
522 if( boardTestJson.contains( "testLabels" ) && boardTestJson["testLabels"].is_array() )
523 {
524 for( const auto& label : boardTestJson["testLabels"] )
525 {
526 if( label.is_string() )
527 {
528 labels.push_back( label.get<std::string>() );
529 }
530 }
531 }
532
533 return labels;
534}
535
536
546static std::vector<boost::unit_test::test_suite*> buildAllegroBoardSuites()
547{
548 using BTS = boost::unit_test::test_suite;
549 std::vector<BTS*> suites;
550 BTS* blockSuite = suites.emplace_back( BOOST_TEST_SUITE( "AllegroBlocks" ) );
551 const ALLEGRO_BLOCK_TEST_REGISTRY* registry = nullptr;
552
553 try
554 {
555 registry = &buildTestRegistry();
556 }
557 catch( const std::exception& ex )
558 {
559 std::string msg = "Failed to load Allegro block test definitions: " + std::string( ex.what() );
560
561 // Register one failing test to report the error, so that we don't just silently skip all the tests
562 const auto failingTestFunction = [=]()
563 {
564 BOOST_TEST( false, msg );
565 };
566
567 blockSuite->add(
568 boost::unit_test::make_test_case(
569 failingTestFunction,
570 "FailureToLoadTestDefinitions",
571 __FILE__,
572 __LINE__
573 )
574 );
575
576 return suites;
577 }
578
579 for( const ALLEGRO_BOARD_TEST_DESCRIPTOR& boardTest : registry->m_BoardTests )
580 {
581 BTS* boardSuite = BOOST_TEST_SUITE( boardTest.m_BrdName );
582 blockSuite->add( boardSuite );
583
584 const nlohmann::json& boardTestJson = registry->GetBoardJson( boardTest.m_BrdName );
585
586 if( boardTest.m_HasHeaderTest )
587 {
588 // Note: captures ref-to-static
589 const auto testRunFunction = [&]()
590 {
592 fixture.RunHeaderTest( boardTest.m_BrdName, boardTestJson );
593 };
594
595 boardSuite->add(
596 boost::unit_test::make_test_case(
597 testRunFunction,
598 "Header",
599 __FILE__,
600 __LINE__
601 )
602 );
603 }
604
605 for( const auto& blockTest : boardTest.m_BlockTests )
606 {
607 // All these captures come from data stored in a static variable, so we can take them
608 // by reference here.
609 const auto testRunFunction = [&boardTest, &boardTestJson, &blockTest]()
610 {
612 fixture.RunBlockTest( boardTest.m_BrdName, boardTestJson, blockTest );
613 };
614
615 wxString testName =
616 wxString::Format( "Block_0x%02x_offset_0x%010zx", blockTest.m_BlockType, blockTest.m_BlockOffset );
617
618 boardSuite->add(
619 boost::unit_test::make_test_case(
620 testRunFunction,
621 testName.ToStdString(),
622 __FILE__,
623 __LINE__
624 )
625 );
626 }
627 }
628
629 // Separate test suite for board expectations, which will run after the header and block parsing tests,
630 // and will have access to the fully parsed board (and obviously be much slower)
631 BTS* boardSuites = suites.emplace_back( BOOST_TEST_SUITE( "AllegroBoards" ) );
632
633 for( const ALLEGRO_BOARD_TEST_DESCRIPTOR& boardTest : registry->m_BoardTests )
634 {
635 if( !boardTest.m_HasBoardFile )
636 {
637 continue;
638 }
639
640 // Board-level suite
641 BTS* boardSuite = BOOST_TEST_SUITE( boardTest.m_BrdName );
642 boardSuites->add( boardSuite );
643
644 const nlohmann::json& boardTestData = registry->GetBoardJson( boardTest.m_BrdName );
645
646 const std::vector<std::string> testLabels = getBoardTestLabels( boardTestData );
647 boost::unit_test::test_case* loadingTestCase = nullptr;
648
649 if( boardTest.m_HasBoardFile )
650 {
651 const auto testLoadFunction = [&boardTest, &boardTestData]()
652 {
653 RunBoardLoad( boardTest.m_BrdName, boardTestData );
654 };
655
656 // The first test unit loads (and caches) the board.
657 loadingTestCase = boost::unit_test::make_test_case(
658 testLoadFunction,
659 "Import",
660 __FILE__,
661 __LINE__
662 );
663
664 for( const std::string& label : testLabels )
665 {
666 loadingTestCase->add_label( label );
667 }
668
669 boardSuite->add( loadingTestCase );
670 }
671
672 if( boardTest.m_ExpectationTests.size() > 0 )
673 {
674 BTS* expectationsSuite = BOOST_TEST_SUITE( "Expectations" );
675 boardSuite->add( expectationsSuite );
676
677 for( const BOARD_EXPECTATION_TEST::DESCRIPTOR& expectationTestRef : boardTest.m_ExpectationTests )
678 {
679 const auto testRunFunction = [&boardTest, &boardTestData, &expectationTestRef]()
680 {
681 if( !boardTestData.contains( "boardFile" ) )
682 {
683 BOOST_FAIL(
684 "Board test JSON does not contain a 'boardFile' entry - cannot run expectations test" );
685 return;
686 }
687
688 const std::string boardFilePath = KI_TEST::AllegroBoardDataDir( boardTest.m_BrdName )
689 + boardTestData["boardFile"].get<std::string>();
690
691 const BOARD* board = KI_TEST::ALLEGRO_CACHED_LOADER::GetInstance().GetCachedBoard( boardFilePath );
692
693 if( !board )
694 {
695 BOOST_FAIL( "Failed to load cached board for expectations test: " + boardFilePath );
696 return;
697 }
698
699 KI_TEST::BOARD_EXPECTATION_TEST::RunFromRef( boardTest.m_BrdName, *board, expectationTestRef );
700 };
701
702 boost::unit_test::test_case* expectationTestCase = boost::unit_test::make_test_case(
703 testRunFunction,
704 expectationTestRef.m_TestName,
705 __FILE__,
706 __LINE__
707 );
708
709 // Label the expectations test case with any tags from the JSON
710 for( const std::string& label : expectationTestRef.m_Tags )
711 {
712 expectationTestCase->add_label( label );
713 }
714
715 expectationsSuite->add( expectationTestCase );
716 }
717
718 // We can only run the expectations test after the board has been loaded
719 // and that test passes.
720 BOOST_REQUIRE( loadingTestCase != nullptr );
721 expectationsSuite->depends_on( loadingTestCase );
722 }
723 }
724
725 return suites;
726}
727
728
734{
736 {
737 std::vector<boost::unit_test::test_suite*> suites = buildAllegroBoardSuites();
738
739 for( boost::unit_test::test_suite* suite : suites )
740 {
741 boost::unit_test::framework::master_test_suite().add( suite );
742 }
743 }
General utilities for PCB file IO for QA programs.
The block parser is responsible for parsing individual blocks of data from the file stream.
std::unique_ptr< BLOCK_BASE > ParseBlock(bool &aEndOfObjectsMarker)
Parse one block from the stream, returning a BLOCK_BASE representing the raw data of the block.
Stream that reads primitive types from a memory buffer containing Allegro .brd (or ....
size_t Position() const
Parses a .brd header, taking care of any version-specific differences.
std::unique_ptr< FILE_HEADER > ParseHeader()
FMT_VER GetFormatVersion() const
Get the parsed format version.
void RunBlockTest(const std::string &aBrdName, const nlohmann::json &aBoardTestJson, const ALLEGRO_BLOCK_TEST_DESCRIPTOR &aBlockTest)
void RunHeaderTest(const std::string &aBrdName, const nlohmann::json &aBoardTestJson)
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
static ALLEGRO_CACHED_LOADER & GetInstance()
Get the singleton instance of the Allegro board cache loader.
static std::vector< DESCRIPTOR > ExtractExpectationTestsFromJson(const nlohmann::json &aExpectationArray)
Extracts expectation tests from the given JSON array and returns a list of test references that can b...
static void RunFromRef(const std::string &aBrdName, const BOARD &aBoard, const BOARD_EXPECTATION_TEST::DESCRIPTOR &aExpectationTestRef)
Constructs a BOARD_EXPECTATION_TEST from the given JSON definition, and runs it on the given board.
BOARD * LoadAndCache(const std::string &aFilePath, REPORTER *aReporter)
Load (or reload) board for the given file path and send the load messages to the given reporter.
BOARD * GetCachedBoard(const std::string &aFilePath)
Get a cached board for the given file path, or load it if not already cached, without forcing a reloa...
Custom REPORTER that captures all messages for later analysis in the unit test framework.
const std::vector< MESSAGE > & GetMessages() const
FMT_VER
The format of an Allegro file.
std::string AllegroBoardDataDir(const std::string &aBoardName)
void RunAdditionalBlockTest(const std::string &aBoardName, size_t aBlockOffset, const ALLEGRO::BLOCK_BASE &aBlock)
Look up and run any additional ad-hoc tests for a block.
std::vector< uint8_t > LoadBinaryData(const std::string &aFilePath, std::optional< size_t > aLoadBytes=std::nullopt)
Load the contents of a file into a vector of bytes.
void PrintBoardStats(const BOARD *aBoard, const std::string &aBoardName)
Print detailed board statistics for debugging using test-framework logging.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
Just enough information about a block-level test to be able to name and register it with the test run...
const nlohmann::json & m_BlockTestJson
Handy ref to the JSON entry for this block test.
The registry of known Allegro board and block tests, populated at static init time by reading the JSO...
const nlohmann::json & GetBoardJson(const std::string &aBoardName) const
std::vector< ALLEGRO_BOARD_TEST_DESCRIPTOR > m_BoardTests
Just enough information about the board test to be able to name and register any tests for this board...
std::vector< BOARD_EXPECTATION_TEST::DESCRIPTOR > m_ExpectationTests
List of expectation tests found in the JSON for this board.
std::vector< ALLEGRO_BLOCK_TEST_DESCRIPTOR > m_BlockTests
ALLEGRO::FMT_VER m_FormatVersion
A complete description of a block test.
uint8_t m_BlockType
The type of the block, as in the first byte.
std::string m_DataSource
The the source of the block data (probably a filename)
bool m_ExtraBlockTest
Do we have an additional block-level test to run for this block?
size_t m_BlockOffset
The offset within the board file where this block is located (used for error messages)
bool m_Skip
Whether to skip this test while parsers don't support a certain format.
Lightweight descriptor for a BOARD_EXPECTATION_TEST, which can be used to refer to the test unambiguo...
std::string m_TestName
If the test has a name, it's that, else an index - this is for naming the test for filtering.
std::vector< std::string > m_Tags
Tags associated with the test, which can be used for filtering.
static struct RegisterBlockSuites s_registerHeaderBlockSuites
static void AssertNoErrors(const CAPTURING_REPORTER &aReporter)
static std::unique_ptr< HEADER_TEST_INFO > createHeaderTestEntry(const std::string &boardDir, const nlohmann::json &headerTestEntry)
static uint8_t getByteFromHexStr(const nlohmann::json &aJsonEntry, const std::string &aFieldName)
static BOARD_TEST_INFO createBoardTestInfo(const std::string &aBrdName, const nlohmann::json &boardTestEntry)
static BLOCK_TEST_INFO createBlockTestEntry(const std::string &boardDir, const ALLEGRO_BLOCK_TEST_DESCRIPTOR &aBlockTestDescriptor)
static std::vector< uint8_t > loadDataByUri(const std::string &aDataSource)
static ALLEGRO_BLOCK_TEST_DESCRIPTOR createBlockTestDescriptor(const nlohmann::json &aBlockTestJson)
static std::vector< boost::unit_test::test_suite * > buildAllegroBoardSuites()
This function initializes the test suites for Allegro block and board parsing.
void RunBoardLoad(const std::string &aBrdName, const nlohmann::json &aBoardTestJson)
static std::vector< std::string > getBoardTestLabels(const nlohmann::json &boardTestJson)
Get the labels associated with a board test, which can be used to e.g.
static std::vector< ALLEGRO_BOARD_TEST_DESCRIPTOR > getBoardTestDefinitions(const nlohmann::json &aJson)
Construct a list of test descriptrs (lightweight objects) for the boards we have test data for,...
static const ALLEGRO_BLOCK_TEST_REGISTRY & buildTestRegistry()
ALLEGRO::FMT_VER getFormatVersionFromStr(const std::string &aFmtVerStr)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
std::string path
IbisParser parser & reporter
std::vector< std::string > header
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
BOOST_TEST_CONTEXT("Test Clearance")