KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_jobs_runner.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
20#include <boost/test/unit_test.hpp>
21
22#include <wx/process.h>
23#include <wx/txtstrm.h>
24#include <wx/filename.h>
25#include <wx/dir.h>
26#include <wx/file.h>
27
28#ifdef _WIN32
29#include <process.h>
30#endif
31
32
33BOOST_AUTO_TEST_SUITE( JobsRunner )
34
35
36
40static int executeViaShell( const wxString& aCmd, wxString& aOutput )
41{
42 wxProcess process;
43 process.Redirect();
44
45#ifdef __WXMSW__
46 // The argv-array form of wxExecute re-escapes embedded double quotes on Windows
47 // (see wxExecuteImpl in wxWidgets' src/msw/utilsexc.cpp), breaking quoted executable
48 // paths with spaces. The string form passes the command line straight to CreateProcess
49 // without modification. This mirrors the production code in runSpecialExecute.
50 int result = static_cast<int>(
51 wxExecute( wxS( "cmd.exe /c " ) + aCmd, wxEXEC_SYNC, &process ) );
52#else
53 const wchar_t* argv[] = { wxS( "/bin/sh" ), wxS( "-c" ), aCmd.wc_str(), nullptr };
54 int result = static_cast<int>( wxExecute( argv, wxEXEC_SYNC, &process ) );
55#endif
56
57 wxInputStream* inputStream = process.GetInputStream();
58
59 if( inputStream )
60 {
61 wxTextInputStream textStream( *inputStream );
62
63 while( !inputStream->Eof() )
64 {
65 wxString line = textStream.ReadLine();
66
67 if( !line.IsEmpty() || !inputStream->Eof() )
68 {
69 if( !aOutput.IsEmpty() )
70 aOutput += wxS( "\n" );
71
72 aOutput += line;
73 }
74 }
75 }
76
77 return result;
78}
79
80
81BOOST_AUTO_TEST_CASE( SimpleCommand )
82{
83 wxString output;
84 int result = executeViaShell( wxS( "echo hello" ), output );
85
87 BOOST_CHECK( output.Contains( wxS( "hello" ) ) );
88}
89
90#ifdef _WIN32
91#define getpid _getpid
92#endif
93
94BOOST_AUTO_TEST_CASE( GlobExpansion )
95{
96 wxString tempDir = wxFileName::GetTempDir() + wxFileName::GetPathSeparator()
97 + wxS( "kicad_test_glob_" ) + wxString::Format( wxS( "%d" ), (int) getpid() );
98
99 BOOST_REQUIRE( wxFileName::Mkdir( tempDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
100
101 wxFile file1;
102 wxFile file2;
103 wxString path1 = tempDir + wxFileName::GetPathSeparator() + wxS( "file_a.txt" );
104 wxString path2 = tempDir + wxFileName::GetPathSeparator() + wxS( "file_b.txt" );
105
106 file1.Create( path1 );
107 file1.Write( wxS( "content_a" ) );
108 file1.Close();
109
110 file2.Create( path2 );
111 file2.Write( wxS( "content_b" ) );
112 file2.Close();
113
114 // Use ls with glob. Without shell interpretation, the glob would not expand.
115#ifdef __WXMSW__
116 wxString cmd = wxString::Format( wxS( "dir /b \"%s\\*.txt\"" ), tempDir );
117#else
118 wxString cmd = wxString::Format( wxS( "ls %s/*.txt" ), tempDir );
119#endif
120
121 wxString output;
122 int result = executeViaShell( cmd, output );
123
125 BOOST_CHECK_MESSAGE( output.Contains( wxS( "file_a.txt" ) ),
126 "Glob should expand to include file_a.txt, got: " + output );
127 BOOST_CHECK_MESSAGE( output.Contains( wxS( "file_b.txt" ) ),
128 "Glob should expand to include file_b.txt, got: " + output );
129
130 wxRemoveFile( path1 );
131 wxRemoveFile( path2 );
132 wxRmdir( tempDir );
133}
134
135
137{
138#ifdef __WXMSW__
139 wxString cmd = wxS( "echo hello world | findstr hello" );
140#else
141 wxString cmd = wxS( "echo hello world | grep hello" );
142#endif
143
144 wxString output;
145 int result = executeViaShell( cmd, output );
146
148 BOOST_CHECK( output.Contains( wxS( "hello" ) ) );
149}
150
151
152BOOST_AUTO_TEST_CASE( ExitCodePropagation )
153{
154#ifdef __WXMSW__
155 wxString cmd = wxS( "cmd /c exit 42" );
156#else
157 wxString cmd = wxS( "exit 42" );
158#endif
159
160 wxString output;
161 int result = executeViaShell( cmd, output );
162
164}
165
166
167BOOST_AUTO_TEST_CASE( CommandWithSingleQuotes )
168{
169#ifndef __WXMSW__
170 wxString cmd = wxS( "echo \"it's working\"" );
171 wxString output;
172 int result = executeViaShell( cmd, output );
173
175 BOOST_CHECK_MESSAGE( output.Contains( wxS( "it's working" ) ),
176 "Should handle single quotes in output, got: " + output );
177#endif
178}
179
180
181#ifdef __WXMSW__
182BOOST_AUTO_TEST_CASE( CommandWithQuotedArgument )
183{
184 // Regression test for a Windows-only bug where a user-supplied command containing
185 // double-quoted arguments with spaces was corrupted by the argv-array form of wxExecute,
186 // which re-escapes embedded " as \" (see wxExecuteImpl in wxWidgets' src/msw/utilsexc.cpp).
187 // cmd.exe does not honour backslash-escaped quotes, so this broke any quoted executable
188 // path containing spaces (e.g. "C:\Program Files\KiCad\10.0\bin\python.exe" --version).
189 // Under the buggy code path, cmd.exe's `echo` would emit \"hello world\"; with the fix
190 // (string form of wxExecute), the user's quoting is preserved and the output contains
191 // the original "hello world".
192 wxString cmd = wxS( "echo \"hello world\"" );
193 wxString output;
194 int result = executeViaShell( cmd, output );
195
197 BOOST_CHECK_MESSAGE( output.Contains( wxS( "\"hello world\"" ) ),
198 "Quoted argument should pass through verbatim, got: " + output );
199}
200#endif
201
202
static PGM_BASE * process
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
static int executeViaShell(const wxString &aCmd, wxString &aOutput)
Helper that mirrors the shell-wrapping execution pattern used in JOBS_RUNNER::runSpecialExecute.
BOOST_AUTO_TEST_CASE(SimpleCommand)
nlohmann::json output
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")