1## 2# Copyright (c) 2023 Apple Inc. All rights reserved. 3# 4# @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5# 6# This file contains Original Code and/or Modifications of Original Code 7# as defined in and that are subject to the Apple Public Source License 8# Version 2.0 (the 'License'). You may not use this file except in 9# compliance with the License. The rights granted to you under the License 10# may not be used to create, or enable the creation or redistribution of, 11# unlawful or unlicensed copies of an Apple operating system, or to 12# circumvent, violate, or enable the circumvention or violation of, any 13# terms of an Apple operating system software license agreement. 14# 15# Please obtain a copy of the License at 16# http://www.opensource.apple.com/apsl/ and read it before using this file. 17# 18# The Original Code and all software distributed under the License are 19# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23# Please see the License for the specific language governing rights and 24# limitations under the License. 25# 26# @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27## 28 29# pylint: disable=invalid-name 30 31""" Unit test examples 32 33 This is not a real test suite. It only demonstrates various approaches developers 34 can use to write a test. 35""" 36 37import contextlib 38import io 39import unittest.mock 40from lldbtest.testcase import LLDBTestCase 41import lldb 42 43from lldbmock.utils import lookup_type 44 45# Import macro function to be tested. 46from process import ShowTask, P_LHASTASK, TF_HASPROC 47 48 49class TestExamples(LLDBTestCase): 50 """ Unit test examples. """ 51 52 ROUNDED_UP_PROC_SIZE = 2048 53 54 # Mock global variable value (accessed by the macro being) 55 @unittest.mock.patch('xnu.kern.globals.proc_struct_size', ROUNDED_UP_PROC_SIZE) 56 def test_function(self): 57 """ This test shows how to run complex function against a mock. """ 58 59 self.reset_mocks() 60 61 PROC_ADDR = 0xffffffff90909090 62 TASK_ADDR = PROC_ADDR + self.ROUNDED_UP_PROC_SIZE 63 PROC_RO_ADDR = 0xffffff0040404040 64 65 # Create fake proc_t instance at 0xffffffff90909090 66 proc = self.create_mock('proc', PROC_ADDR).fromDict({ 67 'p_pid': 12345, 68 'p_lflag': P_LHASTASK, 69 'p_comm': b'test-proc\0' 70 }) 71 72 # Create task which is expected to be placed + sizeof(proc) 73 task = self.create_mock('task', TASK_ADDR).fromDict({ 74 'effective_policy': { 75 'tep_sup_active': 0, 76 'tep_darwinbg': 0, 77 'tep_lowpri_cpu': 1 78 }, 79 't_flags': TF_HASPROC 80 }) 81 82 # Created shared proc_ro reference from both task/proc 83 self.create_mock('proc_ro', PROC_RO_ADDR) 84 proc.p_proc_ro = PROC_RO_ADDR 85 task.bsd_info_ro = PROC_RO_ADDR 86 87 # Capture stdout and check expected output 88 stdout = io.StringIO() 89 with contextlib.redirect_stdout(stdout): 90 ShowTask([f'{TASK_ADDR:#x}']) 91 92 # Note: Not the best way of writing a unit test. 93 expected = ( 94 'task vm_map ipc_space #acts flags' 95 ' pid process io_policy wq_state command' 96 f' \n{TASK_ADDR:#x} 0x0 0x0 ' 97 f' 0 12345 {PROC_ADDR:#x} L 0 0 0' 98 ' test-proc \n' 99 ) 100 self.assertEqual(stdout.getvalue(), expected) 101 102 def test_command(self): 103 """ Test a simple LLDB command from user's CLI. 104 105 Creates mock of a structure and prints out member by using LLDB 106 expression. 107 """ 108 109 self.reset_mocks() 110 111 PROC_ADDR = 0xffffffff90909090 112 113 self.create_mock('proc', PROC_ADDR).fromDict({ 114 'p_pid': 12345, 115 'p_lflag': P_LHASTASK, 116 'p_comm': b'unit-test-proc\0' 117 }) 118 119 res = self.run_command(f'p/x ((proc_t){PROC_ADDR:#x})->p_comm') 120 self.assertEqual(res.GetOutput(), '(command_t) "unit-test-proc"\n') 121 self.assertTrue(res.Succeeded()) 122 123 @unittest.skipIf(LLDBTestCase.kernel().startswith('mach.release'), 124 "Not available in RELEASE embedded") 125 def test_sbapi(self): 126 """ Test SBAPI on top of a mocked target. """ 127 128 DOFHELP_ADDR = 0xffffffff11220000 129 130 # Construct simple data structure mock. 131 self.create_mock('struct dof_helper', DOFHELP_ADDR).fromDict({ 132 'dofhp_mod': b'mock-mod', 133 'dofhp_addr': 0x1234, 134 'dofhp_dof': 0x5678 135 }) 136 137 # Construct SBValue on top of the mock. 138 addr = self.target.ResolveLoadAddress(DOFHELP_ADDR) 139 sbv = self.target.CreateValueFromAddress('test', 140 addr, lookup_type('dof_helper_t')) 141 142 self.assertTrue(sbv.IsValid() and sbv.error.success) 143 144 # Check that LLDB SBAPI returns correct values from mock. 145 err = lldb.SBError() 146 self.assertEqual( 147 sbv.GetChildMemberWithName('dofhp_mod').GetData().GetString(err, 0), 148 "mock-mod" 149 ) 150 self.assertEqual( 151 sbv.GetChildMemberWithName('dofhp_addr').GetValueAsUnsigned(), 152 0x1234 153 ) 154 self.assertEqual( 155 sbv.GetChildMemberWithName('dofhp_dof').GetValueAsUnsigned(), 156 0x5678 157 ) 158 159 @unittest.skipIf(LLDBTestCase.arch() != 'arm64e', "Only on arm64e") 160 def test_skip_arch(self): 161 """ Example of architecture specific test. """ 162 163 self.assertEqual(self.target.triple.split('-', 1)[0], 'arm64e') 164 165 @unittest.skipIf(LLDBTestCase.variant() != 'DEVELOPMENT', "DEVELOPMENT kernel only") 166 def test_skip_development(self): 167 """ Test that runs only on release kernel. """ 168 169 self.assertEqual(LLDBTestCase.variant(), "DEVELOPMENT") 170