testSystemTools.cxx 29 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
#include "kwsysPrivate.h"
4 5

#if defined(_MSC_VER)
6
#pragma warning(disable : 4786)
7 8
#endif

9
#include KWSYS_HEADER(FStream.hxx)
10 11
#include KWSYS_HEADER(SystemTools.hxx)

12 13 14
// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
15
#include "FStream.hxx.in"
16
#include "SystemTools.hxx.in"
17 18
#endif

19 20 21
// Include with <> instead of "" to avoid getting any in-source copy
// left on disk.
#include <testSystemTools.h>
22

23
#include <iostream>
24
#include <sstream>
25
#include <string.h> /* strcmp */
26
#if defined(_WIN32) && !defined(__CYGWIN__)
27 28 29 30
#include <io.h> /* _umask (MSVC) / umask (Borland) */
#ifdef _MSC_VER
#define umask _umask // Note this is still umask on Borland
#endif
31 32 33
#endif
#include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
// Visual C++ does not define mode_t (note that Borland does, however).
34
#if defined(_MSC_VER)
35 36
typedef unsigned short mode_t;
#endif
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
static const char* toUnixPaths[][2] = {
  { "/usr/local/bin/passwd", "/usr/local/bin/passwd" },
  { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" },
  { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" },
  { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" },
  { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" },
  { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" },
  { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" },
  { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" },
  { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" },
  { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" },
  { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" },
  { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" },
  { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" },
  { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" },
  { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo\\ cal/bin/pa\\ sswd" },
  { 0, 0 }
55 56
};

Daniel Pfeifer's avatar
Daniel Pfeifer committed
57 58
static bool CheckConvertToUnixSlashes(std::string const& input,
                                      std::string const& output)
59
{
Brad King's avatar
Brad King committed
60
  std::string result = input;
61
  kwsys::SystemTools::ConvertToUnixSlashes(result);
62 63 64
  if (result != output) {
    std::cerr << "Problem with ConvertToUnixSlashes - input: " << input
              << " output: " << result << " expected: " << output << std::endl;
65
    return false;
66
  }
67 68 69
  return true;
}

70 71 72 73
static const char* checkEscapeChars[][4] = { { "1 foo 2 bar 2", "12", "\\",
                                               "\\1 foo \\2 bar \\2" },
                                             { " {} ", "{}", "#", " #{#} " },
                                             { 0, 0, 0, 0 } };
74

Daniel Pfeifer's avatar
Daniel Pfeifer committed
75 76 77
static bool CheckEscapeChars(std::string const& input,
                             const char* chars_to_escape, char escape_char,
                             std::string const& output)
78
{
Brad King's avatar
Brad King committed
79
  std::string result = kwsys::SystemTools::EscapeChars(
80
    input.c_str(), chars_to_escape, escape_char);
81 82 83
  if (result != output) {
    std::cerr << "Problem with CheckEscapeChars - input: " << input
              << " output: " << result << " expected: " << output << std::endl;
84
    return false;
85
  }
86 87 88
  return true;
}

89
static bool CheckFileOperations()
90 91
{
  bool res = true;
Brad King's avatar
Brad King committed
92
  const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR
93 94
                                        "/testSystemToolsNonExistingFile");
  const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/.");
Brad King's avatar
Brad King committed
95
  const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR
96
                                "/testSystemTools.bin");
Brad King's avatar
Brad King committed
97
  const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR
98
                                "/testSystemTools.cxx");
Brad King's avatar
Brad King committed
99
  const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR
100
                               "/testSystemToolsNewDir");
Brad King's avatar
Brad King committed
101
  const std::string testNewFile(testNewDir + "/testNewFile.txt");
102

103
  if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) !=
104 105 106
      kwsys::SystemTools::FileTypeUnknown) {
    std::cerr << "Problem with DetectFileType - failed to detect type of: "
              << testNonExistingFile << std::endl;
107
    res = false;
108
  }
109

110
  if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) !=
111 112 113
      kwsys::SystemTools::FileTypeUnknown) {
    std::cerr << "Problem with DetectFileType - failed to detect type of: "
              << testDotFile << std::endl;
114
    res = false;
115
  }
116

117
  if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) !=
118 119 120
      kwsys::SystemTools::FileTypeBinary) {
    std::cerr << "Problem with DetectFileType - failed to detect type of: "
              << testBinFile << std::endl;
121
    res = false;
122
  }
123

124
  if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) !=
125 126 127
      kwsys::SystemTools::FileTypeText) {
    std::cerr << "Problem with DetectFileType - failed to detect type of: "
              << testTxtFile << std::endl;
128
    res = false;
129
  }
130

131 132 133
  if (kwsys::SystemTools::FileLength(testBinFile) != 766) {
    std::cerr << "Problem with FileLength - incorrect length for: "
              << testBinFile << std::endl;
134
    res = false;
135
  }
136

137 138 139 140 141 142 143 144 145 146 147 148 149
  kwsys::SystemTools::Stat_t buf;
  if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) {
    std::cerr << "Problem with Stat - unable to stat text file: "
              << testTxtFile << std::endl;
    res = false;
  }

  if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) {
    std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile
              << std::endl;
    res = false;
  }

150 151
  if (!kwsys::SystemTools::MakeDirectory(testNewDir)) {
    std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl;
152
    res = false;
153
  }
154
  // calling it again should just return true
155 156 157
  if (!kwsys::SystemTools::MakeDirectory(testNewDir)) {
    std::cerr << "Problem with second call to MakeDirectory for: "
              << testNewDir << std::endl;
158
    res = false;
159
  }
160
  // calling with 0 pointer should return false
161 162
  if (kwsys::SystemTools::MakeDirectory(0)) {
    std::cerr << "Problem with MakeDirectory(0)" << std::endl;
163
    res = false;
164
  }
165
  // calling with an empty string should return false
166 167
  if (kwsys::SystemTools::MakeDirectory(std::string())) {
    std::cerr << "Problem with MakeDirectory(std::string())" << std::endl;
168
    res = false;
169
  }
170
  // check existence
171 172 173
  if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
    std::cerr << "Problem with FileExists as C string and not file for: "
              << testNewDir << std::endl;
174
    res = false;
175
  }
176
  // check existence
177 178
  if (!kwsys::SystemTools::PathExists(testNewDir)) {
    std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
179
    res = false;
180
  }
181
  // remove it
182 183 184
  if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) {
    std::cerr << "Problem with RemoveADirectory for: " << testNewDir
              << std::endl;
185
    res = false;
186
  }
187
  // check existence
188 189 190 191
  if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
    std::cerr << "After RemoveADirectory: "
              << "Problem with FileExists as C string and not file for: "
              << testNewDir << std::endl;
192
    res = false;
193
  }
194
  // check existence
195 196 197
  if (kwsys::SystemTools::PathExists(testNewDir)) {
    std::cerr << "After RemoveADirectory: "
              << "Problem with PathExists for: " << testNewDir << std::endl;
198
    res = false;
199
  }
200
  // create it using the char* version
201 202 203
  if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) {
    std::cerr << "Problem with second call to MakeDirectory as C string for: "
              << testNewDir << std::endl;
204
    res = false;
205
  }
206

207 208
  if (!kwsys::SystemTools::Touch(testNewFile.c_str(), true)) {
    std::cerr << "Problem with Touch for: " << testNewFile << std::endl;
209
    res = false;
210
  }
211
  // calling MakeDirectory with something that is no file should fail
212 213 214
  if (kwsys::SystemTools::MakeDirectory(testNewFile)) {
    std::cerr << "Problem with to MakeDirectory for: " << testNewFile
              << std::endl;
215
    res = false;
216
  }
217

218
  // calling with 0 pointer should return false
219 220
  if (kwsys::SystemTools::FileExists(0)) {
    std::cerr << "Problem with FileExists(0)" << std::endl;
221
    res = false;
222 223 224
  }
  if (kwsys::SystemTools::FileExists(0, true)) {
    std::cerr << "Problem with FileExists(0) as file" << std::endl;
225
    res = false;
226
  }
227
  // calling with an empty string should return false
228 229
  if (kwsys::SystemTools::FileExists(std::string())) {
    std::cerr << "Problem with FileExists(std::string())" << std::endl;
230
    res = false;
231
  }
232
  // FileExists(x, true) should return false on a directory
233 234 235
  if (kwsys::SystemTools::FileExists(testNewDir, true)) {
    std::cerr << "Problem with FileExists as file for: " << testNewDir
              << std::endl;
236
    res = false;
237 238 239 240
  }
  if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) {
    std::cerr << "Problem with FileExists as C string and file for: "
              << testNewDir << std::endl;
241
    res = false;
242
  }
243
  // FileExists(x, false) should return true even on a directory
244 245 246
  if (!kwsys::SystemTools::FileExists(testNewDir, false)) {
    std::cerr << "Problem with FileExists as not file for: " << testNewDir
              << std::endl;
247
    res = false;
248 249 250 251
  }
  if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
    std::cerr << "Problem with FileExists as C string and not file for: "
              << testNewDir << std::endl;
252
    res = false;
253
  }
254
  // should work, was created as new file before
255 256
  if (!kwsys::SystemTools::FileExists(testNewFile)) {
    std::cerr << "Problem with FileExists for: " << testNewDir << std::endl;
257
    res = false;
258 259 260 261
  }
  if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) {
    std::cerr << "Problem with FileExists as C string for: " << testNewDir
              << std::endl;
262
    res = false;
263 264 265 266
  }
  if (!kwsys::SystemTools::FileExists(testNewFile, true)) {
    std::cerr << "Problem with FileExists as file for: " << testNewDir
              << std::endl;
267
    res = false;
268 269 270 271
  }
  if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) {
    std::cerr << "Problem with FileExists as C string and file for: "
              << testNewDir << std::endl;
272
    res = false;
273
  }
274

275
  // calling with an empty string should return false
276 277
  if (kwsys::SystemTools::PathExists(std::string())) {
    std::cerr << "Problem with PathExists(std::string())" << std::endl;
278
    res = false;
279
  }
280
  // PathExists(x) should return true on a directory
281 282
  if (!kwsys::SystemTools::PathExists(testNewDir)) {
    std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
283
    res = false;
284
  }
285
  // should work, was created as new file before
286 287
  if (!kwsys::SystemTools::PathExists(testNewFile)) {
    std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
288
    res = false;
289
  }
290

291
// Reset umask
292 293 294 295 296 297 298 299 300 301 302
#if defined(_WIN32) && !defined(__CYGWIN__)
  // NOTE:  Windows doesn't support toggling _S_IREAD.
  mode_t fullMask = _S_IWRITE;
#else
  // On a normal POSIX platform, we can toggle all permissions.
  mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO;
#endif
  mode_t orig_umask = umask(fullMask);

  // Test file permissions without umask
  mode_t origPerm, thisPerm;
303 304 305
  if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) {
    std::cerr << "Problem with GetPermissions (1) for: " << testNewFile
              << std::endl;
306
    res = false;
307
  }
308

309 310 311
  if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) {
    std::cerr << "Problem with SetPermissions (1) for: " << testNewFile
              << std::endl;
312
    res = false;
313
  }
314

315 316 317
  if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
    std::cerr << "Problem with GetPermissions (2) for: " << testNewFile
              << std::endl;
318
    res = false;
319
  }
320

321 322 323 324
  if ((thisPerm & fullMask) != 0) {
    std::cerr << "SetPermissions failed to set permissions (1) for: "
              << testNewFile << ": actual = " << thisPerm
              << "; expected = " << 0 << std::endl;
325
    res = false;
326
  }
327 328 329

  // While we're at it, check proper TestFileAccess functionality.
  if (kwsys::SystemTools::TestFileAccess(testNewFile,
330
                                         kwsys::TEST_FILE_WRITE)) {
331
    std::cerr
332
      << "TestFileAccess incorrectly indicated that this is a writable file:"
333
      << testNewFile << std::endl;
334
    res = false;
335
  }
336

337
  if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) {
338
    std::cerr
339
      << "TestFileAccess incorrectly indicated that this file does not exist:"
340
      << testNewFile << std::endl;
341
    res = false;
342
  }
343 344

  // Test restoring/setting full permissions.
345 346 347
  if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) {
    std::cerr << "Problem with SetPermissions (2) for: " << testNewFile
              << std::endl;
348
    res = false;
349
  }
350

351 352 353
  if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
    std::cerr << "Problem with GetPermissions (3) for: " << testNewFile
              << std::endl;
354
    res = false;
355
  }
356

357 358 359 360
  if ((thisPerm & fullMask) != fullMask) {
    std::cerr << "SetPermissions failed to set permissions (2) for: "
              << testNewFile << ": actual = " << thisPerm
              << "; expected = " << fullMask << std::endl;
361
    res = false;
362
  }
363 364

  // Test setting file permissions while honoring umask
365 366 367
  if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) {
    std::cerr << "Problem with SetPermissions (3) for: " << testNewFile
              << std::endl;
368
    res = false;
369
  }
370

371 372 373
  if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
    std::cerr << "Problem with GetPermissions (4) for: " << testNewFile
              << std::endl;
374
    res = false;
375
  }
376

377 378 379 380
  if ((thisPerm & fullMask) != 0) {
    std::cerr << "SetPermissions failed to honor umask for: " << testNewFile
              << ": actual = " << thisPerm << "; expected = " << 0
              << std::endl;
381
    res = false;
382
  }
383 384 385 386 387

  // Restore umask
  umask(orig_umask);

  // Restore file permissions
388 389 390
  if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) {
    std::cerr << "Problem with SetPermissions (4) for: " << testNewFile
              << std::endl;
391
    res = false;
392
  }
393 394

  // Remove the test file
395 396
  if (!kwsys::SystemTools::RemoveFile(testNewFile)) {
    std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl;
397
    res = false;
398
  }
399

Brad King's avatar
Brad King committed
400
  std::string const testFileMissing(testNewDir + "/testMissingFile.txt");
401
  if (!kwsys::SystemTools::RemoveFile(testFileMissing)) {
402
    std::string const& msg = kwsys::SystemTools::GetLastSystemError();
403 404
    std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg
              << "\n";
405
    res = false;
406
  }
407

Brad King's avatar
Brad King committed
408
  std::string const testFileMissingDir(testNewDir + "/missing/file.txt");
409
  if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) {
410
    std::string const& msg = kwsys::SystemTools::GetLastSystemError();
411 412
    std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg
              << "\n";
413
    res = false;
414
  }
415

416
  kwsys::SystemTools::Touch(testNewFile.c_str(), true);
417 418 419
  if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) {
    std::cerr << "Problem with RemoveADirectory for: " << testNewDir
              << std::endl;
420
    res = false;
421
  }
422 423 424 425 426

#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
  // Perform the same file and directory creation and deletion tests but
  // with paths > 256 characters in length.

Brad King's avatar
Brad King committed
427
  const std::string testNewLongDir(
428 429
    TEST_SYSTEMTOOLS_BINARY_DIR
    "/"
430 431 432 433 434
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "01234567890123");
435 436 437
  const std::string testNewLongFile(
    testNewLongDir +
    "/"
438 439 440 441 442 443
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "0123456789.txt");

444 445 446
  if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) {
    std::cerr << "Problem with MakeDirectory for: " << testNewLongDir
              << std::endl;
447
    res = false;
448
  }
449

450 451
  if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) {
    std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl;
452
    res = false;
453
  }
454

455 456
  if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) {
    std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl;
457
    res = false;
458
  }
459 460

  kwsys::SystemTools::Touch(testNewLongFile.c_str(), true);
461 462 463
  if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) {
    std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir
              << std::endl;
464
    res = false;
465
  }
466 467
#endif

468 469 470
  return res;
}

471
static bool CheckStringOperations()
472 473 474
{
  bool res = true;

Brad King's avatar
Brad King committed
475
  std::string test = "mary had a little lamb.";
476 477 478 479
  if (kwsys::SystemTools::CapitalizedWords(test) !=
      "Mary Had A Little Lamb.") {
    std::cerr << "Problem with CapitalizedWords " << '"' << test << '"'
              << std::endl;
480
    res = false;
481
  }
482 483

  test = "Mary Had A Little Lamb.";
484
  if (kwsys::SystemTools::UnCapitalizedWords(test) !=
485 486 487
      "mary had a little lamb.") {
    std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"'
              << std::endl;
488
    res = false;
489
  }
490 491

  test = "MaryHadTheLittleLamb.";
492
  if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) !=
493 494 495
      "Mary Had The Little Lamb.") {
    std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test
              << '"' << std::endl;
496
    res = false;
497
  }
498

499 500 501 502 503
  char* cres =
    kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb.");
  if (strcmp(cres, "Mary Had A Little Lamb.")) {
    std::cerr << "Problem with AppendStrings "
              << "\"Mary Had A\" \" Little Lamb.\"" << std::endl;
504
    res = false;
505 506
  }
  delete[] cres;
507

508 509 510 511
  cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb.");
  if (strcmp(cres, "Mary Had A Little Lamb.")) {
    std::cerr << "Problem with AppendStrings "
              << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl;
512
    res = false;
513 514
  }
  delete[] cres;
515

516 517 518
  if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) {
    std::cerr << "Problem with CountChar "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
519
    res = false;
520
  }
521

522 523 524 525
  cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou");
  if (strcmp(cres, "Mry Hd A Lttl Lmb.")) {
    std::cerr << "Problem with RemoveChars "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
526
    res = false;
527 528
  }
  delete[] cres;
529

530 531 532 533
  cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb.");
  if (strcmp(cres, "A")) {
    std::cerr << "Problem with RemoveCharsButUpperHex "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
534
    res = false;
535 536
  }
  delete[] cres;
537

538 539 540 541 542 543
  char* cres2 = new char[strlen("Mary Had A Little Lamb.") + 1];
  strcpy(cres2, "Mary Had A Little Lamb.");
  kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X');
  if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) {
    std::cerr << "Problem with ReplaceChars "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
544
    res = false;
545 546
  }
  delete[] cres2;
547 548

  if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.",
549 550 551
                                            "Mary ")) {
    std::cerr << "Problem with StringStartsWith "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
552
    res = false;
553
  }
554 555

  if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.",
556 557 558
                                          " Lamb.")) {
    std::cerr << "Problem with StringEndsWith "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
559
    res = false;
560
  }
561 562

  cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb.");
563 564 565
  if (strcmp(cres, "Mary Had A Little Lamb.")) {
    std::cerr << "Problem with DuplicateString "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
566
    res = false;
567 568
  }
  delete[] cres;
569 570

  test = "Mary Had A Little Lamb.";
571 572 573
  if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") {
    std::cerr << "Problem with CropString "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
574
    res = false;
575
  }
576

Brad King's avatar
Brad King committed
577
  std::vector<std::string> lines;
578 579 580 581 582
  kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' ');
  if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" ||
      lines[3] != "Little" || lines[4] != "Lamb.") {
    std::cerr << "Problem with Split "
              << "\"Mary Had A Little Lamb.\"" << std::endl;
583
    res = false;
584
  }
Ken Martin's avatar
Ken Martin committed
585

586 587 588 589 590
  if (kwsys::SystemTools::ConvertToWindowsOutputPath(
        "L://Local Mojo/Hex Power Pack/Iffy Voodoo") !=
      "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") {
    std::cerr << "Problem with ConvertToWindowsOutputPath "
              << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
591
    res = false;
592
  }
593

594 595 596 597 598 599
  if (kwsys::SystemTools::ConvertToWindowsOutputPath(
        "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
      "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") {
    std::cerr << "Problem with ConvertToWindowsOutputPath "
              << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\""
              << std::endl;
600
    res = false;
601
  }
Ken Martin's avatar
Ken Martin committed
602

603 604 605 606 607
  if (kwsys::SystemTools::ConvertToUnixOutputPath(
        "//Local Mojo/Hex Power Pack/Iffy Voodoo") !=
      "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") {
    std::cerr << "Problem with ConvertToUnixOutputPath "
              << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
608
    res = false;
609
  }
Ken Martin's avatar
Ken Martin committed
610

611 612 613
  return res;
}

614 615
static bool CheckPutEnv(const std::string& env, const char* name,
                        const char* value)
616
{
617 618
  if (!kwsys::SystemTools::PutEnv(env)) {
    std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl;
619
    return false;
620
  }
621 622
  std::string v = "(null)";
  kwsys::SystemTools::GetEnv(name, v);
623 624 625
  if (v != value) {
    std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \""
              << value << "\"!" << std::endl;
626
    return false;
627
  }
628 629 630
  return true;
}

631
static bool CheckUnPutEnv(const char* env, const char* name)
632
{
633 634
  if (!kwsys::SystemTools::UnPutEnv(env)) {
    std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl;
635
    return false;
636
  }
637
  std::string v;
638 639 640
  if (kwsys::SystemTools::GetEnv(name, v)) {
    std::cerr << "GetEnv(\"" << name << "\") returned \"" << v
              << "\", not (null)!" << std::endl;
641
    return false;
642
  }
643 644 645
  return true;
}

646
static bool CheckEnvironmentOperations()
647 648 649 650 651 652 653 654 655 656 657 658 659
{
  bool res = true;
  res &= CheckPutEnv("A=B", "A", "B");
  res &= CheckPutEnv("B=C", "B", "C");
  res &= CheckPutEnv("C=D", "C", "D");
  res &= CheckPutEnv("D=E", "D", "E");
  res &= CheckUnPutEnv("A", "A");
  res &= CheckUnPutEnv("B=", "B");
  res &= CheckUnPutEnv("C=D", "C");
  /* Leave "D=E" in environment so a memory checker can test for leaks.  */
  return res;
}

660 661 662
static bool CheckRelativePath(const std::string& local,
                              const std::string& remote,
                              const std::string& expected)
663
{
Brad King's avatar
Brad King committed
664
  std::string result = kwsys::SystemTools::RelativePath(local, remote);
665 666 667
  if (!kwsys::SystemTools::ComparePath(expected, result)) {
    std::cerr << "RelativePath(" << local << ", " << remote << ")  yielded "
              << result << " instead of " << expected << std::endl;
668
    return false;
669
  }
670 671 672 673 674 675 676 677 678
  return true;
}

static bool CheckRelativePaths()
{
  bool res = true;
  res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash");
  res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash");
  res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash");
679 680
  res &=
    CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash");
681 682 683 684
  res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin");
  return res;
}

685 686
static bool CheckCollapsePath(const std::string& path,
                              const std::string& expected)
687
{
Brad King's avatar
Brad King committed
688
  std::string result = kwsys::SystemTools::CollapseFullPath(path);
689 690 691
  if (!kwsys::SystemTools::ComparePath(expected, result)) {
    std::cerr << "CollapseFullPath(" << path << ")  yielded " << result
              << " instead of " << expected << std::endl;
692
    return false;
693
  }
694 695 696 697 698 699 700 701 702 703 704
  return true;
}

static bool CheckCollapsePath()
{
  bool res = true;
  res &= CheckCollapsePath("/usr/share/*", "/usr/share/*");
  res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*");
  return res;
}

705 706 707 708 709
static std::string StringVectorToString(const std::vector<std::string>& vec)
{
  std::stringstream ss;
  ss << "vector(";
  for (std::vector<std::string>::const_iterator i = vec.begin();
710 711
       i != vec.end(); ++i) {
    if (i != vec.begin()) {
712 713
      ss << ", ";
    }
714 715
    ss << *i;
  }
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
  ss << ")";
  return ss.str();
}

static bool CheckGetPath()
{
  const char* envName = "S";
#ifdef _WIN32
  const char* envValue = "C:\\Somewhere\\something;D:\\Temp";
#else
  const char* envValue = "/Somewhere/something:/tmp";
#endif
  const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]";

  std::vector<std::string> originalPathes;
  originalPathes.push_back(registryPath);

  std::vector<std::string> expectedPathes;
  expectedPathes.push_back(registryPath);
#ifdef _WIN32
  expectedPathes.push_back("C:/Somewhere/something");
  expectedPathes.push_back("D:/Temp");
#else
  expectedPathes.push_back("/Somewhere/something");
  expectedPathes.push_back("/tmp");
#endif

  bool res = true;
  res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue);

  std::vector<std::string> pathes = originalPathes;
  kwsys::SystemTools::GetPath(pathes, envName);

749 750 751 752 753
  if (pathes != expectedPathes) {
    std::cerr << "GetPath(" << StringVectorToString(originalPathes) << ", "
              << envName << ")  yielded " << StringVectorToString(pathes)
              << " instead of " << StringVectorToString(expectedPathes)
              << std::endl;
754
    res = false;
755
  }
756 757 758 759 760

  res &= CheckUnPutEnv(envName, envName);
  return res;
}

761 762 763 764
static bool CheckFind()
{
  bool res = true;
  const std::string testFindFileName("testFindFile.txt");
765 766
  const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" +
                                 testFindFileName);
767

768 769
  if (!kwsys::SystemTools::Touch(testFindFile.c_str(), true)) {
    std::cerr << "Problem with Touch for: " << testFindFile << std::endl;
770 771
    // abort here as the existence of the file only makes the test meaningful
    return false;
772
  }
773 774 775

  std::vector<std::string> searchPaths;
  searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR);
776 777 778 779
  if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true)
        .empty()) {
    std::cerr << "Problem with FindFile without system paths for: "
              << testFindFileName << std::endl;
780
    res = false;
781 782 783 784 785
  }
  if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false)
        .empty()) {
    std::cerr << "Problem with FindFile with system paths for: "
              << testFindFileName << std::endl;
786
    res = false;
787
  }
788 789 790 791

  return res;
}

792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
static bool CheckGetLineFromStream()
{
  const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR
                                                 "/README.rst");

  kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in);

  if (!file) {
    std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine
              << std::endl;
    return false;
  }

  std::string line;
  bool has_newline = false;
  bool result;

  file.seekg(0, std::ios::beg);
  result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
  if (!result || line.size() != 5) {
    std::cerr << "First line does not have five characters: " << line.size()
              << std::endl;
    return false;
  }

  file.seekg(0, std::ios::beg);
  result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
  if (!result || line.size() != 5) {
    std::cerr << "First line does not have five characters after rewind: "
              << line.size() << std::endl;
    return false;
  }

  bool ret = true;

827
  for (size_t size = 1; size <= 5; ++size) {
828
    file.seekg(0, std::ios::beg);
829 830
    result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline,
                                                   static_cast<long>(size));
831 832 833 834 835 836 837 838 839 840
    if (!result || line.size() != size) {
      std::cerr << "Should have read " << size << " characters but got "
                << line.size() << std::endl;
      ret = false;
    }
  }

  return ret;
}

841
int testSystemTools(int, char* [])
842
{
843 844
  bool res = true;

845
  int cc;
846
  for (cc = 0; toUnixPaths[cc][0]; cc++) {
847
    res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]);
848
  }
849 850

  // Special check for ~
Brad King's avatar
Brad King committed
851
  std::string output;
852
  if (kwsys::SystemTools::GetEnv("HOME", output)) {
853
    output += "/foo bar/lala";
854
    res &= CheckConvertToUnixSlashes("~/foo bar/lala", output);
855
  }
856

857
  for (cc = 0; checkEscapeChars[cc][0]; cc++) {
858
    res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1],
859
                            *checkEscapeChars[cc][2], checkEscapeChars[cc][3]);
860
  }
861

Ken Martin's avatar
Ken Martin committed
862
  res &= CheckFileOperations();
863

864 865
  res &= CheckStringOperations();

866 867
  res &= CheckEnvironmentOperations();

868 869
  res &= CheckRelativePaths();

870 871
  res &= CheckCollapsePath();

872 873
  res &= CheckGetPath();

874 875
  res &= CheckFind();

876 877
  res &= CheckGetLineFromStream();

878
  return res ? 0 : 1;
879
}