Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2019-08-09 20:37:46 +10:00
commit c1ab004c0c
8 changed files with 480 additions and 7 deletions

View File

@ -1,5 +1,6 @@
from django.test import TestCase
import django.core.exceptions as django_exceptions
from django.core.exceptions import ValidationError
from .validators import validate_overage, validate_part_name
from . import helpers
@ -100,3 +101,50 @@ class TestDownloadFile(TestCase):
def test_download(self):
helpers.DownloadFile("hello world", "out.txt")
helpers.DownloadFile(bytes("hello world".encode("utf8")), "out.bin")
class TestSerialNumberExtraction(TestCase):
""" Tests for serial number extraction code """
def test_simple(self):
e = helpers.ExtractSerialNumbers
sn = e("1-5", 5)
self.assertEqual(len(sn), 5)
for i in range(1, 6):
self.assertIn(i, sn)
sn = e("1, 2, 3, 4, 5", 5)
self.assertEqual(len(sn), 5)
sn = e("1-5, 10-15", 11)
self.assertIn(3, sn)
self.assertIn(13, sn)
def test_failures(self):
e = helpers.ExtractSerialNumbers
# Test duplicates
with self.assertRaises(ValidationError):
e("1,2,3,3,3", 5)
# Test invalid length
with self.assertRaises(ValidationError):
e("1,2,3", 5)
# Test empty string
with self.assertRaises(ValidationError):
e(", , ,", 0)
# Test incorrect sign in group
with self.assertRaises(ValidationError):
e("10-2", 8)
# Test invalid group
with self.assertRaises(ValidationError):
e("1-5-10", 10)
with self.assertRaises(ValidationError):
e("10, a, 7-70j", 4)

View File

@ -0,0 +1,77 @@
""" Unit tests for Order views (see views.py) """
from django.test import TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model
class OrderViewTestCase(TestCase):
fixtures = [
'category',
'part',
'bom',
'location',
'company',
'supplier_part',
'stock',
'order',
]
def setUp(self):
super().setUp()
# Create a user
User = get_user_model()
User.objects.create_user('username', 'user@email.com', 'password')
self.client.login(username='username', password='password')
class OrderListTest(OrderViewTestCase):
def test_order_list(self):
response = self.client.get(reverse('purchase-order-index'))
self.assertEqual(response.status_code, 200)
class POTests(OrderViewTestCase):
""" Tests for PurchaseOrder views """
def test_detail_view(self):
""" Retrieve PO detail view """
response = self.client.get(reverse('purchase-order-detail', args=(1,)))
self.assertEqual(response.status_code, 200)
keys = response.context.keys()
self.assertIn('OrderStatus', keys)
def test_po_create(self):
""" Launch forms to create new PurchaseOrder"""
url = reverse('purchase-order-create')
# Without a supplier ID
response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# With a valid supplier ID
response = self.client.get(url, {'supplier': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# With an invalid supplier ID
response = self.client.get(url, {'supplier': 'goat'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_po_edit(self):
""" Launch form to edit a PurchaseOrder """
response = self.client.get(reverse('purchase-order-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_po_export(self):
""" Export PurchaseOrder """
response = self.client.get(reverse('purchase-order-export', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
# Response should be streaming-content (file download)
self.assertIn('streaming_content', dir(response))

View File

@ -84,7 +84,7 @@ class PurchaseOrderCreate(AjaxCreateView):
try:
supplier = Company.objects.get(id=supplier_id)
initials['supplier'] = supplier
except Company.DoesNotExist:
except (Company.DoesNotExist, ValueError):
pass
return initials

View File

@ -58,4 +58,4 @@
name: 'Bob'
description: 'Can we build it?'
assembly: true
purchaseable: false

View File

@ -0,0 +1,218 @@
""" Unit tests for Part Views (see views.py) """
from django.test import TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model
from .models import Part
class PartViewTestCase(TestCase):
fixtures = [
'category',
'part',
'bom',
'location',
'company',
'supplier_part',
]
def setUp(self):
super().setUp()
# Create a user
User = get_user_model()
User.objects.create_user('username', 'user@email.com', 'password')
self.client.login(username='username', password='password')
class PartListTest(PartViewTestCase):
def test_part_index(self):
response = self.client.get(reverse('part-index'))
self.assertEqual(response.status_code, 200)
keys = response.context.keys()
self.assertIn('csrf_token', keys)
self.assertIn('parts', keys)
self.assertIn('user', keys)
def test_export(self):
""" Export part data to CSV """
response = self.client.get(reverse('part-export'), {'parts': '1,2,3,4,5,6,7,8,9,10'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
self.assertIn('streaming_content', dir(response))
class PartDetailTest(PartViewTestCase):
def test_part_detail(self):
""" Test that we can retrieve a part detail page """
pk = 1
response = self.client.get(reverse('part-detail', args=(pk,)))
self.assertEqual(response.status_code, 200)
part = Part.objects.get(pk=pk)
keys = response.context.keys()
self.assertIn('part', keys)
self.assertIn('category', keys)
self.assertEqual(response.context['part'].pk, pk)
self.assertEqual(response.context['category'], part.category)
self.assertFalse(response.context['editing_enabled'])
def test_editable(self):
pk = 1
response = self.client.get(reverse('part-detail', args=(pk,)), {'edit': True})
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context['editing_enabled'])
def test_bom_download(self):
""" Test downloading a BOM for a valid part """
response = self.client.get(reverse('bom-export', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
self.assertIn('streaming_content', dir(response))
class PartTests(PartViewTestCase):
""" Tests for Part forms """
def test_part_edit(self):
response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
keys = response.context.keys()
data = str(response.content)
self.assertIn('part', keys)
self.assertIn('csrf_token', keys)
self.assertIn('html_form', data)
self.assertIn('"title":', data)
def test_part_create(self):
""" Launch form to create a new part """
response = self.client.get(reverse('part-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# And again, with an invalid category
response = self.client.get(reverse('part-create'), {'category': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# And again, with no category
response = self.client.get(reverse('part-create'), {'name': 'Test part'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_part_duplicate(self):
""" Launch form to duplicate part """
# First try with an invalid part
response = self.client.get(reverse('part-duplicate', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse('part-duplicate', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_make_variant(self):
response = self.client.get(reverse('make-part-variant', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
class PartAttachmentTests(PartViewTestCase):
def test_valid_create(self):
""" test creation of an attachment for a valid part """
response = self.client.get(reverse('part-attachment-create'), {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_invalid_create(self):
""" test creation of an attachment for an invalid part """
with self.assertRaises(Part.DoesNotExist):
self.client.get(reverse('part-attachment-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
def test_edit(self):
""" test editing an attachment """
# TODO
pass
class PartQRTest(PartViewTestCase):
""" Tests for the Part QR Code AJAX view """
def test_html_redirect(self):
# A HTML request for a QR code should be redirected (use an AJAX request instead)
response = self.client.get(reverse('part-qr', args=(1,)))
self.assertEqual(response.status_code, 302)
def test_valid_part(self):
response = self.client.get(reverse('part-qr', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
data = str(response.content)
self.assertIn('Part QR Code', data)
self.assertIn('<img src=', data)
def test_invalid_part(self):
response = self.client.get(reverse('part-qr', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
data = str(response.content)
self.assertIn('Error:', data)
class CategoryTest(PartViewTestCase):
""" Tests for PartCategory related views """
def test_create(self):
""" Test view for creating a new category """
response = self.client.get(reverse('category-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_create_invalid_parent(self):
""" test creation of a new category with an invalid parent """
response = self.client.get(reverse('category-create'), {'category': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
# Form should still return OK
self.assertEqual(response.status_code, 200)
def test_edit(self):
""" Retrieve the part category editing form """
response = self.client.get(reverse('category-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
class BomItemTests(PartViewTestCase):
""" Tests for BomItem related views """
def test_create_valid_parent(self):
""" Create a BomItem for a valid part """
response = self.client.get(reverse('bom-item-create'), {'parent': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_create_no_parent(self):
""" Create a BomItem without a parent """
response = self.client.get(reverse('bom-item-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_create_invalid_parent(self):
""" Create a BomItem with an invalid parent """
response = self.client.get(reverse('bom-item-create'), {'parent': 99999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)

View File

@ -295,7 +295,7 @@ class PartDuplicate(AjaxCreateView):
def get_part_to_copy(self):
try:
return Part.objects.get(id=self.kwargs['pk'])
except Part.DoesNotExist:
except (Part.DoesNotExist, ValueError):
return None
def get_context_data(self):
@ -419,7 +419,7 @@ class PartCreate(AjaxCreateView):
if cat_id:
try:
context['category'] = PartCategory.objects.get(pk=cat_id)
except PartCategory.DoesNotExist:
except (PartCategory.DoesNotExist, ValueError):
pass
return context
@ -494,7 +494,7 @@ class PartCreate(AjaxCreateView):
category = PartCategory.objects.get(pk=self.get_category_id())
initials['category'] = category
initials['keywords'] = category.default_keywords
except PartCategory.DoesNotExist:
except (PartCategory.DoesNotExist, ValueError):
pass
# Allow initial data to be passed through as arguments

View File

@ -0,0 +1,130 @@
""" Unit tests for Stock views (see views.py) """
from django.test import TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model
class StockViewTestCase(TestCase):
fixtures = [
'category',
'part',
'company',
'location',
'supplier_part',
'stock',
]
def setUp(self):
super().setUp()
# Create a user
User = get_user_model()
User.objects.create_user('username', 'user@email.com', 'password')
self.client.login(username='username', password='password')
class StockListTest(StockViewTestCase):
""" Tests for Stock list views """
def test_stock_index(self):
response = self.client.get(reverse('stock-index'))
self.assertEqual(response.status_code, 200)
class StockLocationTest(StockViewTestCase):
""" Tests for StockLocation views """
def test_location_edit(self):
response = self.client.get(reverse('stock-location-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_qr_code(self):
# Request the StockLocation QR view
response = self.client.get(reverse('stock-location-qr', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Test for an invalid StockLocation
response = self.client.get(reverse('stock-location-qr', args=(999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_create(self):
# Test StockLocation creation view
response = self.client.get(reverse('stock-location-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Create with a parent
response = self.client.get(reverse('stock-location-create'), {'location': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Create with an invalid parent
response = self.client.get(reverse('stock-location-create'), {'location': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
class StockItemTest(StockViewTestCase):
"""" Tests for StockItem views """
def test_qr_code(self):
# QR code for a valid item
response = self.client.get(reverse('stock-item-qr', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# QR code for an invalid item
response = self.client.get(reverse('stock-item-qr', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
data = str(response.content)
self.assertIn('Error:', data)
def test_adjust_items(self):
url = reverse('stock-adjust')
# Move items
response = self.client.get(url, {'stock[]': [1, 2, 3, 4, 5], 'action': 'move'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Count part
response = self.client.get(url, {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Remove items
response = self.client.get(url, {'location': 1, 'action': 'take'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Add items
response = self.client.get(url, {'item': 1, 'action': 'add'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Blank response
response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# TODO - Tests for POST data
def test_edit_item(self):
# Test edit view for StockItem
response = self.client.get(reverse('stock-item-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Test with a non-purchaseable part
response = self.client.get(reverse('stock-item-edit', args=(100,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
def test_create_item(self):
# Test creation of StockItem
response = self.client.get(reverse('stock-item-create'), {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse('stock-item-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Copy from a valid item, valid location
response = self.client.get(reverse('stock-item-create'), {'location': 1, 'copy': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# Copy from an invalid item, invalid location
response = self.client.get(reverse('stock-item-create'), {'location': 999, 'copy': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)

View File

@ -168,9 +168,9 @@ class StockAdjust(AjaxView, FormMixin):
elif 'item' in self.request.GET:
items = [StockItem.objects.get(id=self.request.GET.get('item'))]
# Unsupported query
# Unsupported query (no items)
else:
items = None
items = []
for item in items: