/**
   * Test for the SystemUtils.createTempDir() and SystemUtils.deleteDirectory() methods.
   *
   * @throws Exception
   */
  @Test
  public void testCreateDeleteTempDir() throws Exception {

    /* create a temporary directory, making sure that it exists after it's created */
    File dir1 = SystemUtils.createTempDir();
    assertTrue(dir1.exists());

    /* create a second temporary directory, making sure it's different from the first */
    File dir2 = SystemUtils.createTempDir();
    assertTrue(dir1.exists());
    assertNotSame(dir1.toString(), dir2.toString());

    /* store some additional files/directories in the first temp directory */
    File subdir1 = new File(dir1, "subdir1");
    File subdir2 = new File(dir1, "subdir2");
    assertTrue(subdir1.mkdir());
    assertTrue(subdir2.mkdir());
    assertTrue(new File(dir1, "file1").createNewFile());
    assertTrue(new File(dir1, "file2").createNewFile());
    assertTrue(new File(subdir1, "file3").createNewFile());
    assertTrue(new File(subdir1, "file4").createNewFile());

    /* delete the second temp dir */
    assertTrue(SystemUtils.deleteDirectory(dir2));

    /* delete the first temp dir */
    assertTrue(SystemUtils.deleteDirectory(dir1));
  }
  /**
   * Test method for traverseFileSystem
   *
   * @throws Exception
   */
  @Test
  public void testTraverseFileSystem() throws Exception {

    /*
     * Create an object of type FileSystemTraverseCallback that'll be called for each
     * file system path that's reported. Calling getNames() returns an array of Strings
     * containing the file names.
     */
    TestCallback callbackCollector = new TestCallback();

    /* Test a non-existent directory */
    SystemUtils.traverseFileSystem(
        "/non-existent",
        SystemUtils.REPORT_DIRECTORIES | SystemUtils.REPORT_FILES,
        callbackCollector);
    String names[] = callbackCollector.getNames();
    assertEquals(0, names.length);

    /* report all directories in our test hierarchy */
    SystemUtils.traverseFileSystem(
        ourTempDir.toString(), SystemUtils.REPORT_DIRECTORIES, callbackCollector);
    names = callbackCollector.getNames();
    assertEquals(5, names.length);
    assertSortedPathArraysEqual(
        ourTempDir.toString(),
        names,
        new String[] {"", "/dirA", "/dirA/nested", "/dirA/nested/dirB", "/dirC"});

    /* report all files in our test hierarchy */
    SystemUtils.traverseFileSystem(
        ourTempDir.toString(), SystemUtils.REPORT_FILES, callbackCollector);
    names = callbackCollector.getNames();
    assertSortedPathArraysEqual(
        ourTempDir.toString(),
        names,
        new String[] {
          "/dirA/fileInDirA",
          "/dirA/nested/dirB/aThirdFileInDirB",
          "/dirA/nested/dirB/anotherFileInDirB",
          "/dirA/nested/dirB/fileInDirB",
          "/dirA/nested/dirB/onelastFileInDirB",
          "/topLevelFile"
        });

    /* report all files and directories in our test hierarchy */
    SystemUtils.traverseFileSystem(
        ourTempDir.toString(),
        SystemUtils.REPORT_FILES | SystemUtils.REPORT_DIRECTORIES,
        callbackCollector);
    names = callbackCollector.getNames();
    assertSortedPathArraysEqual(
        ourTempDir.toString(),
        names,
        new String[] {
          "",
          "/dirA",
          "/dirA/fileInDirA",
          "/dirA/nested",
          "/dirA/nested/dirB",
          "/dirA/nested/dirB/aThirdFileInDirB",
          "/dirA/nested/dirB/anotherFileInDirB",
          "/dirA/nested/dirB/fileInDirB",
          "/dirA/nested/dirB/onelastFileInDirB",
          "/dirC",
          "/topLevelFile"
        });

    /* filter out the "nested" directory */
    SystemUtils.traverseFileSystem(
        ourTempDir.toString(),
        null,
        "nested",
        SystemUtils.REPORT_FILES | SystemUtils.REPORT_DIRECTORIES,
        callbackCollector);
    names = callbackCollector.getNames();
    assertSortedPathArraysEqual(
        ourTempDir.toString(),
        names,
        new String[] {"", "/dirA", "/dirA/fileInDirA", "/dirC", "/topLevelFile"});

    /* filter out the "nested" and "dirC" directories */
    SystemUtils.traverseFileSystem(
        ourTempDir.toString(),
        null,
        "nested|dirC",
        SystemUtils.REPORT_FILES | SystemUtils.REPORT_DIRECTORIES,
        callbackCollector);
    names = callbackCollector.getNames();
    assertSortedPathArraysEqual(
        ourTempDir.toString(),
        names,
        new String[] {"", "/dirA", "/dirA/fileInDirA", "/topLevelFile"});

    /* only return the files that have "In" in their name */
    SystemUtils.traverseFileSystem(
        ourTempDir.toString(), ".*In.*", null, SystemUtils.REPORT_FILES, callbackCollector);
    names = callbackCollector.getNames();
    assertSortedPathArraysEqual(
        ourTempDir.toString(),
        names,
        new String[] {
          "/dirA/fileInDirA",
          "/dirA/nested/dirB/aThirdFileInDirB",
          "/dirA/nested/dirB/anotherFileInDirB",
          "/dirA/nested/dirB/fileInDirB",
          "/dirA/nested/dirB/onelastFileInDirB"
        });
  }
  /**
   * Test method for {@link com.buildml.utils.os.SystemUtils#executeShellCmd(java.lang.String[],
   * java.lang.String)}.
   *
   * @throws InterruptedException
   * @throws IOException
   */
  @Test
  public void testExecuteShellCmd() throws IOException, InterruptedException {

    ShellResult sr;

    /* Execute an invalid command - should return an IOException */
    try {
      sr = SystemUtils.executeShellCmd(new String[] {"/blah"}, "Hello World\n");
      fail("Failed to throw IOException when executing invalid command");
    } catch (IOException ex) {
      /* passed */
    }

    /* request a specific error code - our perl script always does exit() with it's second argument */
    sr = SystemUtils.executeShellCmd(new String[] {ourTempExe.toString(), "0", "23"}, "\n");
    assertEquals(sr.getReturnCode(), 23);

    /* Simply echo back our stdin - the stdout should be identical to the stdin we provided. */
    sr =
        SystemUtils.executeShellCmd(
            new String[] {ourTempExe.toString(), "0", "0"}, "Hello World\n");
    assertEquals(sr.getReturnCode(), 0);
    assertEquals("Hello World\n", sr.getStdout());
    assertEquals("", sr.getStderr());

    /* Same, but with multiple lines of text. */
    sr =
        SystemUtils.executeShellCmd(
            new String[] {ourTempExe.toString(), "0", "0"}, "Hello World\nHow are you?\n");
    assertEquals(sr.getReturnCode(), 0);
    assertEquals("Hello World\nHow are you?\n", sr.getStdout());
    assertEquals("", sr.getStderr());

    /*
     * Now get the program to generate some of its own output - that is, 5 letters on stdout
     * and 5 digits on stderr.
     */
    sr = SystemUtils.executeShellCmd(new String[] {ourTempExe.toString(), "5", "0"}, "Hi\n");
    assertEquals(sr.getReturnCode(), 0);
    assertEquals("Hi\nABCDE\n", sr.getStdout());
    assertEquals("01234\n", sr.getStderr());

    /*
     * Now try a really really big case, where the stdout and stderr will certainly be intermingled.
     */
    int count = 250000;
    sr =
        SystemUtils.executeShellCmd(
            new String[] {ourTempExe.toString(), String.valueOf(count)}, "");
    assertEquals(sr.getReturnCode(), 0);

    /* first, check the lengths */
    String stdOut = sr.getStdout();
    String stdErr = sr.getStderr();
    assertEquals(count + 1, stdOut.length()); /* include the trailing \n */
    assertEquals(count + 1, stdErr.length());

    /* now check each individual character of what was returned */
    for (int i = 0; i != count; i++) {
      char ch = stdOut.charAt(i);
      int num = (int) stdErr.charAt(i) - '0';
      assertEquals('A' + (i % 26), ch);
      assertEquals(i % 10, num);
    }

    /*
     * Test the non-buffering variant. Even though there's output, we shouldn't get any
     * of it.
     */
    sr =
        SystemUtils.executeShellCmd(
            new String[] {ourTempExe.toString(), "0", "0"}, "Hello World\n", null, false, null);
    assertEquals(sr.getReturnCode(), 0);
    assertEquals("", sr.getStdout());
    assertEquals("", sr.getStderr());

    /*
     * Test with an invalid working directory
     */
    try {
      sr =
          SystemUtils.executeShellCmd(
              new String[] {ourTempExe.toString(), "0", "0"},
              "Hello World\n",
              null,
              false,
              new File("/invalid-path"));
      fail("Failed to throw IOException when executing in invalid directory.");
    } catch (IOException ex) {
      /* passed */
    }

    /*
     * Test with a valid working directory
     */
    sr =
        SystemUtils.executeShellCmd(
            new String[] {ourTempExe.toString(), "0", "0"},
            "Hello World\n",
            null,
            false,
            new File("/tmp"));
    assertEquals(sr.getReturnCode(), 0);
    assertEquals("", sr.getStdout());
    assertEquals("", sr.getStderr());

    /*
     * Note: we can't automatically test the echoToOutput option, unless we had a way to
     * observe our own standard output.
     */
  }