1# Copyright 2024 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Tests for pw_cli.tool_runner.""" 15 16import subprocess 17import sys 18import unittest 19from typing import Any, Iterable 20 21from pw_cli import tool_runner 22from pw_cli.tool_runner import ToolRunner 23 24 25class TestToolRunner(unittest.TestCase): 26 """Tests for tool_runner.TestToolRunner.""" 27 28 def test_basic_subprocess_runner(self): 29 runner = tool_runner.BasicSubprocessRunner() 30 if sys.platform == 'win32': 31 result = runner('python.exe', ('-c', 'print("hello world")')) 32 else: 33 result = runner('echo', ('hello', 'world')) 34 self.assertEqual(result.returncode, 0) 35 self.assertIn('hello world', result.stdout.decode()) 36 37 38class FakeTool(ToolRunner): 39 def __init__(self) -> None: 40 self.received_args: list[str] = [] 41 self.received_kwargs: dict[str, Any] = {} 42 43 def _run_tool( 44 self, tool: str, args, **kwargs 45 ) -> subprocess.CompletedProcess: 46 self.received_args = list(args) 47 self.received_kwargs = kwargs 48 49 full_command = ' '.join((tool, *tuple(args))) 50 51 return subprocess.CompletedProcess( 52 args=full_command, 53 returncode=0xFF, 54 stderr=f'I do not know how to `{full_command}`'.encode(), 55 stdout=b'Failed to execute command', 56 ) 57 58 59class FakeToolWithCustomArgs(FakeTool): 60 @staticmethod 61 def _custom_args() -> Iterable[str]: 62 return ['pw_custom_arg', 'pw_2_custom_2_arg'] 63 64 65class ToolRunnerCallTest(unittest.TestCase): 66 """Tests argument forwarding to ToolRunner implementations.""" 67 68 def test_fake_tool_without_custom_args(self): 69 tool = FakeTool() 70 71 tool( 72 'rm', 73 ('-rf', '/'), 74 capture_output=True, 75 pw_custom_arg='should not be forwarded', 76 ) 77 78 self.assertEqual(tool.received_args, ['-rf', '/']) 79 self.assertEqual( 80 tool.received_kwargs, 81 { 82 'capture_output': True, 83 'stdout': subprocess.PIPE, 84 'stderr': subprocess.PIPE, 85 }, 86 ) 87 88 def test_fake_tool_with_custom_args(self): 89 tool = FakeToolWithCustomArgs() 90 91 tool( 92 'rm', 93 ('-rf', '/'), 94 capture_output=True, 95 pw_custom_arg='should be forwarded', 96 pw_2_custom_2_arg='this one too', 97 pw_foo='but not this', 98 ) 99 100 self.assertEqual(tool.received_args, ['-rf', '/']) 101 self.assertEqual( 102 tool.received_kwargs, 103 { 104 'capture_output': True, 105 'stdout': subprocess.PIPE, 106 'stderr': subprocess.PIPE, 107 'pw_custom_arg': 'should be forwarded', 108 'pw_2_custom_2_arg': 'this one too', 109 }, 110 ) 111 112 113if __name__ == '__main__': 114 unittest.main() 115