#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (C) 2018 Apple Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import atexit import lldb import lldb_webkit import os import sys import unittest from webkitpy.common.system.systemhost import SystemHost # Run just the tests in this file with ./Tools/Scripts/test-webkitpy lldb_webkit_unittest # We cache the lldb debug session state so that we don't create it again for each call to a serial_test_ method. # We store it in a global variable so that we can delete this cached state on exit(3). # FIXME: Remove this once test-webkitpy supports class and module fixtures (i.e. setUpClass()/setUpModule() # are called exactly once per class/module). cached_debug_session = None # FIXME: Remove this once test-webkitpy supports class and module fixtures (i.e. setUpClass()/setUpModule() # are called exactly once per class/module). @atexit.register def destroy_cached_debug_session(): if cached_debug_session: cached_debug_session.tearDown() class LLDBDebugSession(object): @classmethod def setup(cls): BREAK_FOR_TESTING_FUNCTION_NAME = 'breakForTestingSummaryProviders' cls.sbDebugger = lldb.SBDebugger.Create() cls.sbDebugger.SetAsync(False) cls.lldbWebKitTesterExecutable = str(os.environ['LLDB_WEBKIT_TESTER_EXECUTABLE']) cls.sbTarget = cls.sbDebugger.CreateTarget(cls.lldbWebKitTesterExecutable) assert cls.sbTarget cls.sbTarget.BreakpointCreateByName(BREAK_FOR_TESTING_FUNCTION_NAME, cls.sbTarget.GetExecutable().GetFilename()) argv = None envp = None cls.sbProcess = cls.sbTarget.LaunchSimple(argv, envp, os.getcwd()) assert cls.sbProcess assert cls.sbProcess.GetState() == lldb.eStateStopped cls.sbThread = cls.sbProcess.GetThreadAtIndex(0) assert cls.sbThread # Frame 0 is the function with name BREAK_FOR_TESTING_FUNCTION_NAME. We want the frame of the caller of # BREAK_FOR_TESTING_FUNCTION_NAME because it has all the interesting local variables we want to test. cls.sbFrame = cls.sbThread.GetFrameAtIndex(1) assert cls.sbFrame @classmethod def tearDown(cls): cls.sbProcess.Kill() class TestSummaryProviders(unittest.TestCase): @classmethod def shouldSkip(cls): return not SystemHost().platform.is_mac() @classmethod def setUpClass(cls): global cached_debug_session if not cached_debug_session: cached_debug_session = LLDBDebugSession() cached_debug_session.setup() @property def _sbFrame(self): return cached_debug_session.sbFrame # The LLDB Python module does not work with Python multiprocessing and causes errors of the form: # objc[76794]: +[__MDQuery initialize] may have been in progress in another thread when fork() was called. # We cannot safely call it or ignore it in the fork() child process. Crashing instead. # So, we run the following tests serially. # MARK: WTFStringImpl_SummaryProvider test cases def serial_test_WTFStringImpl_SummaryProvider_null_string(self): summary = lldb_webkit.WTFStringImpl_SummaryProvider(self._sbFrame.FindVariable('aNullStringImpl'), {}) self.assertEqual(summary, "{ length = 0, is8bit = 1, contents = '' }") def serial_test_WTFStringImpl_SummaryProvider_empty_string(self): summary = lldb_webkit.WTFStringImpl_SummaryProvider(self._sbFrame.FindVariable('anEmptyStringImpl'), {}) self.assertEqual(summary, "{ length = 0, is8bit = 1, contents = '' }") def serial_test_WTFStringImpl_SummaryProvider_8bit_string(self): summary = lldb_webkit.WTFStringImpl_SummaryProvider(self._sbFrame.FindVariable('an8BitStringImpl'), {}) self.assertEqual(summary, u"{ length = 8, is8bit = 1, contents = 'r\xe9sum\xe9' }") def serial_test_WTFStringImpl_SummaryProvider_16bit_string(self): summary = lldb_webkit.WTFStringImpl_SummaryProvider(self._sbFrame.FindVariable('a16BitStringImpl'), {}) self.assertEqual(summary, u"{ length = 13, is8bit = 0, contents = '\u1680Cappuccino\u1680\x00' }") # MARK: WTFString_SummaryProvider test cases def serial_test_WTFString_SummaryProvider_null_string(self): summary = lldb_webkit.WTFString_SummaryProvider(self._sbFrame.FindVariable('aNullString'), {}) self.assertEqual(summary, "{ length = 0, contents = '' }") def serial_test_WTFString_SummaryProvider_empty_string(self): summary = lldb_webkit.WTFString_SummaryProvider(self._sbFrame.FindVariable('anEmptyString'), {}) self.assertEqual(summary, "{ length = 0, contents = '' }") def serial_test_WTFString_SummaryProvider_8bit_string(self): summary = lldb_webkit.WTFString_SummaryProvider(self._sbFrame.FindVariable('an8BitString'), {}) self.assertEqual(summary, u"{ length = 8, contents = 'r\xe9sum\xe9' }") def serial_test_WTFString_SummaryProvider_16bit_string(self): summary = lldb_webkit.WTFString_SummaryProvider(self._sbFrame.FindVariable('a16BitString'), {}) self.assertEqual(summary, u"{ length = 13, contents = '\u1680Cappuccino\u1680\x00' }") # MARK: WTFVector_SummaryProvider test cases def serial_test_WTFVectorProvider_empty_vector(self): variable = self._sbFrame.FindVariable('anEmptyVector'); summary = lldb_webkit.WTFVector_SummaryProvider(variable, {}) self.assertEqual(summary, "{ size = 0, capacity = 0 }") def serial_test_WTFVectorProvider_vector_size_and_capacity(self): variable = self._sbFrame.FindVariable('aVectorWithOneItem'); summary = lldb_webkit.WTFVector_SummaryProvider(variable, {}) self.assertEqual(summary, "{ size = 1, capacity = 16 }") # MARK: WTFHashMap_SummaryProvider and WTFHashSet_SummaryProvider test cases def serial_test_WTFHashMap_tablesize_and_size(self): variable = self._sbFrame.FindVariable('hashMapOfInts') summary = lldb_webkit.WTFHashMap_SummaryProvider(variable, {}) self.assertEqual(summary, "{ tableSize = 8, keyCount = 2 }") def serial_test_WTFHashMap_of_vectors_tablesize_and_size(self): variable = self._sbFrame.FindVariable('hashMapOfVectors') summary = lldb_webkit.WTFHashMap_SummaryProvider(variable, {}) self.assertEqual(summary, "{ tableSize = 8, keyCount = 1 }") def serial_test_WTFHashSet_tablesize_and_size(self): variable = self._sbFrame.FindVariable('hashSetOfInts') summary = lldb_webkit.WTFHashSet_SummaryProvider(variable, {}) self.assertEqual(summary, "{ tableSize = 8, keyCount = 1 }") # MARK: WTFOptionSet_SummaryProvider test cases def serial_test_WTFOptionSet_SummaryProvider_empty(self): variable = self._sbFrame.FindVariable('exampleFlagsEmpty') summary = lldb_webkit.WTFOptionSet_SummaryProvider(variable, {}) self.assertEqual(summary, "{ size = 0 }") def serial_test_WTFOptionSet_SummaryProvider_simple(self): variable = self._sbFrame.FindVariable('exampleFlagsSimple') summary = lldb_webkit.WTFOptionSet_SummaryProvider(variable, {}) self.assertEqual(summary, "{ size = 3 }") # MARK: WTFOptionSetProvider test cases def serial_test_WTFOptionSetProvider_empty(self): variable = self._sbFrame.FindVariable('exampleFlagsEmpty') provider = lldb_webkit.WTFOptionSetProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), 'm_storage') def serial_test_WTFOptionSetProvider_simple(self): variable = self._sbFrame.FindVariable('exampleFlagsSimple') provider = lldb_webkit.WTFOptionSetProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), 'A') self.assertEqual(provider.get_child_at_index(0).GetValue(), '1') self.assertEqual(provider.get_child_at_index(1).GetName(), 'C') self.assertEqual(provider.get_child_at_index(1).GetValue(), '4') self.assertEqual(provider.get_child_at_index(2).GetName(), 'D') self.assertEqual(provider.get_child_at_index(2).GetValue(), '8') def serial_test_WTFOptionSetProvider_aliased_flag(self): variable = self._sbFrame.FindVariable('exampleFlagsAliasedFlag') provider = lldb_webkit.WTFOptionSetProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), 'A') self.assertEqual(provider.get_child_at_index(0).GetValue(), '1') self.assertEqual(provider.get_child_at_index(1).GetName(), 'D') self.assertEqual(provider.get_child_at_index(1).GetValue(), '8') # MARK: WTFURL_SummaryProvider test cases def serial_test_WTFURL_SummaryProvider(self): variable = lldb_webkit.WTFURL_SummaryProvider(self._sbFrame.FindVariable('aURL'), {}) self.assertEqual(variable, '{ https://www.example.com/ }') # MARK: WTFCompactPointerTuple test cases def serial_test_WTFCompactPointerTuple_SummaryProvider_empty(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleEmpty') summary = lldb_webkit.WTFCompactPointerTuple_SummaryProvider(variable, {}) self.assertEqual(summary, "{ type = 0 }") def serial_test_WTFCompactPointerTuple_SummaryProvider_simple(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleSimple') summary = lldb_webkit.WTFCompactPointerTuple_SummaryProvider(variable, {}) self.assertEqual(summary, "{ type = 7 }") def serial_test_WTFCompactPointerTuple_SummaryProvider_max_type_value(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleMaxTypeValue') summary = lldb_webkit.WTFCompactPointerTuple_SummaryProvider(variable, {}) self.assertEqual(summary, "{ type = 255 }") def serial_test_WTFCompactPointerTuple_SummaryProvider_bool(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleSimpleBool') summary = lldb_webkit.WTFCompactPointerTuple_SummaryProvider(variable, {}) self.assertEqual(summary, "{ type = true }") def serial_test_WTFCompactPointerTupleProvider_empty(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleEmpty') provider = lldb_webkit.WTFCompactPointerTupleProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), '[0]') self.assertEqual(provider.get_child_at_index(0).GetValueAsUnsigned(), 0) self.assertEqual(provider.get_child_at_index(1).GetName(), '[1]') self.assertEqual(provider.get_child_at_index(1).GetValueAsUnsigned(), 0) def serial_test_WTFCompactPointerTupleProvider_simple(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleSimple') provider = lldb_webkit.WTFCompactPointerTupleProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), '[0]') self.assertNotEqual(provider.get_child_at_index(0).GetValueAsUnsigned(), 0) self.assertEqual(provider.get_child_at_index(1).GetName(), '[1]') self.assertEqual(provider.get_child_at_index(1).GetValueAsUnsigned(), 7) def serial_test_WTFCompactPointerTupleProvider_max_type_value(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleMaxTypeValue') provider = lldb_webkit.WTFCompactPointerTupleProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), '[0]') self.assertNotEqual(provider.get_child_at_index(0).GetValueAsUnsigned(), 0) self.assertEqual(provider.get_child_at_index(1).GetName(), '[1]') self.assertEqual(provider.get_child_at_index(1).GetValueAsUnsigned(), 255) def serial_test_WTFCompactPointerTupleProvider_simple_bool(self): variable = self._sbFrame.FindVariable('exampleCompactPointerTupleSimpleBool') provider = lldb_webkit.WTFCompactPointerTupleProvider(variable, {}) self.assertEqual(provider.get_child_at_index(0).GetName(), '[0]') self.assertNotEqual(provider.get_child_at_index(0).GetValueAsUnsigned(), 0) self.assertEqual(provider.get_child_at_index(1).GetName(), '[1]') self.assertEqual(provider.get_child_at_index(1).GetValue(), 'true')