diff --git a/.pylintrc b/.pylintrc index 8686a03..d2f4b04 100644 --- a/.pylintrc +++ b/.pylintrc @@ -11,6 +11,10 @@ # paths. ignore=CVS +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + # Pickle collected data for later comparisons. persistent=yes @@ -35,7 +39,8 @@ extension-pkg-whitelist= # be used to obtain the result of joining multiple strings with the addition # operator. Joining a lot of strings can lead to a maximum recursion error in # Pylint and this flag can prevent that. It has one side effect, the resulting -# AST will be different than the one from reality. +# AST will be different than the one from reality. This option is deprecated +# and it will be removed in Pylint 2.0. optimize-ast=no @@ -60,7 +65,7 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating +disable=nonzero-method,input-builtin,file-builtin,old-division,unicode-builtin,standarderror-builtin,raw_input-builtin,xrange-builtin,suppressed-message,unichr-builtin,execfile-builtin,dict-view-method,coerce-method,round-builtin,long-builtin,delslice-method,getslice-method,dict-iter-method,old-ne-operator,cmp-method,basestring-builtin,old-octal-literal,useless-suppression,raising-string,range-builtin-not-iterating,next-method-called,intern-builtin,long-suffix,filter-builtin-not-iterating,import-star-module-level,print-statement,map-builtin-not-iterating,using-cmp-argument,zip-builtin-not-iterating,coerce-builtin,cmp-builtin,old-raise-syntax,unpacking-in-except,buffer-builtin,reduce-builtin,oct-method,hex-method,parameter-unpacking,metaclass-assignment,apply-builtin,reload-builtin,setslice-method,no-absolute-import,indexing-exception,backtick [REPORTS] @@ -72,7 +77,8 @@ output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". +# written in a file name "pylint_global.[txt|html]". This option is deprecated +# and it will be removed in Pylint 2.0. files-output=no # Tells whether to display a full report or only the messages @@ -92,9 +98,6 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme [BASIC] -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter - # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_,f @@ -108,17 +111,9 @@ name-group= # Include a hint for the correct naming format with invalid-name include-naming-hint=no -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ @@ -132,11 +127,11 @@ attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for attribute names attr-name-hint=[a-z_][a-z0-9_]{2,30}$ -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ @@ -144,11 +139,11 @@ class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Naming hint for class attribute names class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,50}$ -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,50}$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ @@ -156,11 +151,11 @@ class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for class names class-name-hint=[A-Z_][a-zA-Z0-9]+$ -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,40}$ -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,40}$ # Regular expression matching correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ @@ -168,6 +163,18 @@ method-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for method names method-name-hint=[a-z_][a-z0-9_]{2,30}$ +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ @@ -231,7 +238,7 @@ notes=FIXME,XXX,TODO [SIMILARITIES] # Minimum lines number of a similarity. -min-similarity-lines=8 +min-similarity-lines=5 # Ignore comments when computing similarities. ignore-comments=yes @@ -272,16 +279,21 @@ ignore-mixin-members=yes # supports qualified module names, as well as Unix pattern matching. ignored-modules= -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). This supports can work -# with qualified names. -ignored-classes= +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + [VARIABLES] @@ -290,7 +302,7 @@ init-import=no # A regular expression matching the name of dummy variables (i.e. expectedly # not used). -dummy-variables-rgx=_$|dummy +dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. @@ -300,6 +312,10 @@ additional-builtins= # name must start or end with one of those strings. callbacks=cb_,_cb +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins + [CLASSES] @@ -357,7 +373,7 @@ max-bool-expr=5 [IMPORTS] # Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec +deprecated-modules=optparse # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) @@ -371,6 +387,18 @@ ext-import-graph= # not be disabled) int-import-graph= +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + [EXCEPTIONS] diff --git a/.travis.yml b/.travis.yml index aa08c4f..42b5764 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,11 @@ language: python python: - "2.7" - - "3.3" - "3.4" - "3.5" branches: only: - - master -before_install: - - pip install --upgrade pip - - pip install pep8 pylint tox -install: - - python setup.py sdist - - pip install ./dist/* -script: - - gjtk --help - - tox - - pep8 gjtk setup.py - - pylint gjtk setup.py + - master +install: pip install tox-travis coveralls +script: tox +after_success: coveralls diff --git a/MANIFEST.in b/MANIFEST.in index ae35f52..0f115f2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ -graft gjtk global-exclude *.py[cod] __pycache__ include LICENSE +graft gjtk diff --git a/README.rst b/README.rst index 6a4174f..da575c4 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ GeoJSON ToolKit ``gjtk`` is a library for working with `GeoJSON`_. It aims to be as compliant with the specification (soon `standard`_, hopefully) as possible. -|Build Status| |PyPI Version| +|Build Status| |Test Coverage| |PyPI Version| Installation ------------ @@ -213,5 +213,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA .. |Build Status| image:: https://img.shields.io/travis/dmtucker/gjtk-py.svg :target: https://travis-ci.org/dmtucker/gjtk-py +.. |Test Coverage| image:: https://img.shields.io/coveralls/dmtucker/gjtk-py.svg + :target: https://coveralls.io/github/dmtucker/gjtk-py .. |PyPI Version| image:: https://img.shields.io/pypi/v/gjtk.svg :target: https://pypi.python.org/pypi/gjtk diff --git a/gjtk/__init__.py b/gjtk/__init__.py index ef2721b..eddde27 100644 --- a/gjtk/__init__.py +++ b/gjtk/__init__.py @@ -1,6 +1,12 @@ +# coding: utf-8 + """GeoJSON ToolKit""" -from . import extract -from . import generate -from . import random -from . import validate +from __future__ import absolute_import + +from gjtk import cli +from gjtk import example +from gjtk import extract +from gjtk import generate +from gjtk import random +from gjtk import validate diff --git a/gjtk/__main__.py b/gjtk/__main__.py index 2538cee..c9b881f 100644 --- a/gjtk/__main__.py +++ b/gjtk/__main__.py @@ -1,108 +1,9 @@ -"""GJTK CLI Interface""" - -from __future__ import absolute_import -from __future__ import print_function - -import argparse -import json -import sys - -import gjtk - - -def lint(args): - """Validate GeoJSON files.""" - valid = 0 - for path in args.paths: - with open(path, 'r') as f: - anything = json.load(f) - sys.stdout.write(path+'... ') - if gjtk.validate.is_geojson(anything): - valid += 1 - print('valid') - else: - print('invalid') - print(str(valid) + '/' + str(len(args.paths)) + ' valid GeoJSON files') - - -def stat(args): - """Count the number of GeoJSON objects present of each type.""" - valid = 0 - geometries = 0 - features = 0 - feature_collections = 0 - for path in args.paths: - with open(path, 'r') as f: - geojson = json.load(f) - if not gjtk.validate.is_geojson(geojson): - continue - valid += 1 - if gjtk.validate.is_feature_collection(geojson): - feature_collections += 1 - for feature in geojson['features']: - features += 1 - geometries += stat_feature(feature) - elif gjtk.validate.is_feature(geojson): - features += 1 - geometries += stat_feature(geojson) - else: - assert gjtk.validate.is_geometry(geojson), \ - 'A valid GeoJSON object is not a' \ - ' FeatureCollection, Feature, or Geometry!\n{0}'.format( - gjtk.test.error_message(test_data=geojson), - ) - geometries += stat_geometry(geojson) - print(str(valid) + '/' + str(len(args.paths)) + ' valid GeoJSON files') - print(str(feature_collections) + ' FeatureCollections') - print(str(features) + ' Features') - print(str(geometries) + ' Geometries') +# coding: utf-8 +"""This module defines the behavior of python -m.""" -def stat_feature(feature): - """Count the number of Geometries in a Feature.""" - geometries = 0 - if gjtk.validate.is_geometry(feature['geometry']): - geometries += stat_geometry(feature['geometry']) - return geometries - - -def stat_geometry(geometry): - """Count the number of Geometries in a Geometry.""" - geometries = 1 - if gjtk.validate.is_geometry_collection(geometry): - for each in geometry['geometries']: - geometries += stat_geometry(each) - return geometries - - -def main(): - """Parse an execute the CLI.""" - parser = argparse.ArgumentParser(prog="gjtk") - subparsers = parser.add_subparsers() - - lint_parser = subparsers.add_parser( - "lint", - help="Validate a GeoJSON file.", - ) - lint_parser.add_argument( - "paths", nargs='+', metavar="path", - help="Specify GeoJSON file(s).", - ) - lint_parser.set_defaults(func=lint) - - stat_parser = subparsers.add_parser( - "stat", - help="Show information about a GeoJSON file.", - ) - stat_parser.add_argument( - "paths", nargs='+', metavar="path", - help="Specify GeoJSON file(s).", - ) - stat_parser.set_defaults(func=stat) - - args = parser.parse_args() - args.func(args) +from __future__ import absolute_import +import gjtk.cli -if __name__ == '__main__': - main() +gjtk.cli.main() diff --git a/gjtk/cli.py b/gjtk/cli.py new file mode 100644 index 0000000..a7caebc --- /dev/null +++ b/gjtk/cli.py @@ -0,0 +1,56 @@ +# coding: utf-8 + +"""This module defines the GJTK CLI.""" + +from __future__ import absolute_import +from __future__ import print_function + +from io import open # pylint: disable=redefined-builtin + +import argparse +import json +import sys + +import gjtk.validate + + +def parser(argument_parser=None): + """Define a CLI.""" + if argument_parser is None: + argument_parser = argparse.ArgumentParser(prog="gjtk") + argument_parser.add_argument( + "paths", nargs='+', metavar="path", + help="Specify GeoJSON files to validate.", + ) + return argument_parser + + +def main(argv=None): + """Execute CLI invocations.""" + + if argv is None: + argv = sys.argv[1:] + args = parser().parse_args(argv) + + valid_paths = 0 + len_longest_path = max(map(len, args.paths)) + for path in args.paths: + pad = ' ' * (len_longest_path - len(path)) + print(path + pad, end='\t') + try: + with open(path, 'r', encoding='utf-8') as f: + valid_json = json.load(f) + except IOError as ex: + print('error', ex) + continue + except ValueError: + print('invalid JSON') + continue + if gjtk.validate.is_geojson(valid_json): + print('valid') + valid_paths += 1 + else: + print('invalid') + print(str(valid_paths) + '/' + str(len(args.paths)), 'valid GeoJSON files') + + sys.exit(len(args.paths) - valid_paths) diff --git a/gjtk/example.py b/gjtk/example.py new file mode 100644 index 0000000..30ad4d9 --- /dev/null +++ b/gjtk/example.py @@ -0,0 +1,162 @@ +# coding: utf-8 + +"""GeoJSON Examples from the Specification""" + +POINT = { + "type": "Point", + "coordinates": [100.0, 0.0], +} + +MULTI_POINT = { + "type": "MultiPoint", + "coordinates": [[100.0, 0.0], [101.0, 1.0]], +} + +LINE_STRING = { + "type": "LineString", + "coordinates": [[100.0, 0.0], [101.0, 1.0]], +} + +MULTI_LINE_STRING = { + "type": "MultiLineString", + "coordinates": [ + [[100.0, 0.0], [101.0, 1.0]], + [[102.0, 2.0], [103.0, 3.0]], + ], +} + +POLYGON_WITHOUT_HOLE = { + "type": "Polygon", + "coordinates": [ + [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + ], +} + +POLYGON_WITH_HOLE = { + "type": "Polygon", + "coordinates": [ + [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]], + ], +} + +MULTI_POLYGON = { + "type": "MultiPolygon", + "coordinates": [ + [ + [[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]], + ], + [ + [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]], + ], + ], +} + +GEOMETRY_COLLECTION = { + "type": "GeometryCollection", + "geometries": [ + { + "type": "Point", + "coordinates": [100.0, 0.0], + }, + { + "type": "LineString", + "coordinates": [[101.0, 0.0], [102.0, 1.0]], + }, + ], +} + +FEATURE = { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [125.6, 10.1], + }, + "properties": { + "name": "Dinagat Islands", + }, +} + +FEATURE_COLLECTION = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, + "properties": {"prop0": "value0"}, + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [102.0, 0.0], + [103.0, 1.0], + [104.0, 0.0], + [105.0, 1.0], + ], + }, + "properties": { + "prop0": "value0", + "prop1": 0.0, + }, + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0], + ], + ], + }, + "properties": { + "prop0": "value0", + "prop1": {"this": "that"}, + }, + }, + ], +} + +CRS_1 = { + "type": "name", + "properties": { + "name": "urn:ogc:def:crs:OGC:1.3:CRS84", + }, +} + +CRS_2 = { + "type": "link", + "properties": { + "href": "http://example.com/crs/42", + "type": "proj4", + }, +} + +CRS_3 = { + "type": "link", + "properties": { + "href": "data.crs", + "type": "ogcwkt", + }, +} + +LINK_1 = { + "href": "http://example.com/crs/42", + "type": "proj4", +} + +LINK_2 = { + "href": "data.crs", + "type": "ogcwkt", +} + +BBOX_1 = [-10.0, -10.0, 10.0, 10.0] + +BBOX_2 = [100.0, 0.0, 105.0, 1.0] diff --git a/gjtk/extract.py b/gjtk/extract.py index 7a49627..333980e 100644 --- a/gjtk/extract.py +++ b/gjtk/extract.py @@ -1,3 +1,5 @@ +# coding: utf-8 + """Extract GeoJSON objects from other GeoJSON objects.""" diff --git a/gjtk/generate.py b/gjtk/generate.py index 49c80e7..129deb0 100644 --- a/gjtk/generate.py +++ b/gjtk/generate.py @@ -1,3 +1,5 @@ +# coding: utf-8 + """Generate GeoJSON objects from their components.""" diff --git a/gjtk/random.py b/gjtk/random.py index 2a1c9b8..4301d15 100644 --- a/gjtk/random.py +++ b/gjtk/random.py @@ -1,28 +1,36 @@ +# coding: utf-8 + """Generate random GeoJSON elements.""" from __future__ import absolute_import import random -import gjtk +import pytest + +import gjtk.generate +@pytest.fixture def position(max_numbers=3, min_numbers=2): """Generate a random GeoJSON Position.""" assert min_numbers > 1, "There must be at least two elements, and may be more." return [(random.random()-0.5)*100 for _ in range(random.randint(min_numbers, max_numbers))] +@pytest.fixture def point_coordinates(): """Generate random coordinates for a GeoJSON Point.""" return position() +@pytest.fixture def multi_point_coordinates(max_positions=6, min_positions=0): """Generate random coordinates for a GeoJSON MultiPoint.""" return [position() for _ in range(random.randint(min_positions, max_positions))] +@pytest.fixture def line_string_coordinates(max_positions=6, min_positions=2): """Generate random coordinates for a GeoJSON LineString.""" assert min_positions > 1, \ @@ -30,12 +38,14 @@ def line_string_coordinates(max_positions=6, min_positions=2): return [position() for _ in range(random.randint(min_positions, max_positions))] +@pytest.fixture def linear_ring_coordinates(): """Generate a random GeoJSON LinearRing.""" origin = position() return [origin]+line_string_coordinates()+[origin] +@pytest.fixture def multi_line_string_coordinates(max_line_strings=6, min_line_strings=1): """Generate random coordinates for a GeoJSON MultiLineString.""" return [ @@ -44,6 +54,7 @@ def multi_line_string_coordinates(max_line_strings=6, min_line_strings=1): ] +@pytest.fixture def polygon_coordinates(): """Generate random coordinates for a GeoJSON Polygon.""" quadrant = [ @@ -74,11 +85,13 @@ def polygon_coordinates(): ] +@pytest.fixture def multi_polygon_coordinates(max_polygons=6, min_polygons=1): """Generate random coordinates for a GeoJSON MultiPolygon.""" return [polygon_coordinates() for _ in range(random.randint(min_polygons, max_polygons))] +@pytest.fixture def geometry(): """Generate a random GeoJSON Geometry.""" return random.choice([ @@ -92,36 +105,43 @@ def geometry(): ])() +@pytest.fixture def point(): """Generate a random GeoJSON Point.""" return gjtk.generate.point(position=position()) +@pytest.fixture def multi_point(): """Generate a random GeoJSON MultiPoint.""" return gjtk.generate.multi_point(coordinates=multi_point_coordinates()) +@pytest.fixture def line_string(): """Generate a random GeoJSON LineString.""" return gjtk.generate.line_string(coordinates=line_string_coordinates()) +@pytest.fixture def multi_line_string(): """Generate a random GeoJSON MultiLineString.""" return gjtk.generate.multi_line_string(coordinates=multi_line_string_coordinates()) +@pytest.fixture def polygon(): """Generate a random GeoJSON Polygon.""" return gjtk.generate.polygon(coordinates=polygon_coordinates()) +@pytest.fixture def multi_polygon(): """Generate a random GeoJSON MultiPolygon.""" return gjtk.generate.multi_polygon(coordinates=multi_polygon_coordinates()) +@pytest.fixture def geometry_collection(max_geometries=3, min_geometries=0): """Generate a random GeoJSON GeometryCollection.""" return gjtk.generate.geometry_collection( @@ -129,6 +149,7 @@ def geometry_collection(max_geometries=3, min_geometries=0): ) +@pytest.fixture def feature(): """Generate a random GeoJSON Feature.""" return gjtk.generate.feature( @@ -141,6 +162,7 @@ def feature(): ) +@pytest.fixture def feature_collection(max_features=3, min_features=0): """Generate a random GeoJSON FeatureCollection.""" return gjtk.generate.feature_collection( @@ -148,6 +170,7 @@ def feature_collection(max_features=3, min_features=0): ) +@pytest.fixture def crs(): """Generate a random GeoJSON Coordinate Reference System.""" return { @@ -161,6 +184,7 @@ def crs(): } +@pytest.fixture def link(): """Generate a random GeoJSON Link.""" new_link = {"href": "data.crs" if random.random() < 0.5 else "http://example.com/crs/42"} @@ -169,6 +193,7 @@ def link(): return new_link +@pytest.fixture def bbox(max_dimensions=4, min_dimensions=2): """Generate a random GeoJSON Bounding Box.""" lower_bounds = [] diff --git a/gjtk/test/__init__.py b/gjtk/test/__init__.py index fac1d49..948d2a1 100644 --- a/gjtk/test/__init__.py +++ b/gjtk/test/__init__.py @@ -1,37 +1,3 @@ -"""Test Suite for the GeoJSON ToolKit""" - -from __future__ import absolute_import - -import json +# coding: utf-8 - -def error_message(test_data=None, test_result=None): - """Create an error message from test data and results.""" - message = [''] - if test_data is not None: - message.append('// Data') - try: - message.append( - json.dumps( - test_data, - sort_keys=True, - indent=2, - separators=(',', ': ') - ) - ) - except TypeError: - message.append('The test data is not JSON serializable:\n{0}'.format(test_data)) - if test_result is not None: - message.append('// Result') - try: - message.append( - json.dumps( - test_result, - sort_keys=True, - indent=2, - separators=(',', ': ') - ) - ) - except TypeError: - message.append('The test result is not JSON serializable:\n{0}'.format(test_result)) - return '\n'.join(message) +"""Test Suite for the GeoJSON ToolKit""" diff --git a/gjtk/test/conftest.py b/gjtk/test/conftest.py new file mode 100644 index 0000000..8b26ee4 --- /dev/null +++ b/gjtk/test/conftest.py @@ -0,0 +1,9 @@ +# coding: utf-8 + +"""Pytest Configuration""" + +from __future__ import absolute_import + +# pylint: disable=wildcard-import, unused-wildcard-import +from gjtk.test.fixtures import * +from gjtk.random import * diff --git a/gjtk/test/fixtures.py b/gjtk/test/fixtures.py new file mode 100644 index 0000000..4c69dbc --- /dev/null +++ b/gjtk/test/fixtures.py @@ -0,0 +1,323 @@ +# coding: utf-8 + +"""Pytest Fixtures""" + +from __future__ import absolute_import +from __future__ import unicode_literals + +import copy +import json +import random +import sys + +import pytest + +import gjtk.example + +# Pytest fixtures can rely on other fixtures. +# pylint: disable=redefined-outer-name + + +# Generic + + +@pytest.fixture +def immutable(): + """an immutable value""" + return random.choice(((), None, True, 0, '')) + + +@pytest.fixture +def mutable(): + """a mutable value""" + return random.choice(([], {}, object, lambda x: x)) + + +@pytest.fixture +def types(immutable, mutable): + """a value of any type""" + return random.choice((immutable, mutable)) + + +# GeoJSON + + +@pytest.fixture +def crs_without_properties(crs): + """a GeoJSON CRS without a properties key""" + del crs['properties'] + return crs + + +@pytest.fixture +def crs_without_type(crs): + """a GeoJSON CRS without a type key""" + del crs['type'] + return crs + + +@pytest.fixture +def feature_collection_with_bbox(feature_collection, bbox): + """a GeoJSON FeatureCollection with a Bbox""" + feature_collection['bbox'] = bbox + return feature_collection + + +@pytest.fixture +def feature_collection_with_crs(feature_collection, crs): + """a GeoJSON FeatureCollection with a CRS""" + feature_collection['crs'] = crs + return feature_collection + + +@pytest.fixture +def feature_collection_without_features(feature_collection): + """a GeoJSON FeatureCollection without a features key""" + del feature_collection['features'] + return feature_collection + + +@pytest.fixture +def feature_collection_without_type(feature_collection): + """a GeoJSON FeatureCollection without a type key""" + del feature_collection['type'] + return feature_collection + + +@pytest.fixture +def feature_with_bbox(feature, bbox): + """a GeoJSON Feature with a Bbox""" + feature['bbox'] = bbox + return feature + + +@pytest.fixture +def feature_with_crs(feature, crs): + """a GeoJSON Feature with a CRS""" + feature['crs'] = crs + return feature + + +@pytest.fixture +def feature_without_geometry(feature): + """a GeoJSON Feature without a geometry key""" + del feature['geometry'] + return feature + + +@pytest.fixture +def feature_without_type(feature): + """a GeoJSON Feature without a type key""" + del feature['type'] + return feature + + +@pytest.fixture +def geojson(): + """a valid GeoJSON object""" + return random.choice([ + gjtk.random.geometry(), + gjtk.random.feature(), + gjtk.random.feature_collection(), + ]) + + +@pytest.fixture +def geojson_file(tmpdir, geojson): + """a file that contains valid GeoJSON""" + f = tmpdir.join('test.geojson') + args, kwargs = (['w'], {'encoding': 'utf-8'}) if sys.version_info.major > 2 else (['wb'], {}) + with f.open(*args, **kwargs) as tmpfile: + json.dump(geojson, tmpfile) + return str(f) + + +@pytest.fixture +def geometry_with_bbox(geometry, bbox): + """a GeoJSON Geometry with a Bbox""" + geometry['bbox'] = bbox + return geometry + + +@pytest.fixture +def geometry_with_crs(geometry, crs): + """a GeoJSON Geometry with a CRS""" + geometry['crs'] = crs + return geometry + + +@pytest.fixture +def geometry_collection_without_geometries(geometry_collection): + """a GeoJSON GeometryCollection without a geometries key""" + del geometry_collection['geometries'] + return geometry_collection + + +@pytest.fixture +def geometry_collection_without_type(geometry_collection): + """a GeoJSON GeometryCollection without a type key""" + del geometry_collection['type'] + return geometry_collection + + +@pytest.fixture +def invalid_position(types): + """an invalid GeoJSON Position""" + return (types, [1], ['foo', 'bar'], [1, 'a']) + + +@pytest.fixture +def json_file(tmpdir): + """a file that contains valid JSON that is not GeoJSON""" + f = tmpdir.join('test.json') + args, kwargs = (['w'], {'encoding': 'utf-8'}) if sys.version_info.major > 2 else (['wb'], {}) + with f.open(*args, **kwargs) as tmpfile: + json.dump({'not': 'geojson'}, tmpfile) + return str(f) + + +@pytest.fixture +def line_string_without_coordinates(line_string): + """a GeoJSON LineString without a coordinates key""" + del line_string['coordinates'] + return line_string + + +@pytest.fixture +def line_string_without_type(line_string): + """a GeoJSON LineString without a type key""" + del line_string['type'] + return line_string + + +@pytest.fixture +def link_without_href(link): + """a GeoJSON Link without a href key""" + del link['href'] + return link + + +@pytest.fixture +def link_without_type(link): + """a GeoJSON Link without a type key""" + link['type'] = None + del link['type'] + return link + + +@pytest.fixture +def malformed_bbox(bbox): + """an invalid GeoJSON Bbox with a valid structure""" + return [max(bbox[0], bbox[1]), min(bbox[0], bbox[1])] + + +@pytest.fixture +def malformed_polygon(): + """an invalid GeoJSON Polygon with a valid structure""" + polygon = copy.deepcopy(gjtk.example.POLYGON_WITH_HOLE) + polygon['coordinates'] = [polygon['coordinates'][1], polygon['coordinates'][0]] + return polygon + + +@pytest.fixture +def malformed_multi_polygon(multi_polygon): + """an invalid GeoJSON MultiPolygon with a valid structure""" + multi_polygon = copy.deepcopy(gjtk.example.MULTI_POLYGON) + del multi_polygon['coordinates'][0][0][0] + return multi_polygon + + +@pytest.fixture +def multi_line_string_without_coordinates(multi_line_string): + """a GeoJSON MultiLineString without a coordinates key""" + del multi_line_string['coordinates'] + return multi_line_string + + +@pytest.fixture +def multi_line_string_without_type(multi_line_string): + """a GeoJSON MultiLineString without a type key""" + del multi_line_string['type'] + return multi_line_string + + +@pytest.fixture +def multi_point_without_coordinates(multi_point): + """a GeoJSON MultiPoint without a coordinates key""" + del multi_point['coordinates'] + return multi_point + + +@pytest.fixture +def multi_point_without_type(multi_point): + """a GeoJSON MultiPoint without a type key""" + del multi_point['type'] + return multi_point + + +@pytest.fixture +def multi_polygon_without_coordinates(multi_polygon): + """a GeoJSON MultiPolygon without a coordinates key""" + del multi_polygon['coordinates'] + return multi_polygon + + +@pytest.fixture +def multi_polygon_without_type(multi_polygon): + """a GeoJSON MultiPolygon without a type key""" + del multi_polygon['type'] + return multi_polygon + + +@pytest.fixture +def non_utf8_file(tmpdir): + """a file that is not UTF-8 encoded""" + f = tmpdir.join('test.txt') + with f.open('w', encoding='big5') as tmpfile: + tmpfile.write('漢字') + return str(f) + + +@pytest.fixture +def point_without_coordinates(point): + """a GeoJSON Point without a coordinates key""" + del point['coordinates'] + return point + + +@pytest.fixture +def point_without_type(point): + """a GeoJSON Point without a type key""" + del point['type'] + return point + + +@pytest.fixture +def polygon_without_coordinates(polygon): + """a GeoJSON Polygon without a coordinates key""" + del polygon['coordinates'] + return polygon + + +@pytest.fixture +def polygon_without_type(polygon): + """a GeoJSON Polygon without a type key""" + del polygon['type'] + return polygon + + +@pytest.fixture +def text_file(tmpdir): + """a file that does not contain valid JSON""" + f = tmpdir.join('test.txt') + with f.open('w', encoding='ascii') as tmpfile: + tmpfile.write('plaintext') + return str(f) + + +@pytest.fixture +def unequal_positions(position): + """a 2-tuple pair of distinct GeoJSON Position""" + position2 = list(position) + position2[0] = position[0] + 1 + return position, position2 diff --git a/gjtk/test/test_cli.py b/gjtk/test/test_cli.py new file mode 100644 index 0000000..2194672 --- /dev/null +++ b/gjtk/test/test_cli.py @@ -0,0 +1,88 @@ +# coding: utf-8 + +"""Tests for gjtk.cli""" + +from __future__ import absolute_import + +import os + +import decorator + +import gjtk.cli + + +def exit_with_status(comp=None): + """ + Expect a test to raise a SystemExit, optionally with a code that satisfies the given expression. + """ + def _decorator(test_func): + """Decorate tests.""" + def _decorated(test_func, *args, **kwargs): + """A replacement test function that expects tests to raise SystemError.""" + try: + assert test_func(*args, **kwargs) and False + except SystemExit as exc: + expr = str(exc.code) + ' ' + comp + assert True if comp is None else eval(expr), expr # pylint: disable=eval-used + return decorator.decorator(_decorated, test_func) + return _decorator + + +@exit_with_status('!= 0') +def test___main__(): + """Test python -m functionality.""" + import gjtk.__main__ # pylint: disable=redefined-outer-name, unused-variable + + +@exit_with_status('!= 0') +def test_empty(): + """Test invocation with no arguments.""" + gjtk.cli.main() + + +@exit_with_status('!= 0') +def test_nonexistent_file(tmpdir): + """Test invocation with a file that does not exist.""" + gjtk.cli.main(argv=[os.path.join(str(tmpdir), 'x')]) + + +@exit_with_status('!= 0') +def test_non_file(tmpdir): + """Test invocation with a directory.""" + gjtk.cli.main(argv=[str(tmpdir)]) + + +@exit_with_status('!= 0') +def test_incorrect_encoding(non_utf8_file): + """Test invocation with a non-UTF-8 file.""" + gjtk.cli.main(argv=[non_utf8_file]) + + +@exit_with_status('!= 0') +def test_empty_file(tmpdir): + """Test invocation with an empty file.""" + gjtk.cli.main(argv=[str(tmpdir.join('empty'))]) + + +@exit_with_status('!= 0') +def test_non_json_file(text_file): + """Test invocation with a file that does not contain JSON.""" + gjtk.cli.main(argv=[text_file]) + + +@exit_with_status('!= 0') +def test_invalid_file(json_file): + """Test invocation with a valid JSON file that is not GeoJSON.""" + gjtk.cli.main(argv=[json_file]) + + +@exit_with_status('== 0') +def test_valid_file(geojson_file): + """Test invocation with a valid GeoJSON file.""" + gjtk.cli.main(argv=[geojson_file]) + + +@exit_with_status('== 1') +def test_mixed_files(geojson_file, json_file): + """Test invocation with a valid GeoJSON file and an invalid one.""" + gjtk.cli.main(argv=[geojson_file, json_file]) diff --git a/gjtk/test/test_example.py b/gjtk/test/test_example.py new file mode 100644 index 0000000..7a0d8fe --- /dev/null +++ b/gjtk/test/test_example.py @@ -0,0 +1,93 @@ +# coding: utf-8 + +"""Tests for gjtk.example""" + +from __future__ import absolute_import + +import gjtk.example +import gjtk.validate + + +def test_is_point(): + """should return true when provided an example Point""" + assert gjtk.validate.is_point(gjtk.example.POINT) + + +def test_is_multi_point(): + """should return true when provided an example MultiPoint""" + assert gjtk.validate.is_multi_point(gjtk.example.MULTI_POINT) + + +def test_is_line_string(): + """should return true when provided an example LineString""" + assert gjtk.validate.is_line_string(gjtk.example.LINE_STRING) + + +def test_is_multi_line_string(): + """should return true when provided an example MultiLineString""" + assert gjtk.validate.is_multi_line_string(gjtk.example.MULTI_LINE_STRING) + + +def test_is_polygon_without_hole(): + """should return true when provided an example Polygon""" + assert gjtk.validate.is_polygon(gjtk.example.POLYGON_WITHOUT_HOLE) + + +def test_is_polygon_with_hole(): + """should return true when provided an example Polygon""" + assert gjtk.validate.is_polygon(gjtk.example.POLYGON_WITH_HOLE) + + +def test_is_multi_polygon(): + """should return true when provided an example MultiPolygon""" + assert gjtk.validate.is_multi_polygon(gjtk.example.MULTI_POLYGON) + + +def test_is_geometry_collection(): + """should return true when provided an example GeometryCollection""" + assert gjtk.validate.is_geometry_collection(gjtk.example.GEOMETRY_COLLECTION) + + +def test_is_feature(): + """should return true when provided an example Feature""" + assert gjtk.validate.is_feature(gjtk.example.FEATURE) + + +def test_is_feature_collection(): + """should return true when provided an example FeatureCollection""" + assert gjtk.validate.is_feature_collection(gjtk.example.FEATURE_COLLECTION) + + +def test_is_crs_1(): + """should return true when provided an example CRS""" + assert gjtk.validate.is_crs(gjtk.example.CRS_1) + + +def test_is_crs_2(): + """should return true when provided an example CRS""" + assert gjtk.validate.is_crs(gjtk.example.CRS_2) + + +def test_is_crs_3(): + """should return true when provided an example CRS""" + assert gjtk.validate.is_crs(gjtk.example.CRS_3) + + +def test_is_link_1(): + """should return true when provided an example Link""" + assert gjtk.validate.is_link(gjtk.example.LINK_1) + + +def test_is_link_2(): + """should return true when provided an example Link""" + assert gjtk.validate.is_link(gjtk.example.LINK_2) + + +def test_is_bbox_1(): + """should return true when provided an example Bbox""" + assert gjtk.validate.is_bbox(gjtk.example.BBOX_1) + + +def test_is_bbox_2(): + """should return true when provided an example Bbox""" + assert gjtk.validate.is_bbox(gjtk.example.BBOX_2) diff --git a/gjtk/test/test_extract.py b/gjtk/test/test_extract.py index 7f3060e..3ab2580 100644 --- a/gjtk/test/test_extract.py +++ b/gjtk/test/test_extract.py @@ -1,204 +1,259 @@ -"""Tests for GeoJSON ToolKit Extraction Utilities""" - -import unittest - -import gjtk - - -class ExtractPositionsTest(unittest.TestCase): - - """Tests for Position Extraction""" - - def test_valid_point(self): - """should return valid positions when provided a valid Point""" - test_data = gjtk.random.point() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_multi_point(self): - """should return valid positions when provided a valid MultiPoint""" - test_data = gjtk.random.multi_point() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_line_string(self): - """should return valid positions when provided a valid LineString""" - test_data = gjtk.random.line_string() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_multi_line_string(self): - """should return valid positions when provided a valid MultiLineString""" - test_data = gjtk.random.multi_line_string() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_polygon(self): - """should return valid positions when provided a valid Polygon""" - test_data = gjtk.random.polygon() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_multi_polygon(self): - """should return valid positions when provided a valid MultiPolygon""" - test_data = gjtk.random.multi_polygon() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_geometry_collection(self): - """should return valid positions when provided a valid GeometryCollection""" - test_data = gjtk.random.geometry_collection() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_feature(self): - """should return valid positions when provided a valid Feature""" - test_data = gjtk.random.feature() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_feature_collection(self): - """should return valid positions when provided a valid FeatureCollection""" - test_data = gjtk.random.feature_collection() - test_result = gjtk.extract.positions_of(test_data) - self.assertTrue( - all(gjtk.validate.is_position(position) for position in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class ExtractFeaturesTest(unittest.TestCase): - - """Tests for Feature Extraction""" - - def test_valid_feature(self): - """should return valid features when provided a valid Feature""" - test_data = gjtk.random.feature() - test_result = gjtk.extract.features_of(test_data) - self.assertTrue( - all(gjtk.validate.is_feature(feature) for feature in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_feature_collection(self): - """should return valid features when provided a valid FeatureCollection""" - test_data = gjtk.random.feature_collection() - test_result = gjtk.extract.features_of(test_data) - self.assertTrue( - all(gjtk.validate.is_feature(feature) for feature in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class ExtractGeometriesTest(unittest.TestCase): - - """Tests for Geometry Extraction""" - - def test_valid_point(self): - """should return valid geometries when provided a valid Point""" - test_data = gjtk.random.point() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_multi_point(self): - """should return valid geometries when provided a valid MultiPoint""" - test_data = gjtk.random.multi_point() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_line_string(self): - """should return valid geometries when provided a valid LineString""" - test_data = gjtk.random.line_string() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_multi_line_string(self): - """should return valid geometries when provided a valid MultiLineString""" - test_data = gjtk.random.multi_line_string() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_polygon(self): - """should return valid geometries when provided a valid Polygon""" - test_data = gjtk.random.polygon() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_multi_polygon(self): - """should return valid geometries when provided a valid MultiPolygon""" - test_data = gjtk.random.multi_polygon() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_geometry_collection(self): - """should return valid geometries when provided a valid GeometryCollection""" - test_data = gjtk.random.geometry_collection() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_feature(self): - """should return valid geometries when provided a valid Feature""" - test_data = gjtk.random.feature() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_valid_feature_collection(self): - """should return valid geometries when provided a valid FeatureCollection""" - test_data = gjtk.random.feature_collection() - test_result = gjtk.extract.geometries_of(test_data) - self.assertTrue( - all(gjtk.validate.is_geometry(geometry) for geometry in test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -if __name__ == "__main__": - unittest.main() +# coding: utf-8 + +"""Tests for gjtk.extract""" + +from __future__ import absolute_import + +import collections + +import gjtk.example +import gjtk.extract +import gjtk.validate + + +def normalized(mutable): + """Make mutable types comparable.""" + return collections.Counter(map(tuple, mutable)) + + +# POSITIONS + + +def test_positions_of_point(): + """should return valid positions when provided a valid Point""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.POINT)) == + normalized([ + [100.0, 0.0], + ]) + ) + + +def test_positions_of_multi_point(): + """should return valid positions when provided a valid MultiPoint""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.MULTI_POINT)) == + normalized([ + [100.0, 0.0], + [101.0, 1.0], + ]) + ) + + +def test_positions_of_line_string(): + """should return valid positions when provided a valid LineString""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.LINE_STRING)) == + normalized([ + [100.0, 0.0], + [101.0, 1.0], + ]) + ) + + +def test_positions_of_multi_line_string(): + """should return valid positions when provided a valid MultiLineString""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.MULTI_LINE_STRING)) == + normalized([ + [100.0, 0.0], + [101.0, 1.0], + [102.0, 2.0], + [103.0, 3.0], + ]) + ) + + +def test_positions_of_polygon_without_hole(): + """should return valid positions when provided a valid Polygon""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.POLYGON_WITHOUT_HOLE)) == + normalized([ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0], + ]) + ) + + +def test_positions_of_polygon_with_hole(): + """should return valid positions when provided a valid Polygon""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.POLYGON_WITH_HOLE)) == + normalized([ + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0], + [100.2, 0.2], + [100.8, 0.2], + [100.8, 0.8], + [100.2, 0.8], + [100.2, 0.2], + ]) + ) + + +def test_positions_of_multi_polygon(): + """should return valid positions when provided a valid MultiPolygon""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.MULTI_POLYGON)) == + normalized([ + [102.0, 2.0], + [103.0, 2.0], + [103.0, 3.0], + [102.0, 3.0], + [102.0, 2.0], + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0], + [100.2, 0.2], + [100.8, 0.2], + [100.8, 0.8], + [100.2, 0.8], + [100.2, 0.2], + ]) + ) + + +def test_positions_of_geometry_collection(): + """should return valid positions when provided a valid GeometryCollection""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.GEOMETRY_COLLECTION)) == + normalized([ + [100.0, 0.0], + [101.0, 0.0], + [102.0, 1.0], + ]) + ) + + +def test_positions_of_feature(): + """should return valid positions when provided a valid Feature""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.FEATURE)) == + normalized([ + [125.6, 10.1], + ]) + ) + + +def test_positions_of_feature_collection(): + """should return valid positions when provided a valid FeatureCollection""" + assert ( + normalized(gjtk.extract.positions_of(gjtk.example.FEATURE_COLLECTION)) == + normalized([ + [102.0, 0.5], + [102.0, 0.0], + [103.0, 1.0], + [104.0, 0.0], + [105.0, 1.0], + [100.0, 0.0], + [101.0, 0.0], + [101.0, 1.0], + [100.0, 1.0], + [100.0, 0.0], + ]) + ) + + +def test_positions_of_geojson(geojson): + """should return valid positions when provided any valid GeoJSON""" + assert all( + gjtk.validate.is_position(position) for position in gjtk.extract.positions_of(geojson), + ) + + +# GEOMETRIES + + +def test_geometries_of_point(): + """should return valid geometries when provided a valid Point""" + assert gjtk.extract.geometries_of(gjtk.example.POINT) == \ + [gjtk.example.POINT] + + +def test_geometries_of_multi_point(): + """should return valid geometries when provided a valid MultiPoint""" + assert gjtk.extract.geometries_of(gjtk.example.MULTI_POINT) == \ + [gjtk.example.MULTI_POINT] + + +def test_geometries_of_line_string(): + """should return valid geometries when provided a valid LineString""" + assert gjtk.extract.geometries_of(gjtk.example.LINE_STRING) == \ + [gjtk.example.LINE_STRING] + + +def test_geometries_of_multi_line_string(): + """should return valid geometries when provided a valid MultiLineString""" + assert gjtk.extract.geometries_of(gjtk.example.MULTI_LINE_STRING) == \ + [gjtk.example.MULTI_LINE_STRING] + + +def test_geometries_of_polygon_without_hole(): + """should return valid geometries when provided a valid Polygon""" + assert gjtk.extract.geometries_of(gjtk.example.POLYGON_WITHOUT_HOLE) == \ + [gjtk.example.POLYGON_WITHOUT_HOLE] + + +def test_geometries_of_polygon_with_hole(): + """should return valid geometries when provided a valid Polygon""" + assert gjtk.extract.geometries_of(gjtk.example.POLYGON_WITH_HOLE) == \ + [gjtk.example.POLYGON_WITH_HOLE] + + +def test_geometries_of_multi_polygon(): + """should return valid geometries when provided a valid MultiPolygon""" + assert gjtk.extract.geometries_of(gjtk.example.MULTI_POLYGON) == \ + [gjtk.example.MULTI_POLYGON] + + +def test_geometries_of_geometry_collection(): + """should return valid geometries when provided a valid GeometryCollection""" + assert gjtk.extract.geometries_of(gjtk.example.GEOMETRY_COLLECTION) == \ + gjtk.example.GEOMETRY_COLLECTION['geometries'] + + +def test_geometries_of_feature(): + """should return valid geometries when provided a valid Feature""" + assert gjtk.extract.geometries_of(gjtk.example.FEATURE) == \ + [gjtk.example.FEATURE['geometry']] + + +def test_geometries_of_feature_collection(): + """should return valid geometries when provided a valid FeatureCollection""" + assert gjtk.extract.geometries_of(gjtk.example.FEATURE_COLLECTION) == \ + [feature['geometry'] for feature in gjtk.example.FEATURE_COLLECTION['features']] + + +def test_geometries_of_geojson(geojson): + """should return valid geometries when provided any valid GeoJSON""" + assert all( + gjtk.validate.is_geometry(position) for position in gjtk.extract.geometries_of(geojson), + ) + + +# FEATURES + + +def test_features_of_feature(feature): + """should return valid features when provided a valid Feature""" + assert gjtk.extract.features_of(feature) == [feature] + + +def test_features_of_feature_collection(feature_collection): + """should return valid features when provided a valid FeatureCollection""" + assert gjtk.extract.features_of(feature_collection) == feature_collection['features'] + + +def test_features_of_geojson(geojson): + """should return valid features when provided any valid GeoJSON""" + assert all( + gjtk.validate.is_feature(position) for position in gjtk.extract.features_of(geojson), + ) diff --git a/gjtk/test/test_generate.py b/gjtk/test/test_generate.py deleted file mode 100644 index 966ed0a..0000000 --- a/gjtk/test/test_generate.py +++ /dev/null @@ -1,156 +0,0 @@ -"""Tests for GeoJSON ToolKit Generation Utilities""" - -import random -import unittest - -import gjtk - - -class PointTest(unittest.TestCase): - - """Tests for Position Generation""" - - def test_valid_position(self): - """should return a valid Point object when provided a valid Position""" - test_data = gjtk.random.position(max_numbers=6) - test_result = gjtk.generate.point(test_data) - self.assertTrue( - gjtk.validate.is_point(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class MultiPointTest(unittest.TestCase): - - """Tests for MultiPoint Generation""" - - def test_valid_coordinates(self): - """should return a valid MultiPoint object when provided valid coordinates""" - test_data = gjtk.random.multi_point_coordinates() - test_result = gjtk.generate.multi_point(coordinates=test_data) - self.assertTrue( - gjtk.validate.is_multi_point(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class LineStringTest(unittest.TestCase): - - """Tests for LineString Generation""" - - def test_valid_coordinates(self): - """should return a valid LineString object when provided valid coordinates""" - test_data = gjtk.random.line_string_coordinates() - test_result = gjtk.generate.line_string(coordinates=test_data) - self.assertTrue( - gjtk.validate.is_line_string(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class MultiLineStringTest(unittest.TestCase): - - """Tests for MultiLineString Generation""" - - def test_valid_coordinates(self): - """should return a valid MultiLineString object when provided valid coordinates""" - test_data = gjtk.random.multi_line_string_coordinates() - test_result = gjtk.generate.multi_line_string(coordinates=test_data) - self.assertTrue( - gjtk.validate.is_multi_line_string(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class PolygonTest(unittest.TestCase): - - """Tests for Polygon Generation""" - - def test_valid_coordinates(self): - """should return a valid Polygon object when provided valid coordinates""" - test_data = gjtk.random.polygon_coordinates() - test_result = gjtk.generate.polygon(coordinates=test_data) - self.assertTrue( - gjtk.validate.is_polygon(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class MultiPolygonTest(unittest.TestCase): - - """Tests for MultiPolygon Generation""" - - def test_valid_coordinates(self): - """should return a valid MultiPolygon object when provided valid coordinates""" - test_data = gjtk.random.multi_polygon_coordinates() - test_result = gjtk.generate.multi_polygon(coordinates=test_data) - self.assertTrue( - gjtk.validate.is_multi_polygon(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class GeometryCollectionTest(unittest.TestCase): - - """Tests for GeometryCollection Generation""" - - def test_valid_geometries(self): - """should return a valid GeometryCollection object when provided valid Geometries""" - length = round(random.random() * 100) % 3 - test_data = [gjtk.random.geometry() for _ in range(int(length))] - test_result = gjtk.generate.geometry_collection(test_data) - self.assertTrue( - gjtk.validate.is_geometry_collection(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_nothing(self): - """should return a valid GeometryCollection object when provided nothing""" - test_data = None - test_result = gjtk.generate.geometry_collection(test_data) - self.assertTrue( - gjtk.validate.is_geometry_collection(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class FeatureTest(unittest.TestCase): - - """Tests for Feature Generation""" - - def test_valid_geometry(self): - """should return a valid Feature object when provided a valid Geometry""" - test_data = gjtk.random.geometry() - test_result = gjtk.generate.feature(test_data) - self.assertTrue( - gjtk.validate.is_feature(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -class FeatureCollectionTest(unittest.TestCase): - - """Tests for FeatureCollection Generation""" - - def test_valid_features(self): - """should return a valid FeatureCollection object when provided valid Features""" - length = round(random.random() * 100) % 3 - test_data = [gjtk.random.feature() for _ in range(int(length))] - test_result = gjtk.generate.feature_collection(test_data) - self.assertTrue( - gjtk.validate.is_feature_collection(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - def test_nothing(self): - """should return a valid FeatureCollection object when provided nothing""" - test_data = None - test_result = gjtk.generate.feature_collection(test_data) - self.assertTrue( - gjtk.validate.is_feature_collection(test_result), - gjtk.test.error_message(test_data, test_result), - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/gjtk/test/test_random.py b/gjtk/test/test_random.py deleted file mode 100644 index 6322e7b..0000000 --- a/gjtk/test/test_random.py +++ /dev/null @@ -1,282 +0,0 @@ -"""Tests for GeoJSON ToolKit Random Generation Utilities""" - -import unittest - -import gjtk - - -class PositionTest(unittest.TestCase): - - """Tests for Random Position Generation""" - - def test_position(self): - """should return a valid Position""" - test_data = gjtk.random.position(max_numbers=6) - self.assertTrue( - gjtk.validate.is_position(test_data), - gjtk.test.error_message(test_data), - ) - - -class PointCoordinatesTest(unittest.TestCase): - - """Tests for Random Point Coordinates Generation""" - - def test_point_coordinates(self): - """should return a valid Point coordinates""" - test_data = gjtk.random.point_coordinates() - self.assertTrue( - gjtk.validate.is_point_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPointCoordinatesTest(unittest.TestCase): - - """Tests for Random MultiPoint Coordinates Generation""" - - def test_multi_point_coordinates(self): - """should return a valid MultiPoint coordinates""" - test_data = gjtk.random.multi_point_coordinates() - self.assertTrue( - gjtk.validate.is_multi_point_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class LineStringCoordinatesTest(unittest.TestCase): - - """Tests for Random LineString Coordinates Generation""" - - def test_line_string_coordinates(self): - """should return a valid LineString coordinates""" - test_data = gjtk.random.line_string_coordinates() - self.assertTrue( - gjtk.validate.is_line_string_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class LinearRingCoordinatesTest(unittest.TestCase): - - """Tests for Random LinearRing Coordinates Generation""" - - def test_linear_ring_coordinates(self): - """should return a valid LinearRing coordinates""" - test_data = gjtk.random.linear_ring_coordinates() - self.assertTrue( - gjtk.validate.is_linear_ring_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiLineStringCoordinatesTest(unittest.TestCase): - - """Tests for Random MultiLineString Coordinates Generation""" - - def test_multi_line_string_coordinates(self): # pylint: disable=invalid-name - """should return a valid MultiLineString coordinates""" - test_data = gjtk.random.multi_line_string_coordinates() - self.assertTrue( - gjtk.validate.is_multi_line_string_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class PolygonCoordinatesTest(unittest.TestCase): - - """Tests for Random Polygon Coordinates Generation""" - - def test_polygon_coordinates(self): - """should return a valid Polygon coordinates""" - test_data = gjtk.random.polygon_coordinates() - self.assertTrue( - gjtk.validate.is_polygon_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPolygonCoordinatesTest(unittest.TestCase): - - """Tests for Random MultiPolygon Coordinates Generation""" - - def test_multi_polygon_coordinates(self): - """should return a valid MultiPolygon coordinates""" - test_data = gjtk.random.multi_polygon_coordinates() - self.assertTrue( - gjtk.validate.is_multi_polygon_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class GeometryTest(unittest.TestCase): - - """Tests for Random Geometry Generation""" - - def test_geometry(self): - """should return a valid Geometry""" - test_data = gjtk.random.geometry() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - -class PointTest(unittest.TestCase): - - """Tests for Random Point Generation""" - - def test_point(self): - """should return a valid Point""" - test_data = gjtk.random.point() - self.assertTrue( - gjtk.validate.is_point(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPointTest(unittest.TestCase): - - """Tests for Random MultiPoint Generation""" - - def test_multi_point(self): - """should return a valid MultiPoint""" - test_data = gjtk.random.multi_point() - self.assertTrue( - gjtk.validate.is_multi_point(test_data), - gjtk.test.error_message(test_data), - ) - - -class LineStringTest(unittest.TestCase): - - """Tests for Random LineString Generation""" - - def test_line_string(self): - """should return a valid LineString""" - test_data = gjtk.random.line_string() - self.assertTrue( - gjtk.validate.is_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiLineStringTest(unittest.TestCase): - - """Tests for Random MultiLineString Generation""" - - def test_multi_line_string(self): - """should return a valid MultiLineString""" - test_data = gjtk.random.multi_line_string() - self.assertTrue( - gjtk.validate.is_multi_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - -class PolygonTest(unittest.TestCase): - - """Tests for Random Polygon Generation""" - - def test_polygon(self): - """should return a valid Polygon""" - test_data = gjtk.random.polygon() - self.assertTrue( - gjtk.validate.is_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPolygonTest(unittest.TestCase): - - """Tests for Random MultiPolygon Generation""" - - def test_multi_polygon(self): - """should return a valid MultiPolygon""" - test_data = gjtk.random.multi_polygon() - self.assertTrue( - gjtk.validate.is_multi_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - -class GeometryCollectionTest(unittest.TestCase): - - """Tests for Random GeometryCollection Generation""" - - def test_geometry_collection(self): - """should return a valid GeometryCollection""" - test_data = gjtk.random.geometry_collection() - self.assertTrue( - gjtk.validate.is_geometry_collection(test_data), - gjtk.test.error_message(test_data), - ) - - -class FeatureTest(unittest.TestCase): - - """Tests for Random Feature Generation""" - - def test_feature(self): - """should return a valid Feature""" - test_data = gjtk.random.feature() - self.assertTrue( - gjtk.validate.is_feature(test_data), - gjtk.test.error_message(test_data), - ) - - -class FeatureCollectionTest(unittest.TestCase): - - """Tests for Random FeatureCollection Generation""" - - def test_feature_collection(self): - """should return a valid FeatureCollection""" - test_data = gjtk.random.feature_collection() - self.assertTrue( - gjtk.validate.is_feature_collection(test_data), - gjtk.test.error_message(test_data), - ) - - -class CRSTest(unittest.TestCase): - - """Tests for Random CRS Generation""" - - def test_crs(self): - """should return a valid CRS""" - test_data = gjtk.random.crs() - self.assertTrue( - gjtk.validate.is_crs(test_data), - gjtk.test.error_message(test_data), - ) - - -class LinkTest(unittest.TestCase): - - """Tests for Random Link Generation""" - - def test_link(self): - """should return a valid Link""" - test_data = gjtk.random.link() - self.assertTrue( - gjtk.validate.is_link(test_data), - gjtk.test.error_message(test_data), - ) - - -class BBoxTest(unittest.TestCase): - - """Tests for Random BBox Generation""" - - def test_bbox(self): - """should return a valid Bbox""" - test_data = gjtk.random.bbox() - self.assertTrue( - gjtk.validate.is_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/gjtk/test/test_validate.py b/gjtk/test/test_validate.py index 741e098..961cec4 100644 --- a/gjtk/test/test_validate.py +++ b/gjtk/test/test_validate.py @@ -1,1073 +1,402 @@ -"""Tests for GeoJSON ToolKit Validation Utilities""" - -import random -import unittest - -import gjtk - - -class GeoJSONTest(unittest.TestCase): - - """Tests for GeoJSON Validation""" - - def test_geometry(self): - """should return true when provided a valid Geometry object""" - test_data = gjtk.random.geometry() - self.assertTrue( - gjtk.validate.is_geojson(test_data), - gjtk.test.error_message(test_data), - ) - - def test_feature(self): - """should return true when provided a valid Feature object""" - test_data = gjtk.random.feature() - self.assertTrue( - gjtk.validate.is_geojson(test_data), - gjtk.test.error_message(test_data), - ) - - def test_feature_collection(self): - """should return true when provided a valid Feature object""" - test_data = gjtk.random.feature_collection() - self.assertTrue( - gjtk.validate.is_geojson(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_geojson(test_data), - gjtk.test.error_message(test_data), - ) - - -class GeometryTest(unittest.TestCase): - - """Tests for Geometry Validation""" - - def test_point(self): - """should return true when provided a valid Point object""" - test_data = gjtk.random.point() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_multi_point(self): - """should return true when provided a valid MultiPoint object""" - test_data = gjtk.random.multi_point() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_line_string(self): - """should return true when provided a valid LineString object""" - test_data = gjtk.random.line_string() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_multi_line_string(self): - """should return true when provided a valid MultiLineString object""" - test_data = gjtk.random.multi_line_string() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_polygon(self): - """should return true when provided a valid Polygon object""" - test_data = gjtk.random.polygon() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_multi_polygon(self): - """should return true when provided a valid MultiPolygon object""" - test_data = gjtk.random.multi_polygon() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_geometry_collection(self): - """should return true when provided a valid GeometryCollection object""" - test_data = gjtk.random.geometry_collection() - self.assertTrue( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_geometry(test_data), - gjtk.test.error_message(test_data), - ) - - -class PositionTest(unittest.TestCase): - - """Tests for Position Validation""" - - def test_position(self): - """should return true when provided an array of at least 2 numbers""" - test_data = gjtk.random.position(max_numbers=6) - self.assertTrue( - gjtk.validate.is_position(test_data), - gjtk.test.error_message(test_data), - ) - - def test_too_short(self): - """should return false when provided an array of less than 2 numbers""" - test_data = [1] - self.assertFalse( - gjtk.validate.is_position(test_data), - gjtk.test.error_message(test_data), - ) - - def test_incorrect_type(self): - """should return false when provided an array of at least 2 non-numbers""" - test_data = ['foo', 'bar'] - self.assertFalse( - gjtk.validate.is_position(test_data), - gjtk.test.error_message(test_data), - ) - - def test_mixed_types(self): - """ - should return false when provided an array of a mix of at least 2 numbers and non-numbers - """ - test_data = [1, 'a'] - random.shuffle(test_data) - self.assertFalse( - gjtk.validate.is_position(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_position(test_data), - gjtk.test.error_message(test_data), - ) - - -class PointCoordinatesTest(unittest.TestCase): - - """Tests for Point Coordinates Validation""" - - def test_point_coordinates(self): - """should return true when provided valid GeoJSON Point coordinates""" - test_data = gjtk.random.point_coordinates() - self.assertTrue( - gjtk.validate.is_point_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_point_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPointCoordinatesTest(unittest.TestCase): - - """Tests for MultiPoint Coordinates Validation""" - - def test_multi_point_coordinates(self): - """should return true when provided valid GeoJSON MultiPoint coordinates""" - test_data = gjtk.random.multi_point_coordinates() - self.assertTrue( - gjtk.validate.is_multi_point_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_multi_point_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class LineStringCoordinatesTest(unittest.TestCase): - - """Tests for LineString Coordinates Validation""" - - def test_line_string_coordinates(self): - """should return true when provided valid GeoJSON LineString coordinates""" - test_data = gjtk.random.line_string_coordinates() - self.assertTrue( - gjtk.validate.is_line_string_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_line_string_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class LinearRingCoordinatesTest(unittest.TestCase): - - """Tests for LinearRing Coordinates Validation""" - - def test_linear_ring_coordinates(self): - """should return true when provided a valid GeoJSON LinearRing""" - test_data = gjtk.random.linear_ring_coordinates() - self.assertTrue( - gjtk.validate.is_linear_ring_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_linear_ring_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiLineStringCoordinatesTest(unittest.TestCase): - - """Tests for MultiLineString Coordinates Validation""" - - def test_multi_line_string_coordinates(self): # pylint: disable=invalid-name - """should return true when provided valid GeoJSON MultiLineString coordinates""" - test_data = gjtk.random.multi_line_string_coordinates() - self.assertTrue( - gjtk.validate.is_multi_line_string_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_multi_line_string_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class PolygonCoordinatesTest(unittest.TestCase): - - """Tests for Polygon Coordinates Validation""" - - def test_polygon_coordinates(self): - """should return true when provided valid GeoJSON Polygon coordinates""" - test_data = gjtk.random.polygon_coordinates() - self.assertTrue( - gjtk.validate.is_polygon_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_polygon_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPolygonCoordinatesTest(unittest.TestCase): - - """Tests for MultiPolygon Coordinates Validation""" - - def test_multi_polygon_coordinates(self): - """should return true when provided valid GeoJSON MultiPolygon coordinates""" - test_data = gjtk.random.multi_polygon_coordinates() - self.assertTrue( - gjtk.validate.is_multi_polygon_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_multi_polygon_coordinates(test_data), - gjtk.test.error_message(test_data), - ) - - -class PointTest(unittest.TestCase): - - """Tests for Point Validation""" - - def test_point(self): - """should return true when provided a valid Point object""" - test_data = gjtk.random.point() - self.assertTrue( - gjtk.validate.is_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a Point object without a type""" - test_data = gjtk.random.point() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_coordinates(self): - """should return false when provided a Point object without coordinates""" - test_data = gjtk.random.point() - del test_data['coordinates'] - self.assertFalse( - gjtk.validate.is_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_point(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPointTest(unittest.TestCase): - - """Tests for MultiPoint Validation""" - - def test_multi_point(self): - """should return true when provided a valid MultiPoint object""" - test_data = gjtk.random.multi_point() - self.assertTrue( - gjtk.validate.is_multi_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a MultiPoint object without a type""" - test_data = gjtk.random.multi_point() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_multi_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_coordinates(self): - """should return false when provided a MultiPoint object without coordinates""" - test_data = gjtk.random.multi_point() - del test_data['coordinates'] - self.assertFalse( - gjtk.validate.is_multi_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_multi_point(test_data), - gjtk.test.error_message(test_data), - ) - - -class LineStringTest(unittest.TestCase): - - """Tests for LineString Validation""" - - def test_line_string(self): - """should return true when provided a valid LineString object""" - test_data = gjtk.random.line_string() - self.assertTrue( - gjtk.validate.is_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a LineString object without a type""" - test_data = gjtk.random.line_string() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_coordinates(self): - """should return false when provided a LineString object without coordinates""" - test_data = gjtk.random.line_string() - del test_data['coordinates'] - self.assertFalse( - gjtk.validate.is_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiLineStringTest(unittest.TestCase): - - """Tests for MultiLineString Validation""" - - def test_multi_line_string(self): - """should return true when provided a valid MultiLineString object""" - test_data = gjtk.random.multi_line_string() - self.assertTrue( - gjtk.validate.is_multi_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a MultiLineString object without a type""" - test_data = gjtk.random.multi_line_string() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_multi_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_coordinates(self): - """should return false when provided a MultiLineString object without coordinates""" - test_data = gjtk.random.multi_line_string() - del test_data['coordinates'] - self.assertFalse( - gjtk.validate.is_multi_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_multi_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - -class PolygonTest(unittest.TestCase): - - """Tests for Polygon Validation""" - - def test_polygon(self): - """should return true when provided a valid Polygon object""" - test_data = gjtk.random.polygon() - self.assertTrue( - gjtk.validate.is_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a Polygon object without a type""" - test_data = gjtk.random.polygon() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_coordinates(self): - """should return false when provided a Polygon object without coordinates""" - test_data = gjtk.random.polygon() - del test_data['coordinates'] - self.assertFalse( - gjtk.validate.is_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - -class MultiPolygonTest(unittest.TestCase): - - """Tests for MultiPolygon Validation""" - - def test_multi_polygon(self): - """should return true when provided a valid MultiPolygon object""" - test_data = gjtk.random.multi_polygon() - self.assertTrue( - gjtk.validate.is_multi_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a MultiPolygon object without a type""" - test_data = gjtk.random.multi_polygon() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_multi_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_coordinates(self): - """should return false when provided a MultiPolygon object without coordinates""" - test_data = gjtk.random.multi_polygon() - del test_data['coordinates'] - self.assertFalse( - gjtk.validate.is_multi_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_multi_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - -class GeometryCollectionTest(unittest.TestCase): - - """Tests for GeometryCollection Validation""" - - def test_geometry_collection(self): - """should return true when provided a valid GeometryCollection object""" - test_data = gjtk.random.geometry_collection() - self.assertTrue( - gjtk.validate.is_geometry_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a GeometryCollection object without a type""" - test_data = gjtk.random.geometry_collection() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_geometry_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_geometries(self): - """should return false when provided a GeometryCollection object without geometries""" - test_data = gjtk.random.geometry_collection() - del test_data['geometries'] - self.assertFalse( - gjtk.validate.is_geometry_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_geometry_collection(test_data), - gjtk.test.error_message(test_data), - ) - - -class FeatureTest(unittest.TestCase): - - """Tests for Feature Validation""" - - def test_feature(self): - """should return true when provided a valid Feature object""" - test_data = gjtk.random.feature() - self.assertTrue( - gjtk.validate.is_feature(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a Feature object without a type""" - test_data = gjtk.random.feature() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_feature(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_geometry(self): - """should return false when provided a Feature object without geometry""" - test_data = gjtk.random.feature() - del test_data['geometry'] - self.assertFalse( - gjtk.validate.is_feature(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_feature(test_data), - gjtk.test.error_message(test_data), - ) - - -class FeatureCollectionTest(unittest.TestCase): - - """Tests for FeatureCollection Validation""" - - def test_feature_collection(self): - """should return true when provided a valid FeatureCollection object""" - test_data = gjtk.random.feature_collection() - self.assertTrue( - gjtk.validate.is_feature_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a FeatureCollection object without a type""" - test_data = gjtk.random.feature_collection() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_feature_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_features(self): - """should return false when provided a FeatureCollection object without features""" - test_data = gjtk.random.feature_collection() - del test_data['features'] - self.assertFalse( - gjtk.validate.is_feature_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_feature_collection(test_data), - gjtk.test.error_message(test_data), - ) - - -class CRSTest(unittest.TestCase): - - """Tests for CRS Validation""" - - def test_crs(self): - """should return true when provided a valid CRS object""" - test_data = gjtk.random.crs() - self.assertTrue( - gjtk.validate.is_crs(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return false when provided a CRS object without a type""" - test_data = gjtk.random.crs() - del test_data['type'] - self.assertFalse( - gjtk.validate.is_crs(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_properties(self): - """should return false when provided a CRS object without properties""" - test_data = gjtk.random.crs() - del test_data['properties'] - self.assertFalse( - gjtk.validate.is_crs(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_crs(test_data), - gjtk.test.error_message(test_data), - ) - - -class HasCRSTest(unittest.TestCase): - - """Tests for CRS Presence Validation""" - - def test_geometry_crs(self): - """should return true when provided a Geometry with a valid CRS""" - test_data = gjtk.random.geometry() - test_data['crs'] = gjtk.random.crs() - self.assertTrue( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_feature_crs(self): - """should return true when provided a Feature with a valid CRS""" - test_data = gjtk.random.feature() - test_data['crs'] = gjtk.random.crs() - self.assertTrue( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_feature_collection_crs(self): - """should return true when provided a FeatureCollection with a valid CRS""" - test_data = gjtk.random.feature_collection() - test_data['crs'] = gjtk.random.crs() - self.assertTrue( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.has_crs(test_data), - gjtk.test.error_message(test_data), - ) - - -class LinkTest(unittest.TestCase): - - """Tests for Link Validation""" - - def test_link(self): - """should return true when provided a valid Link object""" - test_data = gjtk.random.link() - self.assertTrue( - gjtk.validate.is_link(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_type(self): - """should return true when provided a Link object without a type""" - test_data = gjtk.random.link() - if 'type' in test_data: - del test_data['type'] - self.assertTrue( - gjtk.validate.is_link(test_data), - gjtk.test.error_message(test_data), - ) - - def test_no_href(self): - """should return false when provided a Link object without href""" - test_data = gjtk.random.link() - del test_data['href'] - self.assertFalse( - gjtk.validate.is_link(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_link(test_data), - gjtk.test.error_message(test_data), - ) - - -class BBoxTest(unittest.TestCase): - - """Tests for BBox Validation""" - - def test_bbox(self): - """should return true when provided a valid Bbox""" - test_data = gjtk.random.bbox() - self.assertTrue( - gjtk.validate.is_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - {}, - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.is_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - -class HasBboxTest(unittest.TestCase): - - """Tests for BBox Presence Validation""" - - def test_geometry_bbox(self): - """should return true when provided a Geometry with a valid Bbox""" - test_data = gjtk.random.geometry() - test_data['bbox'] = gjtk.random.bbox() - self.assertTrue( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_feature_bbox(self): - """should return true when provided a Feature with a valid Bbox""" - test_data = gjtk.random.feature() - test_data['bbox'] = gjtk.random.bbox() - self.assertTrue( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_feature_collection_bbox(self): - """should return true when provided a FeatureCollection with a valid Bbox""" - test_data = gjtk.random.feature_collection() - test_data['bbox'] = gjtk.random.bbox() - self.assertTrue( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - def test_invalid(self): - """should return false when provided an invalid object""" - test_data = random.choice([ - True, - 0, - '', - [], - random.choice, - None, - ]) - self.assertFalse( - gjtk.validate.has_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - -# COMPARISON - - -class EqualPositionsTest(unittest.TestCase): - - """Tests for Position Equality Validation""" - - def test_same(self): - """should return true when provided identical Positions""" - test_data = gjtk.random.position(max_numbers=6) - self.assertTrue( - gjtk.validate.equal_positions(test_data, test_data), - gjtk.test.error_message(test_data), - ) - - def test_diff(self): - """should return false when provided different Positions""" - test_data1 = gjtk.random.position(max_numbers=6) - test_data2 = gjtk.random.position(max_numbers=6) - while test_data1[0] == test_data2[0]: - gjtk.random.position(max_numbers=6) - self.assertFalse( - gjtk.validate.equal_positions(test_data1, test_data2), - gjtk.test.error_message([test_data1, test_data2]), - ) - - -class ContainedPolygonTest(unittest.TestCase): - - """Tests for Containg Polygon Validation""" - - def setUp(self): - self.inner = [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]] - self.outer = [[0, 0], [0, 5], [5, 5], [5, 0], [0, 0]] - - def test_contained(self): - """should return true when provided a LinearRing that contains another LinearRing.""" - self.assertTrue(gjtk.validate.contained_polygon(self.inner, self.outer)) - - def test_not_contained(self): - """ - should return false when provided a LinearRing that does not contain another LinearRing. - """ - self.assertFalse(gjtk.validate.contained_polygon(self.outer, self.inner)) - - -# pylint: disable=too-many-lines -if __name__ == "__main__": - unittest.main() +# coding: utf-8 + +"""Tests for gjtk.validate""" + +from __future__ import absolute_import + +import gjtk.validate + + +def test_is_geojson(geojson): + """should return true when provided a valid GeoJSON object""" + assert gjtk.validate.is_geojson(geojson) + + +def test_is_geojson_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_geojson(types) + + +def test_is_geometry(geometry): + """should return true when provided a valid Geometry object""" + assert gjtk.validate.is_geometry(geometry) + + +def test_is_geometry_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_geometry(types) + + +def test_is_position(position): + """should return true when provided an array of at least 2 numbers""" + assert gjtk.validate.is_position(position) + + +def test_is_position_invalid(invalid_position): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_position(invalid_position) + + +def test_is_point_coordinates(point_coordinates): + """should return true when provided valid GeoJSON Point coordinates""" + assert gjtk.validate.is_point_coordinates(point_coordinates) + + +def test_is_point_coordinates_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_point_coordinates(types) + + +def test_is_multi_point_coordinates(multi_point_coordinates): + """should return true when provided valid GeoJSON MultiPoint coordinates""" + assert gjtk.validate.is_multi_point_coordinates(multi_point_coordinates) + + +def test_is_multi_point_coordinates_invalid(immutable): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_multi_point_coordinates(immutable) + + +def test_is_line_string_coordinates(line_string_coordinates): + """should return true when provided valid GeoJSON LineString coordinates""" + assert gjtk.validate.is_line_string_coordinates(line_string_coordinates) + + +def test_is_line_string_coordinates_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_line_string_coordinates(types) + + +def test_is_linear_ring_coordinates(linear_ring_coordinates): + """should return true when provided a valid GeoJSON LinearRing""" + assert gjtk.validate.is_linear_ring_coordinates(linear_ring_coordinates) + + +def test_is_linear_ring_coordinates_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_linear_ring_coordinates(types) + + +def test_is_multi_line_string_coordinates(multi_line_string_coordinates): + """should return true when provided valid GeoJSON MultiLineString coordinates""" + assert gjtk.validate.is_multi_line_string_coordinates(multi_line_string_coordinates) + + +def test_is_multi_line_string_coordinates_invalid(immutable): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_multi_line_string_coordinates(immutable) + + +def test_is_polygon_coordinates(polygon_coordinates): + """should return true when provided valid GeoJSON Polygon coordinates""" + assert gjtk.validate.is_polygon_coordinates(polygon_coordinates) + + +def test_is_polygon_coordinates_invalid(immutable): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_polygon_coordinates(immutable) + + +def test_is_multi_polygon_coordinates(multi_polygon_coordinates): + """should return true when provided valid GeoJSON MultiPolygon coordinates""" + assert gjtk.validate.is_multi_polygon_coordinates(multi_polygon_coordinates) + + +def test_is_multi_polygon_coordinates_invalid(immutable): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_multi_polygon_coordinates(immutable) + + +def test_is_point(point): + """should return true when provided a valid Point object""" + assert gjtk.validate.is_point(point) + + +def test_is_point_no_type(point_without_type): + """should return false when provided a Point object without a type""" + assert not gjtk.validate.is_point(point_without_type) + + +def test_is_point_no_coordinates(point_without_coordinates): + """should return false when provided a Point object without coordinates""" + assert not gjtk.validate.is_point(point_without_coordinates) + + +def test_is_point_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_point(types) + + +def test_is_multi_point(multi_point): + """should return true when provided a valid MultiPoint object""" + assert gjtk.validate.is_multi_point(multi_point) + + +def test_is_multi_point_no_type(multi_point_without_type): + """should return false when provided a MultiPoint object without a type""" + assert not gjtk.validate.is_multi_point(multi_point_without_type) + + +def test_is_multi_point_no_coordinates(multi_point_without_coordinates): + """should return false when provided a MultiPoint object without coordinates""" + assert not gjtk.validate.is_multi_point(multi_point_without_coordinates) + + +def test_is_multi_point_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_multi_point(types) + + +def test_is_line_string(line_string): + """should return true when provided a valid LineString object""" + assert gjtk.validate.is_line_string(line_string) + + +def test_is_line_string_no_type(line_string_without_type): + """should return false when provided a LineString object without a type""" + assert not gjtk.validate.is_line_string(line_string_without_type) + + +def test_is_line_string_no_coordinates(line_string_without_coordinates): + """should return false when provided a LineString object without coordinates""" + assert not gjtk.validate.is_line_string(line_string_without_coordinates) + + +def test_is_line_string_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_line_string(types) + + +def test_is_multi_line_string(multi_line_string): + """should return true when provided a valid MultiLineString object""" + assert gjtk.validate.is_multi_line_string(multi_line_string) + + +def test_is_multi_line_string_no_type(multi_line_string_without_type): + """should return false when provided a MultiLineString object without a type""" + assert not gjtk.validate.is_multi_line_string(multi_line_string_without_type) + + +def test_is_multi_line_string_no_coordinates(multi_line_string_without_coordinates): + """should return false when provided a MultiLineString object without coordinates""" + assert not gjtk.validate.is_multi_line_string(multi_line_string_without_coordinates) + + +def test_is_multi_line_string_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_multi_line_string(types) + + +def test_is_polygon(polygon): + """should return true when provided a valid Polygon object""" + assert gjtk.validate.is_polygon(polygon) + + +def test_is_polygon_malformed(malformed_polygon): + """should return false when provided a malformed Polygon""" + assert not gjtk.validate.is_polygon(malformed_polygon) + + +def test_is_polygon_no_type(polygon_without_type): + """should return false when provided a Polygon object without a type""" + assert not gjtk.validate.is_polygon(polygon_without_type) + + +def test_is_polygon_no_coordinates(polygon_without_coordinates): + """should return false when provided a Polygon object without coordinates""" + assert not gjtk.validate.is_polygon(polygon_without_coordinates) + + +def test_is_polygon_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_polygon(types) + + +def test_is_multi_polygon(multi_polygon): + """should return true when provided a valid MultiPolygon object""" + assert gjtk.validate.is_multi_polygon(multi_polygon) + + +def test_is_multi_polygon_malformed(malformed_multi_polygon): + """should return false when provided a malformed MultiPolygon""" + assert not gjtk.validate.is_multi_polygon(malformed_multi_polygon) + + +def test_is_multi_polygon_no_type(multi_polygon_without_type): + """should return false when provided a MultiPolygon object without a type""" + assert not gjtk.validate.is_multi_polygon(multi_polygon_without_type) + + +def test_is_multi_polygon_no_coordinates(multi_polygon_without_coordinates): + """should return false when provided a MultiPolygon object without coordinates""" + assert not gjtk.validate.is_multi_polygon(multi_polygon_without_coordinates) + + +def test_is_multi_polygon_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_multi_polygon(types) + + +def test_is_geometry_collection(geometry_collection): + """should return true when provided a valid GeometryCollection object""" + assert gjtk.validate.is_geometry_collection(geometry_collection) + + +def test_is_geometry_collection_no_type(geometry_collection_without_type): + """should return false when provided a GeometryCollection object without a type""" + assert not gjtk.validate.is_geometry_collection(geometry_collection_without_type) + + +def test_is_geometry_collection_no_geometries(geometry_collection_without_geometries): + """should return false when provided a GeometryCollection object without geometries""" + assert not gjtk.validate.is_geometry_collection(geometry_collection_without_geometries) + + +def test_is_geometry_collection_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_geometry_collection(types) + + +def test_is_feature(feature): + """should return true when provided a valid Feature object""" + assert gjtk.validate.is_feature(feature) + + +def test_is_feature_no_type(feature_without_type): + """should return false when provided a Feature object without a type""" + assert not gjtk.validate.is_feature(feature_without_type) + + +def test_is_feature_no_geometry(feature_without_geometry): + """should return false when provided a Feature object without geometry""" + assert not gjtk.validate.is_feature(feature_without_geometry) + + +def test_is_feature_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_feature(types) + + +def test_is_feature_collection(feature_collection): + """should return true when provided a valid FeatureCollection object""" + assert gjtk.validate.is_feature_collection(feature_collection) + + +def test_is_feature_collection_no_type(feature_collection_without_type): + """should return false when provided a FeatureCollection object without a type""" + assert not gjtk.validate.is_feature_collection(feature_collection_without_type) + + +def test_is_feature_collection_no_features(feature_collection_without_features): + """should return false when provided a FeatureCollection object without features""" + assert not gjtk.validate.is_feature_collection(feature_collection_without_features) + + +def test_is_feature_collection_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_feature_collection(types) + + +def test_is_crs(crs): + """should return true when provided a valid CRS object""" + assert gjtk.validate.is_crs(crs) + + +def test_is_crs_no_type(crs_without_type): + """should return false when provided a CRS object without a type""" + assert not gjtk.validate.is_crs(crs_without_type) + + +def test_is_crs_no_properties(crs_without_properties): + """should return false when provided a CRS object without properties""" + assert not gjtk.validate.is_crs(crs_without_properties) + + +def test_is_crs_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_crs(types) + + +def test_has_crs_geometry(geometry_with_crs): + """should return true when provided a Geometry with a valid CRS""" + assert gjtk.validate.has_crs(geometry_with_crs) + + +def test_has_crs_feature(feature_with_crs): + """should return true when provided a Feature with a valid CRS""" + assert gjtk.validate.has_crs(feature_with_crs) + + +def test_has_crs_feature_collection(feature_collection_with_crs): + """should return true when provided a FeatureCollection with a valid CRS""" + assert gjtk.validate.has_crs(feature_collection_with_crs) + + +def test_has_crs_invalid(immutable): + """should return false when provided an invalid object""" + assert not gjtk.validate.has_crs(immutable) + + +def test_is_link(link): + """should return true when provided a valid Link object""" + assert gjtk.validate.is_link(link) + + +def test_is_link_no_type(link_without_type): + """should return true when provided a Link object without a type""" + assert gjtk.validate.is_link(link_without_type) + + +def test_is_link_no_href(link_without_href): + """should return false when provided a Link object without href""" + assert not gjtk.validate.is_link(link_without_href) + + +def test_is_link_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_link(types) + + +def test_is_bbox(bbox): + """should return true when provided a valid Bbox""" + assert gjtk.validate.is_bbox(bbox) + + +def test_is_bbox_invalid(types): + """should return false when provided an invalid object""" + assert not gjtk.validate.is_bbox(types) + + +def test_is_bbox_malformed(malformed_bbox): + """should return false when provided a malformed Bbox""" + assert not gjtk.validate.is_bbox(malformed_bbox) + + +def test_has_bbox_geometry(geometry_with_bbox): + """should return true when provided a Geometry with a valid Bbox""" + assert gjtk.validate.has_bbox(geometry_with_bbox) + + +def test_has_bbox_feature(feature_with_bbox): + """should return true when provided a Feature with a valid Bbox""" + assert gjtk.validate.has_bbox(feature_with_bbox) + + +def test_has_bbox_feature_collection(feature_collection_with_bbox): + """should return true when provided a FeatureCollection with a valid Bbox""" + assert gjtk.validate.has_bbox(feature_collection_with_bbox) + + +def test_has_bbox_invalid(immutable): + """should return false when provided an invalid object""" + assert not gjtk.validate.has_bbox(immutable) + + +def test_equal_positions(position): + """should return true when provided identical Positions""" + assert gjtk.validate.equal_positions(position, position) + + +def test_equal_positions_unequal(unequal_positions): + """should return false when provided different Positions""" + assert not gjtk.validate.equal_positions(unequal_positions[0], unequal_positions[1]) diff --git a/gjtk/test/test_validate_examples.py b/gjtk/test/test_validate_examples.py deleted file mode 100644 index 04f6063..0000000 --- a/gjtk/test/test_validate_examples.py +++ /dev/null @@ -1,262 +0,0 @@ -"""Tests for GeoJSON ToolKit Validation Utilities using Example Data""" - -import random -import unittest - -import gjtk - - -class ExampleTest(unittest.TestCase): - - """Tests for Validation using Example Data""" - - def test_is_point(self): - """should return true when provided an example Point""" - test_data = random.choice([ - {"type": "Point", "coordinates": [100.0, 0.0]}, - ]) - self.assertTrue( - gjtk.validate.is_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_multi_point(self): - """should return true when provided an example MultiPoint""" - test_data = random.choice([ - { - "type": "MultiPoint", - "coordinates": [[100.0, 0.0], [101.0, 1.0]], - }, - ]) - self.assertTrue( - gjtk.validate.is_multi_point(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_line_string(self): - """should return true when provided an example LineString""" - test_data = random.choice([ - { - "type": "LineString", - "coordinates": [[100.0, 0.0], [101.0, 1.0]], - }, - ]) - self.assertTrue( - gjtk.validate.is_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_multi_line_string(self): - """should return true when provided an example MultiLineString""" - test_data = random.choice([ - { - "type": "MultiLineString", - "coordinates": [ - [[100.0, 0.0], [101.0, 1.0]], - [[102.0, 2.0], [103.0, 3.0]], - ], - }, - ]) - self.assertTrue( - gjtk.validate.is_multi_line_string(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_polygon(self): - """should return true when provided an example Polygon""" - test_data = random.choice([ - { - "type": "Polygon", - "coordinates": [ - [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], - ], - }, - { - "type": "Polygon", - "coordinates": [ - [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], - [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]], - ], - }, - ]) - self.assertTrue( - gjtk.validate.is_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_multi_polygon(self): - """should return true when provided an example MultiPolygon""" - test_data = random.choice([ - { - "type": "MultiPolygon", - "coordinates": [ - [ - [[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]], - ], - [ - [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], - [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]], - ], - ], - }, - ]) - self.assertTrue( - gjtk.validate.is_multi_polygon(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_geometry_collection(self): - """should return true when provided an example GeometryCollection""" - test_data = random.choice([ - { - "type": "GeometryCollection", - "geometries": [ - { - "type": "Point", - "coordinates": [100.0, 0.0], - }, - { - "type": "LineString", - "coordinates": [[101.0, 0.0], [102.0, 1.0]], - }, - ], - }, - ]) - self.assertTrue( - gjtk.validate.is_geometry_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_feature(self): - """should return true when provided an example Feature""" - test_data = random.choice([ - { - "type": "Feature", - "geometry": { - "type": "Point", - "coordinates": [125.6, 10.1], - }, - "properties": { - "name": "Dinagat Islands", - }, - }, - ]) - self.assertTrue( - gjtk.validate.is_feature(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_feature_collection(self): - """should return true when provided an example FeatureCollection""" - test_data = random.choice([ - { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, - "properties": {"prop0": "value0"}, - }, - { - "type": "Feature", - "geometry": { - "type": "LineString", - "coordinates": [ - [102.0, 0.0], - [103.0, 1.0], - [104.0, 0.0], - [105.0, 1.0], - ], - }, - "properties": { - "prop0": "value0", - "prop1": 0.0, - }, - }, - { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [100.0, 0.0], - [101.0, 0.0], - [101.0, 1.0], - [100.0, 1.0], - [100.0, 0.0], - ], - ], - }, - "properties": { - "prop0": "value0", - "prop1": {"this": "that"}, - }, - }, - ], - } - ]) - self.assertTrue( - gjtk.validate.is_feature_collection(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_crs(self): - """should return true when provided an example CRS""" - test_data = random.choice([ - { - "type": "name", - "properties": { - "name": "urn:ogc:def:crs:OGC:1.3:CRS84", - }, - }, - { - "type": "link", - "properties": { - "href": "http://example.com/crs/42", - "type": "proj4", - }, - }, - { - "type": "link", - "properties": { - "href": "data.crs", - "type": "ogcwkt", - }, - }, - ]) - self.assertTrue( - gjtk.validate.is_crs(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_link(self): - """should return true when provided an example Link""" - test_data = random.choice([ - { - "href": "http://example.com/crs/42", - "type": "proj4", - }, - { - "href": "data.crs", - "type": "ogcwkt", - }, - ]) - self.assertTrue( - gjtk.validate.is_link(test_data), - gjtk.test.error_message(test_data), - ) - - def test_is_bbox(self): - """should return true when provided an example Bbox""" - test_data = random.choice([ - [-10.0, -10.0, 10.0, 10.0], - [100.0, 0.0, 105.0, 1.0], - ]) - self.assertTrue( - gjtk.validate.is_bbox(test_data), - gjtk.test.error_message(test_data), - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/gjtk/validate.py b/gjtk/validate.py index 6a03d5c..82c63d9 100644 --- a/gjtk/validate.py +++ b/gjtk/validate.py @@ -1,3 +1,5 @@ +# coding: utf-8 + """Validate GeoJSON objects.""" from __future__ import absolute_import @@ -88,7 +90,7 @@ def is_linear_ring_coordinates(anything): @boolean_fail -def is_multi_line_string_coordinates(anything): # pylint: disable=invalid-name +def is_multi_line_string_coordinates(anything): """ Validate the coordinates of a GeoJSON MultiLineString. """ return ( isinstance(anything, list) and diff --git a/setup.py b/setup.py index 58d718c..e29b066 100755 --- a/setup.py +++ b/setup.py @@ -19,14 +19,17 @@ description='GeoJSON ToolKit', long_description=README, author='David Tucker', - author_email='david.michael.tucker@gmail.com', + author_email='david@tucker.name', license='LGPLv2+', url='https://github.com/dmtucker/gjtk-py', - packages=find_packages(exclude=['contrib', 'docs', 'tests']), + packages=find_packages(), include_package_data=True, - test_suite="gjtk.test", - install_requires=['matplotlib'], - entry_points={'console_scripts': ['gjtk = gjtk.__main__:main']}, + install_requires=[ + 'decorator ~= 4.0', + 'matplotlib ~= 1.5', + 'pytest ~= 2.9', + ], + entry_points={'console_scripts': ['gjtk = gjtk.cli:main']}, keywords='GeoJSON', classifiers=[ 'License :: OSI Approved :: ' @@ -35,10 +38,9 @@ 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Topic :: Software Development :: Libraries', - 'Development Status :: 4 - Beta', + 'Development Status :: 5 - Production/Stable', ], ) diff --git a/tox.ini b/tox.ini index aef1308..0bdb2dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,3 +1,14 @@ +[tox] +envlist = py27 + py34 + py35 [testenv] -deps=pytest -commands=py.test +deps = coverage + pep8 + pylint + pytest +commands = coverage run --source=gjtk -m pytest + coverage report -m + gjtk --help + pep8 gjtk setup.py + pylint gjtk setup.py