diff --git a/.travis.yml b/.travis.yml index c386329854..cd2093c55a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ before_install: - make setup_ci script: - - make test + - make coverage - make style after_success: diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 94dee8e95c..2b49f7b908 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -74,9 +74,9 @@ class InvenTreeTree(models.Model): @property def children(self): contents = ContentType.objects.get_for_model(type(self)) - children = contents.get_all_objects_for_this_type(parent=self.id) + childs = contents.get_all_objects_for_this_type(parent=self.id) - return children + return childs def getAcceptableParents(self): """ Returns a list of acceptable parent items within this model @@ -187,11 +187,8 @@ def FilterChildren(queryset, parent): elif str2bool(parent, False): return queryset.filter(parent=None) else: - try: - parent_id = int(parent) - if parent_id == 0: - return queryset.filter(parent=None) - else: - return queryset.filter(parent=parent_id) - except: - return queryset + parent_id = int(parent) + if parent_id == 0: + return queryset.filter(parent=None) + else: + return queryset.filter(parent=parent_id) diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index d09e751878..c72aa5209b 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext as _ +from django.urls import reverse from django.db import models from django.core.validators import MinValueValidator @@ -14,7 +15,7 @@ class Build(models.Model): """ def get_absolute_url(self): - return '/build/{pk}/'.format(pk=self.id) + return reverse('build-detail', kwargs={'pk': self.id}) # Build status codes PENDING = 10 # Build is pending / active diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index c2de5b3ab1..1918ce9b27 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -1,6 +1,56 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -# from django.test import TestCase +from django.test import TestCase -# Create your tests here. +from .models import Build +from part.models import Part + + +class BuildTestSimple(TestCase): + + def setUp(self): + part = Part.objects.create(name='Test part', + description='Simple description') + Build.objects.create(part=part, + batch='B1', + status=Build.PENDING, + title='Building 7 parts', + quantity=7, + notes='Some simple notes') + + Build.objects.create(part=part, + batch='B2', + status=Build.COMPLETE, + title='Building 21 parts', + quantity=21, + notes='Some simple notes') + + def test_build_objects(self): + # Ensure the Build objects were correctly created + self.assertEqual(Build.objects.count(), 2) + b = Build.objects.get(pk=2) + self.assertEqual(b.batch, 'B2') + self.assertEqual(b.quantity, 21) + + def test_url(self): + b1 = Build.objects.get(pk=1) + self.assertEqual(b1.get_absolute_url(), '/build/1/') + + def test_is_complete(self): + b1 = Build.objects.get(pk=1) + b2 = Build.objects.get(pk=2) + + self.assertEqual(b1.is_complete, False) + self.assertEqual(b2.is_complete, True) + + def test_is_active(self): + b1 = Build.objects.get(pk=1) + b2 = Build.objects.get(pk=2) + + self.assertEqual(b1.is_active, True) + self.assertEqual(b2.is_active, False) + + def test_required_parts(self): + # TODO - Generate BOM for test part + pass diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index fc864ecc19..fe97d9a90c 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import os from django.db import models +from django.urls import reverse def rename_company_image(instance, filename): @@ -56,7 +57,7 @@ class Company(models.Model): return "{n} - {d}".format(n=self.name, d=self.description) def get_absolute_url(self): - return "/company/{id}/".format(id=self.id) + return reverse('company-detail', kwargs={'pk': self.id}) @property def part_count(self): diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index a79ca8be56..925d9eb104 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -1,3 +1,19 @@ -# from django.test import TestCase +from django.test import TestCase -# Create your tests here. +from .models import Company + + +class CompanySimpleTest(TestCase): + + def setUp(self): + Company.objects.create(name='ABC Co.', + description='Seller of ABC products', + website='www.abc-sales.com', + address='123 Sales St.', + is_customer=False, + is_supplier=True) + + def test_company_model(self): + c = Company.objects.get(pk=1) + self.assertEqual(c.name, 'ABC Co.') + self.assertEqual(c.get_absolute_url(), '/company/1/') diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 28d9941326..4d7d05bba1 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -89,21 +89,21 @@ class EditBomItemForm(HelperForm): class EditSupplierPartForm(HelperForm): - class Meta: - model = SupplierPart - fields = [ - 'supplier', - 'SKU', - 'part', - 'description', - 'URL', - 'manufacturer', - 'MPN', - 'note', - 'single_price', - 'base_cost', - 'multiple', - 'minimum', - 'packaging', - 'lead_time' - ] + class Meta: + model = SupplierPart + fields = [ + 'supplier', + 'SKU', + 'part', + 'description', + 'URL', + 'manufacturer', + 'MPN', + 'note', + 'single_price', + 'base_cost', + 'multiple', + 'minimum', + 'packaging', + 'lead_time' + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 80a4a5da35..6c9dc4ec54 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -9,6 +9,7 @@ import tablib from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError +from django.urls import reverse from django.db import models from django.core.validators import MinValueValidator @@ -25,7 +26,7 @@ class PartCategory(InvenTreeTree): """ def get_absolute_url(self): - return '/part/category/{id}/'.format(id=self.id) + return reverse('category-detail', kwargs={'pk': self.id}) class Meta: verbose_name = "Part Category" @@ -88,7 +89,7 @@ class Part(models.Model): """ def get_absolute_url(self): - return '/part/{id}/'.format(id=self.id) + return reverse('part-detail', kwargs={'pk': self.id}) # Short name of the part name = models.CharField(max_length=100, unique=True, help_text='Part name (must be unique)') @@ -336,7 +337,7 @@ class BomItem(models.Model): """ def get_absolute_url(self): - return '/part/bom/{id}/'.format(id=self.id) + return reverse('bom-detail', kwargs={'pk': self.id}) # A link to the parent part # Each part will get a reverse lookup field 'bom_items' @@ -385,7 +386,7 @@ class SupplierPart(models.Model): """ def get_absolute_url(self): - return "/supplier-part/{id}/".format(id=self.id) + return reverse('supplier-part-detail', kwargs={'pk': self.id}) class Meta: unique_together = ('part', 'supplier', 'SKU') diff --git a/InvenTree/part/test_bom_item.py b/InvenTree/part/test_bom_item.py new file mode 100644 index 0000000000..e3d7aa78ce --- /dev/null +++ b/InvenTree/part/test_bom_item.py @@ -0,0 +1,7 @@ +from django.test import TestCase + + +class BomItemTest(TestCase): + + def setUp(self): + pass diff --git a/InvenTree/part/test_category.py b/InvenTree/part/test_category.py new file mode 100644 index 0000000000..9fee29332c --- /dev/null +++ b/InvenTree/part/test_category.py @@ -0,0 +1,66 @@ +from django.test import TestCase + +from .models import Part, PartCategory + + +class CategoryTest(TestCase): + """ + Tests to ensure that the relational category tree functions correctly. + """ + + def setUp(self): + self.p1 = PartCategory.objects.create(name='A', + description='Most highest level', + parent=None) + + self.p2 = PartCategory.objects.create(name='B', + description='Sits under second', + parent=self.p1) + + self.p3 = PartCategory.objects.create(name='C', + description='Third tier category', + parent=self.p2) + + # Add two parts in p2 + Part.objects.create(name='Flange', category=self.p2) + Part.objects.create(name='Flob', category=self.p2) + + # Add one part in p3 + Part.objects.create(name='Blob', category=self.p3) + + def test_parents(self): + self.assertEqual(self.p1.parent, None) + self.assertEqual(self.p2.parent, self.p1) + self.assertEqual(self.p3.parent, self.p2) + + def test_children_count(self): + self.assertEqual(self.p1.has_children, True) + self.assertEqual(self.p2.has_children, True) + self.assertEqual(self.p3.has_children, False) + + def test_unique_childs(self): + childs = self.p1.getUniqueChildren() + + self.assertIn(self.p2.id, childs) + self.assertIn(self.p2.id, childs) + + def test_unique_parents(self): + parents = self.p2.getUniqueParents() + + self.assertIn(self.p1.id, parents) + + def test_path_string(self): + self.assertEqual(str(self.p3), 'A/B/C') + + def test_url(self): + self.assertEqual(self.p1.get_absolute_url(), '/part/category/1/') + + def test_part_count(self): + # No direct parts in the top-level category + self.assertEqual(self.p1.has_parts, False) + self.assertEqual(self.p2.has_parts, True) + self.assertEqual(self.p3.has_parts, True) + + self.assertEqual(self.p1.partcount, 3) + self.assertEqual(self.p2.partcount, 3) + self.assertEqual(self.p3.partcount, 1) diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py new file mode 100644 index 0000000000..c9ed2fd7b3 --- /dev/null +++ b/InvenTree/part/test_part.py @@ -0,0 +1,23 @@ +from django.test import TestCase + +from .models import Part, PartCategory + + +class SimplePartTest(TestCase): + + def setUp(self): + + cat = PartCategory.objects.create(name='TLC', description='Top level category') + + self.px = Part.objects.create(name='x', description='A part called x', buildable=True) + self.py = Part.objects.create(name='y', description='A part called y', consumable=False) + self.pz = Part.objects.create(name='z', description='A part called z', category=cat) + + def test_metadata(self): + self.assertEqual(self.px.name, 'x') + self.assertEqual(self.py.get_absolute_url(), '/part/2/') + self.assertEqual(str(self.pz), 'z - A part called z') + + def test_category(self): + self.assertEqual(self.px.category_path, '') + self.assertEqual(self.pz.category_path, 'TLC') diff --git a/InvenTree/part/test_supplier_part.py b/InvenTree/part/test_supplier_part.py new file mode 100644 index 0000000000..c34b788257 --- /dev/null +++ b/InvenTree/part/test_supplier_part.py @@ -0,0 +1,7 @@ +from django.test import TestCase + + +class SupplierPartTest(TestCase): + + def setUp(self): + pass diff --git a/InvenTree/part/tests.py b/InvenTree/part/tests.py deleted file mode 100644 index a79ca8be56..0000000000 --- a/InvenTree/part/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -# from django.test import TestCase - -# Create your tests here. diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 75d5041b9c..14a15625f9 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -70,23 +70,3 @@ part_urls = [ # Top level part list (display top level parts and categories) url(r'^.*$', views.PartIndex.as_view(), name='part-index'), ] - -""" -part_param_urls = [ - # Detail of a single part parameter - url(r'^(?P[0-9]+)/?$', views.PartParamDetail.as_view(), name='partparameter-detail'), - - # Parameters associated with a particular part - url(r'^\?.*/?$', views.PartParamList.as_view()), - url(r'^$', views.PartParamList.as_view()), -] - -part_param_template_urls = [ - # Detail of a single part field template - url(r'^(?P[0-9]+)/?$', views.PartTemplateDetail.as_view(), name='partparametertemplate-detail'), - - # List all part field templates - url(r'^\?.*/?$', views.PartTemplateList.as_view()), - url(r'^$', views.PartTemplateList.as_view()) -] -""" diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 6af5b3d4b7..312bff9bbe 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError +from django.urls import reverse from django.db import models, transaction from django.core.validators import MinValueValidator @@ -25,7 +26,7 @@ class StockLocation(InvenTreeTree): """ def get_absolute_url(self): - return '/stock/location/{id}/'.format(id=self.id) + return reverse('stock-location-detail', kwargs={'pk': self.id}) @property def stock_items(self): @@ -109,7 +110,7 @@ class StockItem(models.Model): }) def get_absolute_url(self): - return '/stock/item/{id}/'.format(id=self.id) + return reverse('stock-item-detail', kwargs={'pk': self.id}) class Meta: unique_together = [ @@ -331,7 +332,7 @@ class StockItemTracking(models.Model): """ def get_absolute_url(self): - return '/stock/track/{id}/'.format(id=self.id) + return reverse('stock-tracking-detail', kwargs={'pk': self.id}) # Stock item item = models.ForeignKey(StockItem, on_delete=models.CASCADE, diff --git a/InvenTree/stock/test_stock_item.py b/InvenTree/stock/test_stock_item.py new file mode 100644 index 0000000000..becd6e4e69 --- /dev/null +++ b/InvenTree/stock/test_stock_item.py @@ -0,0 +1,7 @@ +from django.test import TestCase + + +class StockItemTest(TestCase): + + def setUp(self): + pass diff --git a/InvenTree/stock/test_stock_location.py b/InvenTree/stock/test_stock_location.py new file mode 100644 index 0000000000..0a89aeed33 --- /dev/null +++ b/InvenTree/stock/test_stock_location.py @@ -0,0 +1,7 @@ +from django.test import TestCase + + +class StockLocationTest(TestCase): + + def setUp(self): + pass diff --git a/InvenTree/stock/test_stock_tracking.py b/InvenTree/stock/test_stock_tracking.py new file mode 100644 index 0000000000..15b79cbe66 --- /dev/null +++ b/InvenTree/stock/test_stock_tracking.py @@ -0,0 +1,7 @@ +from django.test import TestCase + + +class StockTrackingTest(TestCase): + + def setUp(self): + pass diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py deleted file mode 100644 index a79ca8be56..0000000000 --- a/InvenTree/stock/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -# from django.test import TestCase - -# Create your tests here. diff --git a/Makefile b/Makefile index 7586b678a4..8db2a2110c 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,8 @@ style: flake8 InvenTree --ignore=C901,E501 test: - # Perform Django system checks python InvenTree/manage.py check - - # Run the test framework (through coverage script) - coverage run InvenTree/manage.py test + python manage.py test build company part stock migrate: python InvenTree/manage.py makemigrations company @@ -26,7 +23,6 @@ migrate: python InvenTree/manage.py check install: - # TODO: replace this with a proper setup.py pip install -U -r requirements/base.txt # Generate a secret key @@ -37,5 +33,10 @@ setup: install migrate setup_ci: pip install -U -r requirements/build.txt +coverage: + python InvenTree/manage.py check + coverage run InvenTree/manage.py test build company part stock + coverage html + superuser: python InvenTree/manage.py createsuperuser