| # Copyright 2016 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. |
| |
| """Module to generate a test file with random calls to the Web Bluetooth API.""" |
| |
| import random |
| from fuzzer_helpers import FillInParameter |
| |
| # Contains the different types of base tokens used when generating a test case. |
| BASE_TOKENS = [ |
| 'TRANSFORM_BASIC_BASE', |
| 'TRANSFORM_DEVICE_DISCOVERY_BASE', |
| 'TRANSFORM_CONNECTABLE_BASE', |
| 'TRANSFORM_SERVICES_RETRIEVED_BASE', |
| 'TRANSFORM_CHARACTERISTICS_RETRIEVED_BASE', |
| ] |
| |
| # Contains strings that represent calls to the Web Bluetooth API. These |
| # strings can be sequentially placed together to generate sequences of |
| # calls to the API. These strings are separated by line and placed so |
| # that indentation can be performed more easily. |
| TOKENS = [ |
| [ |
| '})', |
| '.catch(e => console.log(e.name + \': \' + e.message))', |
| '.then(() => {', |
| ], |
| # Request Device Tokens |
| [ |
| ' requestDeviceWithKeyDown(TRANSFORM_REQUEST_DEVICE_OPTIONS);' |
| ], |
| [ |
| ' return requestDeviceWithKeyDown(TRANSFORM_REQUEST_DEVICE_OPTIONS);', |
| '})', |
| '.then(device => {', |
| ], |
| # Connect Tokens |
| [ |
| ' device.gatt.connect();', |
| ], |
| [ |
| ' return device.gatt.connect();', |
| '})' |
| '.then(gatt => {', |
| ], |
| [ |
| ' gatt.connect();', |
| ], |
| [ |
| ' return gatt.connect();', |
| '})' |
| '.then(gatt => {', |
| ], |
| # GetPrimaryService(s) Tokens |
| [ |
| ' device.gatt.TRANSFORM_GET_PRIMARY_SERVICES;', |
| ], |
| [ |
| ' gatt.TRANSFORM_GET_PRIMARY_SERVICES;', |
| ], |
| [ |
| ' return device.gatt.TRANSFORM_GET_PRIMARY_SERVICES;', |
| '})' |
| '.then(services => {', |
| ], |
| [ |
| ' return gatt.TRANSFORM_GET_PRIMARY_SERVICES;', |
| '})' |
| '.then(services => {', |
| ], |
| # GetCharacteristic(s) Tokens |
| [ |
| ' TRANSFORM_PICK_A_SERVICE;', |
| ' service.TRANSFORM_GET_CHARACTERISTICS;', |
| ], |
| [ |
| ' TRANSFORM_PICK_A_SERVICE;', |
| ' return service.TRANSFORM_GET_CHARACTERISTICS;', |
| ], |
| # ReadValue Tokens |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' characteristic.readValue();', |
| ], |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' return characteristic.readValue().then(_ => characteristics);', |
| '})', |
| '.then(characteristics => {', |
| ], |
| # WriteValue Tokens |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' characteristic.writeValue(TRANSFORM_VALUE);', |
| ], |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' return characteristic.writeValue(TRANSFORM_VALUE).then(_ => characteristics);', |
| '})', |
| '.then(characteristics => {', |
| ], |
| # Start Notifications Tokens |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' characteristic.startNotifications();', |
| ], |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' return characteristic.startNotitications().then(_ => characteristics);', |
| '})', |
| '.then(characteristics => {', |
| ], |
| # Stop Notifications Tokens |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' characteristic.stopNotifications();', |
| ], |
| [ |
| ' TRANSFORM_PICK_A_CHARACTERISTIC;', |
| ' return characteristic.stopNotitications().then(() => characteristics);', |
| '})', |
| '.then(characteristics => {', |
| ], |
| # Garbage Collection |
| [ |
| ' runGarbageCollection();', |
| ], |
| [ |
| '})', |
| '.then(runGarbageCollection)', |
| '.then(() => {', |
| ], |
| # Reload Tokens |
| # We generate a unique id for each reload and save it in sessionStorage. |
| # This ensures that the reload is only executed once and that if test cases |
| # share the same sessionStorage all their reloads are executed. |
| [ |
| ' (() => {', |
| ' let reload_id = TRANSFORM_RELOAD_ID;', |
| ' if (!sessionStorage.getItem(reload_id)) {', |
| ' sessionStorage.setItem(reload_id, true);', |
| ' location.reload();', |
| ' }', |
| ' })();', |
| ], |
| ] |
| |
| INDENT = ' ' |
| BREAK = '\n' |
| END_TOKEN = '});' |
| |
| # Maximum number of tokens that will be inserted in the generated |
| # test case. |
| MAX_NUM_OF_TOKENS = 100 |
| |
| |
| def _GenerateSequenceOfRandomTokens(): |
| """Generates a sequence of calls to the Web Bluetooth API. |
| |
| Uses the arrays of strings in TOKENS and randomly picks a number between |
| [1, 100] to generate a random sequence of calls to the Web Bluetooth API, |
| calls to reload the page, and calls to perform garbage collection. |
| |
| Returns: |
| A string containing a sequence of calls to the Web Bluetooth API. |
| """ |
| result = random.choice(BASE_TOKENS) |
| |
| for _ in xrange(random.randint(1, MAX_NUM_OF_TOKENS)): |
| # Get random token. |
| token = random.choice(TOKENS) |
| |
| # Indent and break line. |
| for line in token: |
| result += INDENT + line + BREAK |
| |
| result += INDENT + END_TOKEN |
| |
| return result |
| |
| |
| def GenerateTestFile(template_file_data): |
| """Inserts a sequence of calls to the Web Bluetooth API into a template. |
| |
| Args: |
| template_file_data: A template containing the 'TRANSFORM_RANDOM_TOKENS' |
| string. |
| Returns: |
| A string consisting of template_file_data with the string |
| 'TRANSFORM_RANDOM_TOKENS' replaced with a sequence of calls to the Web |
| Bluetooth API and calls to reload the page and perform garbage |
| collection. |
| """ |
| |
| return FillInParameter('TRANSFORM_RANDOM_TOKENS', |
| _GenerateSequenceOfRandomTokens, |
| template_file_data) |