LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sal / qa / osl / process / osl_process.cxx
blobc396a06b5782a7436abad306813095ecf89a6e0a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifdef IOS
21 #define CPPUNIT_PLUGIN_EXPORTED_NAME cppunitTest_osl_process
22 #endif
24 #include <sal/types.h>
25 #include <cppunit/TestFixture.h>
26 #include <cppunit/extensions/HelperMacros.h>
27 #include <cppunit/plugin/TestPlugIn.h>
29 #include <osl/process.h>
30 #include <osl/file.hxx>
31 #include <osl/thread.h>
32 #include <rtl/ustring.hxx>
33 #include <signal.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <osl/module.hxx>
38 #include <sal/macros.h>
40 #if defined HAVE_VALGRIND_HEADERS
41 #include <valgrind/valgrind.h>
42 #elif !defined _WIN32
43 #define RUNNING_ON_VALGRIND false
44 #endif
46 #if !defined(_WIN32) // Windows
47 #include <unistd.h>
48 #endif
50 #include <iostream>
51 #include <fstream>
52 #include <vector>
53 #include <algorithm>
54 #include <iterator>
55 #include <string>
57 #ifdef UNX
58 #if defined( MACOSX )
59 # include <crt_externs.h>
60 # define environ (*_NSGetEnviron())
61 # else
62 extern char** environ;
63 # endif
64 #endif
66 using namespace osl;
68 /** get binary Path.
70 static OUString getExecutablePath()
72 OUString dirPath;
73 osl::Module::getUrlFromAddress(
74 reinterpret_cast<oslGenericFunction>(&getExecutablePath), dirPath);
75 dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') );
76 dirPath = OUString::Concat(dirPath.subView( 0, dirPath.lastIndexOf('/') + 1)) +
77 "Executable";
78 return dirPath;
81 #if !defined _WIN32
83 namespace {
85 class exclude
87 public:
89 explicit exclude(const std::vector<OString>& exclude_list)
91 for (auto& exclude_list_item : exclude_list)
92 exclude_list_.push_back(env_var_name(exclude_list_item));
95 bool operator() (const OString& env_var) const
97 return (exclude_list_.end() !=
98 std::find(
99 exclude_list_.begin(),
100 exclude_list_.end(),
101 env_var_name(env_var)));
104 private:
106 // extract the name from an environment variable
107 // that is given in the form "NAME=VALUE"
108 static OString env_var_name(const OString& env_var)
110 sal_Int32 pos_equal_sign =
111 env_var.indexOf('=');
113 if (pos_equal_sign != -1)
114 return env_var.copy(0, pos_equal_sign);
116 return OString();
119 private:
120 std::vector<OString> exclude_list_;
123 void tidy_container(std::vector<OString> &env_container)
125 //sort them because there are no guarantees to ordering
126 std::sort(env_container.begin(), env_container.end());
127 if (RUNNING_ON_VALGRIND)
129 env_container.erase(
130 std::remove_if(
131 env_container.begin(), env_container.end(),
132 [](OString const & s) {
133 return s.startsWith("LD_PRELOAD=")
134 || s.startsWith("VALGRIND_LIB="); }),
135 env_container.end());
140 static void read_parent_environment(std::vector<OString>* env_container)
142 for (int i = 0; environ[i] != nullptr; i++)
143 env_container->push_back(OString(environ[i]));
144 tidy_container(*env_container);
147 #endif
149 class Test_osl_executeProcess : public CppUnit::TestFixture
151 const OUString env_param_;
153 OUString temp_file_url_;
154 OUString temp_file_path_;
155 rtl_uString* parameters_[2];
156 static const int parameters_count_ = 2;
157 OUString suCWD;
158 OUString suExecutableFileURL;
160 public:
162 // ctor
163 Test_osl_executeProcess() :
164 env_param_(OUString("-env")), suCWD(getExecutablePath())
166 parameters_[0] = env_param_.pData;
168 #if defined(_WIN32)
169 suExecutableFileURL = suCWD + "/" "osl_process_child.exe";
170 #else
171 suExecutableFileURL = suCWD + "/" "osl_process_child";
172 #endif
175 virtual void setUp() override
177 temp_file_path_ = create_temp_file(temp_file_url_);
178 parameters_[1] = temp_file_path_.pData;
181 virtual void tearDown() override
183 osl::File::remove(temp_file_url_);
186 OUString create_temp_file(OUString &temp_file_url)
188 FileBase::RC rc = FileBase::createTempFile(nullptr, nullptr, &temp_file_url);
189 CPPUNIT_ASSERT_EQUAL_MESSAGE("createTempFile failed", FileBase::E_None, rc);
191 OUString temp_file_path;
192 rc = FileBase::getSystemPathFromFileURL(temp_file_url, temp_file_path);
193 CPPUNIT_ASSERT_EQUAL_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None, rc);
195 return temp_file_path;
198 #if !defined _WIN32
200 void read_child_environment(std::vector<OString>* env_container)
202 OString temp_file_name = OUStringToOString(OUString(
203 parameters_[1]), osl_getThreadTextEncoding());
204 std::ifstream file(temp_file_name.getStr());
206 CPPUNIT_ASSERT_MESSAGE
208 "I/O error, cannot open child environment file",
209 file.is_open()
212 std::string line;
213 line.reserve(1024);
214 while (std::getline(file, line, '\0'))
215 env_container->push_back(OString(line.c_str()));
216 tidy_container(*env_container);
219 // environment of the child process that was
220 // started. The child process writes his
221 // environment into a file
222 void compare_environments()
224 std::vector<OString> parent_env;
225 read_parent_environment(&parent_env);
227 std::vector<OString> child_env;
228 read_child_environment(&child_env);
230 OString msg(
231 OString::number(parent_env.size()) + "/"
232 + OString::number(child_env.size()));
233 auto min = std::min(parent_env.size(), child_env.size());
234 for (decltype(min) i = 0; i != min; ++i) {
235 CPPUNIT_ASSERT_EQUAL_MESSAGE(
236 msg.getStr(), parent_env[i], child_env[i]);
238 if (parent_env.size() != child_env.size()) {
239 CPPUNIT_ASSERT_EQUAL_MESSAGE(
240 (parent_env.size() >= child_env.size()
241 ? parent_env.back() : child_env.back()).getStr(),
242 parent_env.size(), child_env.size());
246 // compare the equal environment parts and the
247 // different part of the child environment
248 bool compare_merged_environments(const std::vector<OString>& different_env_vars)
250 std::vector<OString> parent_env;
251 read_parent_environment(&parent_env);
253 for (auto& env : parent_env)
254 std::cout << "initially parent env: " << env << "\n";
256 //remove the environment variables that we have changed
257 //in the child environment from the read parent environment
258 parent_env.erase(
259 std::remove_if(parent_env.begin(), parent_env.end(), exclude(different_env_vars)),
260 parent_env.end());
262 for (auto& env : parent_env)
263 std::cout << "stripped parent env: " << env << "\n";
265 //read the child environment and exclude the variables that
266 //are different
267 std::vector<OString> child_env;
268 read_child_environment(&child_env);
270 for (auto& env : child_env)
271 std::cout << "initial child env: " << env << "\n";
272 //partition the child environment into the variables that
273 //are different to the parent environment (they come first)
274 //and the variables that should be equal between parent
275 //and child environment
276 auto iter_logical_end =
277 std::stable_partition(child_env.begin(), child_env.end(), exclude(different_env_vars));
279 std::vector<OString> different_child_env_vars(child_env.begin(), iter_logical_end);
280 child_env.erase(child_env.begin(), iter_logical_end);
282 for (auto& env : child_env)
283 std::cout << "stripped child env: " << env << "\n";
285 bool common_env_size_equals = (parent_env.size() == child_env.size());
286 bool common_env_content_equals = std::equal(child_env.begin(), child_env.end(), parent_env.begin());
288 for (auto& env_var : different_env_vars)
289 std::cout << "different should be: " << env_var << "\n";
291 for (auto& env_var : different_child_env_vars)
292 std::cout << "different are: " << env_var << "\n";
294 bool different_env_size_equals = (different_child_env_vars.size() == different_env_vars.size());
295 bool different_env_content_equals =
296 std::equal(different_env_vars.begin(), different_env_vars.end(), different_child_env_vars.begin());
298 return (common_env_size_equals && common_env_content_equals &&
299 different_env_size_equals && different_env_content_equals);
302 // test that parent and child process have the
303 // same environment when osl_executeProcess will
304 // be called without setting new environment
305 // variables
306 void osl_execProc_parent_equals_child_environment()
308 oslProcess process;
309 oslProcessError osl_error = osl_executeProcess(
310 suExecutableFileURL.pData,
311 parameters_,
312 parameters_count_,
313 osl_Process_NORMAL,
314 nullptr,
315 suCWD.pData,
316 nullptr,
318 &process);
320 CPPUNIT_ASSERT_EQUAL_MESSAGE
322 "osl_createProcess failed",
323 osl_Process_E_None, osl_error
326 osl_error = ::osl_joinProcess(process);
328 CPPUNIT_ASSERT_EQUAL_MESSAGE
330 "osl_joinProcess returned with failure",
331 osl_Process_E_None, osl_error
334 osl_freeProcessHandle(process);
336 compare_environments();
339 #define ENV1 "PAT=a:\\"
340 #define ENV2 "PATHb=b:\\"
341 #define ENV3 "Patha=c:\\"
342 #define ENV4 "Patha=d:\\"
344 void osl_execProc_merged_child_environment()
346 rtl_uString* child_env[4];
347 OUString env1(ENV1);
348 OUString env2(ENV2);
349 OUString env3(ENV3);
350 OUString env4(ENV4);
352 child_env[0] = env1.pData;
353 child_env[1] = env2.pData;
354 child_env[2] = env3.pData;
355 child_env[3] = env4.pData;
357 oslProcess process;
358 oslProcessError osl_error = osl_executeProcess(
359 suExecutableFileURL.pData,
360 parameters_,
361 parameters_count_,
362 osl_Process_NORMAL,
363 nullptr,
364 suCWD.pData,
365 child_env,
366 SAL_N_ELEMENTS(child_env),
367 &process);
369 CPPUNIT_ASSERT_EQUAL_MESSAGE
371 "osl_createProcess failed",
372 osl_Process_E_None, osl_error
375 osl_error = ::osl_joinProcess(process);
377 CPPUNIT_ASSERT_EQUAL_MESSAGE
379 "osl_joinProcess returned with failure",
380 osl_Process_E_None, osl_error
383 osl_freeProcessHandle(process);
385 std::vector<OString> different_child_env_vars
387 ENV1,
388 ENV2,
389 ENV4
392 CPPUNIT_ASSERT_MESSAGE
394 "osl_execProc_merged_child_environment",
395 compare_merged_environments(different_child_env_vars)
399 #endif
401 void osl_execProc_test_batch()
403 oslProcess process;
404 #if defined(_WIN32)
405 OUString suBatch = suCWD + "/batch.bat";
406 #else
407 OUString suBatch = suCWD + "/batch.sh";
408 #endif
409 oslProcessError osl_error = osl_executeProcess(
410 suBatch.pData,
411 nullptr,
413 osl_Process_NORMAL,
414 nullptr,
415 suCWD.pData,
416 nullptr,
418 &process);
420 CPPUNIT_ASSERT_EQUAL_MESSAGE
422 "osl_createProcess failed",
423 osl_Process_E_None, osl_error
426 osl_error = ::osl_joinProcess(process);
428 CPPUNIT_ASSERT_EQUAL_MESSAGE
430 "osl_joinProcess returned with failure",
431 osl_Process_E_None, osl_error
434 osl_freeProcessHandle(process);
437 CPPUNIT_TEST_SUITE(Test_osl_executeProcess);
438 //TODO: Repair these (at least under Windows)
439 #if !defined(_WIN32)
440 CPPUNIT_TEST(osl_execProc_parent_equals_child_environment);
441 CPPUNIT_TEST(osl_execProc_merged_child_environment);
442 #endif
443 CPPUNIT_TEST(osl_execProc_test_batch);
444 ///TODO: Repair test (or tested function ;-) - test fails.
445 CPPUNIT_TEST_SUITE_END();
448 CPPUNIT_TEST_SUITE_REGISTRATION(Test_osl_executeProcess);
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */