testSystemTools.cxx 31.6 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 <stdlib.h> /* free */
26
#include <string.h> /* strcmp */
27
#if defined(_WIN32) && !defined(__CYGWIN__)
28 29 30 31
#include <io.h> /* _umask (MSVC) / umask (Borland) */
#ifdef _MSC_VER
#define umask _umask // Note this is still umask on Borland
#endif
32 33 34
#endif
#include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
// Visual C++ does not define mode_t (note that Borland does, however).
35
#if defined(_MSC_VER)
36 37
typedef unsigned short mode_t;
#endif
38

39 40 41
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" },
42
  { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" },
43 44
  { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" },
  { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" },
45
  { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" },
46 47
  { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" },
  { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" },
48
  { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" },
49 50
  { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" },
  { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" },
51
  { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" },
52 53
  { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" },
  { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" },
54
  { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" },
55
  { KWSYS_NULLPTR, KWSYS_NULLPTR }
56 57
};

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

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

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

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

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

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

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

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

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

139 140 141 142 143 144 145 146 147 148 149 150 151
  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;
  }

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

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

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

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

293
// Reset umask
294 295 296 297 298 299 300 301 302 303 304
#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;
305 306 307
  if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) {
    std::cerr << "Problem with GetPermissions (1) for: " << testNewFile
              << std::endl;
308
    res = false;
309
  }
310

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

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

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

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

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

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

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

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

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

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

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

  // Restore umask
  umask(orig_umask);

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

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

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

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

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

#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
429
  const std::string testNewLongDir(
430 431
    TEST_SYSTEMTOOLS_BINARY_DIR
    "/"
432 433 434 435 436
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "01234567890123");
437 438 439
  const std::string testNewLongFile(
    testNewLongDir +
    "/"
440 441 442 443 444 445
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "012345678901234567890123456789012345678901234567890123456789"
    "0123456789.txt");

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

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

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

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

470 471 472
  return res;
}

473
static bool CheckStringOperations()
474 475 476
{
  bool res = true;

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

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

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

501 502 503 504 505
  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;
506
    res = false;
507 508
  }
  delete[] cres;
509

510 511 512 513
  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;
514
    res = false;
515 516
  }
  delete[] cres;
517

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

524 525 526 527
  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;
528
    res = false;
529 530
  }
  delete[] cres;
531

532 533 534 535
  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;
536
    res = false;
537 538
  }
  delete[] cres;
539

540
  char* cres2 = strdup("Mary Had A Little Lamb.");
541 542 543 544
  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;
545
    res = false;
546
  }
547
  free(cres2);
548 549

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

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

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

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

Brad King's avatar
Brad King committed
578
  std::vector<std::string> lines;
579 580 581 582 583
  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;
584
    res = false;
585
  }
Ken Martin's avatar
Ken Martin committed
586

587 588 589 590 591
  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;
592
    res = false;
593
  }
594

595 596 597 598 599 600
  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;
601
    res = false;
602
  }
Ken Martin's avatar
Ken Martin committed
603

604 605 606 607 608
  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;
609
    res = false;
610
  }
Ken Martin's avatar
Ken Martin committed
611

612 613 614
  return res;
}

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

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

647
static bool CheckEnvironmentOperations()
648 649 650 651 652 653 654 655 656 657 658 659 660
{
  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;
}

661 662 663
static bool CheckRelativePath(const std::string& local,
                              const std::string& remote,
                              const std::string& expected)
664
{
Brad King's avatar
Brad King committed
665
  std::string result = kwsys::SystemTools::RelativePath(local, remote);
666 667 668
  if (!kwsys::SystemTools::ComparePath(expected, result)) {
    std::cerr << "RelativePath(" << local << ", " << remote << ")  yielded "
              << result << " instead of " << expected << std::endl;
669
    return false;
670
  }
671 672 673 674 675 676 677 678 679
  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");
680 681
  res &=
    CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash");
682 683 684 685
  res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin");
  return res;
}

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

static bool CheckCollapsePath()
{
  bool res = true;
  res &= CheckCollapsePath("/usr/share/*", "/usr/share/*");
  res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*");
703 704 705 706 707 708 709 710 711 712
  res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib");
  res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib");
  res &= CheckCollapsePath("/usr/share/../../lib", "/lib");
  res &= CheckCollapsePath("/usr/share/.././../lib", "/lib");
  res &= CheckCollapsePath("/../lib", "/lib");
  res &= CheckCollapsePath("/../lib/", "/lib");
  res &= CheckCollapsePath("/", "/");
  res &= CheckCollapsePath("C:/", "C:/");
  res &= CheckCollapsePath("C:/../", "C:/");
  res &= CheckCollapsePath("C:/../../", "C:/");
713 714 715
  return res;
}

716 717 718 719 720
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();
721 722
       i != vec.end(); ++i) {
    if (i != vec.begin()) {
723 724
      ss << ", ";
    }
725 726
    ss << *i;
  }
727 728 729 730 731 732 733 734 735 736 737 738 739 740
  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]";

741 742
  std::vector<std::string> originalPaths;
  originalPaths.push_back(registryPath);
743

744 745
  std::vector<std::string> expectedPaths;
  expectedPaths.push_back(registryPath);
746
#ifdef _WIN32
747 748
  expectedPaths.push_back("C:/Somewhere/something");
  expectedPaths.push_back("D:/Temp");
749
#else
750 751
  expectedPaths.push_back("/Somewhere/something");
  expectedPaths.push_back("/tmp");
752 753 754 755 756
#endif

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

757 758
  std::vector<std::string> paths = originalPaths;
  kwsys::SystemTools::GetPath(paths, envName);
759

760 761 762 763
  if (paths != expectedPaths) {
    std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", "
              << envName << ")  yielded " << StringVectorToString(paths)
              << " instead of " << StringVectorToString(expectedPaths)
764
              << std::endl;
765
    res = false;
766
  }
767 768 769 770 771

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

772 773 774 775 776
static bool CheckGetFilenameName()
{
  const char* windowsFilepath = "C:\\somewhere\\something";
  const char* unixFilepath = "/somewhere/something";

777 778 779 780 781 782
#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
  std::string expectedWindowsFilename = "something";
#else
  std::string expectedWindowsFilename = "C:\\somewhere\\something";
#endif
  std::string expectedUnixFilename = "something";
783 784 785

  bool res = true;
  std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath);
786
  if (filename != expectedWindowsFilename) {
787
    std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded "
788 789
              << filename << " instead of " << expectedWindowsFilename
              << std::endl;
790 791 792 793
    res = false;
  }

  filename = kwsys::SystemTools::GetFilenameName(unixFilepath);
794
  if (filename != expectedUnixFilename) {
795
    std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename
796
              << " instead of " << expectedUnixFilename << std::endl;
797 798 799 800 801
    res = false;
  }
  return res;
}

802 803 804 805
static bool CheckFind()
{
  bool res = true;
  const std::string testFindFileName("testFindFile.txt");
806 807
  const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" +
                                 testFindFileName);
808

809 810
  if (!kwsys::SystemTools::Touch(testFindFile.c_str(), true)) {
    std::cerr << "Problem with Touch for: " << testFindFile << std::endl;
811 812
    // abort here as the existence of the file only makes the test meaningful
    return false;
813
  }
814 815 816

  std::vector<std::string> searchPaths;
  searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR);
817 818 819 820
  if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true)
        .empty()) {
    std::cerr << "Problem with FindFile without system paths for: "
              << testFindFileName << std::endl;
821
    res = false;
822 823 824 825 826
  }
  if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false)
        .empty()) {
    std::cerr << "Problem with FindFile with system paths for: "
              << testFindFileName << std::endl;
827
    res = false;
828
  }
829 830 831 832

  return res;
}

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
static bool CheckIsSubDirectory()
{
  bool res = true;

  if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) {
    std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl;
    res = false;
  }
  if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) {
    std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl;
    res = false;
  }
  if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) {
    std::cerr << "Problem with IsSubDirectory (deep): " << std::endl;
    res = false;
  }
  if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) {
    std::cerr << "Problem with IsSubDirectory (identity): " << std::endl;
    res = false;
  }
  if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) {
    std::cerr << "Problem with IsSubDirectory (substring): " << std::endl;
    res = false;
  }
  if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) {
    std::cerr << "Problem with IsSubDirectory (prepended slash): "
              << std::endl;
    res = false;
  }

  return res;
}

866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
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;

901
  for (size_t size = 1; size <= 5; ++size) {
902
    file.seekg(0, std::ios::beg);
903 904
    result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline,
                                                   static_cast<long>(size));
905 906 907 908 909 910 911 912 913 914
    if (!result || line.size() != size) {
      std::cerr << "Should have read " << size << " characters but got "
                << line.size() << std::endl;
      ret = false;
    }
  }

  return ret;
}

915
int testSystemTools(int, char* [])
916
{
917 918
  bool res = true;

919
  int cc;
920
  for (cc = 0; toUnixPaths[cc][0]; cc++) {
921
    res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]);