def test_get_shortest_path(self): automata = Automata() state0 = State('state0') state1 = State('state1') state2 = State('state2') state3 = State('state3') state4 = State('state4') state5 = State('state5') state6 = State('state6') automata.add_state(state0) automata.add_state(state1) automata.add_state(state2) automata.add_state(state3) automata.add_state(state4) automata.add_state(state5) automata.add_state(state6) automata.add_edge(state0, state1, Clickable('0-1')) automata.add_edge(state0, state2, Clickable('0-2')) automata.add_edge(state0, state3, Clickable('0-3')) automata.add_edge(state2, state4, Clickable('2-4')) automata.add_edge(state4, state5, Clickable('4-5')) automata.add_edge(state3, state5, Clickable('3-5')) automata.add_edge(state3, state5, Clickable('5-0')) automata.add_edge(state5, state6, Clickable('5-6')) self.assertEqual(automata.get_shortest_path(state0), []) edges = automata.get_shortest_path(state6) # 0-3, 3-5, 5-6 self.assertEqual([int(e[0].get_id()) for e in edges], [0, 3, 5])
def test_automata(self): dom1 = self.automata.get_current_state().get_dom() dom1 += '<custom></custom>' dom2 = dom1 state1 = State(dom1) state2 = State(dom2) self.automata.add_state(state1) state3, is_newly_added = self.automata.add_state(state2) self.assertTrue(state3 == state1) self.assertFalse(is_newly_added) self.assertEqual(len(self.automata.get_states()), 2) clickable = self.automata.get_current_state().get_clickables()[0] clickable2 = Clickable('', '//html/body/button[3]') self.assertEqual(len(self.automata.get_current_state().get_clickables()), 1) self.automata.get_current_state().add_clickable(clickable) self.automata.get_current_state().add_clickable(clickable2) self.automata.get_current_state().add_clickable(clickable2) self.assertEqual(len(self.automata.get_current_state().get_clickables()), 2) self.automata.add_edge(self.automata.get_current_state(), state1, self.automata.get_current_state().get_clickables()[0]) self.assertEqual(len(self.automata.get_edges()), 1) state1.add_prev_state(self.automata.get_current_state()) self.assertEqual(self.automata.get_current_state().get_id(), '0') self.automata.change_state(state1) self.assertEqual(self.automata.get_initial_state().get_id(), '0') self.assertEqual(self.automata.get_current_state().get_id(), '1') self.assertEqual(self.automata.get_current_state().get_prev_states()[0].get_id(), '0') '''
def __init__(self, fname=None, load_dom=False): self._states = [] self._edges = [] self._initial_state = None self._current_state = None if fname: assert os.path.isfile(fname) and os.path.exists(fname) t_start = time.time() with open(fname) as f: data = json.load(f) for state in data['state']: if load_dom: with open( os.path.join( os.path.dirname(os.path.realpath(fname)), state['dom_path']), 'r') as df: s = State(df.read()) else: s = State(state['id']) s.set_id(state['id']) for form in state['form']: f = FormField(form['id'], form['xpath']) for the_input in form['input']: f.add_input( InputField(the_input['id'], the_input['xpath'], the_input['type'], the_input['value'])) s.add_form(f) for clickable in state['clickable']: c = Clickable(clickable['id'], clickable['xpath'], clickable['tag']) for form in clickable['form']: f = s.get_form_by_id(form['id']) assert f c.add_form(f) s.add_clickable(c) self.add_state(s) for edge in data['edge']: from_state = self.get_state_by_id(edge['from']) to_state = self.get_state_by_id(edge['to']) clickable = from_state.get_clickable_by_id( edge['clickable']) assert from_state and to_state and clickable self.add_edge(from_state, to_state, clickable) logger.info('automata loaded. loading time: %f sec', time.time() - t_start)
def test_generate_report(self): num_clickables = { 'unexamined': 5, 'true': 10, 'false': 30 } form1 = FormField('form1') form1.add_input(InputField('username', '//*[@id="username"]', 'castman')) form1.add_input(InputField('password', '', 'p@ssw0rd')) form_list = [{ 'state': 1, 'form': form1, 'execution_seq': [Clickable('exe1', '//html/body/button[1]'), Clickable('exe2', '//html/body/button[1]')], 'clickable': [Clickable('btn1', '//html/body/button[1]'), Clickable('btn2', '//html/body/button[1]')] }] inv_violation = [{ 'state': 2, 'name': '{"name": "file-not-found"}', 'sequence': [Clickable('inv-btn1', '//html/body/button[1]'), Clickable('inv-btn2', '//html/body/button[1]')] }] Visualizer.generate_report( 'web', 'trace/example-app-4-webide', 'automata.json', 3, num_clickables, form_list, inv_violation, 9.987 )
def run_arch_test(self, arch=None, arch_agnostic_builder=False, build_cmd=True, restrict_arch_env=None, restrict_arch=None, expect_exception=False): config_env = {} if restrict_arch_env: config_env['CLICKABLE_ARCH'] = restrict_arch_env config_json = {} if arch_agnostic_builder: config_json["builder"] = "pure" else: config_json["builder"] = "cmake" if restrict_arch: config_json["restrict_arch"] = restrict_arch cli_args = [] if arch: cli_args += ["--arch", arch] parser = Clickable.create_parser("Unit Test Call") run_args = parser.parse_args(cli_args) commands = ['no_command'] if build_cmd: commands.append('build') self.setUpConfig( expect_exception = expect_exception, mock_config_json = config_json, mock_config_env = config_env, args = run_args, commands = commands, ) if arch: expected_arch = arch elif restrict_arch: expected_arch = restrict_arch elif arch_agnostic_builder: expected_arch = "all" elif restrict_arch_env: expected_arch = restrict_arch_env else: expected_arch = "armhf" if not expect_exception: self.assertEqual(expected_arch, self.config.arch)
def setUp(self): self.clickable = Clickable() self.original_path = os.getcwd() self.path = os.path.join(os.path.dirname(__file__), 'tmp') self.app_path = os.path.join(self.path, 'appname') if os.path.exists(self.path): shutil.rmtree(self.path) os.makedirs(self.path) os.chdir(self.path) os.environ['CLICKABLE_DEFAULT'] = 'clean build review' os.environ['CLICKABLE_ARCH'] = 'amd64' self.config_file = os.path.expanduser( '~/.clickable/cookiecutter_config.yaml') self.tmp_config_file = '/tmp/cookiecutter_config.yaml' self.restore_config = False if os.path.exists(self.config_file): os.rename(self.config_file, self.tmp_config_file) self.restore_config = True
def __init__(self, fname=None, load_dom=False): self._states = [] self._edges = [] self._initial_state = None self._current_state = None if fname: assert os.path.isfile(fname) and os.path.exists(fname) t_start = time.time() with open(fname) as f: data = json.load(f) for state in data['state']: if load_dom: with open(os.path.join(os.path.dirname(os.path.realpath(fname)), state['dom_path']), 'r') as df: s = State(df.read()) else: s = State(state['id']) s.set_id(state['id']) for form in state['form']: f = FormField(form['id'], form['xpath']) for the_input in form['input']: f.add_input(InputField(the_input['id'], the_input['xpath'], the_input['type'], the_input['value'])) s.add_form(f) for clickable in state['clickable']: c = Clickable(clickable['id'], clickable['xpath'], clickable['tag']) for form in clickable['form']: f = s.get_form_by_id(form['id']) assert f c.add_form(f) s.add_clickable(c) self.add_state(s) for edge in data['edge']: from_state = self.get_state_by_id(edge['from']) to_state = self.get_state_by_id(edge['to']) clickable = from_state.get_clickable_by_id(edge['clickable']) assert from_state and to_state and clickable self.add_edge(from_state, to_state, clickable) logger.info('automata loaded. loading time: %f sec', time.time() - t_start)
def build_trace(self, data): try: edges = [] for edge in data['edges']: state_from = edge['from'] state_to = edge['to'] c = edge['clickable'] clickable = Clickable(c['id'], c['name'], c['xpath'], c['tag']) inputs = [] for i in edge['inputs']: inputs.append( InputField(i['id'], i['name'], i['xpath'], i['type'], i['value'])) selects = [] for s in edge['selects']: selects.append( SelectField(s['id'], s['name'], s['xpath'], s['value'], s['selected'])) checkboxes = [] for c_field in edge['checkboxes']: c_list = [] for c in c_field['checkbox_list']: c_list.append( Checkbox(c['id'], c['name'], c['xpath'], c['value'])) checkboxes.append( CheckboxField(c_list, c_field['checkbox_name'], c_field['checkbox_selected_list'])) radios = [] for r_field in edge['radios']: r_list = [] for r in r_field['radio_list']: r_list.append( Radio(r['id'], r['name'], r['xpath'], r['value'])) radios.append( RadioField(r_list, r_field['radio_name'], r_field['radio_selected'])) iframe_list = edge['iframe_list'] edges.append( Edge(state_from, state_to, clickable, inputs, selects, checkboxes, radios, iframe_list)) return edges except Exception as e: logging.error('can not build trace: %s', str(e))
def load_automata(fname): t_start = time.time() assert os.path.isfile(fname) and os.path.exists(fname) automata = Automata() with open(fname) as f: data = json.load(f) for state in data['state']: with open(os.path.join(os.path.dirname(os.path.realpath(fname)), state['dom_path']), 'r') as df: s = State(df.read()) s.set_id(state['id']) for clickable in state['clickable']: c = Clickable(clickable['id'], clickable['xpath'], clickable['tag']) s.add_clickable(c) automata.add_state(s) for edge in data['edge']: from_state = automata.get_state_by_id(edge['from']) to_state = automata.get_state_by_id(edge['to']) clickable = from_state.get_clickable_by_id(edge['clickable']) assert from_state and to_state and clickable automata.add_edge(from_state, to_state, clickable) return automata
def get_clickables(cls, cs, prev_s=None): # only return newly discovered clickables, i.e. clickables not in prev_clickables cs_candidate_clickables_dict = cs.get_all_candidate_clickables() prev_candidate_clickables_dict = prev_s.get_all_candidate_clickables( ) if prev_s else None clickables_iframe_list = [] for iframe_path_key in cs_candidate_clickables_dict.keys(): #find prev_candidate_clickables if prev_s exists and iframe_path_list same cs_candidate_clickables = cs_candidate_clickables_dict[ iframe_path_key] prev_candidate_clickables = None clickables = [] if prev_candidate_clickables_dict: for prev_i in prev_candidate_clickables_dict.keys(): if iframe_path_key == prev_i: prev_candidate_clickables = prev_candidate_clickables_dict[ prev_i] break for candidate_clickable, clickable_xpath in cs_candidate_clickables: #find if candidate_clickable is same in prev if not cls._is_same_soup_in_prev( prev_candidate_clickables, candidate_clickable, clickable_xpath ) \ and not cls._is_duplicate(clickables, candidate_clickable): clickable_id = cls.make_id( candidate_clickable.get('id') if candidate_clickable. has_attr('id') else None) clickable_name = candidate_clickable.get( 'name') if candidate_clickable.has_attr( 'name') else clickable_id clickable_xpath = cls._get_xpath(candidate_clickable) clickable_tag = candidate_clickable.name clickables.append( Clickable(clickable_id, clickable_name, clickable_xpath, clickable_tag)) clickables_iframe_list.append((clickables, iframe_path_key)) return clickables_iframe_list
def get_clickables(cls, dom, prev_dom=None): # only return newly discovered clickables and forms, i.e. clickables not in prev_clickables prev_clickables = [] prev_forms = [] if prev_dom: prev_soup = BeautifulSoup(prev_dom, 'html.parser') for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): prev_clickables += prev_soup.find_all( tag.get_name(), attrs={attr: value}) else: prev_clickables += prev_soup.find_all(tag.get_name()) prev_forms = prev_soup.find_all('form') soup = BeautifulSoup(dom, 'html.parser') forms = soup.find_all('form') clickables = [] # clickables with forms and inputs attached for form in forms: if form in prev_forms: continue form_id = form.get('id') if not form_id: form_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 f = FormField(form_id, cls._get_xpath(form)) for input_type in cls.input_types: inputs = form.find_all('input', attrs={'type': input_type}) for my_input in inputs: data_set = InlineDataBank.get_data(input_type) if data_set: value = random.choice(list(data_set)) else: value = ''.join( random.choice(string.lowercase) for i in xrange(8)) input_id = my_input.get('id') if not input_id: input_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 f.add_input( InputField(input_id, cls._get_xpath(my_input), input_type, value)) for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): candidate_clickables = form.find_all( tag.get_name(), attrs={attr: value}) else: candidate_clickables = form.find_all(tag.get_name()) for candidate_clickable in candidate_clickables: if candidate_clickable in prev_clickables: continue clickable_id = candidate_clickable.get('id') if not clickable_id: clickable_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 c = Clickable(clickable_id, cls._get_xpath(candidate_clickable), tag.get_name()) c.add_form(f) clickables.append(c) # other clickables for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): candidate_clickables = soup.find_all(tag.get_name(), attrs={attr: value}) else: candidate_clickables = soup.find_all(tag.get_name()) for candidate_clickable in candidate_clickables: #print candidate_clickable if candidate_clickable in prev_clickables: continue if not cls._is_duplicate(clickables, candidate_clickable): clickable_id = candidate_clickable.get('id') if not clickable_id: clickable_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 clickables.append( Clickable(clickable_id, cls._get_xpath(candidate_clickable), tag.get_name())) return clickables
def run_clickable(self, cli_args=[]): parser = Clickable.create_parser("Integration Test Call") run_args = parser.parse_args(cli_args) self.run(run_args.commands, run_args)
def get_clickables(cls, dom, prev_dom=None): # only return newly discovered clickables and forms, i.e. clickables not in prev_clickables prev_clickables = [] prev_forms = [] if prev_dom: prev_soup = BeautifulSoup(prev_dom, 'html.parser') for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): prev_clickables += prev_soup.find_all(tag.get_name(), attrs={attr: value}) else: prev_clickables += prev_soup.find_all(tag.get_name()) prev_forms = prev_soup.find_all('form') soup = BeautifulSoup(dom, 'html.parser') forms = soup.find_all('form') clickables = [] # clickables with forms and inputs attached for form in forms: if form in prev_forms: continue form_id = form.get('id') if not form_id: form_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 f = FormField(form_id, cls._get_xpath(form)) for input_type in cls.input_types: inputs = form.find_all('input', attrs={'type': input_type}) for my_input in inputs: data_set = InlineDataBank.get_data(input_type) if data_set: value = random.choice(list(data_set)) else: value = ''.join(random.choice(string.lowercase) for i in xrange(8)) input_id = my_input.get('id') if not input_id: input_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 f.add_input(InputField(input_id, cls._get_xpath(my_input), input_type, value)) for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): candidate_clickables = form.find_all(tag.get_name(), attrs={attr: value}) else: candidate_clickables = form.find_all(tag.get_name()) for candidate_clickable in candidate_clickables: if candidate_clickable in prev_clickables: continue clickable_id = candidate_clickable.get('id') if not clickable_id: clickable_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 c = Clickable(clickable_id, cls._get_xpath(candidate_clickable), tag.get_name()) c.add_form(f) clickables.append(c) # other clickables for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): candidate_clickables = soup.find_all(tag.get_name(), attrs={attr: value}) else: candidate_clickables = soup.find_all(tag.get_name()) for candidate_clickable in candidate_clickables: #print candidate_clickable if candidate_clickable in prev_clickables: continue if not cls._is_duplicate(clickables, candidate_clickable): clickable_id = candidate_clickable.get('id') if not clickable_id: clickable_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 clickables.append(Clickable(clickable_id, cls._get_xpath(candidate_clickable), tag.get_name())) return clickables
class TestTemplates(TestCase): def setUp(self): self.clickable = Clickable() self.original_path = os.getcwd() self.path = os.path.join(os.path.dirname(__file__), 'tmp') self.app_path = os.path.join(self.path, 'appname') if os.path.exists(self.path): shutil.rmtree(self.path) os.makedirs(self.path) os.chdir(self.path) os.environ['CLICKABLE_DEFAULT'] = 'clean build review' os.environ['CLICKABLE_ARCH'] = 'amd64' self.config_file = os.path.expanduser( '~/.clickable/cookiecutter_config.yaml') self.tmp_config_file = '/tmp/cookiecutter_config.yaml' self.restore_config = False if os.path.exists(self.config_file): os.rename(self.config_file, self.tmp_config_file) self.restore_config = True def tearDown(self): shutil.rmtree(self.path) os.chdir(self.original_path) os.environ['CLICKABLE_DEFAULT'] = '' os.environ['CLICKABLE_ARCH'] = '' if self.restore_config: os.rename(self.tmp_config_file, self.config_file) def create_and_run(self, template): config = ConfigMock() config.container = Container(config) command = CreateCommand(config) command.run(path_arg=template, no_input=True) os.chdir(self.app_path) self.clickable.run(['clean', 'build']) def assertClickExists(self, arch): click = os.path.join( self.app_path, 'build/x86_64-linux-gnu/app/appname.yourname_1.0.0_amd64.click') if arch == 'all': click = os.path.join( self.app_path, 'build/all/app/appname.yourname_1.0.0_all.click') self.assertTrue(os.path.exists(click)) def test_qml_only(self): self.create_and_run('QML Only') self.assertClickExists('all') def test_cpp_plugin(self): self.create_and_run('C++ (Plugin)') self.assertClickExists('amd64') def test_cpp_binary(self): self.create_and_run('C++ (Binary)') self.assertClickExists('amd64') def test_python(self): self.create_and_run('Python') self.assertClickExists('all') def test_html(self): self.create_and_run('HTML') self.assertClickExists('all') # TODO enable this once the go qt library is fixed ''' def test_go(self): self.create_and_run('Go') self.assertClickExists('amd64') ''' def test_rust(self): # TODO see if the rust template can support automatically changing the arch in the manifest config = ConfigMock() config.container = Container(config) command = CreateCommand(config) command.run(path_arg='Rust', no_input=True) manifest_path = os.path.join(self.app_path, 'manifest.json') with open(manifest_path, 'r') as manifest_reader: manifest = json.load(manifest_reader) manifest['architecture'] = 'amd64' with open(manifest_path, 'w') as manifest_writer: json.dump(manifest, manifest_writer, indent=4) os.chdir(self.app_path) self.clickable.run(['clean', 'build']) self.assertClickExists('amd64')
def setUp(self): dom1 = ''' <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body>dom1</body> </html> ''' state = State(dom1) self.automata = Automata() self.automata.add_state(state) self.assertEqual(len(self.automata.get_states()), 1) self.assertEqual(self.automata.get_initial_state().get_id(), self.automata.get_current_state().get_id()) self.assertEqual(self.automata.get_current_state().get_id(), '0') # test adding and removing inputs and forms form1 = FormField('form1') form1.add_input(InputField('username', '//*[@id="username"]', 'castman')) form1.add_input(InputField('password', '', 'p@ssw0rd')) form1.add_input(InputField('password', '', 'p@ssw0rd')) self.assertEqual(len(form1.get_inputs()), 2) form1.remove_input(InputField('username', '//*[@id="username"]', 'castman')) self.assertEqual(len(form1.get_inputs()), 1) form2 = FormField('', '//*[@id="lst-ib"]') clickable = Clickable('', '//*[@id="btn1"]') clickable.add_form(form1) clickable.add_form(FormField('form1')) clickable.add_form(form2) self.assertEqual(len(clickable.get_forms()), 2) clickable.remove_form(FormField('', '//*[@id="lst-ib"]')) self.assertEqual(len(clickable.get_forms()), 1) # add the clickable into state 0 self.automata.get_current_state().add_clickable(clickable)