blob: 4d67a8f07e103d168531b62a2cf7c0bdc2f299c4 [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import unittest
from shell_utils import ParsedShellCommand, ShellCommand, find_command_with_tool
class TestShellCommand(unittest.TestCase):
def test_split_simple(self) -> None:
cmd = ShellCommand("echo a && echo b")
parts = cmd.split()
self.assertEqual(
parts, [ShellCommand("echo a"), ShellCommand("echo b")]
)
def test_split_quoted_operator(self) -> None:
cmd = ShellCommand("echo '&&' || echo b")
parts = cmd.split()
self.assertEqual(
parts, [ShellCommand("echo '&&'"), ShellCommand("echo b")]
)
def test_split_chained(self) -> None:
cmd = ShellCommand("a && b || c && d")
parts = cmd.split()
self.assertEqual(
parts,
[
ShellCommand("a"),
ShellCommand("b"),
ShellCommand("c"),
ShellCommand("d"),
],
)
def test_split_custom_separators(self) -> None:
cmd = ShellCommand("a ; b ; c")
parts = cmd.split(separators={";"})
self.assertEqual(
parts, [ShellCommand("a"), ShellCommand("b"), ShellCommand("c")]
)
def test_unwrap_simple(self) -> None:
cmd = ShellCommand("wrapper -- inner_cmd arg")
unwrapped = cmd.unwrap()
self.assertEqual(unwrapped, ShellCommand("inner_cmd arg"))
def test_unwrap_nested(self) -> None:
cmd = ShellCommand("w1 -- w2 -- inner")
unwrapped = cmd.unwrap()
self.assertEqual(unwrapped, ShellCommand("w2 -- inner"))
def test_unwrap_with_flags(self) -> None:
cmd = ShellCommand("wrapper --opt -- inner --flag")
unwrapped = cmd.unwrap()
self.assertEqual(unwrapped, ShellCommand("inner --flag"))
def test_unwrap_quotes(self) -> None:
cmd = ShellCommand("wrapper -- 'inner --foo'")
unwrapped = cmd.unwrap()
self.assertEqual(unwrapped, ShellCommand("'inner --foo'"))
def test_unwrap_empty_after_separator(self) -> None:
cmd = ShellCommand("wrapper --")
unwrapped = cmd.unwrap()
self.assertEqual(unwrapped, ShellCommand(""))
def test_unwrap_no_separator(self) -> None:
cmd = ShellCommand("echo hello")
self.assertIsNone(cmd.unwrap())
def test_parse_simple(self) -> None:
cmd = ShellCommand("cmd arg")
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({}, "cmd", ["arg"]))
def test_parse_with_env(self) -> None:
cmd = ShellCommand("VAR=1 cmd")
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({"VAR": "1"}, "cmd", []))
def test_parse_complex(self) -> None:
cmd = ShellCommand("VAR=1 ../path/to/cmd --flag")
parsed = cmd.parse()
self.assertEqual(
parsed,
ParsedShellCommand({"VAR": "1"}, "../path/to/cmd", ["--flag"]),
)
def test_parse_quoted_env(self) -> None:
cmd = ShellCommand('VAR="a b" cmd')
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({"VAR": "a b"}, "cmd", []))
def test_parse_env_only(self) -> None:
cmd = ShellCommand("A=B C=D")
parsed = cmd.parse()
self.assertEqual(
parsed, ParsedShellCommand({"A": "B", "C": "D"}, "", [])
)
def test_parse_python_simple(self) -> None:
cmd = ShellCommand("python3 script.py arg")
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({}, "script.py", ["arg"]))
def test_fuchsia_vendored_python(self) -> None:
cmd = ShellCommand("fuchsia-vendored-python script.py arg")
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({}, "script.py", ["arg"]))
def test_parse_python_with_flags(self) -> None:
cmd = ShellCommand("python3 -u script.py arg")
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({}, "script.py", ["arg"]))
def test_parse_python_absolute_path(self) -> None:
cmd = ShellCommand("/usr/bin/python3 script.py")
parsed = cmd.parse()
self.assertEqual(parsed, ParsedShellCommand({}, "script.py", []))
def test_parse_python_no_script(self) -> None:
# Fallback to python as tool if no .py script found
cmd = ShellCommand("python3 -c code")
parsed = cmd.parse()
self.assertEqual(
parsed, ParsedShellCommand({}, "python3", ["-c", "code"])
)
class TestFindCommandWithTool(unittest.TestCase):
def test_find_simple(self) -> None:
cmd = ShellCommand("my_tool arg")
found = find_command_with_tool([cmd], "my_tool")
self.assertEqual(found, cmd)
def test_find_wrapped(self) -> None:
cmd = ShellCommand("wrapper -- my_tool arg")
found = find_command_with_tool([cmd], "my_tool")
self.assertEqual(found, ShellCommand("my_tool arg"))
def test_find_in_list(self) -> None:
cmd1 = ShellCommand("other_tool arg")
cmd2 = ShellCommand("my_tool arg")
found = find_command_with_tool([cmd1, cmd2], "my_tool")
self.assertEqual(found, cmd2)
def test_find_wrapped_in_list(self) -> None:
cmd1 = ShellCommand("other_tool arg")
cmd2 = ShellCommand("wrapper -- my_tool arg")
found = find_command_with_tool([cmd1, cmd2], "my_tool")
self.assertEqual(found, ShellCommand("my_tool arg"))
def test_not_found(self) -> None:
cmd = ShellCommand("other_tool arg")
self.assertIsNone(find_command_with_tool([cmd], "my_tool"))
def test_python_script(self) -> None:
cmd = ShellCommand("python3 script.py arg")
found = find_command_with_tool([cmd], "script.py")
self.assertEqual(found, cmd)
def test_python_script_wrapped(self) -> None:
cmd = ShellCommand("wrapper -- python3 script.py arg")
found = find_command_with_tool([cmd], "script.py")
self.assertEqual(found, ShellCommand("python3 script.py arg"))
def test_find_multi_wrapped(self) -> None:
cmd = ShellCommand("wrapper1 -- wrapper2 -- my_tool arg")
found = find_command_with_tool([cmd], "my_tool")
self.assertEqual(found, ShellCommand("my_tool arg"))
if __name__ == "__main__":
unittest.main()