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

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

commit 60fadbc1ad7bfcc5e71274a5637f27fc60a75040
Author: raiden00pl <[email protected]>
AuthorDate: Tue Aug 4 17:42:22 2026 +0200

    core.py: route runtime check_cmd through config on kernel builds
    
    Runtime checks searched the core ELF or the NSH help output, neither of
    which lists kernel-mode applications. Route check_cmd through
    CoreConfig.cmd_check when the core is a kernel build with a known
    application directory, so runtime checks agree with collection-time
    filtering.
    
    Signed-off-by: raiden00pl <[email protected]>
    Assisted-by: Claude Code
---
 src/ntfc/core.py   | 57 ++++++++++++++++++++++++------------------------------
 tests/test_core.py | 36 ++++++++++++++++++++++++++++++++--
 2 files changed, 59 insertions(+), 34 deletions(-)

diff --git a/src/ntfc/core.py b/src/ntfc/core.py
index 239b541..bc58dd1 100644
--- a/src/ntfc/core.py
+++ b/src/ntfc/core.py
@@ -28,6 +28,7 @@ from typing import (
     Any,
     List,
     Optional,
+    Pattern,
     Tuple,
     Union,
 )
@@ -528,66 +529,58 @@ class ProductCore:
         self._device.start()
 
     def check_cmd(self, cmd_pattern: str) -> bool:
-        """Check if a command pattern is available in the ELF binary.
+        """Check if a command pattern is available on the core.
 
-        This method validates whether a specific command or set of
-        commands is present in the core's ELF binary by searching for
-        corresponding symbols. It supports both single commands and
-        alternative command patterns separated by '|'.
+        Commands are resolved from the core configuration when it knows
+        the application binaries, from the device ELF parser or the
+        shell help output otherwise. It supports both single commands
+        and alternative command patterns separated by '|'.
 
         :param cmd_pattern: Command pattern to check for. Can contain
                            alternatives separated by '|'
                            (e.g., 'test1|test2')
         :return: True if the command pattern is found, False otherwise
-
-        Note:
-            - Requires ELF parser to be available in device
-            - Supports alternative patterns with '|'
-            - Used to validate core capabilities before executing
         """
-        # Check if device supports command checking
+        # Kernel-mode: resolve against the application binary directory
+        # so runtime checks agree with collection-time filtering
+        if self._conf.has_app_bindir:
+            return self._conf.cmd_check(cmd_pattern)
+
+        # Devices that expose their own ELF parser resolve the command
+        # from its symbols
         if hasattr(self._device, "elf_parser") and self._device.elf_parser:
             logger.debug(f"Checking command pattern: {cmd_pattern}")
 
-            # Split by '|' to support alternative patterns
-            alternatives = (
-                cmd_pattern.split("|") if "|" in cmd_pattern else [cmd_pattern]
-            )
-
-            for pattern in alternatives:
+            for pattern in cmd_pattern.split("|"):
                 # For cmocka tests, append _main to symbol name
-                symbol_pattern_str: str = (
+                symbol_str = (
                     f"{pattern}_main" if "cmocka" in pattern else pattern
                 )
 
                 # Support regex wildcards
-                if ".*" in symbol_pattern_str:
-                    symbol_pattern = re.compile(symbol_pattern_str)
-                else:
-                    tmp = symbol_pattern_str
-                    symbol_pattern = tmp  # type: ignore[assignment]
+                symbol: Union[str, Pattern[str]] = (
+                    re.compile(symbol_str)
+                    if ".*" in symbol_str
+                    else symbol_str
+                )
 
-                if self._device.elf_parser.has_symbol(symbol_pattern):
+                if self._device.elf_parser.has_symbol(symbol):
                     return True
 
             return False
 
-        # Fallback: try to execute the command and check if it exists
+        # Fallback: check the command against the shell help output
         logger.warning(
             "ELF parser not available, trying command check for: "
             f"{cmd_pattern}"
         )
 
-        # Send 'help' command to check if command exists
         result = self.sendCommandReadUntilPattern("help", timeout=5)
 
         if result.status == CmdStatus.SUCCESS:
-            # Check if any of the command alternatives are in the help output
-            alternatives = (
-                cmd_pattern.split("|") if "|" in cmd_pattern else [cmd_pattern]
+            return any(
+                pattern.lower() in result.output.lower()
+                for pattern in cmd_pattern.split("|")
             )
-            for pattern in alternatives:
-                if pattern.lower() in result.output.lower():
-                    return True
 
         return False
diff --git a/tests/test_core.py b/tests/test_core.py
index 838513d..ef67281 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -585,8 +585,6 @@ def test_core_check_cmd_with_elf_parser(envconfig_dummy):
         # Test regex wildcard pattern
         mock_elf_parser.has_symbol.side_effect = None
         mock_elf_parser.has_symbol.return_value = True
-        import re
-
         assert p.check_cmd("test.*") is True
         # The pattern should be compiled as regex
         call_args = mock_elf_parser.has_symbol.call_args
@@ -595,3 +593,37 @@ def test_core_check_cmd_with_elf_parser(envconfig_dummy):
         # Test all alternatives not found
         mock_elf_parser.has_symbol.return_value = False
         assert p.check_cmd("nonexistent1|nonexistent2") is False
+
+        # Test with failed help command
+        dev.send_cmd_read_until_pattern.return_value = CmdReturn(
+            CmdStatus.TIMEOUT
+        )
+        assert p.check_cmd("test") is False
+
+
+def test_core_check_cmd_kernel_mode(tmp_path):
+    """Test check_cmd resolves via app_bindir on kernel builds."""
+    from ntfc.coreconfig import CoreConfig
+
+    kernel_cfg = tmp_path / "kv_config"
+    kernel_cfg.write_text("CONFIG_BUILD_KERNEL=y\n")
+    bindir = tmp_path / "bin"
+    bindir.mkdir()
+    (bindir / "hello").write_bytes(b"\x7fELF" + b"\x00" * 12)
+
+    conf = CoreConfig(
+        {
+            "name": "t",
+            "conf_path": str(kernel_cfg),
+            "app_bindir": str(bindir),
+        }
+    )
+
+    with patch("ntfc.device.common.DeviceCommon") as mockdevice:
+        p = ProductCore(mockdevice.return_value, conf)
+
+        # resolved from the application directory, device is not queried
+        assert p.check_cmd("hello") is True
+        assert p.check_cmd("hello_main") is True
+        assert p.check_cmd("nonexistent") is False
+        mockdevice.return_value.send_cmd_read_until_pattern.assert_not_called()

Reply via email to