Skip to content

Commit

Permalink
More tests and limit coverage report
Browse files Browse the repository at this point in the history
  • Loading branch information
zimeon committed Mar 4, 2017
1 parent e2fbeb0 commit 1047bdf
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .gitignore
@@ -1 +1,8 @@
.cache
.c
.coverage
*.egg
.eggs
build
__pycache__
htmlcov
7 changes: 5 additions & 2 deletions .travis.yml
Expand Up @@ -6,9 +6,12 @@ python:
- "3.4"
- "3.5"
install:
- pip install -r requirements.txt
- python setup.py install
- pip install coveralls
script:
- py.test
- python setup.py test
- coverage run --omit=tests/*,setup.py,*.egg --include=iiif-presentation-validator.py setup.py test
- coveralls
before_deploy:
- mkdir build; zip -q -r build/presentation-validator.zip .
deploy:
Expand Down
34 changes: 34 additions & 0 deletions fixtures/1/manifest.json
@@ -0,0 +1,34 @@
{
"@context": "http://iiif.io/api/presentation/2/context.json",
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/1/manifest.json",
"@type": "sc:Manifest",
"label": "Test 1 Manifest: Minimum Required Fields",
"within": "http://iiif.io/api/presentation/2.0/example/fixtures/collection.json",
"sequences": [
{
"@type": "sc:Sequence",
"canvases": [
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/canvas/1/c1.json",
"@type": "sc:Canvas",
"label": "Test 1 Canvas: 1",
"height": 1800,
"width": 1200,
"images": [
{
"@type": "oa:Annotation",
"motivation": "sc:painting",
"resource": {
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/resources/page1-full.png",
"@type": "dctypes:Image",
"height": 1800,
"width": 1200
},
"on": "http://iiif.io/api/presentation/2.0/example/fixtures/canvas/1/c1.json"
}
]
}
]
}
]
}
41 changes: 41 additions & 0 deletions fixtures/2/manifest.json
@@ -0,0 +1,41 @@
{
"@context": "http://iiif.io/api/presentation/2/context.json",
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/2/manifest.json",
"@type": "sc:Manifest",
"label": "Test 2 Manifest: Metadata Pairs",
"metadata": [
{
"label": "date",
"value": "some date"
}
],
"within": "http://iiif.io/api/presentation/2.0/example/fixtures/collection.json",
"sequences": [
{
"@type": "sc:Sequence",
"label": "Test 2 Sequence 1",
"canvases": [
{
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/canvas/2/c1.json",
"@type": "sc:Canvas",
"label": "Test 2 Canvas: 1",
"height": 1800,
"width": 1200,
"images": [
{
"@type": "oa:Annotation",
"motivation": "sc:painting",
"resource": {
"@id": "http://iiif.io/api/presentation/2.0/example/fixtures/resources/page1-full.png",
"@type": "dctypes:Image",
"height": 1800,
"width": 1200
},
"on": "http://iiif.io/api/presentation/2.0/example/fixtures/canvas/2/c1.json"
}
]
}
]
}
]
}
3 changes: 3 additions & 0 deletions fixtures/README.md
@@ -0,0 +1,3 @@
# Test Fixtures

These fixtures are taken from the the Presentation API specifications under <http://iiif.io/api/presentation/2.0/example/fixtures> or <https://github.com/IIIF/iiif.io/tree/master/source/api/presentation/2.1/example/fixtures>.
3 changes: 2 additions & 1 deletion iiif-presentation-validator.py
Expand Up @@ -51,8 +51,9 @@ def check_manifest(self, data, version, warnings=[]):
mf.toJSON()
# Passed!
okay = 1
except Exception as err:
except Exception as e:
# Failed
err = e
okay = 0

warnings.extend(reader.get_warnings())
Expand Down
2 changes: 0 additions & 2 deletions requirements.txt

This file was deleted.

59 changes: 59 additions & 0 deletions setup.py
@@ -0,0 +1,59 @@
"""Setup for iiif/presentation-validator"""
from setuptools import setup, Command
import os
import re

class Coverage(Command):
"""Class to allow coverage run from setup."""

description = "run coverage"
user_options = []

def initialize_options(self):
"""Empty initialize_options."""
pass

def finalize_options(self):
"""Empty finalize_options."""
pass

def run(self):
"""Run coverage program."""
os.system("coverage run --omit=tests/*,setup.py setup.py test")
os.system("coverage report")
os.system("coverage html")
print("See htmlcov/index.html for details.")

setup(
name='iiif',
version='0.0.2',
scripts=['iiif-presentation-validator.py'],
classifiers=["Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
"Topic :: Software Development :: "
"Libraries :: Python Modules",
"Environment :: Web Environment"],
url='https://github.com/IIIF/presentation-validator',
description='Validator for the IIIF Presentation API',
long_description=open('README.md').read(),
install_requires=[
'bottle>=0.12.9',
'iiif_prezi>=0.2.2'
],
test_suite="tests",
tests_require=[
"coverage",
"mock",
],
cmdclass={
'coverage': Coverage,
},
)
83 changes: 81 additions & 2 deletions tests/test_validator.py
@@ -1,19 +1,98 @@
"""Test code for iiif-presentation-validator.py."""
import unittest
from mock import Mock
import imp
from bottle import Response
from bottle import Response, request
try:
# python3
from urllib.request import URLError
except ImportError:
# fall back to python2
from urllib2 import URLError
import json

# The validator isn't a module but with a little magic
# we can load it up as if it were in order to access
# the classes within
fh = open('iiif-presentation-validator.py', 'r')
try:
val_mod = imp.load_module('ipv', fh, '.', ('py','r',imp.PY_SOURCE))
val_mod = imp.load_module('ipv', fh, 'iiif-presentation-validator.py',
('py','r',imp.PY_SOURCE))
finally:
fh.close()


def read_fixture(fixture):
with open(fixture, 'r') as fh:
data = fh.read()
return(data)


class MockWSGI(object):

def __init__(self, fixture):
self.fixture = fixture

def read(self, clen):
return read_fixture(self.fixture)

class MockWebHandle(object):

def __init__(self):
self.headers={}


class TestAll(unittest.TestCase):

def test01_get_bottle_app(self):
v = val_mod.Validator()
self.assertTrue(v.get_bottle_app())

def test02_fetch(self):
v = val_mod.Validator()
(data, wh) = v.fetch('file:fixtures/1/manifest.json')
self.assertTrue(data.startswith('{'))
self.assertRaises(URLError, v.fetch, 'file:DOES_NOT_EXIST')

def test03_check_manifest(self):
v = val_mod.Validator()
# good manifests
for good in ('fixtures/1/manifest.json',
'fixtures/2/manifest.json'):
with open(good, 'r') as fh:
data = fh.read()
j = json.loads(v.check_manifest(data, '2.1'))
self.assertEqual(j['okay'], 1)
# bad manifests
for bad_data in ('', '{}'):
j = json.loads(v.check_manifest(bad_data, '2.1'))
self.assertEqual(j['okay'], 0)

def test04_do_POST_test(self):
v = val_mod.Validator()
# FIXME - nasty hack to mock data for bottle.request
m = MockWSGI('fixtures/1/manifest.json')
request.body = m
request.environ['wsgi.input'] = m.read
j = json.loads(v.do_POST_test())
self.assertEqual(j['okay'], 1)

def test05_do_GET_test(self):
# FIXME - hack to mock data for bottle.request
v = val_mod.Validator()
request.environ['QUERY_STRING'] = 'url=http://example.org/a'
v.fetch = Mock(return_value=(read_fixture('fixtures/1/manifest.json'),MockWebHandle()))
j = json.loads(v.do_GET_test())
self.assertEqual(j['okay'], 1)
# bogus URL
v = val_mod.Validator()
request.environ['QUERY_STRING'] = 'url=not_http://a.b.c/'
v.fetch = Mock(return_value=('',MockWebHandle()))
j = json.loads(v.do_GET_test())
self.assertEqual(j['okay'], 0)
# bogus URL but not caught
v = val_mod.Validator()
request.environ['QUERY_STRING'] = 'url=httpX://a.b/'
v.fetch = Mock(return_value=(read_fixture('fixtures/1/manifest.json'),MockWebHandle()))
j = json.loads(v.do_GET_test())
self.assertEqual(j['okay'], 1) #FIXME!

0 comments on commit 1047bdf

Please sign in to comment.