Ejemplo n.º 1
0
class Meta:
    _ALLOWED_FILTERS = {
        GuiWidgetType.ELEMENT: {'pos'},
        GuiWidgetType.MULTI_ELEMENT: {'pos'},
        GuiWidgetType.DROPDOWN: {'pos'},
        GuiWidgetType.RADIO_GROUP: set(),
    }

    _POS = {"first", "last", "random", "odd", "even"}

    @track("trace")
    def __init__(self, mdict=None):
        from arjuna import log_debug
        log_debug("Input Meta Dict for Meta creation: {}".format(
            repr_dict(mdict)))
        temp_dict = not mdict and CIStringDict() or CIStringDict(mdict)
        self.__mdict = CIStringDict()
        self.__process_type(temp_dict)
        self.__process_relations(temp_dict)
        self.__process_filters(temp_dict)
        self.__process_settings(temp_dict)
        self.__mdict.update({
            k: v
            for k, v in temp_dict.items()
            if k.lower() not in {"type", "relations", "settings", "filters"}
        })
        print(self.__mdict)
        log_debug("Meta dictionary is: {}".format(repr_dict(self.__mdict)))

    def __process_type(self, temp_dict):
        from arjuna import log_debug
        from arjuna.core.constant import GuiWidgetType
        if "type" in temp_dict:
            log_debug("Copying provided type from meta dict: {}".format(
                temp_dict["type"]))
            try:
                widget_type = temp_dict["type"]
                if not isinstance(widget_type, GuiWidgetType):
                    self.__mdict["type"] = GuiWidgetType[widget_type.upper()]
                else:
                    self.__mdict["type"] = temp_dict["type"]
            except Exception as e:
                raise Exception(
                    "{} is not a valid Gui widget type.".format(widget_type))
        else:
            self.__mdict["type"] = GuiWidgetType.ELEMENT

    def __process_relations(self, temp_dict):
        from arjuna import log_debug
        self.__mdict["relations"] = CIStringDict()
        to_remove = list()
        for k, v in temp_dict.items():
            if k.lower() in {'above', 'below', 'left_of', 'right_of', 'near'}:

                to_remove.append(k)
        for k in to_remove:
            del temp_dict[k]

        if "relations" in temp_dict:
            self.__mdict["relations"].update(temp_dict["relations"])
            del temp_dict["relations"]

        from arjuna.tpi.guiauto.base.single_widget import SingleGuiWidget
        from arjuna.tpi.error import GuiWidgetDefinitionError

        for k, v in self.__mdict["relations"].items():
            self.__set_relation(k, v)

    def __process_filters(self, temp_dict):
        from arjuna import log_debug
        self.__mdict["filters"] = CIStringDict()
        to_remove = list()
        for k, v in temp_dict.items():
            if k.lower() in {'pos'}:
                self.__set_filter(k, v)
                to_remove.append(k)
        for k in to_remove:
            del temp_dict[k]
        if "filters" in temp_dict:
            self.__mdict["filters"].update(temp_dict["filters"])
            del temp_dict["filters"]

    def __process_settings(self, temp_dict):
        self.__mdict["settings"] = InteractionConfig(
            temp_dict)  # Interconfig keys are removed

    def update_settings(self, source_wmd):
        self.settings.update(source_wmd.meta.settings)

    def items(self):
        return self.__mdict.items()

    def has(self, name):
        return name.lower() in self.__mdict

    @track("trace")
    def __getattr__(self, name):
        return self[name]

    def __getitem__(self, name):
        from arjuna import log_debug
        if self.has(name):
            return self.__mdict[name]
        else:
            log_debug(f"Meta dict does not have {name}. Returning None.")
            return None

    def __set_relation(self, name, value):
        from arjuna.tpi.guiauto.base.single_widget import SingleGuiWidget
        if isinstance(value, SingleGuiWidget):
            value = value.dispatcher.driver_element
        self.__mdict["relations"][name] = value

    def __format_pos(self, pos):
        from arjuna.tpi.helper.extract import pos as pos_factory
        from arjuna.tpi.helper.extract import Extractor
        if self.__mdict["type"] == GuiWidgetType.RADIO_GROUP:
            raise Exception(
                ">>pos<< filter is not supported for Gui Widget Type RADIO_GROUP."
            )
        if type(pos) is str:
            fpos = pos.lower().strip()
            if fpos in self._POS:
                return pos_factory._create_extractor(fpos)
            else:
                raise Exception(
                    "The only string liternals support for defining position are first/last/random"
                )
        elif type(pos) in {list, tuple}:
            return pos_factory.at(*[int(str(i).strip()) for i in pos])
        elif type(pos) is dict:
            if len(pos) > 1:
                raise Exception(
                    "Extractor specification dictionary can take only one root key. Found entry: {}"
                    .format(pos))
            extractor_name = list(pos.keys())[0].lower().strip()
            extractor_args = list(pos.values())[0]
            if type(extractor_args) in {list, tuple}:
                return pos_factory._create_extractor(extractor_name,
                                                     *extractor_args)
            elif type(extractor_args) is dict:
                return pos_factory._create_extractor(extractor_name,
                                                     **extractor_args)
            else:
                return pos_factory._create_extractor(extractor_name,
                                                     extractor_args)
        elif isinstance(pos, Extractor):
            return pos
        else:
            try:
                return pos_factory.at(int(str(pos).lower().strip()))
            except:
                raise Exception(
                    "Value of pos is not of any allowed type. It can be an int, a list of ints, an extractor specification dictionary or an Extractor object."
                )

    def __set_filter(self, name, value):
        allowed_filters = self._ALLOWED_FILTERS[self.__mdict['type']]
        if name not in allowed_filters:
            raise Exception(
                "{} is not allowed filter meta data for GuiWidget of type: {}. Allowed: {}"
                .format(k, self.__mdict['type'], allowed_filters))
        if name == "pos":
            self.__mdict["filters"][name] = self.__format_pos(value)
        else:
            self.__mdict["filters"][name] = value

    def __setitem__(self, name, value):
        if InteractionConfig.is_a_setting(name):
            self["settings"][name] = value
        elif name.lower() in {"above", "below", "near", "right_of", "left_of"}:
            self.__set_relation(name, value)
        elif name.lower() in {"pos", "slice"}:
            self.__set_filter(name, value)
        else:
            self.__mdict[name] = value

    def __str__(self):
        return repr_dict(self.__mdict)
Ejemplo n.º 2
0
class Options(metaclass=abc.ABCMeta):
    def __init__(self, *, options_dict, creation_context, validate=True):
        self.__options = CIStringDict()
        self.__validate = validate
        if options_dict:
            self.update_all(options_dict)

    def update(self, option_name, option_value):
        option_name = self._process_option_name(option_name)
        try:
            is_not_set = False
            try:
                is_not_set = option_value.lower() == "not_set"
            except:
                pass
            finally:
                option_key = self.__get_option_key(option_name)
                if is_not_set:
                    self.__options[option_key] = "not_set"
                else:
                    validator_name, validator = self._get_validator_for(
                        option_name)
                    if self.__validate:
                        self.__options[option_key] = validator(option_value)
                    else:
                        if validator_name.lower() not in {
                                'absolute_dir_path', 'absolute_file_path'
                        }:
                            self.__options[option_key] = validator(
                                option_value)
                        else:
                            self.__options[option_key] = option_value
        except Exception as e:
            raise Exception(
                "Config option value <{}>(type:{}) for <{}> option did not pass the validation check: [{}]"
                .format(option_value, type(option_value), option_name,
                        validator_name))

    def __get_option_key(self, option_name):
        return isinstance(option_name,
                          Enum) and option_name.name or option_name

    @abc.abstractmethod
    def _process_option_name(self, option_name):
        pass

    @abc.abstractmethod
    def _get_validator_for(self, option_name):
        pass

    def value(self, option_name):
        return self.__options[self.__get_option_key(
            self._process_option_name(option_name))]

    def update_all(self, options):
        if isinstance(options, Options):
            self.__options.update(options.as_dict())
        else:
            if options:
                for k, v in options.items():
                    self.update(k, v)

    def as_dict(self):
        return self.__options

    def is_not_set(self, option_name):
        self._process_option_name(option_name)
        try:
            return self.value(option_name).upper() == "NOT_SET"
        except:
            return False
Ejemplo n.º 3
0
def test(f: Callable = None,
         *,
         id: str = None,
         resources: ListOrTuple = None,
         drive_with: 'DataSource' = None,
         exclude_if: 'Relation' = None,
         xfail: "boolOrXFail" = False,
         skip: "boolOrSkip" = False,
         priority: int = 5,
         author: str = None,
         idea: str = None,
         component: str = None,
         app_version: str = '0.0.0',
         level: str = None,
         reviewed: bool = False,
         unstable: bool = False,
         tags: set = set(),
         bugs: set = set(),
         envs: set = set(),
         **test_attrs):
    '''
        Decorator for marking a function as a test function.

        Args:
            func: A Function with signature **f(request)**. The name request is mandatory and enforced.

        Keyword Arguments:
            id: Alnum string representing an ID which you want to associate with the test.
            resources: Fixtures/Resources that you want to associate this test with. Wraps pytest.mark.usefixtures. Instead of using this, you can also pass the names as direct arguments in the function signature.
            drive_with: Used for data driven testing. Argument can be Arjuna Data Source. Wraps **pytest.mark.parametrize**. If you use this argument, the test function signature must include a **data** argument e.g. 

                .. code-block:: python
                
                    @test(drive_with=<DS>)
                    def check_sample(request, data):
                        pass

            exclude_if: Define exclusion condition. Argument can be an Arjuna Relation. Wraps **pytest.mark.dependency**.
            xfail: Mark this test as a expected fail by setting to True. You can also use helper `xfail()` to create an advanced xfail construct. Wraps **pytest.mark.xfail**.
            skip: Mark this test as a expected skipped by setting to True. You can also use helper `skip()` to create an advanced skip construct. Wraps **pytest.mark.skip** and Wraps **pytest.mark.skipif**.
            priority: An integer value 1-5 depicting priority of this test, 1 being highest, 5 being lowest.
            author: Author of this test
            idea: The idea describing this test
            component: Primary software component that this test targets.
            app_version: Version of SUT that this test targets
            level: Level of this test.
            reviewed: Has this test been reviewed?
            unstable: Is this test unstable?
            tags: Set of tags for this test
            bugs: Set of bugs associated with this test
            envs: Set of Environment names on which this test is supposed to run.
            **test_attrs: Arbitrary name-value pairs to provide further test attributes.

        Note:
            The test function name must start with the prefix **check_**

            The test function must have the minimum signature as **check_<some_name>(request)** with **request** as the first argument.
    '''

    info_dict = CIStringDict()
    info_dict.update({
        'id': id,
        'priority': priority,
        'author': author,
        'idea': idea,
        'component': component,
        'app_version': app_version,
        'level': level,
        'reviewed': reviewed,
        'unstable': unstable,
    })

    info_dict.update({k.lower(): v for k, v in test_attrs.items()})

    test_meta_data = {
        'info': info_dict,
        'tags': tags,
        'bugs': bugs,
        'envs': envs,
    }

    # Check if @test is provided without arguments
    if f is not None:
        return _simple_dec(f, test_meta_data)

    if resources:
        if type(resources) is str:
            resources = (resources)
        elif type(resources) is list:
            resources = tuple(resources)
        else:
            raise Exception(
                "resources value must be a string or list/tuple of strings")

    def format_test_func(func):
        __process_test_meta_data(func, test_meta_data)
        func = __process_func_for_xfail(func, test_meta_data, xfail)
        func = __process_func_for_skip(func, test_meta_data, skip)
        from arjuna import Arjuna
        Arjuna.register_test_meta_data(test_meta_data['info']['qual_name'],
                                       CIStringDict(test_meta_data))
        orig_func = func
        if exclude_if:
            func = pytest.mark.dependency(name=id, depends=exclude_if())(func)
        else:
            func = pytest.mark.dependency(name=id)(func)

        if resources:
            func = pytest.mark.usefixtures(*resources)(func)

        if drive_with:
            records = drive_with.build().all_records
            func = pytest.mark.parametrize('data', records,
                                           ids=_repr_record)(func)

        my = My(test_meta_data)

        @functools.wraps(orig_func)
        def wrapper_without_data(request, *args, **kwargs):
            my.set_req_obj(request)
            _call_func(func, my, *args, **kwargs)

        @functools.wraps(orig_func)
        def wrapper_with_data(request, data, *args, **kwargs):
            my.set_req_obj(request)
            _call_func(func, my, data, *args, **kwargs)

        if drive_with:
            return wrapper_with_data
        else:
            return wrapper_without_data

    return format_test_func