def test_get_check_actions(self): page_source = """<?xml version="1.0" encoding="UTF-8"?><hierarchy rotation="0"><android.widget.Button index="0" text="Display Preferences" class="android.widget.Button" package="org.tomdroid" content-desc="" checkable="true" checked="true" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="******" selected="false" bounds="[32,146][736,210]" resource-id="android:id/title1" instance="1"/> <nest><android.widget.TextView index="0" text="Login" class="android.widget.TextView" package="org.tomdroid" content-desc="" checkable="true" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="******" selected="false" bounds="[32,146][736,210]" resource-id="android:id/title2" instance="1"/> </nest><android.widget.TextView index="0" text="Display Preferences" class="android.widget.TextView" package="org.tomdroid" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="******" selected="false" bounds="[32,146][736,210]" resource-id="android:id/title3" instance="1"/> </hierarchy>""" uncheckable_widgets = [{ "selector": "id", "selectorValue": "android:id/title1", "description": "Display Preferences", "type": "Button", "state": "enabled" }] checkable_widgets = [{ "selector": "id", "selectorValue": "android:id/title2", "description": "Login", "type": "TextView", "state": "enabled" }] expected_actions = [ actions.Click(uncheckable_widgets[0], GUIActionType.UNCHECK, None), actions.Click(checkable_widgets[0], GUIActionType.CHECK, None) ] actual_actions = ui_analysis.get_possible_actions(page_source) self.assertIn(expected_actions[0], actual_actions) self.assertIn(expected_actions[1], actual_actions)
def test_pair_text_entry_with_non_text_entry_actions(self): # Arrange current_state = abstraction.create_state("contactsActivity", "abcdef") target = { "selector": "id", "selectorValue": "txt_first_name", "type": "edittext", "description": "First Name", "state": "enabled" } text_entry_action = actions.TextEntry(target, GUIActionType.TEXT_ENTRY, None) target_1 = { "selector": "id", "selectorValue": "ok_btn", "type": "button", "description": "OK", "state": "enabled" } action_1 = actions.Click(target_1, GUIActionType.CLICK, None) target_2 = { "selector": "id", "selectorValue": "cancel_btn", "type": "button", "description": "Cancel", "state": "enabled" } action_2 = actions.Click(target_2, GUIActionType.CLICK, None) target_3 = { "selector": "id", "selectorValue": "gender_radio_btn", "type": "radiobutton", "description": "Gender", "state": "enabled" } action_3 = actions.Click(target_3, GUIActionType.CLICK, None) non_text_entry_actions = [action_1, action_2, action_3] # Act text_and_act_events = abstraction.pair_text_entry_with_non_text_entry_actions( current_state, text_entry_action, non_text_entry_actions) # Assert expected_event_1 = { "precondition": current_state, "actions": [text_entry_action, action_1] } expected_event_2 = { "precondition": current_state, "actions": [text_entry_action, action_2] } expected_events = [expected_event_1, expected_event_2] self.assertEqual(text_and_act_events, expected_events)
def test_create_single_action_events(self): # Arrange current_state = abstraction.create_state("contactsActivity", "abcdef") target_1 = { "selector": "id", "selectorValue": "ok_btn", "type": "button", "description": "OK", "state": "enabled" } action_1 = actions.Click(target_1, GUIActionType.CLICK, None) target_2 = { "selector": "id", "selectorValue": "cancel_btn", "type": "button", "description": "Cancel", "state": "enabled" } action_2 = actions.Click(target_2, GUIActionType.CLICK, None) target_3 = { "selector": "id", "selectorValue": "gender_radio_btn", "type": "radiobutton", "description": "Gender", "state": "enabled" } action_3 = actions.Click(target_3, GUIActionType.CLICK, None) non_text_entry_actions = [action_1, action_2, action_3] # Act single_action_events = abstraction.create_single_action_events( current_state, non_text_entry_actions) # Assert expected_event_1 = { "precondition": current_state, "actions": [action_1] } expected_event_2 = { "precondition": current_state, "actions": [action_2] } expected_event_3 = { "precondition": current_state, "actions": [action_3] } expected_events = [ expected_event_1, expected_event_2, expected_event_3 ] self.assertEqual(expected_events, single_action_events)
def test_classify_actions(self): text_entry_widgets = [{ "selector": "id", "selectorValue": "android:id/title1", "description": "", "type": "EditText", "state": "enabled" }, { "selector": "id", "selectorValue": "android:id/title2", "description": "", "type": "EditText", "state": "enabled" }] non_text_entry_widgets = [{ "selector": "id", "selectorValue": "android:id/btn1", "description": "Display Preferences", "type": "Button", "state": "enabled" }, { "selector": "id", "selectorValue": "android:id/btn2", "description": "Login", "type": "Button", "state": "enabled" }, { "selector": "id", "selectorValue": "android:id/checkbox1", "description": "Show All", "type": "CheckBox", "state": "enabled" }] possible_actions = [ actions.TextEntry(text_entry_widgets[0], GUIActionType.TEXT_ENTRY, None), actions.TextEntry(text_entry_widgets[1], GUIActionType.TEXT_ENTRY, None), actions.Click(non_text_entry_widgets[0], GUIActionType.CLICK, None), actions.Click(non_text_entry_widgets[1], GUIActionType.CLICK, None), actions.Click(non_text_entry_widgets[2], GUIActionType.CHECK, None), actions.Click(non_text_entry_widgets[2], GUIActionType.UNCHECK, None) ] expected_text_entry_actions = [ actions.TextEntry(text_entry_widgets[0], GUIActionType.TEXT_ENTRY, None), actions.TextEntry(text_entry_widgets[1], GUIActionType.TEXT_ENTRY, None) ] expected_non_text_entry_actions = [ actions.Click(non_text_entry_widgets[0], GUIActionType.CLICK, None), actions.Click(non_text_entry_widgets[1], GUIActionType.CLICK, None), actions.Click(non_text_entry_widgets[2], GUIActionType.CHECK, None), actions.Click(non_text_entry_widgets[2], GUIActionType.UNCHECK, None) ] text_entry_actions, non_text_entry_actions = ui_analysis.classify_actions(possible_actions) self.assertEqual(text_entry_actions, expected_text_entry_actions) self.assertEqual(non_text_entry_actions, expected_non_text_entry_actions)
def test_event_hash_is_stable(self): # Arrange target = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } event = { "actions": [actions.Click(target, GUIActionType.CLICK, None)], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } # Act hashes = [] for i in range(10): event_hash = hashing.generate_event_hash(event) hashes.append(event_hash) # Assert self.assertEqual(len(set(hashes)), 1)
def test_synthesize(self): action_target = { "selector": "id", "selectorValue": "android:id/title", "description": "Display Preferences", "type": "TextView", "state": "enabled" } action_type = GUIActionType.CLICK action = actions.Click(action_target, action_type, None) partial_event = { "actions": [action], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } current_state = { "activityName": "contactsActivity", "stateId": "fedcba" } expected_complete_event = { "actions": [action], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" }, "postcondition": { "activityName": "contactsActivity", "stateId": "fedcba" } } actual_complete_event = abstraction.synthesize(partial_event, current_state) self.assertEqual(expected_complete_event, actual_complete_event)
def test_state_hash_ignores_order(self): widgets = [{ "selector": "id", "selectorValue": "android:id/title1", "description": "", "type": "EditText", "state": "enabled" }, { "selector": "id", "selectorValue": "android:id/title2", "description": "", "type": "EditText", "state": "enabled" }, { "selector": "id", "selectorValue": "android:id/btn2", "description": "Login", "type": "TextView", "state": "enabled" }, { "selector": "id", "selectorValue": "android:id/checkbox1", "description": "Show All", "type": "CheckBox", "state": "enabled" }] possible_actions = [ actions.TextEntry(widgets[0], GUIActionType.TEXT_ENTRY, "Hello World!"), actions.TextEntry(widgets[1], GUIActionType.TEXT_ENTRY, None), actions.Click(widgets[2], GUIActionType.CLICK, None), actions.Click(widgets[3], GUIActionType.CHECK, None), actions.Click(widgets[3], GUIActionType.UNCHECK, None) ] hashes = [] for i in range(10): random.shuffle(possible_actions) state_id = hashing.generate_state_hash(possible_actions) hashes.append(state_id) self.assertEqual(len(set(hashes)), 1)
def test_generate_test_case_hash_with_different_order_of_events(self): # Arrange target_1 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } action_1 = actions.Click(target_1, GUIActionType.CLICK, None) event_1 = { "actions": [action_1], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } target_2 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "disabled" } action_2 = actions.Click(target_2, GUIActionType.CLICK, None) event_2 = { "precondition": { "activityName": "launchActivity", "stateId": "abcdef" }, "actions": [action_2] } test_case1 = [event_1, event_2] test_case2 = [event_2, event_1] # Act test_case_hash1 = hashing.generate_test_case_hash(test_case1) test_case_hash2 = hashing.generate_test_case_hash(test_case2) # Assert self.assertNotEqual(test_case_hash1, test_case_hash2)
def test_that_disabled_and_enabled_events_have_different_hash(self): # Arrange enabled_target = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } enabled_action = actions.Click(enabled_target, GUIActionType.CLICK, None) enabled_event = { "actions": [enabled_action], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } disabled_target = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "disabled" } disabled_action = actions.Click(disabled_target, GUIActionType.CLICK, None) disabled_event = { "precondition": { "activityName": "launchActivity", "stateId": "abcdef" }, "actions": [disabled_action] } # Act enabled_event_hash = hashing.generate_event_hash(enabled_event) disabled_event_hash = hashing.generate_event_hash(disabled_event) # Assert self.assertNotEqual(enabled_event_hash, disabled_event_hash)
def test_generate_test_case_hash(self): # Arrange target_1 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } action_1 = actions.Click(target_1, GUIActionType.CLICK, None) event_1 = { "actions": [action_1], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } target_2 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "disabled" } action_2 = actions.Click(target_2, GUIActionType.CLICK, None) event_2 = { "precondition": { "activityName": "launchActivity", "stateId": "abcdef" }, "actions": [action_2] } test_case = [event_1, event_2] # Act test_case_hash = hashing.generate_test_case_hash(test_case) # Assert self.assertEqual(test_case_hash, "854ec40eabd6348cd96507a1339d9bd64919e747")
def test_create_action(self): action_type = GUIActionType.CLICK widget = { "selector": "id", "selectorValue": "widget_id", "description": "Login", "type": "Button", "state": "enabled" } created_action = abstraction.create_action(action_type, widget) expected_action = actions.Click(widget, action_type, None) self.assertEqual(created_action, expected_action)
def test_event_hash_is_same_regardless_of_value(self): # Arrange target_1 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "EditText", "state": "enabled" } action_1 = actions.Click(target_1, GUIActionType.CLICK, "Wunderland") event_1 = { "actions": [action_1], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } target_2 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "EditText", "state": "enabled" } action_2 = actions.Click(target_2, GUIActionType.CLICK, "Jekyll") event_2 = { "actions": [action_2], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } # Act event_hash1 = hashing.generate_event_hash(event_1) event_hash2 = hashing.generate_event_hash(event_2) # Assert self.assertEqual(event_hash1, event_hash2)
def test_event_hashing_does_not_change_with_key_order(self): # Arrange target_1 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } action_1 = actions.Click(target_1, GUIActionType.CLICK, None) event_1 = { "actions": [action_1], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } target_2 = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } action_2 = actions.Click(target_2, GUIActionType.CLICK, None) event_2 = { "precondition": { "activityName": "launchActivity", "stateId": "abcdef" }, "actions": [action_2] } # Act event_hash1 = hashing.generate_event_hash(event_1) event_hash2 = hashing.generate_event_hash(event_2) # Assert self.assertEqual(event_hash1, event_hash2)
def test_action_does_not_pair_with_text_entry(self): # Arrange target = { "selector": "id", "selectorValue": "gender_radio_btn", "type": "radiobutton", "description": "Gender", "state": "enabled" } non_pair_action = actions.Click(target, GUIActionType.CLICK, None) # Act action_pairs_with_text_entry = abstraction.does_action_pair_with_text_entry( non_pair_action) # Assert self.assertFalse(action_pairs_with_text_entry)
def test_create_partial_event(self): # Arrange precondition = abstraction.create_state("contactsActivity", "abcdef") action_target = { "selector": "id", "selectorValue": "delete_btn", "type": TargetType.BUTTON, "description": "Delete", "state": TargetState.ENABLED } action_type = GUIActionType.CLICK action = actions.Click(action_target, action_type, None) gui_actions = [action] # Act partial_event = abstraction.create_partial_event( precondition, gui_actions) # Assert expected_event = {"precondition": precondition, "actions": gui_actions} self.assertEqual(partial_event, expected_event)
def test_get_hash_event(self): # Arrange target = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } event = { "actions": [actions.Click(target, GUIActionType.CLICK, None)], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } # Act hash_event = hashing._get_hash_event(event) # Assert self.assertNotIn("value", hash_event["actions"][0])
def test_can_make_event_serializable_when_single_action(self): # Arrange target = abstraction.create_target("id", "element_id", "description", "button", "enabled") action_1 = actions.Click(target, GUIActionType.CLICK, None) precondition = {"activityName": "activity_1", "stateId": "state_id_1"} postcondition = {"activityName": "activity_2", "stateId": "state_id_1"} event = { "actions": [action_1], "precondition": precondition, "postcondition": postcondition } # Act event_with_actions_as_dict = abstraction.make_event_serializable(event) # Assert action_as_dict = event_with_actions_as_dict["actions"][0] self.assertIsInstance(action_as_dict, dict) self.assertEqual(action_as_dict["target"], action_1.target) self.assertEqual(action_as_dict["type"], action_1.action_type) self.assertEqual(action_as_dict["value"], action_1.value)
def test_event_hashing(self): # Arrange target = { "selector": "id", "selectorValue": "android:id/display_preferences", "description": "Display Preferences", "type": "TextView", "state": "enabled" } event = { "actions": [actions.Click(target, GUIActionType.CLICK, None)], "precondition": { "activityName": "launchActivity", "stateId": "abcdef" } } # Act event_hash = hashing.generate_event_hash(event) # Assert self.assertEqual(event_hash, "1c7d92889def3c42168491899e45bfb9a70ef790")
def test_can_get_available_events_with_one_click_event(self): # Arrange webdriver_mock = MagicMock(name="webdriver") webdriver_mock.page_source = """<?xml version="1.0" encoding="UTF-8"?><hierarchy rotation="0"><android.widget.Button index="0" text="Display Preferences" class="android.widget.Button" package="org.tomdroid" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="******" selected="false" bounds="[32,146][736,210]" resource-id="android:id/title1" instance="1"/> <nest><android.widget.TextView index="0" text="Login" class="android.widget.TextView" package="org.tomdroid" content-desc="" checkable="false" checked="false" clickable="false" enabled="false" focusable="false" focused="false" scrollable="false" long-clickable="false" password="******" selected="false" bounds="[32,146][736,210]" resource-id="android:id/title2" instance="1"/> </nest><android.widget.TextView index="0" text="Display Preferences" class="android.widget.TextView" package="org.tomdroid" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="******" selected="false" bounds="[32,146][736,210]" resource-id="android:id/title3" instance="1"/> </hierarchy>""" webdriver_mock.current_activity = "contactsActivity" current_state = ui_analysis.get_current_state(webdriver_mock) # Act available_events = ui_analysis.get_available_events(webdriver_mock) # Assert expected_target = abstraction.create_target("id", "android:id/title1", "Display Preferences", TargetType.BUTTON, TargetState.ENABLED) expected_available_events = [ { "precondition": current_state, "actions": [actions.Click(expected_target, GUIActionType.CLICK, None)] }, abstraction.create_back_event(current_state), abstraction.create_background_event(current_state) ] self.assertEqual(available_events, expected_available_events)
def test_create_partial_text_events_with_multiple_text_fields(self): # Arrange current_state = abstraction.create_state("contactsActivity", "abcdef") text_entry_target_1 = { "selector": "id", "selectorValue": "txt_first_name", "type": "edittext", "description": "First Name", "state": "enabled" } text_entry_action_1 = actions.TextEntry(text_entry_target_1, GUIActionType.TEXT_ENTRY, None) text_entry_target_2 = { "selector": "id", "selectorValue": "txt_last_name", "type": "edittext", "description": "Last Name", "state": "enabled" } text_entry_action_2 = actions.TextEntry(text_entry_target_2, GUIActionType.TEXT_ENTRY, None) text_entry_actions = [text_entry_action_1, text_entry_action_2] non_text_entry_target_1 = { "selector": "id", "selectorValue": "ok_btn", "type": "button", "description": "OK", "state": "enabled" } non_text_entry_action_1 = actions.Click(non_text_entry_target_1, GUIActionType.CLICK, None) non_text_entry_target_2 = { "selector": "id", "selectorValue": "cancel_btn", "type": "button", "description": "Cancel", "state": "enabled" } non_text_entry_action_2 = actions.Click(non_text_entry_target_2, GUIActionType.CLICK, None) non_text_entry_target_3 = { "selector": "id", "selectorValue": "gender_radio_btn", "type": "radiobutton", "description": "Gender", "state": "enabled" } non_text_entry_action_3 = actions.Click(non_text_entry_target_3, GUIActionType.CLICK, None) non_text_entry_actions = [ non_text_entry_action_1, non_text_entry_action_2, non_text_entry_action_3 ] # Act events = abstraction.create_partial_text_events( current_state, text_entry_actions, non_text_entry_actions) # Assert expected_event_1 = { "precondition": current_state, "actions": text_entry_actions + [non_text_entry_action_1] } expected_event_2 = { "precondition": current_state, "actions": text_entry_actions + [non_text_entry_action_2] } expected_event_3 = { "precondition": current_state, "actions": [non_text_entry_action_1] } expected_event_4 = { "precondition": current_state, "actions": [non_text_entry_action_2] } expected_event_5 = { "precondition": current_state, "actions": [non_text_entry_action_3] } expected_events = [ expected_event_1, expected_event_2, expected_event_3, expected_event_4, expected_event_5 ] self.assertEqual(expected_events, events)
def test_create_partial_text_events_with_single_text_field(self): # Arrange current_state = abstraction.create_state("contactsActivity", "abcdef") text_entry_target_1 = { "selector": "id", "selectorValue": "txt_first_name", "type": "edittext", "description": "First Name", "state": "enabled" } text_entry_action_1 = actions.TextEntry(text_entry_target_1, GUIActionType.TEXT_ENTRY, None) text_entry_actions = [text_entry_action_1] non_text_entry_target_1 = { "selector": "id", "selectorValue": "ok_btn", "type": "button", "description": "OK", "state": "enabled" } non_text_entry_action_1 = actions.Click(non_text_entry_target_1, GUIActionType.CLICK, None) non_text_entry_target_2 = { "selector": "id", "selectorValue": "cancel_btn", "type": "button", "description": "Cancel", "state": "enabled" } non_text_entry_action_2 = actions.Click(non_text_entry_target_2, GUIActionType.CLICK, None) non_text_entry_target_3 = { "selector": "id", "selectorValue": "gender_radio_btn", "type": "radiobutton", "description": "Gender", "state": "enabled" } non_text_entry_action_3 = actions.Click(non_text_entry_target_3, GUIActionType.CLICK, None) non_text_entry_actions = [ non_text_entry_action_1, non_text_entry_action_2, non_text_entry_action_3 ] # Act partial_text_events = abstraction.create_partial_text_events( current_state, text_entry_actions, non_text_entry_actions) # Assert - potentially improve tests to not assert on lists but use membership assert text_entry_action = text_entry_actions[0] text_entry_action.value = "[random string]" enter_action = abstraction.create_action( "enter", abstraction.create_enter_target()) expected_event_1 = { "precondition": current_state, "actions": [text_entry_action, non_text_entry_action_1] } expected_event_2 = { "precondition": current_state, "actions": [text_entry_action, non_text_entry_action_2] } expected_event_3 = { "precondition": current_state, "actions": [text_entry_action, enter_action] } expected_event_4 = { "precondition": current_state, "actions": [non_text_entry_action_1] } expected_event_5 = { "precondition": current_state, "actions": [non_text_entry_action_2] } expected_event_6 = { "precondition": current_state, "actions": [non_text_entry_action_3] } expected_events = [ expected_event_1, expected_event_2, expected_event_3, expected_event_4, expected_event_5, expected_event_6 ] self.assertEqual(partial_text_events, expected_events)