From af2a5605ce9f5cd85e21f3eb044e4386a1b7fb5a Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 25 Jul 2018 12:43:57 -0400 Subject: [PATCH] Add constraints to Location object --- stix2/test/v21/test_location.py | 108 ++++++++++++++++++++++++++++++++ stix2/v21/sdo.py | 22 +++++++ 2 files changed, 130 insertions(+) diff --git a/stix2/test/v21/test_location.py b/stix2/test/v21/test_location.py index b5e781b..abcb046 100644 --- a/stix2/test/v21/test_location.py +++ b/stix2/test/v21/test_location.py @@ -87,3 +87,111 @@ def test_parse_location(data): assert location.region == 'north-america' rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(location)) assert rep == EXPECTED_LOCATION_2_REPR + + +@pytest.mark.parametrize( + "data", [ + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "latitude": 90.01, + "longitude": 0.0, + }, + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "latitude": -90.1, + "longitude": 0.0, + }, + ], +) +def test_location_bad_latitude(data): + with pytest.raises(ValueError) as excinfo: + stix2.parse(data) + + assert str(excinfo.value) == "{id} 'latitude' must be between -90 and 90. Received {latitude}".format(**data) + + +@pytest.mark.parametrize( + "data", [ + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "latitude": 80, + "longitude": 180.1, + }, + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "latitude": 80, + "longitude": -180.1, + }, + ], +) +def test_location_bad_longitude(data): + with pytest.raises(ValueError) as excinfo: + stix2.parse(data) + + assert str(excinfo.value) == "{id} 'longitude' must be between -180 and 180. Received {longitude}".format(**data) + + +@pytest.mark.parametrize( + "data", [ + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "longitude": 175.7, + "precision": 20, + }, + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "latitude": 80, + "precision": 20, + }, + ], +) +def test_location_properties_missing_when_precision_is_present(data): + with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo: + stix2.parse(data) + + assert any(x in str(excinfo.value) for x in ("(latitude, precision)", "(longitude, precision)")) + + +@pytest.mark.parametrize( + "data", [ + { + "type": "location", + "spec_version": "2.1", + "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "latitude": 18.468842, + "longitude": -66.120711, + "precision": -100.0, + }, + ], +) +def test_location_negative_precision(data): + with pytest.raises(ValueError) as excinfo: + stix2.parse(data) + + assert str(excinfo.value) == "{id} 'precision' must be a positive value. Received {precision}".format(**data) diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 24206b8..ef1f38d 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -1,6 +1,7 @@ """STIX 2.1 Domain Objects""" from collections import OrderedDict +from math import fabs import itertools from ..base import _STIXBase @@ -225,6 +226,27 @@ class Location(STIXDomainObject): ('granular_markings', ListProperty(GranularMarking)), ]) + def _check_object_constraints(self): + super(Location, self)._check_object_constraints() + if self.get('precision'): + self._check_properties_dependency(['longitude', 'latitude'], ['precision']) + if self.precision < 0.0: + msg = ("{0.id} 'precision' must be a positive value. Received " + "{0.precision}") + raise ValueError(msg.format(self)) + + self._check_properties_dependency(['latitude'], ['longitude']) + + if self.get('latitude') is not None and fabs(self.latitude) > 90.0: + msg = ("{0.id} 'latitude' must be between -90 and 90. Received " + "{0.latitude}") + raise ValueError(msg.format(self)) + + if self.get('longitude') is not None and fabs(self.longitude) > 180.0: + msg = ("{0.id} 'longitude' must be between -180 and 180. Received " + "{0.longitude}") + raise ValueError(msg.format(self)) + class AnalysisType(_STIXBase):