21#define BOOST_TEST_NO_MAIN
22#include <boost/test/unit_test.hpp>
35#include <wx/filename.h>
44 std::function<bool( wxString* )>
resolver = []( wxString* token ) ->
bool
46 if( *token == wxT(
"VAR" ) )
48 *token = wxT(
"value" );
51 else if( *token == wxT(
"X" ) )
56 else if( *token == wxT(
"Y" ) )
72 BOOST_CHECK(
result == wxT(
"value" ) );
79 BOOST_CHECK(
result == wxT(
"5+2" ) );
87 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
95 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
96 BOOST_CHECK(
result.Contains( wxT(
"value" ) ) );
104 BOOST_CHECK(
result.StartsWith( wxT(
"value" ) ) );
105 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
118 "Expected escape marker in result" );
122 "Expected '+2' (from ${Y} expansion) in result" );
125 BOOST_CHECK(
result == wxT(
"@{<<<ESC_DOLLAR:X}+2}" ) );
137 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
147 "Expected '+2' (from ${Y} expansion) in: " +
result );
153 while( ( pos =
result.find( wxT(
"<<<ESC_DOLLAR:" ), pos ) ) != wxString::npos )
168 BOOST_CHECK(
result.StartsWith( wxT(
"value" ) ) );
169 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_AT:" ) ) );
181 while( ( pos =
result.find( wxT(
"<<<ESC_DOLLAR:" ), pos ) ) != wxString::npos )
199 BOOST_CHECK(
result.Contains( wxT(
"<<<ESC_DOLLAR:" ) ) );
208 BOOST_CHECK(
result == wxT(
"subdir/value_file.txt" ) );
227 "Variable after backslash separator should expand, not escape. Got: " +
result );
228 BOOST_CHECK(
result == wxT(
"Output\\BoM/value_file.csv" ) );
237 BOOST_CHECK(
result == wxT(
"Output\\BoM/5_V2.csv" ) );
246 BOOST_CHECK(
result == wxT(
"Output/BoM/value.csv" ) );
256 BOOST_CHECK(
path == wxT(
"Output\\BoM\\literal.csv" ) );
276 wxString
path = wxT(
"Board Stats\\${REVISION}_Stats.txt" );
281 "Text variable after backslash path separator should not be escaped. Got: "
284 "Expected resolved REVISION in path. Got: " +
result );
298 wxString
path = wxT(
"Output\\${COMMENT1}_${REVISION}_file.txt" );
302 "Expected COMMENT1 expanded in path. Got: " +
result );
304 "Expected REVISION expanded in path. Got: " +
result );
317 wxString
path = wxT(
"Output\\Generated_${REVISION}_file.txt" );
321 "Expected variable expansion with preceding literal text. Got: " +
result );
349 std::filesystem::path tmp = std::filesystem::temp_directory_path() /
350 "kicad_qa_overlap_env_vars";
352 std::filesystem::remove_all( tmp, ec );
353 std::filesystem::create_directories( tmp /
"V10" /
"symbols", ec );
355 rootDir = wxString::FromUTF8( tmp.string() );
357 innerDir = wxString::FromUTF8( ( tmp /
"V10" ).
string() );
358 targetDir = wxString::FromUTF8( ( tmp /
"V10" /
"symbols" ).
string() );
360 wxSetEnv( wxS(
"KICAD_QA_3RD_PARTY_OUTER" ),
outerDir );
361 wxSetEnv( wxS(
"KICAD_QA_USER_LIB_INNER" ),
innerDir );
366 wxUnsetEnv( wxS(
"KICAD_QA_3RD_PARTY_OUTER" ) );
367 wxUnsetEnv( wxS(
"KICAD_QA_USER_LIB_INNER" ) );
369 std::filesystem::path tmp = std::filesystem::temp_directory_path() /
370 "kicad_qa_overlap_env_vars";
372 std::filesystem::remove_all( tmp, ec );
390 wxFileName target( targetDir, wxS(
"test.kicad_sym" ) );
393 wxString normalized =
NormalizePath( target, &envMap, wxEmptyString );
397 normalized == wxS(
"${KICAD_QA_USER_LIB_INNER}/symbols/test.kicad_sym" ),
398 wxString::Format( wxS(
"Expected '%s' but got '%s'" ),
399 wxS(
"${KICAD_QA_USER_LIB_INNER}/symbols/test.kicad_sym" ),
406 wxFileName target( targetDir, wxS(
"test.kicad_sym" ) );
409 wxString normalized =
NormalizePath( target, &envMap, wxEmptyString );
412 wxFileName expandedFn( expanded );
413 expandedFn.Normalize( wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE );
415 wxFileName originalFn( target );
416 originalFn.Normalize( wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE );
419 expandedFn.GetFullPath() == originalFn.GetFullPath(),
421 wxS(
"Round-trip mismatch: normalized='%s' expanded='%s' original='%s'" ),
422 normalized, expandedFn.GetFullPath(), originalFn.GetFullPath() ) );
445 std::function<bool( wxString* )>
resolver = []( wxString* token ) ->
bool
447 if( *token == wxT(
"#" ) )
453 if( *token == wxT(
"ROW" ) )
462 const std::vector<wxString> inputs = {
463 wxT(
"Out@{(${#}-2)*8+0}" ),
464 wxT(
"Net_@{${ROW}*2+1}" ),
465 wxT(
"@{(2-2)*8+0}" ),
466 wxT(
"${ROW}:@{${ROW}*${ROW}}" ),
467 wxT(
"plain_label_no_expr" ),
468 wxT(
"@{1+1}_@{2+2}_@{3+3}" ),
471 const unsigned int numThreads = std::max( 4u, std::thread::hardware_concurrency() );
472 const int iterations = 2000;
474 std::atomic<bool> failed{
false };
475 std::atomic<int> totalRuns{ 0 };
476 std::vector<std::thread> threads;
477 threads.reserve( numThreads );
479 for(
unsigned int t = 0; t < numThreads; ++t )
481 threads.emplace_back(
486 for(
int i = 0; i < iterations; ++i )
488 const wxString& src = inputs[( t + i ) % inputs.size()];
492 totalRuns.fetch_add( 1, std::memory_order_relaxed );
497 failed.store(
true, std::memory_order_relaxed );
502 for(
auto& th : threads )
505 BOOST_CHECK( !failed.load() );
506 BOOST_CHECK_EQUAL( totalRuns.load(),
static_cast<int>( numThreads ) * iterations );
531 if( wxGetEnv( wxS(
"KICAD_QA_INNER" ), &existing ) )
534 if( wxGetEnv( wxS(
"KICAD_QA_OUTER" ), &existing ) )
538 ( std::filesystem::temp_directory_path() /
"kicad-qa-24244" ).generic_string() );
540 wxSetEnv( wxS(
"KICAD_QA_INNER" ),
innerPath );
541 wxSetEnv( wxS(
"KICAD_QA_OUTER" ), wxS(
"${KICAD_QA_INNER}/templates" ) );
547 wxSetEnv( wxS(
"KICAD_QA_INNER" ), *
oldInner );
549 wxUnsetEnv( wxS(
"KICAD_QA_INNER" ) );
552 wxSetEnv( wxS(
"KICAD_QA_OUTER" ), *
oldOuter );
554 wxUnsetEnv( wxS(
"KICAD_QA_OUTER" ) );
563 BOOST_REQUIRE( wxGetEnv( wxS(
"KICAD_QA_OUTER" ), &rawValue ) );
566 BOOST_CHECK( rawValue.Contains( wxS(
"${KICAD_QA_INNER}" ) ) );
569 wxString
expected = innerPath + wxS(
"/templates" );
573 wxString::Format( wxS(
"Expected '%s', got '%s'" ),
expected, expanded ) );
582 wxUnsetEnv( wxS(
"KICAD_QA_INNER" ) );
585 BOOST_REQUIRE( wxGetEnv( wxS(
"KICAD_QA_OUTER" ), &rawValue ) );
588 BOOST_CHECK( expanded.Contains( wxS(
"${" ) ) );
591 wxSetEnv( wxS(
"KICAD_QA_INNER" ), innerPath );
619 ( std::filesystem::temp_directory_path() /
"kicad-qa-24460-stock.pretty" ).generic_string() );
626 if( wxGetEnv( wxS(
"KICAD_USER_FOOTPRINT_DIR" ), &existing ) )
629 if( wxGetEnv( wxS(
"KICAD5_FOOTPRINT_DIR" ), &existing ) )
635 wxUnsetEnv( wxS(
"KICAD_USER_FOOTPRINT_DIR" ) );
636 wxUnsetEnv( wxS(
"KICAD5_FOOTPRINT_DIR" ) );
641 auto restore = [&](
const wxString& aName,
const std::optional<wxString>& aOld )
644 wxSetEnv( aName, *aOld );
650 restore( wxS(
"KICAD_USER_FOOTPRINT_DIR" ),
oldUser );
651 restore( wxS(
"KICAD5_FOOTPRINT_DIR" ),
oldLegacy );
659 const wxString uri = wxS(
"${KICAD_USER_FOOTPRINT_DIR}/conn_custom.pretty" );
665 BOOST_CHECK( !expanded.Contains( stockDir ) );
671 BOOST_REQUIRE( wxS(
"KICAD5_FOOTPRINT_DIR" ) != versionedName );
685 std::optional<wxString> oldSymbol;
686 std::optional<wxString> oldAlias;
689 if( wxGetEnv( symbolName, &existing ) )
690 oldSymbol = existing;
692 if( wxGetEnv( wxS(
"KICAD_SYMBOL_DIR" ), &existing ) )
695 wxSetEnv( symbolName, stockDir );
696 wxUnsetEnv( wxS(
"KICAD_SYMBOL_DIR" ) );
704 wxSetEnv( symbolName, *oldSymbol );
706 wxUnsetEnv( symbolName );
709 wxSetEnv( wxS(
"KICAD_SYMBOL_DIR" ), *oldAlias );
711 wxUnsetEnv( wxS(
"KICAD_SYMBOL_DIR" ) );
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 NormalizeFilePathForTextVars(const wxString &aPath)
Normalize a file path so its text variables survive ExpandTextVars.
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.
Functions related to environment variables, including help functions.
static FILENAME_RESOLVER * resolver
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
KICOMMON_API bool IsVersionedEnvVar(const wxString &aName, const wxString &aBaseName)
Test whether a name is a versioned KiCad environment variable for the given base, i....
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
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()
Regression test for KiCad GitLab issue #24460.
std::optional< wxString > oldUser
VersionedEnvVarFallbackFixture()
std::optional< wxString > oldVersioned
std::optional< wxString > oldLegacy
~VersionedEnvVarFallbackFixture()
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")