"""ExTests for :py:class:`extools.view.ExView`."""
from unittest import mock
import random
from extools.view import (exview, ExView)
from extools.view.errors import (ExViewError, ExViewOpenError)
from extools.test import ExTestCase
try:
from accpac import *
except ImportError:
pass
ORDER_HEADER_VIEWID = "OE0520"
ORDER_DETAIL_VIEWID = "OE0500"
ORDER_OPTFIELD_VIEWID = "OE0522"
DEFAULT_ORDNUMBER = "ORD000000000001"
ORDNUMBER_1 = "ORD000000000001"
ORDNUMBER_2 = "ORD000000000002"
AR_CUSTOMER_VIEWID = "AR0024"
AR_CUSTOMER_COUNT = 27
AR_CUSTOMER_FIRST = "1100"
AR_CUSTOMER_LAST = "WEBCUST"
[docs]def main(*args, **kwargs):
"""This main hook is picked up by ExTestRunner for automatic execution."""
# ExViewCMTestCase, ExViewExceptionsTestCase,
for klass in [ExViewCMTestCase,
ExViewInternalsTestCase,
ExViewExceptionsTestCase,
ExViewViewCacheTestCase,
ExViewProxyMethodsTestCase, ]:
ext = klass()
ext.run()
[docs]class ExViewCMTestCase(ExTestCase):
"""Test the :py:class:`extools.view.exview` context manager."""
[docs] def test_exview_contextmanager(self):
"""Verify that the :py:meth:`extools.view.exview` context manager
is working:
- Opens and seeks to the first record by default.
- Opens and seeks to the provided criteria.
- Raises on an invalid view id.
"""
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
self.assert_equal(exv.get("ORDNUMBER"), DEFAULT_ORDNUMBER)
with exview(ORDER_HEADER_VIEWID, self.index,
seek_to={"ORDNUMBER": ORDNUMBER_2}) as exv:
self.assert_equal(exv.get("ORDNUMBER"), ORDNUMBER_2)
""" TODO: check ViewID is valid before opening. Currently crashes Sage
with self.assert_raises(ExViewOpenError):
with exview("BADID") as exv:
self.exm.info("In exview.")
pass
"""
[docs]class ExViewExceptionsTestCase(ExTestCase):
"""Verify :py:class:`extools.view.ExView` raises on non-zero returns."""
[docs] def setup_class(self):
"""Dynamically generate the tests for wrapped methods."""
self.generate_raise_tests()
def _mock_bad_return(self):
"""Any non-zero return is a failure, try random ones."""
return random.randint(1, 4096)
[docs] def generate_raise_tests(self):
"""Generate mocked raise tests for all wrapped methods.
Dynamically create a test for each method in
:py:data:`extools.view.ExView.WRAP`. This should be run during the
``.setup_class()`` hook so that the tests are defined before ``.run()``
is called.
"""
for method in ExView.WRAP:
self._generate_raise_test_for(method)
self._generate_no_raise_test_for(method)
def _generate_no_raise_test_for(self, method):
def test_doesnt_raise():
"""Verify that wrapped methods do not raise on 0 returns.
This test is to make sure that the wrapping of this function is
working properly. The ``accpac.View`` is mocked out and always
returns a zero.
"""
with mock.patch("accpac.View") as MockView:
instance = MockView.return_value
_method = getattr(instance, method)
_method.return_value = 0
exv = ExView(ORDER_HEADER_VIEWID, self.index)
exv._view = MockView()
getattr(exv, method)()
setattr(self, "test_{}_doesnt_raise".format(method), test_doesnt_raise)
def _generate_raise_test_for(self, method):
def test_raises():
"""Verify that wrapped methods raise on non-zero returns.
This test is to make sure that the wrapping of this function is
working properly. The ``accpac.View`` is mocked out and always
returns a non-zero value.
"""
with mock.patch("accpac.View") as MockView:
instance = MockView.return_value
_method = getattr(instance, method)
_method.return_value = self._mock_bad_return()
exv = ExView(ORDER_HEADER_VIEWID, self.index)
exv._view = MockView()
with self.assert_raises(ExViewError):
getattr(exv, method)()
setattr(self, "test_{}_raises".format(method), test_raises)
[docs]class ExViewInternalsTestCase(ExTestCase):
"""Verify :py:class:`extools.view.ExView` internals are working."""
[docs] def setup(self):
"""Clear the class internals before each test."""
ExView._view_cache = {}
[docs] def test_index_detection(self):
"""Verify indexes are identified through introspection on init."""
indexes = [['ORDUNIQ', ],
['ORDNUMBER', ],
['CUSTOMER', ],
['TYPE', 'COMPLETE', 'ORDUNIQ', ],
['CUSTOMER', 'ORDNUMBER', ],
['REFERENCE', 'ORDNUMBER', ],
['CUSTOMER', 'PONUMBER', ],
['CUSTOMER', 'ONHOLD', 'TYPE', ],
['COMPANYID', 'OPPOID', ], ]
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
# Check that we have the right number of indexes
self.assert_equal(len(exv.indexes), len(indexes))
# And then that they're the right one.
for index in indexes:
self.assert_true(index in exv.indexes)
[docs] def test_detail_view_detection(self):
"""Verify that detail views are detected and helpers added."""
detail_attribs = ['lines', 'lines_from', 'lines_where', ]
# Make sure the header is not identified as a detail view
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
self.assert_true(not exv.detail_view)
# The detail view should be set after the compose completes
exv.compose()
self.assert_true(exv.detail_view)
# And it shouldn't point to self.
self.assert_true(exv.detail_view != exv)
# For each of the dynamic methods, check that the're defined
for attrib in detail_attribs:
self.assert_true(hasattr(exv, attrib))
self.assert_true(hasattr(exv.detail_view, attrib))
# But the Order Detail view is identified as one
with exview(ORDER_DETAIL_VIEWID, self.index) as exv:
self.assert_true(exv.detail_view)
self.assert_true(exv.detail_view == exv)
return True
[docs] def test_intial_optfield_view_detection(self):
"""Verify that optfield views are detected and helpers added."""
# Make sure the header is not identified as an optional field view
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
self.assert_true(not exv.optfield_view)
# But the Order optional field view is identified as one
with exview(ORDER_OPTFIELD_VIEWID, self.index) as exv:
self.assert_true(exv.optfield_view)
self.assert_true(exv.optfield_view == exv)
[docs] def test_compose_optfield_view_detection(self):
"""Verify that optfield views are detected and helpers added."""
optfield_attribs = ['create_optfield',
'has_optfield',
'all_optfields',
'update_optfield',
'update_or_create_optfield',
'delete_optfield', ]
# Check that on compose, the optfield_view and helpers are correct.
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
# The optfield view should be set after the compose completes
exv.compose()
self.assert_true(exv.optfield_view)
# And it shouldn't point to self.
self.assert_true(exv.optfield_view != exv)
# For each of the dynamic methods, check that the're defined
for attrib in optfield_attribs:
self.assert_true(hasattr(exv, attrib))
self.assert_true(hasattr(exv.optfield_view, attrib))
return True
[docs] def test_composed_view_list(self):
"""Verify that the list of composed views is determined correctly."""
view_list = ['OE0500', None, 'OE0180', 'OE0740', 'OE0526', 'OE0522', ]
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
# Check that we have the right number of views.
self.assert_equal(len(exv._views), len(view_list))
# And then that they're the right ones.
for view in [v if v else None for v in view_list]:
self.assert_true(view in exv._views)
[docs] def test_field_names(self):
"""Verify that the list of fiel names is determined correctly."""
order_header_field_count = 406
order_header_first_field = "ORDUNIQ"
order_header_last_field = "PMTTYPEID"
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
# field names shoud be populated on introspection
self.assert_equal(len(exv.field_names), order_header_field_count)
self.assert_equal(exv.field_names[0], order_header_first_field)
self.assert_equal(exv.field_names[-1], order_header_last_field)
[docs] def test_view_cache(self):
"""Verify that the view cache is populated correctly."""
compose_tree = ["OE0520",
"OE0500",
"OE0740",
"OE0180",
"OE0526",
"OE0522",
"OE0508",
"OE0507",
"OE0501",
"OE0502",
"OE0504",
"OE0506",
"OE0503", ]
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
# After starting up self should be in the cache.
self.assert_equal(list(exv._view_cache.keys()),
[ORDER_HEADER_VIEWID, ])
# On compose, the full tree should be in cache.
exv.compose()
self.assert_equal(len(exv._view_cache.keys()), len(compose_tree))
for (viewid, view) in exv._view_cache.items():
# It is one of the ones we expect...
self.assert_true(viewid in compose_tree)
# And is actually a view with the correct view id
self.assert_true(isinstance(view, ExView))
self.assert_equal(view.rotoid, viewid)
return True
[docs] def test_detail_view_wrapper(self):
"""Verify that the detail view wrappers work as expected."""
detail_lines = 4
items = ["A1-103/0", "A1-105/0" ,"A1-400/0" , "A1-450/0", ]
with exview(ORDER_HEADER_VIEWID, self.index,
seek_to={'ORDNUMBER': DEFAULT_ORDNUMBER}) as exv:
exv.compose()
self.assert_equal([l.get("ITEM") for l in exv.lines()], items)
exv.oe0500.seek_to()
self.assert_equal([l.get("ITEM") for l in exv.lines_from(1,2)],
items[1:3])
exv.oe0500.seek_to()
self.assert_equal([l.get("ITEM") for l in exv.lines_where(
ITEM=items[-1])
],
items[-1:])
[docs] def test_optfield_view_wrapper(self):
"""Verify that the optfield view wrappers work as expected."""
optional_field = "CREDTWARNING"
optional_field_value = "0"
optional_field_update_value = "1"
optional_field_count = 13
bad_optional_field = "IDONTEXIST"
# Open the order headers view.
with exview(ORDER_HEADER_VIEWID, index=self.index,
seek_to={'ORDNUMBER': DEFAULT_ORDNUMBER}) as exv:
exv.compose()
# Get all optional fields, check count and presence
optfields = [o.get("OPTFIELD") for o in exv.all_optfields()]
self.assert_equal(len(optfields), optional_field_count)
self.assert_true(optional_field in optfields)
self.exm.debug("has {}? {}".format(
optional_field, exv.has_optfield(optional_field)))
# Does it have optional field? Yes
self.assert_true(exv.has_optfield(optional_field))
self.assert_equal(exv.get_optfield(optional_field).strip(),
optional_field_value)
# Does it have bad optional field? No - Crashes Sage
""" TODO: filter optfields before call.
self.assert_true(not exv.has_optfield(bad_optional_field))
"""
self.exm.debug("Deleting {}".format(optional_field))
# Delete good optional field
exv.delete_optfield(optional_field)
# Delete bad optional field - raises
# Create bad optional field with value "CREATE" - raises
""" TODO: filter optfields before call.
with self.assert_raises(ExViewError):
exv.delete_optfield(optional_field)
with self.assert_raises(ExViewError):
exv.create_optfield(bad_optional_field, "CREATE")
"""
# Create optional field with value "No"
exv.create_optfield(optional_field, optional_field_value)
self.assert_equal(exv.get_optfield(optional_field).strip(),
optional_field_value)
# Update optional field with value "Yes"
exv.update_optfield(optional_field, optional_field_update_value)
self.assert_equal(exv.get_optfield(optional_field).strip(),
optional_field_update_value)
# Delete optional field
exv.delete_optfield(optional_field)
self.assert_true(not exv.has_optfield(optional_field))
# Create or update optional field with value "Yes"
exv.update_or_create_optfield(optional_field,
optional_field_update_value)
self.assert_equal(exv.get_optfield(optional_field).strip(),
optional_field_update_value)
# Create or update optional field with value "No"
exv.update_or_create_optfield(optional_field,
optional_field_value)
self.assert_equal(exv.get_optfield(optional_field).strip(),
optional_field_value)
[docs]class ExViewViewCacheTestCase(ExTestCase):
"""Verify :py:class:`extools.view.ExView` view cache is working."""
[docs] def setup(self):
"""Clear the class internals before each test."""
ExView._view_cache = {}
[docs] def test__view_cache(self):
"""Verify that _view_cache returns the cache namespace."""
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
v, c = exv.cached_view(ORDER_HEADER_VIEWID)
self.assert_true(not c)
self.assert_true(v)
ns = exv._view_cache
self.assert_true(len(ns) == 1)
self.assert_true(ORDER_HEADER_VIEWID in ns.keys())
[docs] def test_cached_view(self):
"""Verify that cached_view returns views in the cache namespace."""
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
v, c = exv.cached_view(ORDER_HEADER_VIEWID)
self.assert_true(not c)
self.assert_true(v)
[docs] def test_cached_view_create(self):
"""Verify that cached_view returns view in the cache namespace."""
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
v, c = exv.cached_view(ORDER_DETAIL_VIEWID)
self.assert_true(c)
self.assert_true(v)
[docs] def test_remove_cached_view(self):
"""Verify that remove_cached_view removes from the cache namespace."""
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
v, c = exv.cached_view(ORDER_DETAIL_VIEWID)
self.assert_true(c)
self.assert_true(v)
exv.remove_cached_view(ORDER_DETAIL_VIEWID)
self.assert_true(ORDER_DETAIL_VIEWID not in exv._view_cache.keys())
[docs]class ExViewProxyMethodsTestCase(ExTestCase):
"""Verify :py:class:`extools.view.ExView` proxy methods are working."""
[docs] def setup(self):
"""Clear the class internals before each test."""
ExView._view_cache = {}
[docs] def test_all(self):
"""Verify that ``all`` yields all records in a view."""
with exview(AR_CUSTOMER_VIEWID, self.index) as exv:
customers = [c.get("IDCUST") for c in exv.all()]
self.assert_equal(len(customers), AR_CUSTOMER_COUNT)
self.assert_equal(customers[0], AR_CUSTOMER_FIRST)
self.assert_equal(customers[-1], AR_CUSTOMER_LAST)
[docs] def test_where(self):
"""Verify that ``where`` yields all matching in a view."""
barmart_customers = ["1100", "1105", "BARMART", ]
with exview(AR_CUSTOMER_VIEWID, self.index) as exv:
customers = [c.get("IDCUST") for c in exv.where(IDNATACCT='BARMART')]
self.assert_equal(len(customers), len(barmart_customers))
for i in range(0, len(customers)):
self.assert_equal(customers[i], barmart_customers[i])
[docs] def test_create(self):
"""Verify that ``where`` yields all matching in a view."""
with exview(ORDER_HEADER_VIEWID, self.index) as exv:
exv.compose()
lines = len([l for l in exv.lines()])
exv.oe0500.create(ITEM="A1-103/0")
self.assert_equal(lines + 1, len([l for l in exv.lines()]))
self.exm.info([l.get("ITEM") for l in exv.lines()])
def test_update(self):
pass
def test_fetch(self):
pass
def test_order(self):
pass
def test_close(self):
pass
def test_seek_to(self):
pass
[docs]class ExViewAttributesTestCase(ExTestCase):
"""Verify :py:class:`extools.view.ExView` passes attrs to the view."""
attrs = ['handle', ]
[docs] def setup_class(self):
"""Generate the attribute proxy tests."""
pass
[docs] def setup(self):
"""Clear the class internals before each test."""
ExView._view_cache = {}
def generate_attr_tests(self):
pass