21#define BOOST_TEST_NO_MAIN
22#include <boost/test/unit_test.hpp>
34#include <wx/filename.h>
43 std::function<bool( wxString* )>
resolver = []( wxString* token ) ->
bool
45 if( *token == wxT(
"VAR" ) )
47 *token = wxT(
"value" );
50 else if( *token == wxT(
"X" ) )
55 else if( *token == wxT(
"Y" ) )
71 BOOST_CHECK(
result == wxT(
"value" ) );
78 BOOST_CHECK(
result == wxT(
"5+2" ) );
86 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
94 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
95 BOOST_CHECK(
result.Contains( wxT(
"value" ) ) );
103 BOOST_CHECK(
result.StartsWith( wxT(
"value" ) ) );
104 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
117 "Expected escape marker in result" );
121 "Expected '+2' (from ${Y} expansion) in result" );
124 BOOST_CHECK(
result == wxT(
"@{<<<ESC_DOLLAR:X}+2}" ) );
136 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
146 "Expected '+2' (from ${Y} expansion) in: " +
result );
152 while( ( pos =
result.find( wxT(
"<<<ESC_DOLLAR:" ), pos ) ) != wxString::npos )
167 BOOST_CHECK(
result.StartsWith( wxT(
"value" ) ) );
168 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_AT:" ) ) );
180 while( ( pos =
result.find( wxT(
"<<<ESC_DOLLAR:" ), pos ) ) != wxString::npos )
198 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
207 BOOST_CHECK(
result == wxT(
"subdir/value_file.txt" ) );
227 wxString
path = wxT(
"Board Stats\\${REVISION}_Stats.txt" );
232 "Text variable after backslash path separator should not be escaped. Got: "
235 "Expected resolved REVISION in path. Got: " +
result );
249 wxString
path = wxT(
"Output\\${COMMENT1}_${REVISION}_file.txt" );
253 "Expected COMMENT1 expanded in path. Got: " +
result );
255 "Expected REVISION expanded in path. Got: " +
result );
268 wxString
path = wxT(
"Output\\Generated_${REVISION}_file.txt" );
272 "Expected variable expansion with preceding literal text. Got: " +
result );
300 std::filesystem::path tmp = std::filesystem::temp_directory_path() /
301 "kicad_qa_overlap_env_vars";
303 std::filesystem::remove_all( tmp, ec );
304 std::filesystem::create_directories( tmp /
"V10" /
"symbols", ec );
306 rootDir = wxString::FromUTF8( tmp.string() );
308 innerDir = wxString::FromUTF8( ( tmp /
"V10" ).
string() );
309 targetDir = wxString::FromUTF8( ( tmp /
"V10" /
"symbols" ).
string() );
311 wxSetEnv( wxS(
"KICAD_QA_3RD_PARTY_OUTER" ),
outerDir );
312 wxSetEnv( wxS(
"KICAD_QA_USER_LIB_INNER" ),
innerDir );
317 wxUnsetEnv( wxS(
"KICAD_QA_3RD_PARTY_OUTER" ) );
318 wxUnsetEnv( wxS(
"KICAD_QA_USER_LIB_INNER" ) );
320 std::filesystem::path tmp = std::filesystem::temp_directory_path() /
321 "kicad_qa_overlap_env_vars";
323 std::filesystem::remove_all( tmp, ec );
341 wxFileName target( targetDir, wxS(
"test.kicad_sym" ) );
344 wxString normalized =
NormalizePath( target, &envMap, wxEmptyString );
348 normalized == wxS(
"${KICAD_QA_USER_LIB_INNER}/symbols/test.kicad_sym" ),
349 wxString::Format( wxS(
"Expected '%s' but got '%s'" ),
350 wxS(
"${KICAD_QA_USER_LIB_INNER}/symbols/test.kicad_sym" ),
357 wxFileName target( targetDir, wxS(
"test.kicad_sym" ) );
360 wxString normalized =
NormalizePath( target, &envMap, wxEmptyString );
363 wxFileName expandedFn( expanded );
364 expandedFn.Normalize( wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE );
366 wxFileName originalFn( target );
367 originalFn.Normalize( wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE );
370 expandedFn.GetFullPath() == originalFn.GetFullPath(),
372 wxS(
"Round-trip mismatch: normalized='%s' expanded='%s' original='%s'" ),
373 normalized, expandedFn.GetFullPath(), originalFn.GetFullPath() ) );
396 std::function<bool( wxString* )>
resolver = []( wxString* token ) ->
bool
398 if( *token == wxT(
"#" ) )
404 if( *token == wxT(
"ROW" ) )
413 const std::vector<wxString> inputs = {
414 wxT(
"Out@{(${#}-2)*8+0}" ),
415 wxT(
"Net_@{${ROW}*2+1}" ),
416 wxT(
"@{(2-2)*8+0}" ),
417 wxT(
"${ROW}:@{${ROW}*${ROW}}" ),
418 wxT(
"plain_label_no_expr" ),
419 wxT(
"@{1+1}_@{2+2}_@{3+3}" ),
422 const unsigned int numThreads = std::max( 4u, std::thread::hardware_concurrency() );
423 const int iterations = 2000;
425 std::atomic<bool> failed{
false };
426 std::atomic<int> totalRuns{ 0 };
427 std::vector<std::thread> threads;
428 threads.reserve( numThreads );
430 for(
unsigned int t = 0; t < numThreads; ++t )
432 threads.emplace_back(
437 for(
int i = 0; i < iterations; ++i )
439 const wxString& src = inputs[( t + i ) % inputs.size()];
443 totalRuns.fetch_add( 1, std::memory_order_relaxed );
448 failed.store(
true, std::memory_order_relaxed );
453 for(
auto& th : threads )
456 BOOST_CHECK( !failed.load() );
457 BOOST_CHECK_EQUAL( totalRuns.load(),
static_cast<int>( numThreads ) * iterations );
482 if( wxGetEnv( wxS(
"KICAD_QA_INNER" ), &existing ) )
485 if( wxGetEnv( wxS(
"KICAD_QA_OUTER" ), &existing ) )
489 ( std::filesystem::temp_directory_path() /
"kicad-qa-24244" ).generic_string() );
491 wxSetEnv( wxS(
"KICAD_QA_INNER" ),
innerPath );
492 wxSetEnv( wxS(
"KICAD_QA_OUTER" ), wxS(
"${KICAD_QA_INNER}/templates" ) );
498 wxSetEnv( wxS(
"KICAD_QA_INNER" ), *
oldInner );
500 wxUnsetEnv( wxS(
"KICAD_QA_INNER" ) );
503 wxSetEnv( wxS(
"KICAD_QA_OUTER" ), *
oldOuter );
505 wxUnsetEnv( wxS(
"KICAD_QA_OUTER" ) );
514 BOOST_REQUIRE( wxGetEnv( wxS(
"KICAD_QA_OUTER" ), &rawValue ) );
517 BOOST_CHECK( rawValue.Contains( wxS(
"${KICAD_QA_INNER}" ) ) );
520 wxString
expected = innerPath + wxS(
"/templates" );
524 wxString::Format( wxS(
"Expected '%s', got '%s'" ),
expected, expanded ) );
533 wxUnsetEnv( wxS(
"KICAD_QA_INNER" ) );
536 BOOST_REQUIRE( wxGetEnv( wxS(
"KICAD_QA_OUTER" ), &rawValue ) );
539 BOOST_CHECK( expanded.Contains( wxS(
"${" ) ) );
542 wxSetEnv( wxS(
"KICAD_QA_INNER" ), innerPath );
KiCad uses environment variables internally for determining the base paths for libraries,...
wxString ResolveOutputPath(const wxString &aPath, bool aPathIsDirectory, PROJECT *aProject) const
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Hold the information shown in the lower right corner of a plot, printout, or editing view.
void SetRevision(const wxString &aRevision)
void SetComment(int aIdx, const wxString &aComment)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Helper functions to substitute paths with environmental variables.
static FILENAME_RESOLVER * resolver
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
Regression test for KiCad GitLab issue #24244.
~EnvVarRecursiveExpansionFixture()
std::optional< wxString > oldInner
EnvVarRecursiveExpansionFixture()
std::optional< wxString > oldOuter
Test fixture for ExpandTextVars tests.
std::function< bool(wxString *)> resolver
Regression tests for overlapping-prefix environment variables.
OverlappingEnvVarsFixture()
ENV_VAR_MAP BuildEnvMap() const
~OverlappingEnvVarsFixture()
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(SimpleVariable)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")