bool TestExtProcess::test_proc_open_env_inh() {
  Array descriptorspec =
    CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
                1, CREATE_VECTOR2("pipe", "w"),
                2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));

  Variant pipes;

  g_context->setenv("inherit_me", "please");
  Variant process = f_proc_open("echo $inherit_me", descriptorspec, ref(pipes));
  VERIFY(!same(process, false));

  {
    File *f = pipes[1].toObject().getTyped<File>();
    VERIFY(f->valid());
    StringBuffer sbuf;
    sbuf.read(f);
    f->close();
    VS(sbuf.detach(), "please\n");
  }

  VS(f_proc_close(process.toObject()), 0);

  // Ensure that PATH makes it through too
  process = f_proc_open("echo $PATH", descriptorspec, ref(pipes));
  VERIFY(!same(process, false));

  {
    File *f = pipes[1].toObject().getTyped<File>();
    VERIFY(f->valid());
    StringBuffer sbuf;
    sbuf.read(f);
    f->close();

    VERIFY(sbuf.length() != 0);
  }

  VS(f_proc_close(process.toObject()), 0);

  // And check that the libc putenv() takes effect, even though we don't
  // want to use that in a threaded environment

  putenv("ZOO=animals");
  process = f_proc_open("echo $ZOO", descriptorspec, ref(pipes));
  VERIFY(!same(process, false));

  {
    File *f = pipes[1].toObject().getTyped<File>();
    VERIFY(f->valid());
    StringBuffer sbuf;
    sbuf.read(f);
    f->close();
    VS(sbuf.detach(), "animals\n");
  }

  VS(f_proc_close(process.toObject()), 0);

  return Count(true);
}
bool TestExtProcess::test_proc_open() {
  Array descriptorspec =
    CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
                1, CREATE_VECTOR2("pipe", "w"),
                2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
  String cwd = "/tmp";
  Array env = CREATE_MAP1("some_option", "aeiou");

  Variant pipes;
  Variant process = f_proc_open(php_path, descriptorspec, ref(pipes), cwd, env);
  VERIFY(!same(process, false));

  {
    File *f = pipes[0].toObject().getTyped<File>();
    VERIFY(f->valid());
    String s("<?php print(getenv('some_option')); ?>", AttachLiteral);
    f->write(s);
    f->close();
  }
  {
    File *f = pipes[1].toObject().getTyped<File>();
    VERIFY(f->valid());
    StringBuffer sbuf;
    sbuf.read(f);
    f->close();
    VS(sbuf.detach(), "aeiou");
  }

  VS(f_proc_close(process.toObject()), 0);
  return Count(true);
}
bool TestExtProcess::test_proc_get_status() {
  Array descriptorspec =
    CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
                1, CREATE_VECTOR2("pipe", "w"),
                2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
  Variant pipes;
  Variant process = f_proc_open("php", descriptorspec, ref(pipes));
  VERIFY(!same(process, false));
  Array ret = f_proc_get_status(process.toObject());
  VS(ret["command"], "php");
  VERIFY(ret["pid"].toInt32() > 0);
  VERIFY(ret["running"]);
  VERIFY(!ret["signaled"]);
  VS(ret["exitcode"], -1);
  VS(ret["termsig"], 0);
  VS(ret["stopsig"], 0);

  {
    File *f = pipes[0].toObject().getTyped<File>();
    VERIFY(f->valid());
    f->close();
  }
  {
    File *f = pipes[1].toObject().getTyped<File>();
    VERIFY(f->valid());
    f->close();
  }
  VS(f_proc_close(process.toObject()), 0);
  return Count(true);
}
bool TestExtProcess::test_proc_terminate() {
  Array descriptorspec =
    CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
                1, CREATE_VECTOR2("pipe", "w"),
                2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
  Variant pipes;
  Variant process = f_proc_open(php_path, descriptorspec, ref(pipes));
  VERIFY(!same(process, false));
  VERIFY(f_proc_terminate(process.toObject()));
  // still need to close it, not to leave a zombie behind
  f_proc_close(process.toObject());
  return Count(true);
}
bool TestExtProcess::test_proc_get_status() {
  static const StaticString
    s_command("command"),
    s_pid("pid"),
    s_running("running"),
    s_signaled("signaled"),
    s_exitcode("exitcode"),
    s_termsig("termsig"),
    s_stopsig("stopsig");

  Array descriptorspec =
    CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
                1, CREATE_VECTOR2("pipe", "w"),
                2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));
  Variant pipes;
  Variant process = f_proc_open(php_path, descriptorspec, ref(pipes));
  VERIFY(!same(process, false));
  Array ret = f_proc_get_status(process.toObject());
  VS(ret[s_command], php_path);
  VERIFY(ret[s_pid].toInt32() > 0);
  VERIFY(ret[s_running]);
  VERIFY(!ret[s_signaled]);
  VS(ret[s_exitcode], -1);
  VS(ret[s_termsig], 0);
  VS(ret[s_stopsig], 0);

  {
    File *f = pipes[0].toObject().getTyped<File>();
    VERIFY(f->valid());
    f->close();
  }
  {
    File *f = pipes[1].toObject().getTyped<File>();
    VERIFY(f->valid());
    f->close();
  }
  VS(f_proc_close(process.toObject()), 0);
  return Count(true);
}
bool TestExtProcess::test_proc_open_env_inh() {
    Array descriptorspec =
        CREATE_MAP3(0, CREATE_VECTOR2("pipe", "r"),
                    1, CREATE_VECTOR2("pipe", "w"),
                    2, CREATE_VECTOR3("file", "/tmp/error-output.txt", "a"));

    Variant pipes;
    g_context->setenv("inherit_me", "please");
    Variant process = f_proc_open("echo $inherit_me", descriptorspec, ref(pipes));
    VERIFY(!same(process, false));

    {
        File *f = pipes[1].toObject().getTyped<File>();
        VERIFY(f->valid());
        StringBuffer sbuf;
        sbuf.read(f);
        f->close();
        VS(sbuf.detach(), "please\n");
    }

    VS(f_proc_close(process.toObject()), 0);

    return Count(true);
}