Initial tests.

This doesn't add much in the way of useful tests but it should pave the way for
more. Tests may be run like so:

{{{
python setup.py nosetests --with-coverage
}}}
This commit is contained in:
Lance Edgar 2013-06-19 14:21:45 -07:00
parent 4174e6d77d
commit 84225f00e1
17 changed files with 250 additions and 90 deletions

View file

@ -0,0 +1,53 @@
import unittest
from pyramid import testing
class TestCase(unittest.TestCase):
"""
Base class for all test suites.
"""
def setUp(self):
self.config = testing.setUp()
# self.config = testing.setUp(settings={
# 'mako.directories': [
# 'rattail.pyramid:templates',
# 'edbob.pyramid:templates',
# ],
# })
def tearDown(self):
testing.tearDown()
# class DataTestCase(TestCase):
# """
# Base class for all test suites which require fixture data.
# """
# def setUp(self):
# from sqlalchemy import create_engine
# from edbob import db
# from rattail.pyramid import Session
# from edbob.db.util import install_core_schema
# from edbob.db.extensions import activate_extension
# from rattail.pyramid.tests.fixtures import load_fixtures
# engine = create_engine('postgresql://rattail:1pKglVgdHOP1MYGVdUZr@localhost/rattail.test')
# db.engines = {'default': engine}
# db.engine = engine
# db.Session.configure(bind=engine)
# Session.configure(bind=engine)
# install_core_schema(engine)
# activate_extension('rattail', engine)
# load_fixtures(engine)
# super(DataTestCase, self).setUp()
# # def tearDown(self):
# # from rattail.pyramid import Session
# # super(DataTestCase, self).tearDown()
# # Session.configure(bind=None)

View file

@ -0,0 +1,28 @@
import fixture
from rattail.db import model
class DepartmentData(fixture.DataSet):
class grocery:
number = 1
name = 'Grocery'
class supplements:
number = 2
name = 'Supplements'
def load_fixtures(engine):
dbfixture = fixture.SQLAlchemyFixture(
env={
'DepartmentData': model.Department,
},
engine=engine)
data = dbfixture.data(DepartmentData)
data.setup()

View file

@ -0,0 +1,46 @@
from pyramid import testing
from rattail.pyramid.tests import TestCase
from rattail.pyramid.views import departments
from rattail.db.model import Department
class DepartmentTests(TestCase):
"""
Test Department views.
"""
def test_grid(self):
request = testing.DummyRequest(has_perm=lambda p: True)
view = departments.DepartmentsGrid(request)
view._data = None
view._sort_config = None
self.assertIsInstance(view, departments.DepartmentsGrid)
self.assertIsInstance(view.filter_map(), dict)
self.assertIsInstance(view.filter_config(), dict)
self.assertIsInstance(view.sort_map(), dict)
self.assertIsInstance(view.grid(), object)
def test_crud(self):
request = testing.DummyRequest()
view = departments.DepartmentCrud(request)
self.assertIsInstance(view, departments.DepartmentCrud)
self.assertIsInstance(view.fieldset(Department), object)
def test_autocomplete(self):
request = testing.DummyRequest()
view = departments.DepartmentsAutocomplete(request)
self.assertIsInstance(view, departments.DepartmentsAutocomplete)
def test_vendor_grid(self):
request = testing.DummyRequest(params={'uuid': 'bogus'})
view = departments.DepartmentsByVendorGrid(request)
view._data = None
self.assertIsInstance(view, departments.DepartmentsByVendorGrid)
self.assertIsInstance(view.query(), object)
self.assertIsInstance(view.grid(), object)
def test_includeme(self):
self.config.include(departments)

View file

@ -0,0 +1,11 @@
from rattail.pyramid.tests import TestCase
class RootTests(TestCase):
"""
Test root module.
"""
def test_includeme(self):
self.config.include('rattail.pyramid')

View file

@ -0,0 +1,11 @@
from rattail.pyramid.tests import TestCase
class ViewTests(TestCase):
"""
Test root views module.
"""
def test_includeme(self):
self.config.include('rattail.pyramid.views')

View file

@ -40,12 +40,13 @@ from edbob.pyramid.views import SearchableAlchemyGridView, CrudView, View
import rattail
from rattail import batches
from rattail.db.model import Batch
from rattail.threads import Thread
class BatchesGrid(SearchableAlchemyGridView):
mapped_class = rattail.Batch
mapped_class = Batch
config_prefix = 'batches'
sort = 'id'
@ -53,15 +54,15 @@ class BatchesGrid(SearchableAlchemyGridView):
def executed_is(q, v):
if v == 'True':
return q.filter(rattail.Batch.executed != None)
return q.filter(Batch.executed != None)
else:
return q.filter(rattail.Batch.executed == None)
return q.filter(Batch.executed == None)
def executed_isnot(q, v):
if v == 'True':
return q.filter(rattail.Batch.executed == None)
return q.filter(Batch.executed == None)
else:
return q.filter(rattail.Batch.executed != None)
return q.filter(Batch.executed != None)
return self.make_filter_map(
exact=['id'],
@ -113,7 +114,7 @@ class BatchesGrid(SearchableAlchemyGridView):
class BatchCrud(CrudView):
mapped_class = rattail.Batch
mapped_class = Batch
home_route = 'batches'
def fieldset(self, model):
@ -159,7 +160,7 @@ class ExecuteBatch(View):
def __call__(self):
uuid = self.request.matchdict['uuid']
batch = Session.query(rattail.Batch).get(uuid) if uuid else None
batch = Session.query(Batch).get(uuid) if uuid else None
if not batch:
return HTTPFound(location=self.request.route_url('batches'))

View file

@ -29,12 +29,12 @@
from edbob.pyramid.views import (
SearchableAlchemyGridView, CrudView, AutocompleteView)
import rattail
from rattail.db.model import Brand
class BrandsGrid(SearchableAlchemyGridView):
mapped_class = rattail.Brand
mapped_class = Brand
config_prefix = 'brands'
sort = 'name'
@ -70,7 +70,7 @@ class BrandsGrid(SearchableAlchemyGridView):
class BrandCrud(CrudView):
mapped_class = rattail.Brand
mapped_class = Brand
home_route = 'brands'
def fieldset(self, model):
@ -84,7 +84,7 @@ class BrandCrud(CrudView):
class BrandsAutocomplete(AutocompleteView):
mapped_class = rattail.Brand
mapped_class = Brand
fieldname = 'name'

View file

@ -28,12 +28,12 @@
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
import rattail
from rattail.db.model import Category
class CategoriesGrid(SearchableAlchemyGridView):
mapped_class = rattail.Category
mapped_class = Category
config_prefix = 'categories'
sort = 'number'
@ -70,7 +70,7 @@ class CategoriesGrid(SearchableAlchemyGridView):
class CategoryCrud(CrudView):
mapped_class = rattail.Category
mapped_class = Category
home_route = 'categories'
def fieldset(self, model):

View file

@ -28,13 +28,13 @@
from edbob.pyramid.views import SearchableAlchemyGridView
import rattail
from rattail.pyramid.views import CrudView
from rattail.db.model import CustomerGroup
class CustomerGroupsGrid(SearchableAlchemyGridView):
mapped_class = rattail.CustomerGroup
mapped_class = CustomerGroup
config_prefix = 'customer_groups'
sort = 'name'
@ -71,7 +71,7 @@ class CustomerGroupsGrid(SearchableAlchemyGridView):
class CustomerGroupCrud(CrudView):
mapped_class = rattail.CustomerGroup
mapped_class = CustomerGroup
home_route = 'customer_groups'
pretty_name = "Customer Group"

View file

@ -30,12 +30,12 @@
from edbob.pyramid.views import (
SearchableAlchemyGridView, CrudView, AlchemyGridView, AutocompleteView)
import rattail
from rattail.db.model import Department, Product, ProductCost, Vendor
class DepartmentsGrid(SearchableAlchemyGridView):
mapped_class = rattail.Department
mapped_class = Department
config_prefix = 'departments'
sort = 'name'
@ -72,7 +72,7 @@ class DepartmentsGrid(SearchableAlchemyGridView):
class DepartmentCrud(CrudView):
mapped_class = rattail.Department
mapped_class = Department
home_route = 'departments'
def fieldset(self, model):
@ -87,19 +87,19 @@ class DepartmentCrud(CrudView):
class DepartmentsByVendorGrid(AlchemyGridView):
mapped_class = rattail.Department
mapped_class = Department
config_prefix = 'departments.by_vendor'
checkboxes = True
partial_only = True
def query(self):
q = self.make_query()
q = q.outerjoin(rattail.Product)
q = q.join(rattail.ProductCost)
q = q.join(rattail.Vendor)
q = q.filter(rattail.Vendor.uuid == self.request.params['uuid'])
q = q.outerjoin(Product)
q = q.join(ProductCost)
q = q.join(Vendor)
q = q.filter(Vendor.uuid == self.request.params['uuid'])
q = q.distinct()
q = q.order_by(rattail.Department.name)
q = q.order_by(Department.name)
return q
def grid(self):
@ -114,7 +114,7 @@ class DepartmentsByVendorGrid(AlchemyGridView):
class DepartmentsAutocomplete(AutocompleteView):
mapped_class = rattail.Department
mapped_class = Department
fieldname = 'name'

View file

@ -37,12 +37,12 @@ from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
from edbob.pyramid.grids.search import BooleanSearchFilter
from edbob.pyramid.forms import StrippingFieldRenderer
import rattail
from rattail.db.model import LabelProfile
class ProfilesGrid(SearchableAlchemyGridView):
mapped_class = rattail.LabelProfile
mapped_class = LabelProfile
config_prefix = 'label_profiles'
sort = 'ordinal'
@ -82,7 +82,7 @@ class ProfilesGrid(SearchableAlchemyGridView):
class ProfileCrud(CrudView):
mapped_class = rattail.LabelProfile
mapped_class = LabelProfile
home_route = 'label_profiles'
pretty_name = "Label Profile"
update_cancel_route = 'label_profile.read'
@ -134,7 +134,7 @@ class ProfileCrud(CrudView):
def printer_settings(request):
uuid = request.matchdict['uuid']
profile = Session.query(rattail.LabelProfile).get(uuid) if uuid else None
profile = Session.query(LabelProfile).get(uuid) if uuid else None
if not profile:
return HTTPFound(location=request.route_url('label_profiles'))

View file

@ -38,13 +38,14 @@ import edbob
from edbob.pyramid.progress import SessionProgress
from edbob.pyramid.views import SearchableAlchemyGridView
import rattail
import rattail.labels
from rattail import sil
from rattail import batches
from rattail.threads import Thread
from rattail.exceptions import LabelPrintingError
from rattail.db.model import ProductPrice, ProductCode
from rattail.db.model import (
Product, ProductPrice, ProductCost, ProductCode,
Brand, Vendor, Department, Subdepartment, LabelProfile)
from rattail.pyramid import Session
from rattail.pyramid.forms import (AutocompleteFieldRenderer,
@ -54,7 +55,7 @@ from rattail.pyramid.views import CrudView
class ProductsGrid(SearchableAlchemyGridView):
mapped_class = rattail.Product
mapped_class = Product
config_prefix = 'products'
sort = 'description'
@ -62,29 +63,29 @@ class ProductsGrid(SearchableAlchemyGridView):
def join_vendor(q):
q = q.outerjoin(
rattail.ProductCost,
ProductCost,
and_(
rattail.ProductCost.product_uuid == rattail.Product.uuid,
rattail.ProductCost.preference == 1,
ProductCost.product_uuid == Product.uuid,
ProductCost.preference == 1,
))
q = q.outerjoin(rattail.Vendor)
q = q.outerjoin(Vendor)
return q
return {
'brand':
lambda q: q.outerjoin(rattail.Brand),
lambda q: q.outerjoin(Brand),
'department':
lambda q: q.outerjoin(rattail.Department,
rattail.Department.uuid == rattail.Product.department_uuid),
lambda q: q.outerjoin(Department,
Department.uuid == Product.department_uuid),
'subdepartment':
lambda q: q.outerjoin(rattail.Subdepartment,
rattail.Subdepartment.uuid == rattail.Product.subdepartment_uuid),
lambda q: q.outerjoin(Subdepartment,
Subdepartment.uuid == Product.subdepartment_uuid),
'regular_price':
lambda q: q.outerjoin(rattail.ProductPrice,
rattail.ProductPrice.uuid == rattail.Product.regular_price_uuid),
lambda q: q.outerjoin(ProductPrice,
ProductPrice.uuid == Product.regular_price_uuid),
'current_price':
lambda q: q.outerjoin(rattail.ProductPrice,
rattail.ProductPrice.uuid == rattail.Product.current_price_uuid),
lambda q: q.outerjoin(ProductPrice,
ProductPrice.uuid == Product.current_price_uuid),
'vendor':
join_vendor,
'code':
@ -101,7 +102,7 @@ class ProductsGrid(SearchableAlchemyGridView):
except ValueError:
return q
else:
return q.filter(rattail.Product.upc == v) if v else q
return q.filter(Product.upc == v) if v else q
def filter_not(q, v):
try:
@ -109,17 +110,17 @@ class ProductsGrid(SearchableAlchemyGridView):
except ValueError:
return q
else:
return q.filter(rattail.Product.upc != v) if v else q
return q.filter(Product.upc != v) if v else q
return {'is': filter_is, 'nt': filter_not}
return self.make_filter_map(
ilike=['description', 'size'],
upc=filter_upc(),
brand=self.filter_ilike(rattail.Brand.name),
department=self.filter_ilike(rattail.Department.name),
subdepartment=self.filter_ilike(rattail.Subdepartment.name),
vendor=self.filter_ilike(rattail.Vendor.name),
brand=self.filter_ilike(Brand.name),
department=self.filter_ilike(Department.name),
subdepartment=self.filter_ilike(Subdepartment.name),
vendor=self.filter_ilike(Vendor.name),
code=self.filter_ilike(ProductCode.code))
def filter_config(self):
@ -139,21 +140,21 @@ class ProductsGrid(SearchableAlchemyGridView):
def sort_map(self):
return self.make_sort_map(
'upc', 'description', 'size',
brand=self.sorter(rattail.Brand.name),
department=self.sorter(rattail.Department.name),
subdepartment=self.sorter(rattail.Subdepartment.name),
regular_price=self.sorter(rattail.ProductPrice.price),
current_price=self.sorter(rattail.ProductPrice.price),
vendor=self.sorter(rattail.Vendor.name))
brand=self.sorter(Brand.name),
department=self.sorter(Department.name),
subdepartment=self.sorter(Subdepartment.name),
regular_price=self.sorter(ProductPrice.price),
current_price=self.sorter(ProductPrice.price),
vendor=self.sorter(Vendor.name))
def query(self):
q = self.make_query()
q = q.options(joinedload(rattail.Product.brand))
q = q.options(joinedload(rattail.Product.department))
q = q.options(joinedload(rattail.Product.subdepartment))
q = q.options(joinedload(rattail.Product.regular_price))
q = q.options(joinedload(rattail.Product.current_price))
q = q.options(joinedload(rattail.Product.vendor))
q = q.options(joinedload(Product.brand))
q = q.options(joinedload(Product.department))
q = q.options(joinedload(Product.subdepartment))
q = q.options(joinedload(Product.regular_price))
q = q.options(joinedload(Product.current_price))
q = q.options(joinedload(Product.vendor))
return q
def grid(self):
@ -184,7 +185,7 @@ class ProductsGrid(SearchableAlchemyGridView):
g.deletable = True
g.delete_route_name = 'product.delete'
q = Session.query(rattail.LabelProfile)
q = Session.query(LabelProfile)
if q.count():
def labels(row):
return link_to("Print", '#', class_='print-label')
@ -193,15 +194,15 @@ class ProductsGrid(SearchableAlchemyGridView):
return g
def render_kwargs(self):
q = Session.query(rattail.LabelProfile)
q = q.filter(rattail.LabelProfile.visible == True)
q = q.order_by(rattail.LabelProfile.ordinal)
q = Session.query(LabelProfile)
q = q.filter(LabelProfile.visible == True)
q = q.order_by(LabelProfile.ordinal)
return {'label_profiles': q.all()}
class ProductCrud(CrudView):
mapped_class = rattail.Product
mapped_class = Product
home_route = 'products'
def get_model(self, key):
@ -239,12 +240,12 @@ class ProductCrud(CrudView):
def print_labels(request):
profile = request.params.get('profile')
profile = Session.query(rattail.LabelProfile).get(profile) if profile else None
profile = Session.query(LabelProfile).get(profile) if profile else None
if not profile:
return {'error': "Label profile not found"}
product = request.params.get('product')
product = Session.query(rattail.Product).get(product) if product else None
product = Session.query(Product).get(product) if product else None
if not product:
return {'error': "Product not found"}

View file

@ -30,34 +30,34 @@ from sqlalchemy import and_
from edbob.pyramid.views import SearchableAlchemyGridView
import rattail
from rattail.pyramid.views import CrudView
from rattail.db.model import Store, StoreEmailAddress, StorePhoneNumber
class StoresGrid(SearchableAlchemyGridView):
mapped_class = rattail.Store
mapped_class = Store
config_prefix = 'stores'
sort = 'id'
def join_map(self):
return {
'email':
lambda q: q.outerjoin(rattail.StoreEmailAddress, and_(
rattail.StoreEmailAddress.parent_uuid == rattail.Store.uuid,
rattail.StoreEmailAddress.preference == 1)),
lambda q: q.outerjoin(StoreEmailAddress, and_(
StoreEmailAddress.parent_uuid == Store.uuid,
StoreEmailAddress.preference == 1)),
'phone':
lambda q: q.outerjoin(rattail.StorePhoneNumber, and_(
rattail.StorePhoneNumber.parent_uuid == rattail.Store.uuid,
rattail.StorePhoneNumber.preference == 1)),
lambda q: q.outerjoin(StorePhoneNumber, and_(
StorePhoneNumber.parent_uuid == Store.uuid,
StorePhoneNumber.preference == 1)),
}
def filter_map(self):
return self.make_filter_map(
exact=['id'],
ilike=['name'],
email=self.filter_ilike(rattail.StoreEmailAddress.address),
phone=self.filter_ilike(rattail.StorePhoneNumber.number))
email=self.filter_ilike(StoreEmailAddress.address),
phone=self.filter_ilike(StorePhoneNumber.number))
def filter_config(self):
return self.make_filter_config(
@ -68,8 +68,8 @@ class StoresGrid(SearchableAlchemyGridView):
def sort_map(self):
return self.make_sort_map(
'id', 'name',
email=self.sorter(rattail.StoreEmailAddress.address),
phone=self.sorter(rattail.StorePhoneNumber.number))
email=self.sorter(StoreEmailAddress.address),
phone=self.sorter(StorePhoneNumber.number))
def grid(self):
g = self.make_grid()
@ -94,7 +94,7 @@ class StoresGrid(SearchableAlchemyGridView):
class StoreCrud(CrudView):
mapped_class = rattail.Store
mapped_class = Store
home_route = 'stores'
def fieldset(self, model):

View file

@ -28,12 +28,12 @@
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
import rattail
from rattail.db.model import Subdepartment
class SubdepartmentsGrid(SearchableAlchemyGridView):
mapped_class = rattail.Subdepartment
mapped_class = Subdepartment
config_prefix = 'subdepartments'
sort = 'name'
@ -71,7 +71,7 @@ class SubdepartmentsGrid(SearchableAlchemyGridView):
class SubdepartmentCrud(CrudView):
mapped_class = rattail.Subdepartment
mapped_class = Subdepartment
home_route = 'subdepartments'
def fieldset(self, model):

View file

@ -28,16 +28,16 @@
import formalchemy
import edbob
from edbob.pyramid.views import users
from rattail.pyramid.views import CrudView
from rattail.pyramid.forms import PersonFieldRenderer
from rattail.db.model import User
class UserCrud(CrudView):
mapped_class = edbob.User
mapped_class = User
home_route = 'users'
def fieldset(self, user):

7
setup.cfg Normal file
View file

@ -0,0 +1,7 @@
[nosetests]
nocapture = 1
cover-package = rattail.pyramid
cover-erase = 1
cover-inclusive = 1
cover-html = 1
cover-html-dir = htmlcov

View file

@ -94,6 +94,8 @@ setup(
],
install_requires = requires,
tests_require = requires + ['nose', 'coverage'],
test_suite = 'nose.collector',
namespace_packages = ['rattail'],
packages = find_packages(),