UNPKG

chrome-devtools-frontend

Version:
451 lines (396 loc) • 20.9 kB
// Copyright 2020 The Chromium 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 { dispatchClickEvent, getElementsWithinComponent, getElementWithinComponent, getEventPromise, renderElementIntoDOM, } from '../../../testing/DOMHelpers.js'; import {describeWithLocale} from '../../../testing/EnvironmentHelpers.js'; import * as LinearMemoryInspectorComponents from './components.js'; export const DISPLAY_JUMP_TO_POINTER_BUTTON_SELECTOR = '[data-jump]'; describeWithLocale('ValueInterpreterDisplay', () => { const combinationsForNumbers = [ {endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, signed: true}, {endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, signed: false}, {endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.BIG, signed: false}, {endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.BIG, signed: true}, ]; function testNumberFormatCombinations( baseData: { buffer: ArrayBuffer, type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode, }, combinations: Array< {endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness, signed: boolean}>) { const expectedIntValue = 20; const expectedFloatValue = -234.03; for (let i = 0; i < combinations.length; ++i) { const {endianness, signed} = combinations[i]; let expectedValue; const isLittleEndian = endianness === LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE; const view = new DataView(baseData.buffer); switch (baseData.type) { case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT8: expectedValue = signed ? -expectedIntValue : expectedIntValue; signed ? view.setInt8(0, expectedValue) : view.setInt8(0, expectedValue); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT16: expectedValue = signed ? -expectedIntValue : expectedIntValue; signed ? view.setInt16(0, expectedValue, isLittleEndian) : view.setUint16(0, expectedValue, isLittleEndian); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT32: expectedValue = signed ? -expectedIntValue : expectedIntValue; signed ? view.setInt32(0, expectedValue, isLittleEndian) : view.setUint32(0, expectedValue, isLittleEndian); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT64: expectedValue = signed ? -expectedIntValue : expectedIntValue; signed ? view.setBigInt64(0, BigInt(expectedValue), isLittleEndian) : view.setBigUint64(0, BigInt(expectedValue), isLittleEndian); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32: expectedValue = expectedFloatValue; view.setFloat32(0, expectedValue, isLittleEndian); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT64: expectedValue = expectedFloatValue; view.setFloat64(0, expectedValue, isLittleEndian); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER32: expectedValue = '0x' + expectedIntValue.toString(16); view.setInt32(0, expectedIntValue, isLittleEndian); break; case LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER64: expectedValue = '0x' + expectedIntValue.toString(16); view.setBigUint64(0, BigInt(expectedIntValue), isLittleEndian); break; default: throw new Error(`Unknown type ${baseData.type}`); } const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.format({...baseData, ...combinations[i]}); assert.strictEqual(actualValue, expectedValue.toString()); } } it('correctly formats signed/unsigned and endianness for Integer 8-bit (decimal)', () => { const formatData = { buffer: new ArrayBuffer(1), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT8, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats signed/unsigned and endianness for Integer 16-bit (decimal)', () => { const formatData = { buffer: new ArrayBuffer(2), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT16, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats signed/unsigned and endianness for Integer 32-bit (decimal)', () => { const formatData = { buffer: new ArrayBuffer(4), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT32, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats signed/unsigned and endianness for Integer 64-bit (decimal)', () => { const formatData = { buffer: new ArrayBuffer(8), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT64, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats endianness for Float 32-bit (decimal)', () => { const formatData = { buffer: new ArrayBuffer(4), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats endianness for Float 64-bit (decimal)', () => { const formatData = { buffer: new ArrayBuffer(8), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT64, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats endianness for Pointer 32-bit', () => { const formatData = { buffer: new ArrayBuffer(4), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER32, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.HEXADECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats endianness for Pointer 64-bit', () => { const formatData = { buffer: new ArrayBuffer(8), type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER64, mode: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.HEXADECIMAL, }; testNumberFormatCombinations(formatData, combinationsForNumbers); }); it('correctly formats floats in decimal mode', () => { const expectedFloat = 341.34; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatFloat( expectedFloat, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL); assert.strictEqual(actualValue, '341.34'); }); it('correctly formats floats in scientific mode', () => { const expectedFloat = 341.34; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatFloat( expectedFloat, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.SCIENTIFIC); assert.strictEqual(actualValue, '3.41e+2'); }); it('correctly formats integers in decimal mode', () => { const expectedInteger = 120; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatInteger( expectedInteger, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL); assert.strictEqual(actualValue, '120'); }); it('correctly formats integers in hexadecimal mode', () => { const expectedInteger = 16; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatInteger( expectedInteger, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.HEXADECIMAL); assert.strictEqual(actualValue, '0x10'); }); it('returns N/A for negative hex numbers', () => { const negativeInteger = -16; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatInteger( negativeInteger, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.HEXADECIMAL); assert.strictEqual(actualValue, 'N/A'); }); it('correctly formats integers in octal mode', () => { const expectedInteger = 16; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatInteger( expectedInteger, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.OCTAL); assert.strictEqual(actualValue, '20'); }); it('returns N/A for negative octal numbers', () => { const expectedInteger = -16; const actualValue = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.formatInteger( expectedInteger, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.OCTAL); assert.strictEqual(actualValue, 'N/A'); }); it('renders pointer values in LinearMemoryInspector.ValueInterpreterDisplayUtils.ValueTypes', () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [1, 132, 172, 71, 43, 12, 12, 66]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER32, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER64, ]), memoryLength: array.length, }; renderElementIntoDOM(component); const dataValues = getElementsWithinComponent(component, '[data-value]', HTMLDivElement); assert.lengthOf(dataValues, 2); const actualValues = Array.from(dataValues).map(x => x.innerText); const expectedValues = ['0x47AC8401', '0x420C0C2B47AC8401']; assert.deepEqual(actualValues, expectedValues); }); it('renders value in selected LinearMemoryInspector.ValueInterpreterDisplayUtils.ValueTypes', () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [1, 132, 172, 71]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT16, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32, ]), memoryLength: array.length, }; renderElementIntoDOM(component); const dataValues = getElementsWithinComponent(component, '[data-value]', HTMLSpanElement); assert.lengthOf(dataValues, 3); const actualValues = Array.from(dataValues).map(x => x.innerText); const expectedValues = ['33793', '-31743', '88328.01']; assert.deepEqual(actualValues, expectedValues); }); it('renders only unsigned values for Octal and Hexadecimal representation', () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [0xC8, 0xC9, 0xCA, 0XCB]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT8, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT16, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT32, ]), valueTypeModes: new Map([ [ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT8, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.OCTAL, ], [ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT16, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.HEXADECIMAL, ], [ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT32, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL, ], ]), memoryLength: array.length, }; renderElementIntoDOM(component); const dataValues = getElementsWithinComponent(component, '[data-value]', HTMLSpanElement); assert.lengthOf(dataValues, 4); const actualValues = Array.from(dataValues).map(x => x.innerText); const expectedValues = ['310', '0xC9C8', '3419064776', '-875902520']; assert.deepEqual(actualValues, expectedValues); }); it('triggers a value changed event on selecting a new mode', async () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [1, 132, 172, 71]; const oldMode = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.DECIMAL; const newMode = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueTypeMode.SCIENTIFIC; const mapping = LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.getDefaultValueTypeMapping(); mapping.set(LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32, oldMode); component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32, ]), valueTypeModes: mapping, memoryLength: array.length, }; const input = getElementWithinComponent(component, '[data-mode-settings]', HTMLSelectElement); assert.strictEqual(input.value, oldMode); input.value = newMode; const eventPromise = getEventPromise<LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueTypeModeChangedEvent>( component, 'valuetypemodechanged'); const changeEvent = new Event('change'); input.dispatchEvent(changeEvent); const event = await eventPromise; assert.deepEqual( event.data, {type: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32, mode: newMode}); }); it('triggers an event on jumping to an address from a 32-bit pointer', async () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [1, 0, 0, 0]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER32, ]), memoryLength: array.length, }; renderElementIntoDOM(component); const button = getElementWithinComponent(component, DISPLAY_JUMP_TO_POINTER_BUTTON_SELECTOR, HTMLButtonElement); const eventPromise = getEventPromise<LinearMemoryInspectorComponents.ValueInterpreterDisplay.JumpToPointerAddressEvent>( component, 'jumptopointeraddress'); dispatchClickEvent(button); const event = await eventPromise; assert.deepEqual(event.data, 1); }); it('triggers an event on jumping to an address from a 64-bit pointer', async () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [1, 0, 0, 0, 0, 0, 0, 0]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER64, ]), memoryLength: array.length, }; renderElementIntoDOM(component); const button = getElementWithinComponent(component, DISPLAY_JUMP_TO_POINTER_BUTTON_SELECTOR, HTMLButtonElement); const eventPromise = getEventPromise<LinearMemoryInspectorComponents.ValueInterpreterDisplay.JumpToPointerAddressEvent>( component, 'jumptopointeraddress'); dispatchClickEvent(button); const event = await eventPromise; assert.deepEqual(event.data, 1); }); it('renders a disabled jump-to-address button if address is invalid', () => { const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [8, 0, 0, 0, 0, 0, 0, 0]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER32, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER64, ]), memoryLength: array.length, }; renderElementIntoDOM(component); const buttons = getElementsWithinComponent(component, DISPLAY_JUMP_TO_POINTER_BUTTON_SELECTOR, HTMLButtonElement); assert.lengthOf(buttons, 2); assert.isTrue(buttons[0].disabled); assert.isTrue(buttons[1].disabled); }); it('selects text in data-value elements if user selects it', () => { // To test the failing case, set .value-type user-select to `none`. // This is necessary as we render the component in isolation, so it doesn't // inherit this property from its parent. const component = new LinearMemoryInspectorComponents.ValueInterpreterDisplay.ValueInterpreterDisplay(); const array = [1, 132, 172, 71]; component.data = { buffer: new Uint8Array(array).buffer, endianness: LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.Endianness.LITTLE, valueTypes: new Set([ LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT8, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.INT16, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.FLOAT32, LinearMemoryInspectorComponents.ValueInterpreterDisplayUtils.ValueType.POINTER32, ]), memoryLength: array.length, }; renderElementIntoDOM(component); const dataValues = getElementsWithinComponent(component, '.selectable-text', HTMLSpanElement); assert.lengthOf(dataValues, 9); const expectedValues = [ 'Integer 8-bit', '1', 'Integer 16-bit', '33793', '-31743', 'Float 32-bit', '88328.01', 'Pointer 32-bit', '0x47AC8401', ]; // Workaround for selecting text (instead of double-clicking it). // We can use a range to specify an element. Range can be converted into // a selection. We then check if the selected text meets our expectations. // Continuous part of a document, independent of any visual representation. const range = document.createRange(); // Represents user's highlighted text. const selection = document.getSelection(); for (let i = 0; i < dataValues.length; ++i) { if (selection === null) { assert.fail('Selection is null'); } // Set range around the element. range.selectNodeContents(dataValues[i]); // Remove ranges associated with selection. selection?.removeAllRanges(); // Select element using range. selection?.addRange(range); const text = window.getSelection()?.toString(); assert.strictEqual(text, expectedValues[i]); } }); });