Tidy and flesh out tests

This commit is contained in:
Simeon Warner 2020-12-24 11:07:55 -05:00
parent 065363e462
commit 518fd94e5c
2 changed files with 86 additions and 67 deletions

View File

@ -14,6 +14,22 @@ import collections.abc
from .w3c_datetime import datetime_to_str from .w3c_datetime import datetime_to_str
def _str_datetime_now(x='now'):
"""Return datetime string for use with time attributes.
Handling depends on input:
'now' - returns datetime for now
other string - no change, return same value
otherwise - assume datetime value, generate string
"""
if (x == 'now' or not isinstance(x, str)):
# Now, this is wht datetime_to_str() with no arg gives
return datetime_to_str(x)
else:
# Assume valid datetime string
return x
class ResourceContainer(object): class ResourceContainer(object):
"""Class containing resource-like objects. """Class containing resource-like objects.
@ -26,6 +42,11 @@ class ResourceContainer(object):
- uri is optional identifier of this container object - uri is optional identifier of this container object
- capability_name - name of this capability - capability_name - name of this capability
The properties md_from, md_at, md_until and md_completed are datetime
strings. The setters acceopt either a string value (not checked), the value
'now' to generate the current datetime, or otherwise an integer timestamp
value that is converted to a string.
Derived classes may add extra functionality such as len() etc.. Derived classes may add extra functionality such as len() etc..
However, any code designed to work with any ResourceContainer However, any code designed to work with any ResourceContainer
should use only the core functionality. should use only the core functionality.
@ -45,19 +66,16 @@ class ResourceContainer(object):
Baseline implementation use iterator given by resources property. Baseline implementation use iterator given by resources property.
""" """
return(iter(self.resources)) return iter(self.resources)
def __getitem__(self, index): def __getitem__(self, index):
"""Feed through for __getitem__ of resources property.""" """Feed through for __getitem__ of resources property."""
return(self.resources[index]) return self.resources[index]
@property @property
def capability(self): def capability(self):
"""Get/set the <rs:md capability="" .../> attribute.""" """Get/set the <rs:md capability="" .../> attribute, None if not set."""
if ('capability' in self.md): return self.md.get('capability')
return(self.md['capability'])
else:
return(None)
@capability.setter @capability.setter
def capability(self, capability): def capability(self, capability):
@ -65,65 +83,53 @@ class ResourceContainer(object):
@property @property
def md_from(self): def md_from(self):
"""Get/set the <rs:md from="" .../> attribute.""" """Get/set the <rs:md from="" .../> attribute, None if not set."""
if ('md_from' in self.md): return self.md.get('md_from')
return(self.md['md_from'])
else:
return(None)
@md_from.setter @md_from.setter
def md_from(self, md_from): def md_from(self, md_from):
self.md['md_from'] = self._str_datetime_now(md_from) self.md['md_from'] = _str_datetime_now(md_from)
@property @property
def md_until(self): def md_until(self):
"""Get/set the <rs:md until="" .../> attribute.""" """Get/set the <rs:md until="" .../> attribute, None if not set."""
if ('md_until' in self.md): return self.md.get('md_until')
return(self.md['md_until'])
else:
return(None)
@md_until.setter @md_until.setter
def md_until(self, md_until): def md_until(self, md_until):
self.md['md_until'] = self._str_datetime_now(md_until) self.md['md_until'] = _str_datetime_now(md_until)
@property @property
def md_at(self): def md_at(self):
"""Get/set the <rs:md at="" attribute.""" """Get/set the <rs:md at="" attribute."""
if ('md_at' in self.md): return self.md.get('md_at')
return(self.md['md_at'])
else:
return(None)
@md_at.setter @md_at.setter
def md_at(self, md_at): def md_at(self, md_at):
self.md['md_at'] = self._str_datetime_now(md_at) self.md['md_at'] = _str_datetime_now(md_at)
@property @property
def md_completed(self): def md_completed(self):
"""Get/set the <rs:md completed="" .../> attribute.""" """Get/set the <rs:md completed="" .../> attribute, None if not set."""
if ('md_completed' in self.md): return self.md.get('md_completed')
return(self.md['md_completed'])
else:
return(None)
@md_completed.setter @md_completed.setter
def md_completed(self, md_completed): def md_completed(self, md_completed):
self.md['md_completed'] = self._str_datetime_now(md_completed) self.md['md_completed'] = _str_datetime_now(md_completed)
def link(self, rel): def link(self, rel):
"""Look for link with specified rel, return else None.""" """Look for link with specified rel, return else None."""
for link in self.ln: for link in self.ln:
if ('rel' in link and link['rel'] == rel): if ('rel' in link and link['rel'] == rel):
return(link) return link
return(None) return None
def link_href(self, rel): def link_href(self, rel):
"""Look for link with specified rel, return href from it or None.""" """Look for link with specified rel, return href from it or None."""
link = self.link(rel) link = self.link(rel)
if (link is not None): if (link is not None):
link = link['href'] link = link['href']
return(link) return link
def link_set(self, rel, href, **atts): def link_set(self, rel, href, **atts):
"""Set/create link with specified rel, set href and any other attributes. """Set/create link with specified rel, set href and any other attributes.
@ -132,16 +138,16 @@ class ResourceContainer(object):
also defines the type attributes and others are permitted also. See also defines the type attributes and others are permitted also. See
description of allowed formats in description of allowed formats in
http://www.openarchives.org/rs/resourcesync.html#DocumentFormats http://www.openarchives.org/rs/resourcesync#DocumentFormats
""" """
link = self.link(rel) link = self.link(rel)
if (link is not None): if link is None:
# overwrite current value
link['href'] = href
else:
# create new link # create new link
link = {'rel': rel, 'href': href} link = {'rel': rel, 'href': href}
self.ln.append(link) self.ln.append(link)
else:
# overwrite current value
link['href'] = href
for k in atts: for k in atts:
link[k] = atts[k] link[k] = atts[k]
@ -232,29 +238,3 @@ class ResourceContainer(object):
pruned2.append(r) pruned2.append(r)
self.resources = pruned2 self.resources = pruned2
return(n) return(n)
def __str__(self):
"""Return string of all resources in order given by interator."""
s = ''
for resource in self:
s += str(resource) + "\n"
return(s)
def _str_datetime_now(self, x=None):
"""Return datetime string for use with time attributes.
Handling depends on input:
'now' - returns datetime for now
number - assume datetime values, generate string
other - no change, return same value
"""
if (x == 'now'):
# Now, this is wht datetime_to_str() with no arg gives
return(datetime_to_str())
try:
# Test for number
junk = x + 0.0
return datetime_to_str(x)
except TypeError:
# Didn't look like a number, treat as string
return x

View File

@ -1,6 +1,8 @@
"""Tests for resync.resource_container."""
import unittest import unittest
from resync.resource import Resource from resync.resource import Resource
from resync.resource_container import ResourceContainer from resync.resource_container import ResourceContainer, _str_datetime_now
class TestResourceContainer(unittest.TestCase): class TestResourceContainer(unittest.TestCase):
@ -8,9 +10,12 @@ class TestResourceContainer(unittest.TestCase):
def test01_create_and_add(self): def test01_create_and_add(self):
rc = ResourceContainer(resources=[]) rc = ResourceContainer(resources=[])
self.assertEqual(len(rc.resources), 0, "empty") self.assertEqual(len(rc.resources), 0, "empty")
rc.resources.append(Resource('a', timestamp=1)) rc.add(Resource('a', timestamp=1))
rc.resources.append(Resource('b', timestamp=2)) rc.add(Resource('b', timestamp=2))
self.assertEqual(len(rc.resources), 2, "two resources") self.assertEqual(len(rc.resources), 2, "two resources")
# Add two more
rc.add([Resource('c'), Resource('d')])
self.assertEqual(len(rc.resources), 4, "four resources")
def test02_iter(self): def test02_iter(self):
rc = ResourceContainer(resources=[]) rc = ResourceContainer(resources=[])
@ -93,3 +98,37 @@ class TestResourceContainer(unittest.TestCase):
self.assertEqual(rc.up, None) self.assertEqual(rc.up, None)
rc.up = "up_uri" rc.up = "up_uri"
self.assertEqual(rc.up, "up_uri") self.assertEqual(rc.up, "up_uri")
def test09_capability(self):
"""Test capability property."""
rc = ResourceContainer()
self.assertEqual(rc.capability, None)
rc.capability = "fixit"
self.assertEqual(rc.capability, 'fixit')
def test10_link_set(self):
"""Test link_set method."""
rc = ResourceContainer()
self.assertEqual(rc.link('alink'), None) # non-spec rel should be supported
rc.link_set('alink', 'uri:l', extra1='one', extra2='two')
ln = rc.link('alink')
self.assertEqual(rc.link('alink'), {'rel': 'alink', 'href': 'uri:l',
'extra1': 'one', 'extra2': 'two'})
# Can update existing link
rc.link_set('alink', 'uri:new', extra1='1')
self.assertEqual(rc.link('alink'), {'rel': 'alink', 'href': 'uri:new',
'extra1': '1', 'extra2': 'two'})
def test11_index(self):
"""Test index property."""
rc = ResourceContainer()
self.assertEqual(rc.index, None)
rc.index = 'uri:i'
self.assertEqual(rc.index, 'uri:i')
def test12_str_datetime_now(self):
"""Test _str_datetime_now function."""
self.assertTrue(isinstance(_str_datetime_now(), str))
self.assertTrue(isinstance(_str_datetime_now('now'), str))
self.assertEqual(_str_datetime_now(0), '1970-01-01T00:00:00Z')
self.assertEqual(_str_datetime_now('2020-12-24T16:01:00Z'), '2020-12-24T16:01:00Z')