This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 97802bd9e0ae57ec18a74e777a58f2eb143c4aa7
Author: cuiziwei <[email protected]>
AuthorDate: Tue Apr 28 17:29:12 2026 +0800

    testing/libc/popen: add popen/dpopen test for shell and no-shell modes
    
    Add tests for popen()/pclose() and dpopen()/dpclose() that work in
    both shell (NSH) and no-shell (direct posix_spawnp) modes.  The test
    binary doubles as its own target via the --echo sub-command.
    
    Tests:
     1-4: popen  - basic read, multi-arg, pclose, invalid mode
     5-7: dpopen - basic read, multi-arg, dpclose
    
    Signed-off-by: cuiziwei <[email protected]>
---
 testing/libc/popen/CMakeLists.txt |  33 +++++
 testing/libc/popen/Kconfig        |  16 +++
 testing/libc/popen/Make.defs      |  25 ++++
 testing/libc/popen/Makefile       |  32 +++++
 testing/libc/popen/popen_test.c   | 250 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 356 insertions(+)

diff --git a/testing/libc/popen/CMakeLists.txt 
b/testing/libc/popen/CMakeLists.txt
new file mode 100644
index 000000000..867a56891
--- /dev/null
+++ b/testing/libc/popen/CMakeLists.txt
@@ -0,0 +1,33 @@
+# 
##############################################################################
+# apps/testing/libc/popen/CMakeLists.txt
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor
+# license agreements.  See the NOTICE file distributed with this work for
+# additional information regarding copyright ownership.  The ASF licenses this
+# file to you under the Apache License, Version 2.0 (the "License"); you may 
not
+# use this file except in compliance with the License.  You may obtain a copy 
of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+# 
##############################################################################
+
+if(CONFIG_TESTING_POPEN)
+  nuttx_add_application(
+    NAME
+    popen_test
+    STACKSIZE
+    ${CONFIG_DEFAULT_TASK_STACKSIZE}
+    MODULE
+    ${CONFIG_TESTING_POPEN}
+    SRCS
+    popen_test.c)
+endif()
diff --git a/testing/libc/popen/Kconfig b/testing/libc/popen/Kconfig
new file mode 100644
index 000000000..73d4beb36
--- /dev/null
+++ b/testing/libc/popen/Kconfig
@@ -0,0 +1,16 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config TESTING_POPEN
+       tristate "popen()/dpopen() test"
+       default n
+       depends on SYSTEM_POPEN
+       ---help---
+               Test popen()/pclose() and dpopen()/dpclose() in both shell
+               and no-shell modes. The test binary doubles as its own
+               popen/dpopen target via --echo.
+
+if TESTING_POPEN
+endif
diff --git a/testing/libc/popen/Make.defs b/testing/libc/popen/Make.defs
new file mode 100644
index 000000000..eac91c500
--- /dev/null
+++ b/testing/libc/popen/Make.defs
@@ -0,0 +1,25 @@
+############################################################################
+# apps/testing/libc/popen/Make.defs
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_TESTING_POPEN),)
+CONFIGURED_APPS += $(APPDIR)/testing/libc/popen
+endif
diff --git a/testing/libc/popen/Makefile b/testing/libc/popen/Makefile
new file mode 100644
index 000000000..1ef31c7ab
--- /dev/null
+++ b/testing/libc/popen/Makefile
@@ -0,0 +1,32 @@
+############################################################################
+# apps/testing/libc/popen/Makefile
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+PROGNAME = popen_test
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
+MODULE = $(CONFIG_TESTING_POPEN)
+
+MAINSRC = popen_test.c
+
+include $(APPDIR)/Application.mk
diff --git a/testing/libc/popen/popen_test.c b/testing/libc/popen/popen_test.c
new file mode 100644
index 000000000..bbe3a7e59
--- /dev/null
+++ b/testing/libc/popen/popen_test.c
@@ -0,0 +1,250 @@
+/****************************************************************************
+ * apps/testing/libc/popen/popen_test.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int test_popen_read(void)
+{
+  FILE *fp;
+  char buf[256];
+  int found = 0;
+
+  printf("[TEST 1] popen read...\n");
+  fp = popen("popen_test --echo hello_popen", "r");
+  if (fp == NULL)
+    {
+      printf("[FAIL] popen returned NULL\n");
+      return 1;
+    }
+
+  while (fgets(buf, sizeof(buf), fp) != NULL)
+    {
+      printf("  > %s", buf);
+      if (strstr(buf, "hello_popen"))
+        {
+          found = 1;
+        }
+    }
+
+  pclose(fp);
+  printf("%s\n", found ? "[PASS]" : "[FAIL] missing output");
+  return !found;
+}
+
+static int test_popen_multiarg(void)
+{
+  FILE *fp;
+  char buf[256];
+  int found = 0;
+
+  printf("[TEST 2] popen multi-arg...\n");
+  fp = popen("popen_test --echo aaa bbb ccc", "r");
+  if (fp == NULL)
+    {
+      printf("[FAIL] popen returned NULL\n");
+      return 1;
+    }
+
+  while (fgets(buf, sizeof(buf), fp) != NULL)
+    {
+      printf("  > %s", buf);
+      if (strstr(buf, "aaa bbb ccc"))
+        {
+          found = 1;
+        }
+    }
+
+  pclose(fp);
+  printf("%s\n", found ? "[PASS]" : "[FAIL] wrong output");
+  return !found;
+}
+
+static int test_pclose_complete(void)
+{
+  FILE *fp;
+  char buf[256];
+
+  printf("[TEST 3] pclose completes...\n");
+  fp = popen("popen_test --echo ok", "r");
+  if (fp == NULL)
+    {
+      printf("[FAIL] popen returned NULL\n");
+      return 1;
+    }
+
+  while (fgets(buf, sizeof(buf), fp) != NULL);
+  pclose(fp);
+  printf("[PASS]\n");
+  return 0;
+}
+
+static int test_popen_invalid_mode(void)
+{
+  FILE *fp;
+
+  printf("[TEST 4] popen invalid mode...\n");
+  fp = popen("popen_test", "x");
+  if (fp == NULL)
+    {
+      printf("[PASS]\n");
+      return 0;
+    }
+
+  pclose(fp);
+  printf("[FAIL] should return NULL\n");
+  return 1;
+}
+
+static int test_dpopen_read(void)
+{
+  char buf[256];
+  ssize_t n;
+  pid_t pid;
+  int found = 0;
+  int fd;
+
+  printf("[TEST 5] dpopen read...\n");
+  fd = dpopen("popen_test --echo hello_dpopen", O_RDONLY, &pid);
+  if (fd < 0)
+    {
+      printf("[FAIL] dpopen returned %d\n", fd);
+      return 1;
+    }
+
+  while ((n = read(fd, buf, sizeof(buf) - 1)) > 0)
+    {
+      buf[n] = '\0';
+      printf("  > %s", buf);
+      if (strstr(buf, "hello_dpopen"))
+        {
+          found = 1;
+        }
+    }
+
+  dpclose(fd, pid);
+  printf("%s\n", found ? "[PASS]" : "[FAIL] missing output");
+  return !found;
+}
+
+static int test_dpopen_multiarg(void)
+{
+  char buf[256];
+  ssize_t n;
+  pid_t pid;
+  int found = 0;
+  int fd;
+
+  printf("[TEST 6] dpopen multi-arg...\n");
+  fd = dpopen("popen_test --echo xxx yyy zzz", O_RDONLY, &pid);
+  if (fd < 0)
+    {
+      printf("[FAIL] dpopen returned %d\n", fd);
+      return 1;
+    }
+
+  while ((n = read(fd, buf, sizeof(buf) - 1)) > 0)
+    {
+      buf[n] = '\0';
+      printf("  > %s", buf);
+      if (strstr(buf, "xxx yyy zzz"))
+        {
+          found = 1;
+        }
+    }
+
+  dpclose(fd, pid);
+  printf("%s\n", found ? "[PASS]" : "[FAIL] wrong output");
+  return !found;
+}
+
+static int test_dpclose_complete(void)
+{
+  char buf[256];
+  pid_t pid;
+  int fd;
+
+  printf("[TEST 7] dpclose completes...\n");
+  fd = dpopen("popen_test --echo ok", O_RDONLY, &pid);
+  if (fd < 0)
+    {
+      printf("[FAIL] dpopen returned %d\n", fd);
+      return 1;
+    }
+
+  while (read(fd, buf, sizeof(buf)) > 0);
+  dpclose(fd, pid);
+  printf("[PASS]\n");
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  int fail = 0;
+
+  /* Sub-command: echo args back, used as popen/dpopen target */
+
+  if (argc > 1 && strcmp(argv[1], "--echo") == 0)
+    {
+      int i;
+      for (i = 2; i < argc; i++)
+        {
+          printf("%s%s", i > 2 ? " " : "", argv[i]);
+        }
+
+      printf("\n");
+      return 0;
+    }
+
+  printf("=== popen/dpopen test ===\n\n");
+
+  /* popen tests */
+
+  fail += test_popen_read();
+  fail += test_popen_multiarg();
+  fail += test_pclose_complete();
+  fail += test_popen_invalid_mode();
+
+  /* dpopen tests */
+
+  fail += test_dpopen_read();
+  fail += test_dpopen_multiarg();
+  fail += test_dpclose_complete();
+
+  printf("\n=== Results: %d failed ===\n", fail);
+  return fail;
+}

Reply via email to