def swipe(self, start_position, end_position): """Swipe from one point to another point. :param start_position: A `stbt.Region` or (x, y) tuple of coordinates at which to start. :param end_position: A `stbt.Region` or (x, y) tuple of coordinates at which to stop. Example:: d.swipe((100, 100), (100, 400)) """ x1, y1 = _region_to_tuple(start_position) x2, y2 = _region_to_tuple(end_position) stbt.debug("AdbDevice.swipe((%d,%d), (%d,%d))" % (x1, y1, x2, y2)) x1, y1 = self._to_native_coordinates(x1, y1) x2, y2 = self._to_native_coordinates(x2, y2) command = [ "shell", "input", "swipe", str(x1), str(y1), str(x2), str(y2) ] self.adb(command, timeout_secs=10)
def main(argv): parser = _stbt.core.argparser() parser.prog = 'stbt record' parser.description = 'Create an stb-tester test script' parser.add_argument( '--control-recorder', default=stbt.get_config('record', 'control_recorder'), help='The source of remote control keypresses (default: %(default)s)') parser.add_argument( '-o', '--output-file', default=stbt.get_config('record', 'output_file'), help='The filename of the generated script (default: %(default)s)') args = parser.parse_args(argv[1:]) stbt.debug("Arguments:\n" + "\n".join([ "%s: %s" % (k, v) for k, v in args.__dict__.items()])) try: script = open(args.output_file, 'w') except IOError as e: e.strerror = "Failed to write to output-file '%s': %s" % ( args.output_file, e.strerror) raise with _stbt.core.new_device_under_test_from_config(args) as dut: record(dut, args.control_recorder, script)
def find_player(selected_image, unselected_image): """Navigates to the specified player. Precondition: In the OnDemand Players screen. Uses `unselected_image` to find where the player is on screen; navigates there; uses `selected_image` to know that it has reached the player. """ page_changes = [0] def next_page(): if page_changes[0] < 3: stbt.press("FASTFORWARD") time.sleep(1) page_changes[0] += 1 else: raise stbt.MatchTimeout(None, unselected_image, 0) while not _player_selected(selected_image): target = stbt.detect_match(unselected_image).next() if target.match: source = _matches("images/any-player-selected.png").next() stbt.debug("find_player: source=%d,%d target=%d,%d" % ( source.position.x, source.position.y, target.position.x, target.position.y)) stbt.press(_next_key(source.position, target.position)) _wait_for_selection_to_move(source) else: next_page()
def main(argv): parser = _stbt.core.argparser() parser.prog = 'stbt run' parser.description = 'Run an stb-tester test script' parser.add_argument( '--save-screenshot', default='on-failure', choices=['always', 'on-failure', 'never'], help="Save a screenshot at the end of the test to screenshot.png") parser.add_argument( '--save-thumbnail', default='never', choices=['always', 'on-failure', 'never'], help="Save a thumbnail at the end of the test to thumbnail.jpg") parser.add_argument( 'script', metavar='FILE[::TESTCASE]', help=( "The python test script to run. Optionally specify a python " "function name to run that function; otherwise only the script's " "top-level will be executed.")) parser.add_argument( 'args', nargs=argparse.REMAINDER, metavar='ARG', help='Additional arguments passed on to the test script (in sys.argv)') args = parser.parse_args(argv[1:]) stbt.debug("Arguments:\n" + "\n".join([ "%s: %s" % (k, v) for k, v in args.__dict__.items()])) dut = _stbt.core.new_device_under_test_from_config(args) with sane_unicode_and_exception_handling(args.script), video(args, dut): test_function = load_test_function(args.script, args.args) test_function.call()
def main(argv): parser = _stbt.core.argparser() parser.prog = 'stbt record' parser.description = 'Create an stb-tester test script' parser.add_argument( '--control-recorder', default=stbt.get_config('record', 'control_recorder'), help='The source of remote control keypresses (default: %(default)s)') parser.add_argument( '-o', '--output-file', default=stbt.get_config('record', 'output_file'), help='The filename of the generated script (default: %(default)s)') args = parser.parse_args(argv[1:]) stbt.debug("Arguments:\n" + "\n".join(["%s: %s" % (k, v) for k, v in args.__dict__.items()])) try: script = open(args.output_file, 'w') except IOError as e: e.strerror = "Failed to write to output-file '%s': %s" % ( args.output_file, e.strerror) raise with _stbt.core.new_device_under_test_from_config(args) as dut: record(dut, args.control_recorder, script)
def text(self): if self._text is None and self.__nonzero__(): diff = cv2.cvtColor( cv2.absdiff( crop(self._frame, self.region), numpy.repeat(self._background, self.region.width, 1)), cv2.COLOR_BGR2GRAY) self._text = stbt.ocr(diff) stbt.debug("Selection text: %s" % self._text) return self._text
def _read_text(self, title, patterns=None): title = stbt.match_text( title, frame=self._frame, region=stbt.Region(x=620, y=145, right=950, bottom=460), text_color=(124, 94, 114)) if not title: stbt.debug("NetworkAbout: Didn't find %r" % title) return None region = title.region.right_of().extend(x=10, y=-5, bottom=10) return stbt.ocr(self._frame, region, tesseract_user_patterns=patterns)
def _adb(self, command, timeout_secs=None, **kwargs): _command = [] if timeout_secs is not None: _command += ["timeout", "%fs" % timeout_secs] _command += [self.adb_binary] if self.adb_server: _command += ["-H", self.adb_server] if self.adb_device: _command += ["-s", self.adb_device] _command += command stbt.debug("AdbDevice.adb: About to run command: %r\n" % _command) output = subprocess.check_output( _command, stderr=subprocess.STDOUT, **kwargs) return output
def press(self, key): """Send a keypress. :param str key: An Android keycode as listed in <https://developer.android.com/reference/android/view/KeyEvent.html>. Particularly useful key codes are "KEYCODE_HOME" and "KEYCODE_BACK", which are physical buttons on some phones so you can't hit them with `AdbDevice.tap`. """ # "adb shell input keyevent xxx" always returns success, so we need to # validate key names. if key not in _KEYCODES: raise ValueError("Unknown key code %r" % (key,)) stbt.debug("AdbDevice.press(%r)" % key) self.adb(["shell", "input", "keyevent", key], timeout_secs=10)
def press(self, key): """Send a keypress. :param str key: An Android keycode as listed in <https://developer.android.com/reference/android/view/KeyEvent.html>. Particularly useful key codes are "KEYCODE_HOME" and "KEYCODE_BACK", which are physical buttons on some phones so you can't hit them with `AdbDevice.tap`. """ # "adb shell input keyevent xxx" always returns success, so we need to # validate key names. if key not in _KEYCODES: raise ValueError("Unknown key code %r" % (key, )) stbt.debug("AdbDevice.press(%r)" % key) self.adb(["shell", "input", "keyevent", key], timeout_secs=10)
def tap(self, position): """Tap on a particular location. :param position: A `stbt.Region`, or an (x,y) tuple. Example:: d.tap((100, 20)) d.tap(stbt.match(...).region) """ x, y = _region_to_tuple(position) stbt.debug("AdbDevice.tap((%d,%d))" % (x, y)) x, y = self._to_native_coordinates(x, y) self.adb(["shell", "input", "tap", str(x), str(y)], timeout_secs=10)
def swipe(self, start_position, end_position): """Swipe from one point to another point. :param start_position: A `stbt.Region` or (x, y) tuple of coordinates at which to start. :param end_position: A `stbt.Region` or (x, y) tuple of coordinates at which to stop. Example:: d.swipe((100, 100), (100, 400)) """ x1, y1 = _region_to_tuple(start_position) x2, y2 = _region_to_tuple(end_position) stbt.debug("AdbDevice.swipe((%d,%d), (%d,%d))" % (x1, y1, x2, y2)) x1, y1 = self._to_native_coordinates(x1, y1) x2, y2 = self._to_native_coordinates(x2, y2) command = ["shell", "input", "swipe", str(x1), str(y1), str(x2), str(y2)] self.adb(command, timeout_secs=10)
def select(self, menu, *submenus): """Select the specified menu item (and sub-menus, if specified). Example:: Menu().select("Settings", "Network", "About") """ assert self.is_visible original_value = self.selection f = self # FrameObject of current video-frame being processed target = menu for _ in range(20): assert f.is_visible current_value = f.selection if current_value == target: stbt.debug("Menu.select: Found %s" % target) if submenus: transition = stbt.press_and_wait("KEY_OK") assert transition f = Menu(frame=transition.frame) assert f.selection != current_value return f.select(submenus[0], *submenus[1:]) else: return f stbt.debug("Menu.select: target=%r, current=%r, " "going to press KEY_DOWN" % (target, current_value)) transition = stbt.press_and_wait("KEY_DOWN") assert transition f = Menu(frame=transition.frame) assert f.is_visible assert f.selection != current_value assert f.selection != original_value, ( "Menu.select wrapped around to %r without finding %r" % (original_value, target))
def find_selection_horizontal_repeat( frame, background, region=stbt.Region.ALL, match_threshold=0.95): """Find the selected menu item by looking for the specified background. This is an example to demonstrate that you can implement your own custom image processing with OpenCV. :param frame: An OpenCV image, as returned by `stbt.get_frame` or `cv2.imread`. If `None`, will pull a new frame from the system under test. :param background: The path to a 1-pixel-wide image of your system-under-test's menu selection/highlight. :param region: If specified, restrict the search to this region of the frame. :returns: A `Selection` object representing the selected item. Example:: >>> frame = load_image("selftest-screenshots/roku-home.png") >>> find_selection_horizontal_repeat( ... frame, "images/roku-menu-selection-background.png") Selection(region=Region(x=119, y=162, right=479, bottom=204), text=u'Home') """ if frame is None: frame = stbt.get_frame() frame = crop(frame, region) bg = load_image(background) correlation = 1 - cv2.matchTemplate(frame, bg, cv2.TM_SQDIFF_NORMED) _, max_, _, _ = cv2.minMaxLoc(correlation) selection_region = None if max_ >= match_threshold: # Find y coordinate rowmax = numpy.amax(correlation, axis=1) goodness = rowmax _, _, _, maxloc = cv2.minMaxLoc(goodness) y = maxloc[1] # Got the y position, now work out the horizontal extents line_uint8 = numpy.uint8(correlation[y, :]*255) _, binary = cv2.threshold(line_uint8, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY) binary = binary.flatten() nonzeros = list(_combine_neighbouring_extents( list(_zeros_to_extents(binary.nonzero()[0])))) if nonzeros: widest = max(nonzeros, key=lambda a: a[1] - a[0]) x, right = widest selection_region = ( stbt.Region(x, y, right=right, bottom=y + bg.shape[0]) .translate(x=max(0, region.x), y=max(0, region.y))) if selection_region.width > 10: # Remove the rounded corners of the selection; after subtracting # the background they look like single-quotes to the OCR engine. selection_region = selection_region.extend(x=5, right=-5) if not selection_region: stbt.debug( "find_selection didn't find match (%.2f) above the threshold (%.2f)" % (max_, match_threshold)) return Selection(selection_region, frame, bg)
def find_selection_horizontal_repeat(frame, background, region=stbt.Region.ALL, match_threshold=0.95): """Find the selected menu item by looking for the specified background. This is an example to demonstrate that you can implement your own custom image processing with OpenCV. :param frame: An OpenCV image, as returned by `stbt.get_frame` or `cv2.imread`. If `None`, will pull a new frame from the system under test. :param background: The path to a 1-pixel-wide image of your system-under-test's menu selection/highlight. :param region: If specified, restrict the search to this region of the frame. :returns: A `Selection` object representing the selected item. Example:: >>> frame = load_image("../selftest/screenshots/roku-home.png") >>> find_selection_horizontal_repeat( ... frame, "images/roku-menu-selection-background.png") Selection(region=Region(x=116, y=157, right=483, bottom=208), text=u'Home') """ if frame is None: frame = stbt.get_frame() frame = crop(frame, region) bg = load_image(background) correlation = 1 - cv2.matchTemplate(frame, bg, cv2.TM_SQDIFF_NORMED) _, max_, _, _ = cv2.minMaxLoc(correlation) selection_region = None if max_ >= match_threshold: # Find y coordinate rowmax = numpy.amax(correlation, axis=1) goodness = rowmax _, _, _, maxloc = cv2.minMaxLoc(goodness) y = maxloc[1] # Got the y position, now work out the horizontal extents line_uint8 = numpy.uint8(correlation[y, :] * 255) _, binary = cv2.threshold(line_uint8, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY) binary = binary.flatten() nonzeros = list( _combine_neighbouring_extents( list(_zeros_to_extents(binary.nonzero()[0])))) if nonzeros: widest = max(nonzeros, key=lambda a: a[1] - a[0]) x, right = widest selection_region = (stbt.Region(x, y, right=right, bottom=y + bg.shape[0]).translate( x=max(0, region.x), y=max(0, region.y))) if selection_region.width > 10: # Remove the rounded corners of the selection; after subtracting # the background they look like single-quotes to the OCR engine. selection_region = selection_region.extend(x=5, right=-5) if not selection_region: stbt.debug( "find_selection didn't find match (%.2f) above the threshold (%.2f)" % (max_, match_threshold)) return Selection(selection_region, frame, bg)