1#!/usr/bin/env python 2# Copyright 2023 The Pigweed Authors 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); you may not 5# use this file except in compliance with the License. You may obtain a copy of 6# the License at 7# 8# https://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13# License for the specific language governing permissions and limitations under 14# the License. 15"""Emulator API tests.""" 16 17import unittest 18 19from typing import Any 20 21from pw_emu.core import ( 22 ConfigError, 23 InvalidChannelType, 24 InvalidProperty, 25 InvalidPropertyPath, 26) 27from mock_emu_frontend import _mock_emu 28from config_helper import ConfigHelperWithEmulator 29 30 31class TestEmulator(ConfigHelperWithEmulator): 32 """Test Emulator APIs.""" 33 34 _config = { 35 'emulators': { 36 'mock-emu': { 37 'launcher': 'mock_emu_frontend.MockEmuLauncher', 38 'connector': 'mock_emu_frontend.MockEmuConnector', 39 } 40 }, 41 'mock-emu': { 42 'gdb_channel': True, 43 }, 44 'gdb': _mock_emu + ['--exit', '--'], 45 'targets': {'test-target': {'mock-emu': {}}}, 46 } 47 48 def setUp(self) -> None: 49 super().setUp() 50 self._emu.start('test-target') 51 52 def tearDown(self) -> None: 53 self._emu.stop() 54 super().tearDown() 55 56 def test_gdb_target_remote(self) -> None: 57 output = self._emu.run_gdb_cmds([]).stdout 58 host, port = self._emu.get_channel_addr('gdb') 59 self.assertTrue(f'{host}:{port}' in output.decode('utf-8')) 60 61 def test_gdb_commands(self) -> None: 62 output = self._emu.run_gdb_cmds(['test_gdb_cmd']).stdout 63 self.assertTrue( 64 output and '-ex test_gdb_cmd' in output.decode('utf-8'), output 65 ) 66 67 def test_gdb_executable(self) -> None: 68 output = self._emu.run_gdb_cmds([], 'test_gdb_exec').stdout 69 self.assertTrue('test_gdb_exec' in output.decode('utf-8')) 70 71 def test_gdb_pause(self) -> None: 72 output = self._emu.run_gdb_cmds([], pause=True).stdout 73 self.assertTrue('-ex disconnect' in output.decode('utf-8')) 74 75 # Minimal testing for APIs that are straight wrappers over Connector APIs. 76 def test_running(self) -> None: 77 self.assertTrue(self._emu.running()) 78 79 def test_reset(self) -> None: 80 self._emu.reset() 81 82 def test_cont(self) -> None: 83 self._emu.cont() 84 85 def test_list_properties(self) -> None: 86 with self.assertRaises(InvalidPropertyPath): 87 self._emu.list_properties('invalid path') 88 self.assertEqual(self._emu.list_properties('path1'), ['prop1']) 89 90 def test_get_property(self) -> None: 91 with self.assertRaises(InvalidProperty): 92 self._emu.get_property('path1', 'invalid property') 93 with self.assertRaises(InvalidPropertyPath): 94 self._emu.get_property('invalid path', 'prop1') 95 self.assertEqual(self._emu.get_property('path1', 'prop1'), 'val1') 96 97 def test_set_property(self) -> None: 98 with self.assertRaises(InvalidPropertyPath): 99 self._emu.set_property('invalid path', 'prop1', 'test') 100 with self.assertRaises(InvalidProperty): 101 self._emu.set_property('path1', 'invalid property', 'test') 102 self._emu.set_property('path1', 'prop1', 'val2') 103 self.assertEqual(self._emu.get_property('path1', 'prop1'), 'val2') 104 105 def test_get_channel_type(self) -> None: 106 self.assertEqual(self._emu.get_channel_type('gdb'), 'tcp') 107 108 def test_get_channel_path(self) -> None: 109 with self.assertRaises(InvalidChannelType): 110 self._emu.get_channel_path('gdb') 111 112 def test_get_channel_addr(self) -> None: 113 self.assertEqual(len(self._emu.get_channel_addr('gdb')), 2) 114 115 def test_channel_stream(self) -> None: 116 with self._emu.get_channel_stream('gdb') as _: 117 pass 118 119 120class TestGdbEmptyConfig(ConfigHelperWithEmulator): 121 """Check that ConfigError is raised when running gdb with an empty 122 gdb config. 123 124 """ 125 126 _config: dict[str, Any] = { 127 'emulators': { 128 'mock-emu': { 129 'launcher': 'mock_emu_frontend.MockEmuLauncher', 130 'connector': 'mock_emu_frontend.MockEmuConnector', 131 } 132 }, 133 'targets': {'test-target': {'mock-emu': {}}}, 134 } 135 136 def setUp(self) -> None: 137 super().setUp() 138 self._emu.start('test-target') 139 140 def tearDown(self) -> None: 141 self._emu.stop() 142 super().tearDown() 143 144 def test_gdb_config_error(self) -> None: 145 with self.assertRaises(ConfigError): 146 self._emu.run_gdb_cmds([]) 147 148 149if __name__ == '__main__': 150 unittest.main() 151