KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_expand_text_vars.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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
20
21#define BOOST_TEST_NO_MAIN
22#include <boost/test/unit_test.hpp>
23#include <qa_utils/file_utils.h>
25
26#include <atomic>
27#include <optional>
28#include <thread>
29#include <vector>
30
31#include <wx/filename.h>
32#include <wx/utils.h>
33
34#include <common.h>
35#include <env_paths.h>
36#include <env_vars.h>
38#include <pgm_base.h>
40#include <title_block.h>
41
46{
47 // Simple resolver that maps VAR->value, X->5, Y->2
48 std::function<bool( wxString* )> resolver =
49 []( wxString* token ) -> bool
50 {
51 if( *token == wxT( "VAR" ) )
52 {
53 *token = wxT( "value" );
54 return true;
55 }
56 else if( *token == wxT( "X" ) )
57 {
58 *token = wxT( "5" );
59 return true;
60 }
61 else if( *token == wxT( "Y" ) )
62 {
63 *token = wxT( "2" );
64 return true;
65 }
66
67 return false;
68 };
69};
70
71BOOST_FIXTURE_TEST_SUITE( ExpandTextVarsTests, ExpandTextVarsFixture )
72
73BOOST_AUTO_TEST_CASE( AssertionsRemainAvailableOnlyDuringRuleChecks )
74{
75 for( const wxString& prefix : { wxString( "ERC_WARNING" ), wxString( "ERC_ERROR" ),
76 wxString( "DRC_WARNING" ), wxString( "DRC_ERROR" ) } )
77 {
78 const wxString assertion = "${" + prefix + " Check this item}";
79 BOOST_CHECK_EQUAL( ExpandTextVars( assertion, &resolver, FOR_ERC_DRC ), assertion );
80 BOOST_CHECK( ExpandTextVars( assertion, &resolver, FOR_CANVAS ).empty() );
81 BOOST_CHECK_EQUAL( ExpandTextVars( assertion, &resolver, RAW_VALUE ), assertion );
82 }
83}
84
85
86// Basic variable expansion
87BOOST_AUTO_TEST_CASE( SimpleVariable )
88{
89 wxString result = ExpandTextVars( wxT( "${VAR}" ), &resolver, INTERNAL );
90 BOOST_CHECK( result == wxT( "value" ) );
91}
92
93// Multiple variables in one string
94BOOST_AUTO_TEST_CASE( MultipleVariables )
95{
96 wxString result = ExpandTextVars( wxT( "${X}+${Y}" ), &resolver, INTERNAL );
97 BOOST_CHECK( result == wxT( "5+2" ) );
98}
99
100// Escaped variable should produce escape marker (not expanded)
101BOOST_AUTO_TEST_CASE( EscapedVariable )
102{
103 wxString result = ExpandTextVars( wxT( "\\${VAR}" ), &resolver, INTERNAL );
104 // The escape marker should be in the output
105 BOOST_CHECK( result.Contains( wxT( "<<<ESC_DOLLAR:" ) ) );
106}
107
108// Escaped variable followed by regular variable - both should be processed correctly
109BOOST_AUTO_TEST_CASE( EscapedThenRegularVariable )
110{
111 wxString result = ExpandTextVars( wxT( "\\${literal}${VAR}" ), &resolver, INTERNAL );
112 // Should have escape marker for literal, and "value" for VAR
113 BOOST_CHECK( result.Contains( wxT( "<<<ESC_DOLLAR:" ) ) );
114 BOOST_CHECK( result.Contains( wxT( "value" ) ) );
115}
116
117// Regular variable followed by escaped variable
118BOOST_AUTO_TEST_CASE( RegularThenEscapedVariable )
119{
120 wxString result = ExpandTextVars( wxT( "${VAR}\\${literal}" ), &resolver, INTERNAL );
121 // Should have "value" for VAR and escape marker for literal
122 BOOST_CHECK( result.StartsWith( wxT( "value" ) ) );
123 BOOST_CHECK( result.Contains( wxT( "<<<ESC_DOLLAR:" ) ) );
124}
125
126// Issue 22497: Escaped variable inside math expression should not prevent other expansions
127// This is the key test case for the bug fix
128BOOST_AUTO_TEST_CASE( EscapedInsideMathExpression )
129{
130 // First pass: @{\${X}+${Y}} should become @{<<<ESC_DOLLAR:X}+2}
131 // Second pass: the marker should be preserved and +2 should NOT be lost
132 wxString result = ExpandTextVars( wxT( "@{\\${X}+${Y}}" ), &resolver, INTERNAL );
133
134 // The result should contain the escape marker
135 BOOST_CHECK_MESSAGE( result.Contains( wxT( "<<<ESC_DOLLAR:" ) ),
136 "Expected escape marker in result" );
137
138 // The result should also contain +2 (the expanded Y variable)
139 BOOST_CHECK_MESSAGE( result.Contains( wxT( "+2" ) ),
140 "Expected '+2' (from ${Y} expansion) in result" );
141
142 // The result should be @{<<<ESC_DOLLAR:X}+2}
143 BOOST_CHECK( result == wxT( "@{<<<ESC_DOLLAR:X}+2}" ) );
144}
145
146// Nested escaped variable in regular variable reference
147BOOST_AUTO_TEST_CASE( EscapedInsideVariableReference )
148{
149 // ${prefix\${suffix}} - looking up variable with literal ${suffix} in name
150 // This should try to resolve "prefix\${suffix}" which won't resolve,
151 // but the recursive expansion should convert \${suffix} to the marker
152 wxString result = ExpandTextVars( wxT( "${prefix\\${suffix}}" ), &resolver, INTERNAL );
153
154 // The unresolved reference should be preserved with escape marker
155 BOOST_CHECK( result.Contains( wxT( "<<<ESC_DOLLAR:" ) ) );
156}
157
158// Multiple escape markers in a math expression
159BOOST_AUTO_TEST_CASE( MultipleEscapedInMathExpression )
160{
161 wxString result = ExpandTextVars( wxT( "@{\\${A}+\\${B}+${Y}}" ), &resolver, INTERNAL );
162
163 // Should have two escape markers and the expanded Y (2)
164 BOOST_CHECK_MESSAGE( result.Contains( wxT( "+2" ) ),
165 "Expected '+2' (from ${Y} expansion) in: " + result );
166
167 // Count escape markers (should be 2)
168 int dollarCount = 0;
169 size_t pos = 0;
170
171 while( ( pos = result.find( wxT( "<<<ESC_DOLLAR:" ), pos ) ) != wxString::npos )
172 {
173 dollarCount++;
174 pos += 14;
175 }
176
177 BOOST_CHECK_EQUAL( dollarCount, 2 );
178}
179
180// Math expression with escaped @ sign
181BOOST_AUTO_TEST_CASE( EscapedAtInExpression )
182{
183 wxString result = ExpandTextVars( wxT( "${VAR}\\@{literal}" ), &resolver, INTERNAL );
184
185 // Should have "value" for VAR and escape marker for @{literal}
186 BOOST_CHECK( result.StartsWith( wxT( "value" ) ) );
187 BOOST_CHECK( result.Contains( wxT( "<<<ESC_AT:" ) ) );
188}
189
190// Escaped followed by escaped (both should be preserved)
191BOOST_AUTO_TEST_CASE( ConsecutiveEscaped )
192{
193 wxString result = ExpandTextVars( wxT( "\\${A}\\${B}" ), &resolver, INTERNAL );
194
195 // Should have two escape markers
196 int dollarCount = 0;
197 size_t pos = 0;
198
199 while( ( pos = result.find( wxT( "<<<ESC_DOLLAR:" ), pos ) ) != wxString::npos )
200 {
201 dollarCount++;
202 pos += 14;
203 }
204
205 BOOST_CHECK_EQUAL( dollarCount, 2 );
206}
207
208// Issue 23599: backslash path separator before text variable should NOT be treated as an escape.
209// This test documents the ExpandTextVars behavior: \${ IS treated as an escape at this level.
210// The fix is applied at call sites that deal with file paths, which normalize backslashes to
211// forward slashes before calling ExpandTextVars.
212BOOST_AUTO_TEST_CASE( BackslashBeforeVariableIsEscape )
213{
214 wxString result = ExpandTextVars( wxT( "subdir\\${VAR}_file.txt" ), &resolver, INTERNAL );
215
216 // ExpandTextVars treats \${ as an escape, so VAR is NOT expanded
217 BOOST_CHECK( result.Contains( wxT( "<<<ESC_DOLLAR:" ) ) );
218}
219
220
221// With forward slashes the variable is expanded normally
222BOOST_AUTO_TEST_CASE( ForwardSlashBeforeVariableExpands )
223{
224 wxString result = ExpandTextVars( wxT( "subdir/${VAR}_file.txt" ), &resolver, INTERNAL );
225
226 BOOST_CHECK( result == wxT( "subdir/value_file.txt" ) );
227}
228
230
231
232// Issue 24776: user-entered file paths with a text variable immediately after a backslash
233// separator (e.g. the Symbol Fields Table BOM export path "Output\BoM\${PROJECTNAME}.csv")
234// must expand. Callers route the path through NormalizeFilePathForTextVars before ExpandTextVars.
235BOOST_FIXTURE_TEST_SUITE( NormalizeFilePathForTextVarsTests, ExpandTextVarsFixture )
236
237BOOST_AUTO_TEST_CASE( BackslashSeparatorBeforeVarExpands )
238{
239 wxString path = NormalizeFilePathForTextVars( wxT( "Output\\BoM\\${VAR}_file.csv" ) );
240 wxString result = ExpandTextVars( path, &resolver, INTERNAL );
241
242 // Only the backslash immediately before the variable is rewritten to a separator; the
243 // variable expands and the earlier literal backslash is preserved.
244 BOOST_CHECK_MESSAGE( !result.Contains( wxT( "<<<ESC_DOLLAR:" ) ),
245 "Variable after backslash separator should expand, not escape. Got: " + result );
246 BOOST_CHECK( result == wxT( "Output\\BoM/value_file.csv" ) );
247}
248
249
250BOOST_AUTO_TEST_CASE( MultipleVarsAfterBackslashSeparators )
251{
252 wxString path = NormalizeFilePathForTextVars( wxT( "Output\\BoM\\${X}_V${Y}.csv" ) );
253 wxString result = ExpandTextVars( path, &resolver, INTERNAL );
254
255 BOOST_CHECK( result == wxT( "Output\\BoM/5_V2.csv" ) );
256}
257
258
259BOOST_AUTO_TEST_CASE( ForwardSlashPathUnchanged )
260{
261 wxString path = NormalizeFilePathForTextVars( wxT( "Output/BoM/${VAR}.csv" ) );
262 wxString result = ExpandTextVars( path, &resolver, INTERNAL );
263
264 BOOST_CHECK( result == wxT( "Output/BoM/value.csv" ) );
265}
266
267
268// Backslashes that do not immediately precede a text variable are a legitimate part of the
269// filename (notably on POSIX) and must survive normalization unchanged.
270BOOST_AUTO_TEST_CASE( NonVariableBackslashesArePreserved )
271{
272 wxString path = NormalizeFilePathForTextVars( wxT( "Output\\BoM\\literal.csv" ) );
273
274 BOOST_CHECK( path == wxT( "Output\\BoM\\literal.csv" ) );
275}
276
278
279
280// Issue 23599: JOB::ResolveOutputPath must expand text variables even when preceded by backslash
281// path separators. This suite tests the fix in ResolveOutputPath that normalizes backslashes
282// before calling ExpandTextVars.
283BOOST_AUTO_TEST_SUITE( JobResolveOutputPath )
284
285BOOST_AUTO_TEST_CASE( BackslashPathSeparatorBeforeTextVar )
286{
288
289 TITLE_BLOCK titleBlock;
290 titleBlock.SetRevision( wxT( "RevA" ) );
291 job.SetTitleBlock( titleBlock );
292
293 // Simulates Windows path with text variable immediately after backslash separator
294 wxString path = wxT( "Board Stats\\${REVISION}_Stats.txt" );
295 wxString result = job.ResolveOutputPath( path, false, nullptr );
296
297 // The variable should be expanded, not escaped
298 BOOST_CHECK_MESSAGE( !result.Contains( wxT( "<<<ESC_DOLLAR:" ) ),
299 "Text variable after backslash path separator should not be escaped. Got: "
300 + result );
301 BOOST_CHECK_MESSAGE( result.Contains( wxT( "RevA" ) ),
302 "Expected resolved REVISION in path. Got: " + result );
303}
304
305
306BOOST_AUTO_TEST_CASE( BackslashPathSeparatorBeforeMultipleTextVars )
307{
309
310 TITLE_BLOCK titleBlock;
311 titleBlock.SetRevision( wxT( "B" ) );
312 titleBlock.SetComment( 0, wxT( "DWG-001" ) );
313 job.SetTitleBlock( titleBlock );
314
315 // The COMMENT1 variable maps to Comment(0) in TITLE_BLOCK
316 wxString path = wxT( "Output\\${COMMENT1}_${REVISION}_file.txt" );
317 wxString result = job.ResolveOutputPath( path, false, nullptr );
318
319 BOOST_CHECK_MESSAGE( result.Contains( wxT( "DWG-001" ) ),
320 "Expected COMMENT1 expanded in path. Got: " + result );
321 BOOST_CHECK_MESSAGE( result.Contains( wxT( "_B_" ) ),
322 "Expected REVISION expanded in path. Got: " + result );
323}
324
325
326BOOST_AUTO_TEST_CASE( TextVarNotFirstInFilename )
327{
329
330 TITLE_BLOCK titleBlock;
331 titleBlock.SetRevision( wxT( "C" ) );
332 job.SetTitleBlock( titleBlock );
333
334 // When there's literal text between the backslash and the variable, it always worked
335 wxString path = wxT( "Output\\Generated_${REVISION}_file.txt" );
336 wxString result = job.ResolveOutputPath( path, false, nullptr );
337
338 BOOST_CHECK_MESSAGE( result.Contains( wxT( "Generated_C_file.txt" ) ),
339 "Expected variable expansion with preceding literal text. Got: " + result );
340}
341
342
356BOOST_AUTO_TEST_CASE( OverlappingPrefix_NormalizePicksLongestPrefix )
357{
358 // NormalizePath only considers env var paths that exist as readable directories.
359 KI_TEST::SCOPED_TEMP_DIR tempDir( wxS( "overlapping-env-vars" ) );
360
361 const wxString innerDir = tempDir.CreateChildDirStr( "V10" ); // .../V10
362 const wxFileName targetFilename( innerDir, wxS( "test.kicad_sym" ) ); // ..../V10/test.kicad_sym
363
364 KI_TEST::SCOPED_PGM_ENV_VAR scopedOuterEnvVar( wxS( "KICAD_QA_3RD_PARTY_OUTER" ), tempDir.PathStr() );
365 KI_TEST::SCOPED_PGM_ENV_VAR scopedInnerEnvVar( wxS( "KICAD_QA_USER_LIB_INNER" ), innerDir );
366
367 // ---- Setup done
368
369 // NormalizePath should pick KICAD_QA_USER_LIB_INNER because it is a deeper match.
370 const wxString normalized = NormalizePath( targetFilename, &Pgm().GetLocalEnvVariables(), wxEmptyString );
371 const wxString expected = wxS( "${KICAD_QA_USER_LIB_INNER}/test.kicad_sym" );
372
374}
375
376
378
379
380
392BOOST_AUTO_TEST_SUITE( TextVarExpressionEvaluatorConcurrency )
393
394BOOST_AUTO_TEST_CASE( ParallelResolveTextVarsWithMathExpressions )
395{
396 std::function<bool( wxString* )> resolver =
397 []( wxString* token ) -> bool
398 {
399 if( *token == wxT( "#" ) )
400 {
401 *token = wxT( "3" );
402 return true;
403 }
404
405 if( *token == wxT( "ROW" ) )
406 {
407 *token = wxT( "4" );
408 return true;
409 }
410
411 return false;
412 };
413
414 const std::vector<wxString> inputs = {
415 wxT( "Out@{(${#}-2)*8+0}" ),
416 wxT( "Net_@{${ROW}*2+1}" ),
417 wxT( "@{(2-2)*8+0}" ),
418 wxT( "${ROW}:@{${ROW}*${ROW}}" ),
419 wxT( "plain_label_no_expr" ),
420 wxT( "@{1+1}_@{2+2}_@{3+3}" ),
421 };
422
423 const unsigned int numThreads = std::max( 4u, std::thread::hardware_concurrency() );
424 const int iterations = 2000;
425
426 std::atomic<bool> failed{ false };
427 std::atomic<int> totalRuns{ 0 };
428 std::vector<std::thread> threads;
429 threads.reserve( numThreads );
430
431 for( unsigned int t = 0; t < numThreads; ++t )
432 {
433 threads.emplace_back(
434 [&, t]()
435 {
436 try
437 {
438 for( int i = 0; i < iterations; ++i )
439 {
440 const wxString& src = inputs[( t + i ) % inputs.size()];
441 int depth = 0;
442 wxString result = ResolveTextVars( src, &resolver, depth );
443 (void) result;
444 totalRuns.fetch_add( 1, std::memory_order_relaxed );
445 }
446 }
447 catch( ... )
448 {
449 failed.store( true, std::memory_order_relaxed );
450 }
451 } );
452 }
453
454 for( auto& th : threads )
455 th.join();
456
457 BOOST_CHECK( !failed.load() );
458 BOOST_CHECK_EQUAL( totalRuns.load(), static_cast<int>( numThreads ) * iterations );
459}
460
462
463
464BOOST_AUTO_TEST_SUITE( EnvVarResolution )
465
466
467BOOST_AUTO_TEST_CASE( ExpandsNestedReferences )
468{
469 const wxString innerPath = "/inner/path";
470
471 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedInnerEnvVar( wxS( "KICAD_QA_INNER" ), innerPath );
472 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedOuterEnvVar( wxS( "KICAD_QA_OUTER" ), wxS( "${KICAD_QA_INNER}/templates" ) );
473
474 wxString expanded = ExpandEnvVarSubstitutions( wxS( "${KICAD_QA_OUTER}" ), nullptr );
475 wxString expected = innerPath + wxS( "/templates" );
476
477 // After expansion the inner reference must be resolved to its concrete path.
478 BOOST_CHECK_EQUAL( expanded, expected );
479}
480
481
482BOOST_AUTO_TEST_CASE( UndefinedReferenceLeavesLiteralMarker )
483{
484 // If a referenced variable is undefined, ExpandEnvVarSubstitutions preserves the
485 // original token. Callers that then mkdir the result would create a literal
486 // "${MISSING}" directory; production code must detect this and bail out.
487
488 const wxString innerPath = "/inner/path";
489
490 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedInnerEnvVar( wxS( "KICAD_QA_INNER" ), std::nullopt );
491 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedOuterEnvVar( wxS( "KICAD_QA_OUTER" ), wxS( "${KICAD_QA_INNER}/templates" ) );
492
493 wxString expanded = ExpandEnvVarSubstitutions( wxS( "${KICAD_QA_OUTER}" ), nullptr );
494 BOOST_CHECK_EQUAL( expanded, "${KICAD_QA_INNER}/templates" );
495}
496
497
498BOOST_AUTO_TEST_CASE( UserVarIsNotTreatedAsVersionedLibraryDir )
499{
500 const wxString stockLibPath = "/some/path/to/stock-libraries";
501 const wxString versionedName = ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) );
502
503 // Clear the user var
504 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedUserEnvVar( wxS( "KICAD_USER_FOOTPRINT_DIR" ), std::nullopt );
505 // Set the versioned var to some specific path
506 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedVersionedEnvVar( versionedName, stockLibPath );
507
508 const wxString uri = wxS( "${KICAD_USER_FOOTPRINT_DIR}/conn_custom.pretty" );
509
510 wxString expanded = ExpandEnvVarSubstitutions( uri, nullptr );
511
512 // An unresolved user var must stay literal, never fall back to the library directory.
513 BOOST_CHECK_EQUAL( expanded, uri );
514}
515
516
517/*
518 * A project or board from an older KiCad may reference an older versioned library variable
519 * (for example ${KICAD5_FOOTPRINT_DIR} from a KiCad 5 project). If that exact variable is not
520 * set on this machine, the expander falls back to the current install's equivalent so the path
521 * still resolves.
522 */
523BOOST_AUTO_TEST_CASE( LegacyVersionedVarStillResolvesToCurrentDir )
524{
525 const wxString libPath = "/some/path/to/stock-libraries";
526 const wxString currentVersionedName = ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) );
527
528 // Condition: the legacy var is not the same as the current versioned var.
529 BOOST_REQUIRE( wxS( "KICAD5_FOOTPRINT_DIR" ) != currentVersionedName );
530
531 // Ensure legacy var is unset so the direct lookup fails and the fallback runs.
532 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedLegacyEnvVar( wxS( "KICAD5_FOOTPRINT_DIR" ), std::nullopt );
533 // Set the current versioned var, which is what the fallback resolves to.
534 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedVersionedEnvVar( currentVersionedName, libPath );
535
536 wxString expanded =
537 ExpandEnvVarSubstitutions( wxS( "${KICAD5_FOOTPRINT_DIR}/conn_custom.pretty" ), nullptr );
538
539 // The missing fallback resolves to the current versioned footprint directory.
540 BOOST_CHECK_EQUAL( expanded, libPath + wxS( "/conn_custom.pretty" ) );
541}
542
543
544BOOST_AUTO_TEST_CASE( DeprecatedUnversionedAliasStillResolves )
545{
546 // KICAD_SYMBOL_DIR is a documented deprecated alias for the versioned symbol dir.
547 // It must still fall back to the current install even though it carries no
548 // version info.
549 const wxString libPath = "/some/path/to/stock-libraries";
550 const wxString currentVersionedName = ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) );
551
552 // Ensure the "correct" alias is unset so the direct lookup fails and the fallback runs.
553 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedAliasEnvVar( wxS( "KICAD_SYMBOL_DIR" ), std::nullopt );
554 // Set the current versioned var, which is what the fallback resolves to.
555 KI_TEST::SCOPED_PROCESS_ENV_VAR scopedVersionedEnvVar( currentVersionedName, libPath );
556
557 // A user-provided path that uses the deprecated alias.
558 wxString expanded =
559 ExpandEnvVarSubstitutions( wxS( "${KICAD_SYMBOL_DIR}/Device.kicad_sym" ), nullptr );
560
561 // Should have resolved to the current versioned var's value.
562 BOOST_CHECK_EQUAL( expanded, libPath + wxS( "/Device.kicad_sym" ) );
563}
564
565
566BOOST_AUTO_TEST_CASE( IsVersionedEnvVarPredicate )
567{
568 BOOST_CHECK( ENV_VAR::IsVersionedEnvVar( wxS( "KICAD7_FOOTPRINT_DIR" ), wxS( "FOOTPRINT_DIR" ) ) );
569 BOOST_CHECK( ENV_VAR::IsVersionedEnvVar( wxS( "KICAD10_FOOTPRINT_DIR" ), wxS( "FOOTPRINT_DIR" ) ) );
570
571 BOOST_CHECK( !ENV_VAR::IsVersionedEnvVar( wxS( "KICAD_USER_FOOTPRINT_DIR" ), wxS( "FOOTPRINT_DIR" ) ) );
572 BOOST_CHECK( !ENV_VAR::IsVersionedEnvVar( wxS( "KICAD_FOOTPRINT_DIR" ), wxS( "FOOTPRINT_DIR" ) ) );
573 BOOST_CHECK( !ENV_VAR::IsVersionedEnvVar( wxS( "KICAD7_SYMBOL_DIR" ), wxS( "FOOTPRINT_DIR" ) ) );
574}
575
static std::optional< VECTOR2D > normalized(const VECTOR2D &aVec)
wxString ResolveOutputPath(const wxString &aPath, bool aPathIsDirectory, PROJECT *aProject) const
Definition job.cpp:100
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition job.h:204
RAII helper that sets a KiCad program-level environment variable for the lifetime of the object.
RAII helper that sets a process-level environment variable for the lifetime of the object.
wxString PathStr() const
Get the path to the temporary directory as a wxString.
Definition file_utils.h:62
wxString CreateChildDirStr(const wxString &aName) const
Create and return the path to a direct child directory as a wxString.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:38
void SetRevision(const wxString &aRevision)
Definition title_block.h:78
void SetComment(int aIdx, const wxString &aComment)
Definition title_block.h:98
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:776
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, RESOLUTION_CONTEXT aContext)
Definition common.cpp:60
wxString NormalizeFilePathForTextVars(const wxString &aPath)
Normalize a file path so its text variables survive ExpandTextVars.
Definition common.cpp:72
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
Definition common.cpp:333
@ FOR_ERC_DRC
Definition common.h:93
@ FOR_CANVAS
Definition common.h:90
@ RAW_VALUE
Definition common.h:96
@ INTERNAL
Definition common.h:94
static bool empty(const wxTextEntryBase *aCtrl)
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Definition env_paths.cpp:73
Helper functions to substitute paths with environmental variables.
Functions related to environment variables, including help functions.
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....
Definition env_vars.cpp:87
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:78
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
Test fixture for ExpandTextVars tests.
std::function< bool(wxString *)> resolver
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(AssertionsRemainAvailableOnlyDuringRuleChecks)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
VECTOR3I expected(15, 30, 45)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")