示例#1
0
    def test_with_all_data(self):
        fdm_data = FdmSwaggerParser().parse_spec(self.base_data)
        validator = FdmSwaggerValidator(fdm_data)
        models = fdm_data['models']
        operations = fdm_data['operations']

        invalid = set({})
        for operation in operations:
            model_name = operations[operation]['modelName']
            method = operations[operation]['method']
            if method != 'get' and model_name in models:
                if 'example' in models[model_name]:
                    example = models[model_name]['example']
                    try:
                        valid, rez = validator.validate_data(
                            operation, example)
                        assert valid
                    except Exception:
                        invalid.add(model_name)
        assert invalid == set([
            'TCPPortObject', 'UDPPortObject', 'ICMPv4PortObject',
            'ICMPv6PortObject', 'StandardAccessList', 'ExtendedAccessList',
            'ASPathList', 'RouteMap', 'StandardCommunityList',
            'ExpandedCommunityList', 'IPV4PrefixList', 'IPV6PrefixList',
            'PolicyList', 'SyslogServer', 'HAConfiguration',
            'TestIdentitySource'
        ])
 def test_types_of_required_fields_are_incorrect(self):
     data = {
         'subType': True,
         'type': 1,
         'value': False
     }
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert not valid
     assert sort_validator_rez({
         'invalid_type': [
             {
                 'path': 'subType',
                 'expected_type': 'enum',
                 'actually_value': True
             },
             {
                 'path': 'value',
                 'expected_type': 'string',
                 'actually_value': False
             },
             {
                 'path': 'type',
                 'expected_type': 'string',
                 'actually_value': 1
             }
         ]
     }) == sort_validator_rez(rez)
     data = {
         'subType': {},
         'type': [],
         'value': {}
     }
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert not valid
     assert sort_validator_rez({
         'invalid_type': [
             {
                 'path': 'subType',
                 'expected_type': 'enum',
                 'actually_value': {}
             },
             {
                 'path': 'value',
                 'expected_type': 'string',
                 'actually_value': {}
             },
             {
                 'path': 'type',
                 'expected_type': 'string',
                 'actually_value': []
             }
         ]
     }) == sort_validator_rez(rez)
    def test_simple_types(self):
        local_mock_data = {
            'models': {
                'TestModel': {
                    'type': 'object',
                    'properties': {
                        'f_string': {'type': 'string'},
                        'f_number': {'type': 'number'},
                        'f_boolean': {'type': 'boolean'},
                        'f_integer': {'type': 'integer'}
                    },
                    'required': []
                }
            },
            'operations': {
                'getdata': {
                    'modelName': 'TestModel'
                }
            }
        }
        valid_data = {
            "f_string": "test",
            "f_number": 2.2,
            "f_boolean": False,
            "f_integer": 1
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', valid_data)
        assert valid
        assert rez is None

        valid_data = {
            "f_string": "",
            "f_number": 0,
            "f_boolean": True,
            "f_integer": 0
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', valid_data)
        assert valid
        assert rez is None

        valid_data = {
            "f_string": "0",
            "f_number": 100,
            "f_boolean": True,
            "f_integer": 2
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', valid_data)
        assert valid
        assert rez is None
    def test_invalid_nested_required_fields(self):
        invalid_data = {'f_integer': 2}

        valid, rez = FdmSwaggerValidator(nested_mock_data1).validate_data(
            'getdata', invalid_data)
        assert not valid
        assert {'required': ['nested_model']} == rez

        invalid_data = {'nested_model': {'f_number': 1.2}}

        valid, rez = FdmSwaggerValidator(nested_mock_data1).validate_data(
            'getdata', invalid_data)
        assert not valid
        assert {'required': ['nested_model.f_string']} == rez
 def test_errors_if_no_data_was_passed(self):
     data = {}
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert not valid
     assert sort_validator_rez({
         'required': ['subType', 'type', 'value']
     }) == sort_validator_rez(rez)
    def test_invalid_type_in_nested_fields(self):
        invalid_data = {
            'nested_model': {
                "f_string": 1,
                "f_number": "ds",
                "f_boolean": 1.3,
                "f_integer": True
            }
        }

        valid, rez = FdmSwaggerValidator(nested_mock_data1).validate_data(
            'getdata', invalid_data)
        assert not valid
        assert sort_validator_rez({
            'invalid_type': [{
                'path': 'nested_model.f_string',
                'expected_type': 'string',
                'actually_value': 1
            }, {
                'path': 'nested_model.f_number',
                'expected_type': 'number',
                'actually_value': "ds"
            }, {
                'path': 'nested_model.f_boolean',
                'expected_type': 'boolean',
                'actually_value': 1.3
            }, {
                'path': 'nested_model.f_integer',
                'expected_type': 'integer',
                'actually_value': True
            }]
        }) == sort_validator_rez(rez)
    def test_nested_required_fields(self):
        valid_data = {'nested_model': {'f_string': "test"}}

        valid, rez = FdmSwaggerValidator(nested_mock_data1).validate_data(
            'getdata', valid_data)
        assert valid
        assert rez is None
 def test_errors_if_one_required_field_is_empty(self):
     data = {
         'subType': 'NETWORK',
         'value': '1.1.1.1'
     }
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert not valid
     assert {'required': ['type']} == rez
    def test_pass_no_data_with_no_required_fields(self):
        spec = copy.deepcopy(mock_data)
        del spec['models']['NetworkObject']['required']

        valid, rez = FdmSwaggerValidator(spec).validate_data('getNetworkObjectList', {})

        assert valid
        assert rez is None
 def test_errors_for_required_fields(self):
     data = {'name': 'test'}
     valid, rez = FdmSwaggerValidator(mock_data).validate_data(
         'getNetworkObjectList', data)
     assert not valid
     assert sort_validator_rez({'required':
                                ['subType', 'type',
                                 'value']}) == sort_validator_rez(rez)
    def validate_url_data_with_empty_data(self, method, parameters_type):
        local_mock_spec = {
            'models': {},
            'operations': {
                'getNetwork': {
                    'method': 'get',
                    'parameters': {
                        parameters_type: {
                            'objId': {
                                'required': True,
                                'type': "string"
                            }
                        }
                    }
                }
            }
        }
        validator = FdmSwaggerValidator(local_mock_spec)
        valid, rez = getattr(validator, method)('getNetwork', None)
        assert not valid
        assert {'required': ['objId']} == rez

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)('getNetwork', ''),
            "The params parameter must be a dict")

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)('getNetwork', []),
            "The params parameter must be a dict")

        valid, rez = getattr(validator, method)('getNetwork', {})
        assert not valid
        assert {'required': ['objId']} == rez

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)(None, {
                'name': 'test'
            }), "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)('', {
                'name': 'test'
            }), "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)([], {
                'name': 'test'
            }), "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)({}, {
                'name': 'test'
            }), "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(
            lambda: getattr(validator, method)('operation_does_not_exist', {
                'name': 'test'
            }), "operation_does_not_exist operation does not support")
 def test_pass_only_required_fields(self):
     data = {
         'subType': 'NETWORK',
         'type': 'networkobject',
         'value': '1.1.1.1'
     }
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert valid
     assert rez is None
 def url_data_required_fields(method, parameters_type):
     local_mock_spec = {
         'models': {},
         'operations': {
             'getNetwork': {
                 'method': 'get',
                 'parameters': {
                     parameters_type: {
                         'objId': {
                             'required': True,
                             'type': "string"
                         },
                         'parentId': {
                             'required': True,
                             'type': "string"
                         },
                         'someParam': {
                             'required': False,
                             'type': "string"
                         },
                         'p_integer': {
                             'required': False,
                             'type': "integer"
                         },
                         'p_boolean': {
                             'required': False,
                             'type': "boolean"
                         },
                         'p_number': {
                             'required': False,
                             'type': "number"
                         }
                     }
                 }
             }
         }
     }
     validator = FdmSwaggerValidator(local_mock_spec)
     valid, rez = getattr(validator, method)('getNetwork', None)
     assert not valid
     assert sort_validator_rez({
         'required': ['objId', 'parentId']
     }) == sort_validator_rez(rez)
     valid, rez = getattr(validator, method)('getNetwork', {})
     assert not valid
     assert sort_validator_rez({
         'required': ['objId', 'parentId']
     }) == sort_validator_rez(rez)
     data = {
         'someParam': "test"
     }
     valid, rez = getattr(validator, method)('getNetwork', data)
     assert not valid
     assert sort_validator_rez({
         'required': ['objId', 'parentId']
     }) == sort_validator_rez(rez)
 def test_array_data_is_not_correct(self):
     data = {
         'name': 'test_name',
         'subType': 'NETWORK',
         'type': 'networkobject',
         'value': '1.1.1.1',
         'objects': [
             {
                 'id': 'fs-sf'
             },
             {
                 'type': 'type'
             },
             {},
             {
                 'id': 1,
                 'type': True
             },
             [],
             'test'
         ]
     }
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert not valid
     assert sort_validator_rez({
         'required': ['objects[0].type', 'objects[1].id', 'objects[2].id', 'objects[2].type'],
         'invalid_type': [
             {
                 'path': 'objects[3].id',
                 'expected_type': 'string',
                 'actually_value': 1
             },
             {
                 'path': 'objects[3].type',
                 'expected_type': 'string',
                 'actually_value': True
             },
             {
                 'path': 'objects[4]',
                 'expected_type': 'object',
                 'actually_value': []
             },
             {
                 'path': 'objects[5]',
                 'expected_type': 'object',
                 'actually_value': 'test'
             }
         ]
     }) == sort_validator_rez(rez)
 def test_pass_all_fields_with_correct_data(self):
     data = {
         'id': 'id-di',
         'version': 'v',
         'name': 'test_name',
         'subType': 'NETWORK',
         'type': 'networkobject',
         'value': '1.1.1.1',
         'description': 'des',
         'isSystemDefined': False,
         'dnsResolution': 'IPV4_ONLY',
         'objects': [{
             'type': 'port',
             'id': 'fs-sf'
         }]
     }
     valid, rez = FdmSwaggerValidator(mock_data).validate_data('getNetworkObjectList', data)
     assert valid
     assert rez is None
 def url_data_valid(method, parameters_type):
     local_mock_spec = {
         'models': {},
         'operations': {
             'getNetwork': {
                 'method': 'get',
                 'parameters': {
                     parameters_type: {
                         'objId': {
                             'required': True,
                             'type': "string"
                         },
                         'p_integer': {
                             'required': False,
                             'type': "integer"
                         },
                         'p_boolean': {
                             'required': False,
                             'type': "boolean"
                         },
                         'p_number': {
                             'required': False,
                             'type': "number"
                         }
                     }
                 }
             }
         }
     }
     data = {
         'objId': "value1",
         'p_integer': 1,
         'p_boolean': True,
         'p_number': 2.3
     }
     validator = FdmSwaggerValidator(local_mock_spec)
     valid, rez = getattr(validator, method)('getNetwork', data)
     assert valid
     assert rez is None
 def url_params_invalid_params(method, parameters_type):
     local_mock_spec = {
         'models': {},
         'operations': {
             'getNetwork': {
                 'method': 'get',
                 'parameters': {
                     parameters_type: {
                         'objId': {
                             'required': True,
                             'type': "string"
                         },
                         'parentId': {
                             'required': True,
                             'type': "string"
                         },
                         'someParam': {
                             'required': False,
                             'type': "string"
                         },
                         'p_integer': {
                             'required': False,
                             'type': "integer"
                         },
                         'p_boolean': {
                             'required': False,
                             'type': "boolean"
                         },
                         'p_number': {
                             'required': False,
                             'type': "number"
                         }
                     }
                 }
             }
         }
     }
     validator = FdmSwaggerValidator(local_mock_spec)
     data = {
         'objId': 1,
         'parentId': True,
         'someParam': [],
         'p_integer': 1.2,
         'p_boolean': 0,
         'p_number': False
     }
     valid, rez = getattr(validator, method)('getNetwork', data)
     assert not valid
     assert sort_validator_rez({
         'invalid_type': [
             {
                 'path': 'objId',
                 'expected_type': 'string',
                 'actually_value': 1
             },
             {
                 'path': 'parentId',
                 'expected_type': 'string',
                 'actually_value': True
             },
             {
                 'path': 'someParam',
                 'expected_type': 'string',
                 'actually_value': []
             },
             {
                 'path': 'p_integer',
                 'expected_type': 'integer',
                 'actually_value': 1.2
             },
             {
                 'path': 'p_boolean',
                 'expected_type': 'boolean',
                 'actually_value': 0
             },
             {
                 'path': 'p_number',
                 'expected_type': 'number',
                 'actually_value': False
             }
         ]
     }) == sort_validator_rez(rez)
     data = {
         'objId': {},
         'parentId': 0,
         'someParam': 1.2,
         'p_integer': True,
         'p_boolean': 1,
         'p_number': True
     }
     valid, rez = getattr(validator, method)('getNetwork', data)
     assert not valid
     assert sort_validator_rez({
         'invalid_type': [
             {
                 'path': 'objId',
                 'expected_type': 'string',
                 'actually_value': {}
             },
             {
                 'path': 'parentId',
                 'expected_type': 'string',
                 'actually_value': 0
             },
             {
                 'path': 'someParam',
                 'expected_type': 'string',
                 'actually_value': 1.2
             },
             {
                 'path': 'p_integer',
                 'expected_type': 'integer',
                 'actually_value': True
             },
             {
                 'path': 'p_boolean',
                 'expected_type': 'boolean',
                 'actually_value': 1
             },
             {
                 'path': 'p_number',
                 'expected_type': 'number',
                 'actually_value': True
             }
         ]
     }) == sort_validator_rez(rez)
     data = {
         'objId': {},
         'parentId': 0,
         'someParam': 1.2,
         'p_integer': "1",
         'p_boolean': "",
         'p_number': "2.1"
     }
     valid, rez = getattr(validator, method)('getNetwork', data)
     assert not valid
     assert sort_validator_rez({
         'invalid_type': [
             {
                 'path': 'objId',
                 'expected_type': 'string',
                 'actually_value': {}
             },
             {
                 'path': 'parentId',
                 'expected_type': 'string',
                 'actually_value': 0
             },
             {
                 'path': 'someParam',
                 'expected_type': 'string',
                 'actually_value': 1.2
             },
             {
                 'path': 'p_boolean',
                 'expected_type': 'boolean',
                 'actually_value': ""
             }
         ]
     }) == sort_validator_rez(rez)
 def test_pass_only_required_fields_with_none_values(self):
     data = {'subType': 'NETWORK', 'type': 'networkobject', 'value': None}
     valid, rez = FdmSwaggerValidator(mock_data).validate_data(
         'getNetworkObjectList', data)
     assert not valid
     assert {'required': ['value']} == rez
    def test_invalid_simple_types(self):
        local_mock_data = {
            'models': {
                'TestModel': {
                    'type': 'object',
                    'properties': {
                        'f_string': {'type': 'string'},
                        'f_number': {'type': 'number'},
                        'f_boolean': {'type': 'boolean'},
                        'f_integer': {'type': 'integer'}
                    },
                    'required': []
                }
            },
            'operations': {
                'getdata': {
                    'modelName': 'TestModel'
                }
            }
        }
        invalid_data = {
            "f_string": True,
            "f_number": True,
            "f_boolean": 1,
            "f_integer": True
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', invalid_data)
        assert not valid
        assert sort_validator_rez({
            'invalid_type': [
                {
                    'path': 'f_string',
                    'expected_type': 'string',
                    'actually_value': True
                },
                {
                    'path': 'f_number',
                    'expected_type': 'number',
                    'actually_value': True
                },
                {
                    'path': 'f_boolean',
                    'expected_type': 'boolean',
                    'actually_value': 1
                },
                {
                    'path': 'f_integer',
                    'expected_type': 'integer',
                    'actually_value': True
                }
            ]
        }) == sort_validator_rez(rez)

        invalid_data = {
            "f_string": 1,
            "f_number": False,
            "f_boolean": 0,
            "f_integer": "test"
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', invalid_data)
        assert not valid
        assert sort_validator_rez({
            'invalid_type': [
                {
                    'path': 'f_string',
                    'expected_type': 'string',
                    'actually_value': 1
                },
                {
                    'path': 'f_number',
                    'expected_type': 'number',
                    'actually_value': False
                },
                {
                    'path': 'f_boolean',
                    'expected_type': 'boolean',
                    'actually_value': 0
                },
                {
                    'path': 'f_integer',
                    'expected_type': 'integer',
                    'actually_value': "test"
                }
            ]
        }) == sort_validator_rez(rez)

        invalid_data = {
            "f_string": False,
            "f_number": "1",
            "f_boolean": "",
            "f_integer": "1.2"
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', invalid_data)
        assert not valid
        assert sort_validator_rez({
            'invalid_type': [
                {
                    'path': 'f_string',
                    'expected_type': 'string',
                    'actually_value': False
                },
                {
                    'path': 'f_boolean',
                    'expected_type': 'boolean',
                    'actually_value': ""
                },
                {
                    'path': 'f_integer',
                    'expected_type': 'integer',
                    'actually_value': '1.2'
                }
            ]
        }) == sort_validator_rez(rez)
    def test_few_levels_nested_fields(self):
        local_mock_data = {
            'models': {
                'Model2': {
                    'type': 'object',
                    'required': ['ms', 'ts'],
                    'properties': {
                        'ms': {'type': 'array',
                               'items': {
                                   'type': 'object',
                                   '$ref': '#/definitions/ReferenceModel'}},
                        'ts': {'type': 'array',
                               'items': {
                                   'type': 'object',
                                   '$ref': '#/definitions/ReferenceModel'}}
                    }
                },
                'NetworkObjectType': {'type': 'string', 'enum': ['HOST', 'NETWORK', 'IPRANGE', 'FQDN']},
                'Fragment': {'type': 'object',
                             'required': ['type', 'objects', 'subType', 'object'],
                             'properties': {
                                 'objects': {'type': 'array',
                                             'items': {
                                                 'type': 'object',
                                                 '$ref': '#/definitions/ReferenceModel'}},
                                 'object': {'type': 'object',
                                            '$ref': '#/definitions/Model2'},
                                 'subType': {'type': 'object',
                                             '$ref': '#/definitions/NetworkObjectType'},
                                 'type': {'type': 'string'},
                                 'value': {'type': 'number'},
                                 'name': {'type': 'string'}}},
                'ReferenceModel': {'type': 'object', 'required': ['id', 'type'],
                                   'properties': {
                                       'id': {'type': 'string'},
                                       'type': {'type': 'string'},
                                       'version': {'type': 'string'},
                                       'name': {'type': 'string'}}},
                'model1': {
                    'type': 'object',
                    'properties': {
                        'f_string': {'type': 'string'},
                        'f_number': {'type': 'number'},
                        'f_boolean': {'type': 'boolean'},
                        'f_integer': {'type': 'integer'},
                        'objects': {'type': 'array',
                                    'items': {
                                        'type': 'object',
                                        '$ref': '#/definitions/ReferenceModel'}},
                        'fragments': {'type': 'array',
                                      'items': {
                                          'type': 'object',
                                          '$ref': '#/definitions/Fragment'}}
                    },
                    'required': ['f_string', 'objects', 'fragments']
                },
                'TestModel': {
                    'type': 'object',
                    'properties': {
                        'nested_model': {'type': 'object',
                                         '$ref': '#/definitions/model1'},
                        'f_integer': {'type': 'integer'}
                    },
                    'required': ['nested_model']
                }
            },
            'operations': {
                'getdata': {
                    'modelName': 'TestModel'
                }
            }
        }

        valid_data = {
            "nested_model": {
                'objects': [{
                    'type': 't1',
                    'id': 'id1'
                }],
                'fragments': [{
                    'type': "test",
                    'subType': 'NETWORK',
                    'object': {
                        'ts': [],
                        'ms': [{
                            'type': "tt",
                            'id': 'id'
                        }]
                    },
                    'objects': [{
                        'type': 't',
                        'id': 'id'
                    }]
                }],
                'f_string': '1'
            }
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', valid_data)
        assert valid
        assert rez is None

        valid_data = {
            "nested_model": {
                'objects': [{
                    'type': 't1',
                    'id': 'id1'
                }],
                'fragments': [{
                    'type': "test",
                    'subType': 'NETWORK',
                    'object': {
                        'ms': {}
                    },
                    'objects': [{
                        'type': 't',
                        'id': 'id'
                    }]
                }],
                'f_string': '1'
            }
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', valid_data)
        assert not valid
        assert sort_validator_rez({
            'required': ['nested_model.fragments[0].object.ts'],
            'invalid_type': [{
                'path': 'nested_model.fragments[0].object.ms',
                'expected_type': 'array',
                'actually_value': {}
            }]
        }) == sort_validator_rez(rez)

        valid_data = {
            "nested_model": {
                'objects': [{
                    'type': 't1',
                    'id': 'id1'
                }],
                'fragments': [{
                    'type': "test",
                    'subType': 'NETWORK',
                    'object': [],
                    'objects': {}
                }],
                'f_string': '1'
            }
        }

        valid, rez = FdmSwaggerValidator(local_mock_data).validate_data('getdata', valid_data)
        assert not valid
        assert sort_validator_rez({
            'invalid_type': [
                {
                    'path': 'nested_model.fragments[0].objects',
                    'expected_type': 'array',
                    'actually_value': {}
                },
                {
                    'path': 'nested_model.fragments[0].object',
                    'expected_type': 'object',
                    'actually_value': []}
            ]}) == sort_validator_rez(rez)
    def test_validate_data_method_with_empty_data(self):
        validator = FdmSwaggerValidator(mock_data)
        valid, rez = validator.validate_data('getNetworkObjectList', None)
        assert not valid
        assert sort_validator_rez({
            'required': ['subType', 'type', 'value']
        }) == sort_validator_rez(rez)

        self.check_illegal_argument_exception(lambda: validator.validate_data('getNetworkObjectList', ''),
                                              "The data parameter must be a dict")

        self.check_illegal_argument_exception(lambda: validator.validate_data('getNetworkObjectList', []),
                                              "The data parameter must be a dict")
        valid, rez = validator.validate_data('getNetworkObjectList', {})
        assert not valid
        assert sort_validator_rez({
            'required': ['subType', 'type', 'value']
        }) == sort_validator_rez(rez)

        self.check_illegal_argument_exception(lambda: validator.validate_data(None, {'name': 'test'}),
                                              "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(lambda: validator.validate_data('', {'name': 'test'}),
                                              "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(lambda: validator.validate_data([], {'name': 'test'}),
                                              "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(lambda: validator.validate_data({}, {'name': 'test'}),
                                              "The operation_name parameter must be a non-empty string")

        self.check_illegal_argument_exception(
            lambda: validator.validate_data('operation_does_not_exist', {'name': 'test'}),
            "operation_does_not_exist operation does not support")