Merge branch 'develop' into feature/unit-conversion
# Conflicts: # requirements.txt
This commit is contained in:
@ -6,7 +6,7 @@ from django.urls import reverse
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from pytest_factoryboy import LazyFixture, register
|
||||
|
||||
from cookbook.models import Food, FoodInheritField, Ingredient, ShoppingList, ShoppingListEntry
|
||||
from cookbook.models import Food, Ingredient, ShoppingListEntry
|
||||
from cookbook.tests.factories import (FoodFactory, IngredientFactory, ShoppingListEntryFactory,
|
||||
SupermarketCategoryFactory)
|
||||
|
||||
@ -56,23 +56,32 @@ def obj_tree_1(request, space_1):
|
||||
params = request.param # request.param is a magic variable
|
||||
except AttributeError:
|
||||
params = {}
|
||||
objs = []
|
||||
inherit = params.pop('inherit', False)
|
||||
objs.extend(FoodFactory.create_batch(3, space=space_1, **params))
|
||||
FoodFactory.create_batch(3, space=space_1, **params)
|
||||
objs = Food.objects.values_list('id', flat=True)
|
||||
obj_id = objs[1]
|
||||
child_id = objs[0]
|
||||
parent_id = objs[2]
|
||||
|
||||
# set all foods to inherit everything
|
||||
if inherit:
|
||||
inherit = Food.inheritable_fields
|
||||
Through = Food.objects.filter(space=space_1).first().inherit_fields.through
|
||||
Through = Food.objects.filter(
|
||||
space=space_1).first().inherit_fields.through
|
||||
for i in inherit:
|
||||
Through.objects.bulk_create([
|
||||
Through(food_id=x, foodinheritfield_id=i.id)
|
||||
for x in Food.objects.filter(space=space_1).values_list('id', flat=True)
|
||||
])
|
||||
|
||||
objs[0].move(objs[1], node_location)
|
||||
objs[1].move(objs[2], node_location)
|
||||
return Food.objects.get(id=objs[1].id) # whenever you move/merge a tree it's safest to re-get the object
|
||||
Food.objects.get(id=child_id).move(
|
||||
Food.objects.get(id=obj_id), node_location)
|
||||
|
||||
Food.objects.get(id=obj_id).move(
|
||||
Food.objects.get(id=parent_id), node_location)
|
||||
|
||||
# whenever you move/merge a tree it's safest to re-get the object
|
||||
return Food.objects.get(id=obj_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
@ -107,19 +116,23 @@ def test_list_filter(obj_1, obj_2, u1_s1):
|
||||
assert obj_2.name in [x['name'] for x in response['results']]
|
||||
assert response['results'][0]['name'] < response['results'][1]['name']
|
||||
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?page_size=1').content)
|
||||
response = json.loads(
|
||||
u1_s1.get(f'{reverse(LIST_URL)}?page_size=1').content)
|
||||
assert len(response['results']) == 1
|
||||
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?limit=1').content)
|
||||
assert len(response['results']) == 1
|
||||
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query=''&limit=1').content)
|
||||
response = json.loads(
|
||||
u1_s1.get(f'{reverse(LIST_URL)}?query=''&limit=1').content)
|
||||
assert len(response['results']) == 1
|
||||
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query=chicken').content)
|
||||
response = json.loads(
|
||||
u1_s1.get(f'{reverse(LIST_URL)}?query=chicken').content)
|
||||
assert response['count'] == 0
|
||||
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?query={obj_1.name[:-4]}').content)
|
||||
response = json.loads(
|
||||
u1_s1.get(f'{reverse(LIST_URL)}?query={obj_1.name[:-4]}').content)
|
||||
assert response['count'] == 1
|
||||
|
||||
|
||||
@ -262,8 +275,9 @@ def test_integrity(u1_s1, recipe_1_s1):
|
||||
|
||||
def test_move(u1_s1, obj_tree_1, obj_2, obj_3, space_1):
|
||||
with scope(space=space_1):
|
||||
# for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj
|
||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
assert parent.get_num_children() == 1
|
||||
assert parent.get_descendant_count() == 2
|
||||
assert Food.get_root_nodes().filter(space=space_1).count() == 2
|
||||
@ -295,8 +309,9 @@ def test_move(u1_s1, obj_tree_1, obj_2, obj_3, space_1):
|
||||
|
||||
def test_move_errors(u1_s1, obj_tree_1, obj_3, space_1):
|
||||
with scope(space=space_1):
|
||||
# for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj
|
||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
# move child to root
|
||||
r = u1_s1.put(reverse(MOVE_URL, args=[obj_tree_1.id, 0]))
|
||||
assert r.status_code == 200
|
||||
@ -351,7 +366,7 @@ def test_merge_shopping_entries(obj_tree_1, u1_s1, space_1):
|
||||
with scope(space=space_1):
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
ShoppingListEntryFactory.create(food=parent, space=space_1)
|
||||
ShoppingListEntryFactory.create(food=parent, space=space_1)
|
||||
ShoppingListEntryFactory.create(food=child, space=space_1)
|
||||
assert parent.get_num_children() == 1
|
||||
assert parent.get_descendant_count() == 2
|
||||
@ -371,8 +386,10 @@ def test_merge_shopping_entries(obj_tree_1, u1_s1, space_1):
|
||||
assert obj_tree_1.shopping_entries.count() == 1 # now has child's ingredient
|
||||
|
||||
|
||||
def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1):
|
||||
def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1):
|
||||
with scope(space=space_1):
|
||||
# for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj
|
||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
assert parent.get_num_children() == 1
|
||||
@ -416,8 +433,9 @@ def test_merge(u1_s1, obj_tree_1, obj_1, obj_3, space_1):
|
||||
|
||||
def test_merge_errors(u1_s1, obj_tree_1, obj_3, space_1):
|
||||
with scope(space=space_1):
|
||||
# for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj
|
||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
|
||||
# attempt to merge with non-existent parent
|
||||
r = u1_s1.put(
|
||||
@ -451,44 +469,63 @@ def test_merge_errors(u1_s1, obj_tree_1, obj_3, space_1):
|
||||
|
||||
def test_root_filter(obj_tree_1, obj_2, obj_3, u1_s1):
|
||||
with scope(space=obj_tree_1.space):
|
||||
# for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj
|
||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
|
||||
# should return root objects in the space (obj_1, obj_2), ignoring query filters
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?root=0').content)
|
||||
assert len(response['results']) == 2
|
||||
|
||||
# django_tree bypasses ORM - best to retrieve all changed objects
|
||||
with scopes_disabled():
|
||||
obj_2.move(parent, node_location)
|
||||
obj_2 = Food.objects.get(id=obj_2.id)
|
||||
parent = Food.objects.get(id=parent.id)
|
||||
# should return direct children of parent (obj_tree_1, obj_2), ignoring query filters
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?root={parent.id}').content)
|
||||
response = json.loads(
|
||||
u1_s1.get(f'{reverse(LIST_URL)}?root={parent.id}').content)
|
||||
assert response['count'] == 2
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?root={parent.id}&query={obj_2.name[4:]}').content)
|
||||
response = json.loads(u1_s1.get(
|
||||
f'{reverse(LIST_URL)}?root={parent.id}&query={obj_2.name[4:]}').content)
|
||||
assert response['count'] == 2
|
||||
|
||||
|
||||
def test_tree_filter(obj_tree_1, obj_2, obj_3, u1_s1):
|
||||
with scope(space=obj_tree_1.space):
|
||||
# for some reason the 'path' attribute changes between the factory and the test when using both obj_tree and obj
|
||||
parent = obj_tree_1.get_parent()
|
||||
child = obj_tree_1.get_descendants()[0]
|
||||
obj_2.move(parent, node_location)
|
||||
obj_2 = Food.objects.get(id=obj_2.id)
|
||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||
parent = Food.objects.get(id=parent.id)
|
||||
|
||||
# should return full tree starting at parent (obj_tree_1, obj_2), ignoring query filters
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?tree={parent.id}').content)
|
||||
response = json.loads(
|
||||
u1_s1.get(f'{reverse(LIST_URL)}?tree={parent.id}').content)
|
||||
assert response['count'] == 4
|
||||
response = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?tree={parent.id}&query={obj_2.name[4:]}').content)
|
||||
response = json.loads(u1_s1.get(
|
||||
f'{reverse(LIST_URL)}?tree={parent.id}&query={obj_2.name[4:]}').content)
|
||||
assert response['count'] == 4
|
||||
|
||||
|
||||
# This is more about the model than the API - should this be moved to a different test?
|
||||
@pytest.mark.parametrize("obj_tree_1, field, inherit, new_val", [
|
||||
({'has_category': True, 'inherit': True}, 'supermarket_category', True, 'cat_1'),
|
||||
({'has_category': True, 'inherit': False}, 'supermarket_category', False, 'cat_1'),
|
||||
({'ignore_shopping': True, 'inherit': True}, 'ignore_shopping', True, 'false'),
|
||||
({'ignore_shopping': True, 'inherit': False}, 'ignore_shopping', False, 'false'),
|
||||
({'substitute_children': True, 'inherit': True}, 'substitute_children', True, 'false'),
|
||||
({'substitute_children': True, 'inherit': False}, 'substitute_children', False, 'false'),
|
||||
({'substitute_siblings': True, 'inherit': True}, 'substitute_siblings', True, 'false'),
|
||||
({'substitute_siblings': True, 'inherit': False}, 'substitute_siblings', False, 'false'),
|
||||
({'has_category': True, 'inherit': True},
|
||||
'supermarket_category', True, 'cat_1'),
|
||||
({'has_category': True, 'inherit': False},
|
||||
'supermarket_category', False, 'cat_1'),
|
||||
({'ignore_shopping': True, 'inherit': True}, 'ignore_shopping', True, 'false'),
|
||||
({'ignore_shopping': True, 'inherit': False},
|
||||
'ignore_shopping', False, 'false'),
|
||||
({'substitute_children': True, 'inherit': True},
|
||||
'substitute_children', True, 'false'),
|
||||
({'substitute_children': True, 'inherit': False},
|
||||
'substitute_children', False, 'false'),
|
||||
({'substitute_siblings': True, 'inherit': True},
|
||||
'substitute_siblings', True, 'false'),
|
||||
({'substitute_siblings': True, 'inherit': False},
|
||||
'substitute_siblings', False, 'false'),
|
||||
], indirect=['obj_tree_1']) # indirect=True populates magic variable request.param of obj_tree_1 with the parameter
|
||||
def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1):
|
||||
with scope(space=obj_tree_1.space):
|
||||
@ -498,8 +535,10 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1):
|
||||
new_val = request.getfixturevalue(new_val)
|
||||
# if this test passes it demonstrates that inheritance works
|
||||
# when moving to a parent as each food is created with a different category
|
||||
assert (getattr(parent, field) == getattr(obj_tree_1, field)) in [inherit, True]
|
||||
assert (getattr(obj_tree_1, field) == getattr(child, field)) in [inherit, True]
|
||||
assert (getattr(parent, field) == getattr(
|
||||
obj_tree_1, field)) in [inherit, True]
|
||||
assert (getattr(obj_tree_1, field) == getattr(
|
||||
child, field)) in [inherit, True]
|
||||
# change parent to a new value
|
||||
setattr(parent, field, new_val)
|
||||
with scope(space=parent.space):
|
||||
@ -515,7 +554,8 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1):
|
||||
|
||||
|
||||
@pytest.mark.parametrize("obj_tree_1", [
|
||||
({'has_category': True, 'inherit': False, 'ignore_shopping': True, 'substitute_children': True, 'substitute_siblings': True}),
|
||||
({'has_category': True, 'inherit': False, 'ignore_shopping': True,
|
||||
'substitute_children': True, 'substitute_siblings': True}),
|
||||
], indirect=['obj_tree_1'])
|
||||
@pytest.mark.parametrize("global_reset", [True, False])
|
||||
@pytest.mark.parametrize("field", ['ignore_shopping', 'substitute_children', 'substitute_siblings', 'supermarket_category'])
|
||||
@ -534,10 +574,13 @@ def test_reset_inherit_space_fields(obj_tree_1, space_1, global_reset, field):
|
||||
assert getattr(parent, field) != getattr(obj_tree_1, field)
|
||||
|
||||
if global_reset:
|
||||
space_1.food_inherit.add(*Food.inheritable_fields.values_list('id', flat=True)) # set default inherit fields
|
||||
# set default inherit fields
|
||||
space_1.food_inherit.add(
|
||||
*Food.inheritable_fields.values_list('id', flat=True))
|
||||
parent.reset_inheritance(space=space_1)
|
||||
else:
|
||||
obj_tree_1.child_inherit_fields.set(Food.inheritable_fields.values_list('id', flat=True))
|
||||
obj_tree_1.child_inherit_fields.set(
|
||||
Food.inheritable_fields.values_list('id', flat=True))
|
||||
obj_tree_1.save()
|
||||
parent.reset_inheritance(space=space_1, food=obj_tree_1)
|
||||
# djangotree bypasses ORM and need to be retrieved again
|
||||
@ -545,12 +588,14 @@ def test_reset_inherit_space_fields(obj_tree_1, space_1, global_reset, field):
|
||||
parent = Food.objects.get(id=parent.id)
|
||||
child = Food.objects.get(id=child.id)
|
||||
|
||||
assert (getattr(parent, field) == getattr(obj_tree_1, field)) == global_reset
|
||||
assert (getattr(parent, field) == getattr(
|
||||
obj_tree_1, field)) == global_reset
|
||||
assert getattr(obj_tree_1, field) == getattr(child, field)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("obj_tree_1", [
|
||||
({'has_category': True, 'inherit': False, 'ignore_shopping': True, 'substitute_children': True, 'substitute_siblings': True}),
|
||||
({'has_category': True, 'inherit': False, 'ignore_shopping': True,
|
||||
'substitute_children': True, 'substitute_siblings': True}),
|
||||
], indirect=['obj_tree_1'])
|
||||
@pytest.mark.parametrize("field", ['ignore_shopping', 'substitute_children', 'substitute_siblings', 'supermarket_category'])
|
||||
def test_reset_inherit_no_food_instances(obj_tree_1, space_1, field):
|
||||
@ -558,13 +603,17 @@ def test_reset_inherit_no_food_instances(obj_tree_1, space_1, field):
|
||||
parent = obj_tree_1.get_parent()
|
||||
Food.objects.all().delete()
|
||||
|
||||
space_1.food_inherit.add(*Food.inheritable_fields.values_list('id', flat=True)) # set default inherit fields
|
||||
# set default inherit fields
|
||||
space_1.food_inherit.add(
|
||||
*Food.inheritable_fields.values_list('id', flat=True))
|
||||
parent.reset_inheritance(space=space_1)
|
||||
|
||||
|
||||
def test_onhand(obj_1, u1_s1, u2_s1):
|
||||
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == False
|
||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == False
|
||||
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
||||
'food_onhand'] == False
|
||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
||||
'food_onhand'] == False
|
||||
|
||||
u1_s1.patch(
|
||||
reverse(
|
||||
@ -574,10 +623,13 @@ def test_onhand(obj_1, u1_s1, u2_s1):
|
||||
{'food_onhand': True},
|
||||
content_type='application/json'
|
||||
)
|
||||
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == True
|
||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == False
|
||||
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
||||
'food_onhand'] == True
|
||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
||||
'food_onhand'] == False
|
||||
|
||||
user1 = auth.get_user(u1_s1)
|
||||
user2 = auth.get_user(u2_s1)
|
||||
user1.userpreference.shopping_share.add(user2)
|
||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] == True
|
||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
||||
'food_onhand'] == True
|
||||
|
@ -1,20 +1,14 @@
|
||||
import json
|
||||
from datetime import timedelta
|
||||
|
||||
import factory
|
||||
import pytest
|
||||
# work around for bug described here https://stackoverflow.com/a/70312265/15762829
|
||||
from django.conf import settings
|
||||
from django.contrib import auth
|
||||
from django.forms import model_to_dict
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from pytest_factoryboy import LazyFixture, register
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.models import Food, Ingredient, ShoppingListEntry, Step
|
||||
from cookbook.tests.factories import (IngredientFactory, MealPlanFactory, RecipeFactory,
|
||||
StepFactory, UserFactory)
|
||||
from cookbook.models import Food, Ingredient
|
||||
from cookbook.tests.factories import MealPlanFactory, RecipeFactory, StepFactory, UserFactory
|
||||
|
||||
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
||||
'django.db.backends.postgresql']:
|
||||
@ -32,9 +26,12 @@ def user2(request, u1_s1):
|
||||
except AttributeError:
|
||||
params = {}
|
||||
user = auth.get_user(u1_s1)
|
||||
user.userpreference.mealplan_autoadd_shopping = params.get('mealplan_autoadd_shopping', True)
|
||||
user.userpreference.mealplan_autoinclude_related = params.get('mealplan_autoinclude_related', True)
|
||||
user.userpreference.mealplan_autoexclude_onhand = params.get('mealplan_autoexclude_onhand', True)
|
||||
user.userpreference.mealplan_autoadd_shopping = params.get(
|
||||
'mealplan_autoadd_shopping', True)
|
||||
user.userpreference.mealplan_autoinclude_related = params.get(
|
||||
'mealplan_autoinclude_related', True)
|
||||
user.userpreference.mealplan_autoexclude_onhand = params.get(
|
||||
'mealplan_autoexclude_onhand', True)
|
||||
user.userpreference.save()
|
||||
return u1_s1
|
||||
|
||||
@ -50,7 +47,6 @@ def recipe(request, space_1, u1_s1):
|
||||
return RecipeFactory(**params)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['g1_s1', 204],
|
||||
['u1_s1', 204],
|
||||
@ -59,11 +55,14 @@ def recipe(request, space_1, u1_s1):
|
||||
])
|
||||
@pytest.mark.parametrize("recipe, sle_count", [
|
||||
({}, 10),
|
||||
({'steps__recipe_count': 1}, 20), # shopping list from recipe with StepRecipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), # shopping list from recipe with food recipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), # shopping list from recipe with StepRecipe and food recipe
|
||||
# shopping list from recipe with StepRecipe
|
||||
({'steps__recipe_count': 1}, 20),
|
||||
# shopping list from recipe with food recipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19),
|
||||
# shopping list from recipe with StepRecipe and food recipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29),
|
||||
], indirect=['recipe'])
|
||||
def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1):
|
||||
def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
user = auth.get_user(c)
|
||||
user.userpreference.mealplan_autoadd_shopping = True
|
||||
@ -78,16 +77,20 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1):
|
||||
if r.status_code == 204: # skip anonymous user
|
||||
|
||||
r = json.loads(c.get(reverse(SHOPPING_LIST_URL)).content)
|
||||
assert len(r) == sle_count # recipe factory creates 10 ingredients by default
|
||||
# recipe factory creates 10 ingredients by default
|
||||
assert len(r) == sle_count
|
||||
assert [x['created_by']['id'] for x in r].count(user.id) == sle_count
|
||||
# user in space can't see shopping list
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0
|
||||
user.userpreference.shopping_share.add(auth.get_user(u2_s1))
|
||||
# after share, user in space can see shopping list
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
# confirm that the author of the recipe doesn't have access to shopping list
|
||||
if c != u1_s1:
|
||||
assert len(json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0
|
||||
assert len(json.loads(
|
||||
u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0
|
||||
|
||||
r = c.get(url)
|
||||
assert r.status_code == 405
|
||||
@ -99,9 +102,12 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1):
|
||||
|
||||
@pytest.mark.parametrize("recipe, sle_count", [
|
||||
({}, 10),
|
||||
({'steps__recipe_count': 1}, 20), # shopping list from recipe with StepRecipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), # shopping list from recipe with food recipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), # shopping list from recipe with StepRecipe and food recipe
|
||||
# shopping list from recipe with StepRecipe
|
||||
({'steps__recipe_count': 1}, 20),
|
||||
# shopping list from recipe with food recipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19),
|
||||
# shopping list from recipe with StepRecipe and food recipe
|
||||
({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29),
|
||||
], indirect=['recipe'])
|
||||
@pytest.mark.parametrize("use_mealplan", [(False), (True), ])
|
||||
def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u2_s1):
|
||||
@ -115,31 +121,33 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u
|
||||
user.userpreference.save()
|
||||
|
||||
if use_mealplan:
|
||||
mealplan = MealPlanFactory(space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe)
|
||||
mealplan = MealPlanFactory(
|
||||
space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe)
|
||||
else:
|
||||
u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}))
|
||||
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
|
||||
assert [x['created_by']['id'] for x in r].count(user.id) == sle_count
|
||||
all_ing = [x['ingredient'] for x in r]
|
||||
keep_ing = all_ing[1:-1] # remove first and last element
|
||||
del keep_ing[int(len(keep_ing)/2)] # remove a middle element
|
||||
del keep_ing[int(len(keep_ing) / 2)] # remove a middle element
|
||||
list_recipe = r[0]['list_recipe']
|
||||
amount_sum = sum([x['amount'] for x in r])
|
||||
|
||||
# test modifying shopping list as different user
|
||||
# test increasing servings size of recipe shopping list
|
||||
if use_mealplan:
|
||||
mealplan.servings = 2*recipe.servings
|
||||
mealplan.servings = 2 * recipe.servings
|
||||
mealplan.save()
|
||||
else:
|
||||
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
|
||||
{'list_recipe': list_recipe, 'servings': 2*recipe.servings},
|
||||
{'list_recipe': list_recipe, 'servings': 2 * recipe.servings},
|
||||
content_type='application/json'
|
||||
)
|
||||
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
|
||||
assert sum([x['amount'] for x in r]) == amount_sum * 2
|
||||
assert len(r) == sle_count
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
|
||||
# testing decreasing servings size of recipe shopping list
|
||||
if use_mealplan:
|
||||
@ -153,7 +161,8 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u
|
||||
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
|
||||
assert sum([x['amount'] for x in r]) == amount_sum * .5
|
||||
assert len(r) == sle_count
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
|
||||
# test removing 3 items from shopping list
|
||||
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
|
||||
@ -162,7 +171,8 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u
|
||||
)
|
||||
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
|
||||
assert len(r) == sle_count - 3
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count - 3
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count - 3
|
||||
|
||||
# add all ingredients to existing shopping list - don't change serving size
|
||||
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
|
||||
@ -172,14 +182,16 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u
|
||||
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
|
||||
assert sum([x['amount'] for x in r]) == amount_sum * .5
|
||||
assert len(r) == sle_count
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
|
||||
|
||||
|
||||
@pytest.mark.parametrize("user2, sle_count", [
|
||||
({'mealplan_autoadd_shopping': False}, (0, 18)),
|
||||
({'mealplan_autoinclude_related': False}, (9, 9)),
|
||||
({'mealplan_autoexclude_onhand': False}, (20, 20)),
|
||||
({'mealplan_autoexclude_onhand': False, 'mealplan_autoinclude_related': False}, (10, 10)),
|
||||
({'mealplan_autoexclude_onhand': False,
|
||||
'mealplan_autoinclude_related': False}, (10, 10)),
|
||||
], indirect=['user2'])
|
||||
@pytest.mark.parametrize("use_mealplan", [(False), (True), ])
|
||||
@pytest.mark.parametrize("recipe", [({'steps__recipe_count': 1})], indirect=['recipe'])
|
||||
@ -191,20 +203,24 @@ def test_shopping_recipe_userpreference(recipe, sle_count, use_mealplan, user2):
|
||||
food = Food.objects.get(id=ingredients[2].food.id)
|
||||
food.onhand_users.add(user)
|
||||
food.save()
|
||||
food = recipe.steps.exclude(step_recipe=None).first().step_recipe.steps.first().ingredients.first().food
|
||||
food = recipe.steps.exclude(step_recipe=None).first(
|
||||
).step_recipe.steps.first().ingredients.first().food
|
||||
food = Food.objects.get(id=food.id)
|
||||
food.onhand_users.add(user)
|
||||
food.save()
|
||||
|
||||
if use_mealplan:
|
||||
mealplan = MealPlanFactory(space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe)
|
||||
assert len(json.loads(user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[0]
|
||||
MealPlanFactory(
|
||||
space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe)
|
||||
assert len(json.loads(
|
||||
user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[0]
|
||||
else:
|
||||
user2.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}))
|
||||
assert len(json.loads(user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[1]
|
||||
assert len(json.loads(
|
||||
user2.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count[1]
|
||||
|
||||
|
||||
def test_shopping_recipe_mixed_authors(u1_s1, u2_s1,space_1):
|
||||
def test_shopping_recipe_mixed_authors(u1_s1, u2_s1, space_1):
|
||||
with scopes_disabled():
|
||||
user1 = auth.get_user(u1_s1)
|
||||
user2 = auth.get_user(u2_s1)
|
||||
@ -213,15 +229,19 @@ def test_shopping_recipe_mixed_authors(u1_s1, u2_s1,space_1):
|
||||
recipe1 = RecipeFactory(created_by=user1, space=space)
|
||||
recipe2 = RecipeFactory(created_by=user2, space=space)
|
||||
recipe3 = RecipeFactory(created_by=user3, space=space)
|
||||
food = Food.objects.get(id=recipe1.steps.first().ingredients.first().food.id)
|
||||
food = Food.objects.get(
|
||||
id=recipe1.steps.first().ingredients.first().food.id)
|
||||
food.recipe = recipe2
|
||||
food.save()
|
||||
recipe1.steps.add(StepFactory(step_recipe=recipe3, ingredients__count=0, space=space))
|
||||
recipe1.steps.add(StepFactory(step_recipe=recipe3,
|
||||
ingredients__count=0, space=space))
|
||||
recipe1.save()
|
||||
|
||||
u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe1.id}))
|
||||
assert len(json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 29
|
||||
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0
|
||||
assert len(json.loads(
|
||||
u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 29
|
||||
assert len(json.loads(
|
||||
u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("recipe", [{'steps__ingredients__header': 1}], indirect=['recipe'])
|
||||
@ -230,4 +250,5 @@ def test_shopping_with_header_ingredient(u1_s1, recipe):
|
||||
# recipe.step_set.first().ingredient_set.add(IngredientFactory(ingredients__header=1))
|
||||
u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}))
|
||||
assert len(json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)) == 10
|
||||
assert len(json.loads(u1_s1.get(reverse('api:ingredient-list')).content)['results']) == 11
|
||||
assert len(json.loads(
|
||||
u1_s1.get(reverse('api:ingredient-list')).content)['results']) == 11
|
||||
|
@ -5,12 +5,11 @@ import uuid
|
||||
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django_scopes import scopes_disabled
|
||||
from pytest_factoryboy import LazyFixture, register
|
||||
from pytest_factoryboy import register
|
||||
|
||||
from cookbook.models import Food, Ingredient, Recipe, Space, Step, Unit
|
||||
from cookbook.tests.factories import FoodFactory, SpaceFactory, UserFactory
|
||||
from cookbook.models import Food, Ingredient, Recipe, Step, Unit
|
||||
from cookbook.tests.factories import SpaceFactory, UserFactory
|
||||
|
||||
register(SpaceFactory, 'space_1')
|
||||
register(SpaceFactory, 'space_2')
|
||||
@ -60,8 +59,10 @@ def get_random_recipe(space_1, u1_s1):
|
||||
internal=True,
|
||||
)
|
||||
|
||||
s1 = Step.objects.create(name=str(uuid.uuid4()), instruction=str(uuid.uuid4()), space=space_1, )
|
||||
s2 = Step.objects.create(name=str(uuid.uuid4()), instruction=str(uuid.uuid4()), space=space_1, )
|
||||
s1 = Step.objects.create(name=str(uuid.uuid4()),
|
||||
instruction=str(uuid.uuid4()), space=space_1, )
|
||||
s2 = Step.objects.create(name=str(uuid.uuid4()),
|
||||
instruction=str(uuid.uuid4()), space=space_1, )
|
||||
|
||||
r.steps.add(s1)
|
||||
r.steps.add(s2)
|
||||
@ -70,8 +71,10 @@ def get_random_recipe(space_1, u1_s1):
|
||||
s1.ingredients.add(
|
||||
Ingredient.objects.create(
|
||||
amount=1,
|
||||
food=Food.objects.get_or_create(name=str(uuid.uuid4()), space=space_1)[0],
|
||||
unit=Unit.objects.create(name=str(uuid.uuid4()), space=space_1, ),
|
||||
food=Food.objects.get_or_create(
|
||||
name=str(uuid.uuid4()), space=space_1)[0],
|
||||
unit=Unit.objects.create(
|
||||
name=str(uuid.uuid4()), space=space_1, ),
|
||||
note=str(uuid.uuid4()),
|
||||
space=space_1,
|
||||
)
|
||||
@ -80,8 +83,10 @@ def get_random_recipe(space_1, u1_s1):
|
||||
s2.ingredients.add(
|
||||
Ingredient.objects.create(
|
||||
amount=1,
|
||||
food=Food.objects.get_or_create(name=str(uuid.uuid4()), space=space_1)[0],
|
||||
unit=Unit.objects.create(name=str(uuid.uuid4()), space=space_1, ),
|
||||
food=Food.objects.get_or_create(
|
||||
name=str(uuid.uuid4()), space=space_1)[0],
|
||||
unit=Unit.objects.create(
|
||||
name=str(uuid.uuid4()), space=space_1, ),
|
||||
note=str(uuid.uuid4()),
|
||||
space=space_1,
|
||||
)
|
||||
@ -99,8 +104,10 @@ def get_random_json_recipe():
|
||||
{
|
||||
"instruction": str(uuid.uuid4()),
|
||||
"ingredients": [
|
||||
{"food": {"name": str(uuid.uuid4())}, "unit": {"name": str(uuid.uuid4())}, "amount": random.randint(0, 10)},
|
||||
{"food": {"name": str(uuid.uuid4())}, "unit": {"name": str(uuid.uuid4())}, "amount": random.randint(0, 10)},
|
||||
{"food": {"name": str(uuid.uuid4())}, "unit": {"name": str(
|
||||
uuid.uuid4())}, "amount": random.randint(0, 10)},
|
||||
{"food": {"name": str(uuid.uuid4())}, "unit": {"name": str(
|
||||
uuid.uuid4())}, "amount": random.randint(0, 10)},
|
||||
],
|
||||
}
|
||||
],
|
||||
@ -133,7 +140,8 @@ def validate_recipe(expected, recipe):
|
||||
for key in expected_lists:
|
||||
for k in expected_lists[key]:
|
||||
try:
|
||||
print('comparing ', any([dict_compare(k, i) for i in target_lists[key]]))
|
||||
print('comparing ', any([dict_compare(k, i)
|
||||
for i in target_lists[key]]))
|
||||
assert any([dict_compare(k, i) for i in target_lists[key]])
|
||||
except AssertionError:
|
||||
for result in [dict_compare(k, i, details=True) for i in target_lists[key]]:
|
||||
@ -152,7 +160,8 @@ def dict_compare(d1, d2, details=False):
|
||||
added = d1_keys - d2_keys
|
||||
removed = d2_keys - d1_keys
|
||||
modified = {o: (d1[o], d2[o]) for o in not_dicts if d1[o] != d2[o]}
|
||||
modified_dicts = {o: (d1[o], d2[o]) for o in sub_dicts if not d1[o].items() <= d2[o].items()}
|
||||
modified_dicts = {o: (d1[o], d2[o])
|
||||
for o in sub_dicts if not d1[o].items() <= d2[o].items()}
|
||||
if details:
|
||||
return added, removed, modified, modified_dicts
|
||||
else:
|
||||
@ -173,12 +182,12 @@ def transpose(text, number=2):
|
||||
positions = random.sample(range(len(tokens[token_pos])), number)
|
||||
|
||||
# swap the positions
|
||||
l = list(tokens[token_pos])
|
||||
lt = list(tokens[token_pos])
|
||||
for first, second in zip(positions[::2], positions[1::2]):
|
||||
l[first], l[second] = l[second], l[first]
|
||||
lt[first], lt[second] = lt[second], lt[first]
|
||||
|
||||
# replace original tokens with swapped
|
||||
tokens[token_pos] = ''.join(l)
|
||||
tokens[token_pos] = ''.join(lt)
|
||||
|
||||
# return text with the swapped token
|
||||
return ' '.join(tokens)
|
||||
|
@ -4,13 +4,12 @@ from decimal import Decimal
|
||||
|
||||
import factory
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django_scopes import scopes_disabled
|
||||
from faker import Factory as FakerFactory
|
||||
from pytest_factoryboy import register
|
||||
|
||||
from cookbook.models import Recipe, Step, UserSpace
|
||||
from cookbook.models import UserSpace
|
||||
|
||||
# this code will run immediately prior to creating the model object useful when you want a reverse relationship
|
||||
# log = factory.RelatedFactory(
|
||||
@ -53,7 +52,8 @@ class SpaceFactory(factory.django.DjangoModelFactory):
|
||||
class UserFactory(factory.django.DjangoModelFactory):
|
||||
|
||||
"""User factory."""
|
||||
username = factory.LazyAttribute(lambda x: faker.simple_profile()['username'])
|
||||
username = factory.LazyAttribute(
|
||||
lambda x: faker.simple_profile()['username'])
|
||||
first_name = factory.LazyAttribute(lambda x: faker.first_name())
|
||||
last_name = factory.LazyAttribute(lambda x: faker.last_name())
|
||||
email = factory.LazyAttribute(lambda x: faker.email())
|
||||
@ -65,7 +65,8 @@ class UserFactory(factory.django.DjangoModelFactory):
|
||||
return
|
||||
|
||||
if extracted:
|
||||
us = UserSpace.objects.create(space=self.space, user=self, active=True)
|
||||
us = UserSpace.objects.create(
|
||||
space=self.space, user=self, active=True)
|
||||
us.groups.add(Group.objects.get(name=extracted))
|
||||
|
||||
@factory.post_generation
|
||||
@ -75,10 +76,12 @@ class UserFactory(factory.django.DjangoModelFactory):
|
||||
|
||||
if extracted:
|
||||
for prefs in extracted:
|
||||
self.userpreference[prefs] = extracted[prefs]/0 # intentionally break so it can be debugged later
|
||||
# intentionally break so it can be debugged later
|
||||
self.userpreference[prefs] = extracted[prefs] / 0
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
django_get_or_create = ('username', 'space',)
|
||||
|
||||
|
||||
@register
|
||||
@ -98,18 +101,22 @@ class SupermarketCategoryFactory(factory.django.DjangoModelFactory):
|
||||
class FoodFactory(factory.django.DjangoModelFactory):
|
||||
"""Food factory."""
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)[:128])
|
||||
plural_name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3, variable_nb_words=False))
|
||||
plural_name = factory.LazyAttribute(
|
||||
lambda x: faker.sentence(nb_words=3, variable_nb_words=False))
|
||||
description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10))
|
||||
supermarket_category = factory.Maybe(
|
||||
factory.LazyAttribute(lambda x: x.has_category),
|
||||
yes_declaration=factory.SubFactory(SupermarketCategoryFactory, space=factory.SelfAttribute('..space')),
|
||||
factory.LazyAttribute(lambda x: x.has_category),
|
||||
yes_declaration=factory.SubFactory(
|
||||
SupermarketCategoryFactory, space=factory.SelfAttribute('..space')),
|
||||
no_declaration=None
|
||||
)
|
||||
recipe = factory.Maybe(
|
||||
factory.LazyAttribute(lambda x: x.has_recipe),
|
||||
yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')),
|
||||
factory.LazyAttribute(lambda x: x.has_recipe),
|
||||
yes_declaration=factory.SubFactory(
|
||||
'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')),
|
||||
no_declaration=None
|
||||
)
|
||||
path = None
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
@factory.post_generation
|
||||
@ -127,17 +134,19 @@ class FoodFactory(factory.django.DjangoModelFactory):
|
||||
|
||||
class Meta:
|
||||
model = 'cookbook.Food'
|
||||
django_get_or_create = ('name', 'plural_name', 'space',)
|
||||
django_get_or_create = ('name', 'plural_name', 'path', 'space',)
|
||||
|
||||
|
||||
@register
|
||||
class RecipeBookFactory(factory.django.DjangoModelFactory):
|
||||
"""RecipeBook factory."""
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3, variable_nb_words=False))
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(
|
||||
nb_words=3, variable_nb_words=False))
|
||||
description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10))
|
||||
icon = None
|
||||
# shared = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
filter = None
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
@ -149,7 +158,8 @@ class RecipeBookFactory(factory.django.DjangoModelFactory):
|
||||
@register
|
||||
class RecipeBookEntryFactory(factory.django.DjangoModelFactory):
|
||||
"""RecipeBookEntry factory."""
|
||||
book = factory.SubFactory(RecipeBookFactory, space=factory.SelfAttribute('..recipe.space'))
|
||||
book = factory.SubFactory(
|
||||
RecipeBookFactory, space=factory.SelfAttribute('..recipe.space'))
|
||||
recipe = None
|
||||
|
||||
class Meta:
|
||||
@ -173,7 +183,8 @@ class UnitFactory(factory.django.DjangoModelFactory):
|
||||
@register
|
||||
class KeywordFactory(factory.django.DjangoModelFactory):
|
||||
"""Keyword factory."""
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=2, variable_nb_words=False))
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(
|
||||
nb_words=2, variable_nb_words=False))
|
||||
# icon = models.CharField(max_length=16, blank=True, null=True)
|
||||
description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10))
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
@ -184,15 +195,17 @@ class KeywordFactory(factory.django.DjangoModelFactory):
|
||||
|
||||
class Meta:
|
||||
model = 'cookbook.Keyword'
|
||||
django_get_or_create = ('name', 'space',)
|
||||
django_get_or_create = ('name', 'space')
|
||||
exclude = ('num')
|
||||
|
||||
|
||||
@register
|
||||
class IngredientFactory(factory.django.DjangoModelFactory):
|
||||
"""Ingredient factory."""
|
||||
food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space'))
|
||||
unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space'))
|
||||
food = factory.SubFactory(
|
||||
FoodFactory, space=factory.SelfAttribute('..space'))
|
||||
unit = factory.SubFactory(
|
||||
UnitFactory, space=factory.SelfAttribute('..space'))
|
||||
amount = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=10))
|
||||
note = factory.LazyAttribute(lambda x: faker.sentence(nb_words=8))
|
||||
is_header = False
|
||||
@ -210,7 +223,8 @@ class MealTypeFactory(factory.django.DjangoModelFactory):
|
||||
# icon =
|
||||
color = factory.LazyAttribute(lambda x: faker.safe_hex_color())
|
||||
default = False
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
class Meta:
|
||||
@ -220,14 +234,18 @@ class MealTypeFactory(factory.django.DjangoModelFactory):
|
||||
@register
|
||||
class MealPlanFactory(factory.django.DjangoModelFactory):
|
||||
recipe = factory.Maybe(
|
||||
factory.LazyAttribute(lambda x: x.has_recipe),
|
||||
yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')),
|
||||
factory.LazyAttribute(lambda x: x.has_recipe),
|
||||
yes_declaration=factory.SubFactory(
|
||||
'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')),
|
||||
no_declaration=None
|
||||
)
|
||||
servings = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=1000)/100))
|
||||
servings = factory.LazyAttribute(
|
||||
lambda x: Decimal(faker.random_int(min=1, max=1000) / 100))
|
||||
title = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5))
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
meal_type = factory.SubFactory(MealTypeFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
meal_type = factory.SubFactory(
|
||||
MealTypeFactory, space=factory.SelfAttribute('..space'))
|
||||
note = factory.LazyAttribute(lambda x: faker.paragraph())
|
||||
date = factory.LazyAttribute(lambda x: faker.future_date())
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
@ -243,12 +261,14 @@ class MealPlanFactory(factory.django.DjangoModelFactory):
|
||||
class ShoppingListRecipeFactory(factory.django.DjangoModelFactory):
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5))
|
||||
recipe = factory.Maybe(
|
||||
factory.LazyAttribute(lambda x: x.has_recipe),
|
||||
yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')),
|
||||
factory.LazyAttribute(lambda x: x.has_recipe),
|
||||
yes_declaration=factory.SubFactory(
|
||||
'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')),
|
||||
no_declaration=None
|
||||
)
|
||||
servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=10))
|
||||
mealplan = factory.SubFactory(MealPlanFactory, space=factory.SelfAttribute('..space'))
|
||||
mealplan = factory.SubFactory(
|
||||
MealPlanFactory, space=factory.SelfAttribute('..space'))
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
class Params:
|
||||
@ -263,26 +283,33 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory):
|
||||
"""ShoppingListEntry factory."""
|
||||
|
||||
list_recipe = factory.Maybe(
|
||||
factory.LazyAttribute(lambda x: x.has_mealplan),
|
||||
yes_declaration=factory.SubFactory(ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')),
|
||||
factory.LazyAttribute(lambda x: x.has_mealplan),
|
||||
yes_declaration=factory.SubFactory(
|
||||
ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')),
|
||||
no_declaration=None
|
||||
)
|
||||
food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space'))
|
||||
unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space'))
|
||||
food = factory.SubFactory(
|
||||
FoodFactory, space=factory.SelfAttribute('..space'))
|
||||
unit = factory.SubFactory(
|
||||
UnitFactory, space=factory.SelfAttribute('..space'))
|
||||
# # ingredient = factory.SubFactory(IngredientFactory)
|
||||
amount = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=100))/10)
|
||||
amount = factory.LazyAttribute(
|
||||
lambda x: Decimal(faker.random_int(min=1, max=100)) / 10)
|
||||
order = factory.Sequence(int)
|
||||
checked = False
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_at = factory.LazyAttribute(lambda x: faker.past_date())
|
||||
completed_at = None
|
||||
delay_until = None
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
@classmethod
|
||||
def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date
|
||||
# override create to prevent auto_add_now from changing the created_at date
|
||||
def _create(cls, target_class, *args, **kwargs):
|
||||
created_at = kwargs.pop('created_at', None)
|
||||
obj = super(ShoppingListEntryFactory, cls)._create(target_class, *args, **kwargs)
|
||||
obj = super(ShoppingListEntryFactory, cls)._create(
|
||||
target_class, *args, **kwargs)
|
||||
if created_at is not None:
|
||||
obj.created_at = created_at
|
||||
obj.save()
|
||||
@ -298,7 +325,8 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory):
|
||||
@register
|
||||
class StepFactory(factory.django.DjangoModelFactory):
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5))
|
||||
instruction = factory.LazyAttribute(lambda x: ''.join(faker.paragraphs(nb=5)))
|
||||
instruction = factory.LazyAttribute(
|
||||
lambda x: ''.join(faker.paragraphs(nb=5)))
|
||||
# TODO add optional recipe food, make dependent on recipe, make number of recipes a Params
|
||||
ingredients__count = 10 # default number of ingredients to add
|
||||
ingredients__header = 0
|
||||
@ -330,14 +358,16 @@ class StepFactory(factory.django.DjangoModelFactory):
|
||||
for i in range(num_ing):
|
||||
if num_food_recipe > 0:
|
||||
has_recipe = True
|
||||
num_food_recipe = num_food_recipe-1
|
||||
num_food_recipe = num_food_recipe - 1
|
||||
else:
|
||||
has_recipe = False
|
||||
self.ingredients.add(IngredientFactory(space=self.space, food__has_recipe=has_recipe))
|
||||
self.ingredients.add(IngredientFactory(
|
||||
space=self.space, food__has_recipe=has_recipe))
|
||||
num_header = kwargs.get('header', 0)
|
||||
if num_header > 0:
|
||||
for i in range(num_header):
|
||||
self.ingredients.add(IngredientFactory(food=None, unit=None, amount=0, is_header=True, space=self.space))
|
||||
self.ingredients.add(IngredientFactory(
|
||||
food=None, unit=None, amount=0, is_header=True, space=self.space))
|
||||
elif extracted:
|
||||
for ing in extracted:
|
||||
self.ingredients.add(ing)
|
||||
@ -351,20 +381,27 @@ class RecipeFactory(factory.django.DjangoModelFactory):
|
||||
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=7))
|
||||
description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10))
|
||||
servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=20))
|
||||
servings_text = factory.LazyAttribute(lambda x: faker.sentence(nb_words=1)) # TODO generate list of expected servings text that can be iterated through
|
||||
# TODO generate list of expected servings text that can be iterated through
|
||||
servings_text = factory.LazyAttribute(lambda x: faker.sentence(nb_words=1))
|
||||
keywords__count = 5 # default number of keywords to generate
|
||||
steps__count = 1 # default number of steps to create
|
||||
steps__recipe_count = 0 # default number of step recipes to create
|
||||
steps__food_recipe_count = {} # by default, don't create food recipes, to override {'steps__food_recipe_count': {'step': 0, 'count': 1}}
|
||||
working_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360))
|
||||
waiting_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360))
|
||||
# by default, don't create food recipes, to override {'steps__food_recipe_count': {'step': 0, 'count': 1}}
|
||||
steps__food_recipe_count = {}
|
||||
working_time = factory.LazyAttribute(
|
||||
lambda x: faker.random_int(min=0, max=360))
|
||||
waiting_time = factory.LazyAttribute(
|
||||
lambda x: faker.random_int(min=0, max=360))
|
||||
internal = False
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=date(2000, 1, 1), date_end=date(2020, 12, 31)))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(
|
||||
date_start=date(2000, 1, 1), date_end=date(2020, 12, 31)))
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
@classmethod
|
||||
def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date
|
||||
# override create to prevent auto_add_now from changing the created_at date
|
||||
def _create(cls, target_class, *args, **kwargs):
|
||||
created_at = kwargs.pop('created_at', None)
|
||||
# updated_at = kwargs.pop('updated_at', None)
|
||||
obj = super(RecipeFactory, cls)._create(target_class, *args, **kwargs)
|
||||
@ -401,11 +438,13 @@ class RecipeFactory(factory.django.DjangoModelFactory):
|
||||
ing_recipe_count = 0
|
||||
if food_recipe_count.get('step', None) == i:
|
||||
ing_recipe_count = food_recipe_count.get('count', 0)
|
||||
self.steps.add(StepFactory(space=self.space, ingredients__food_recipe_count=ing_recipe_count, ingredients__header=num_ing_headers))
|
||||
num_ing_headers+-1
|
||||
self.steps.add(StepFactory(
|
||||
space=self.space, ingredients__food_recipe_count=ing_recipe_count, ingredients__header=num_ing_headers))
|
||||
num_ing_headers + - 1
|
||||
if num_recipe_steps > 0:
|
||||
for j in range(num_recipe_steps):
|
||||
self.steps.add(StepFactory(space=self.space, step_recipe__has_recipe=True, ingredients__count=0))
|
||||
self.steps.add(StepFactory(
|
||||
space=self.space, step_recipe__has_recipe=True, ingredients__count=0))
|
||||
if extracted and (num_steps + num_recipe_steps == 0):
|
||||
for step in extracted:
|
||||
self.steps.add(step)
|
||||
@ -428,15 +467,18 @@ class RecipeFactory(factory.django.DjangoModelFactory):
|
||||
@register
|
||||
class CookLogFactory(factory.django.DjangoModelFactory):
|
||||
"""CookLog factory."""
|
||||
recipe = factory.SubFactory(RecipeFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
recipe = factory.SubFactory(
|
||||
RecipeFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_at = factory.LazyAttribute(lambda x: faker.date_this_decade())
|
||||
rating = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=5))
|
||||
servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=32))
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
@classmethod
|
||||
def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date
|
||||
# override create to prevent auto_add_now from changing the created_at date
|
||||
def _create(cls, target_class, *args, **kwargs):
|
||||
created_at = kwargs.pop('created_at', None)
|
||||
obj = super(CookLogFactory, cls)._create(target_class, *args, **kwargs)
|
||||
if created_at is not None:
|
||||
@ -451,13 +493,17 @@ class CookLogFactory(factory.django.DjangoModelFactory):
|
||||
@register
|
||||
class ViewLogFactory(factory.django.DjangoModelFactory):
|
||||
"""ViewLog factory."""
|
||||
recipe = factory.SubFactory(RecipeFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_at = factory.LazyAttribute(lambda x: faker.past_datetime(start_date='-365d'))
|
||||
recipe = factory.SubFactory(
|
||||
RecipeFactory, space=factory.SelfAttribute('..space'))
|
||||
created_by = factory.SubFactory(
|
||||
UserFactory, space=factory.SelfAttribute('..space'))
|
||||
created_at = factory.LazyAttribute(
|
||||
lambda x: faker.past_datetime(start_date='-365d'))
|
||||
space = factory.SubFactory(SpaceFactory)
|
||||
|
||||
@classmethod
|
||||
def _create(cls, target_class, *args, **kwargs): # override create to prevent auto_add_now from changing the created_at date
|
||||
# override create to prevent auto_add_now from changing the created_at date
|
||||
def _create(cls, target_class, *args, **kwargs):
|
||||
created_at = kwargs.pop('created_at', None)
|
||||
obj = super(ViewLogFactory, cls)._create(target_class, *args, **kwargs)
|
||||
if created_at is not None:
|
||||
|
@ -11,6 +11,11 @@ from cookbook.tests.factories import FoodFactory, RecipeFactory
|
||||
# TODO returns recipes with all ingredients via child substitute
|
||||
# TODO returns recipes with all ingredients via sibling substitute
|
||||
|
||||
if (Food.node_order_by):
|
||||
node_location = 'sorted-child'
|
||||
else:
|
||||
node_location = 'last-child'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def recipes(space_1):
|
||||
@ -19,7 +24,8 @@ def recipes(space_1):
|
||||
|
||||
@pytest.fixture
|
||||
def makenow_recipe(request, space_1):
|
||||
onhand_user = auth.get_user(request.getfixturevalue(request.param.get('onhand_users', 'u1_s1')))
|
||||
onhand_user = auth.get_user(request.getfixturevalue(
|
||||
request.param.get('onhand_users', 'u1_s1')))
|
||||
|
||||
recipe = RecipeFactory.create(space=space_1)
|
||||
for food in Food.objects.filter(ingredient__step__recipe=recipe.id):
|
||||
@ -55,13 +61,16 @@ def test_makenow_ignoreshopping(recipes, makenow_recipe, user1, space_1):
|
||||
request = type('', (object,), {'space': space_1, 'user': user1})()
|
||||
search = RecipeSearch(request, makenow='true')
|
||||
with scope(space=space_1):
|
||||
food = Food.objects.filter(ingredient__step__recipe=makenow_recipe.id).first()
|
||||
food = Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id).first()
|
||||
food.onhand_users.clear()
|
||||
assert search.get_queryset(Recipe.objects.all()).count() == 0
|
||||
food.ignore_shopping = True
|
||||
food.save()
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, ignore_shopping=True).count() == 1
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, ignore_shopping=True).count() == 1
|
||||
search = search.get_queryset(Recipe.objects.all())
|
||||
assert search.count() == 1
|
||||
assert search.first().id == makenow_recipe.id
|
||||
@ -74,13 +83,17 @@ def test_makenow_substitute(recipes, makenow_recipe, user1, space_1):
|
||||
request = type('', (object,), {'space': space_1, 'user': user1})()
|
||||
search = RecipeSearch(request, makenow='true')
|
||||
with scope(space=space_1):
|
||||
food = Food.objects.filter(ingredient__step__recipe=makenow_recipe.id).first()
|
||||
food = Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id).first()
|
||||
onhand_user = food.onhand_users.first()
|
||||
food.onhand_users.clear()
|
||||
assert search.get_queryset(Recipe.objects.all()).count() == 0
|
||||
food.substitute.add(FoodFactory.create(space=space_1, onhand_users=[onhand_user]))
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, substitute__isnull=False).count() == 1
|
||||
food.substitute.add(FoodFactory.create(
|
||||
space=space_1, onhand_users=[onhand_user]))
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, substitute__isnull=False).count() == 1
|
||||
|
||||
search = search.get_queryset(Recipe.objects.all())
|
||||
assert search.count() == 1
|
||||
@ -94,16 +107,20 @@ def test_makenow_child_substitute(recipes, makenow_recipe, user1, space_1):
|
||||
request = type('', (object,), {'space': space_1, 'user': user1})()
|
||||
search = RecipeSearch(request, makenow='true')
|
||||
with scope(space=space_1):
|
||||
food = Food.objects.filter(ingredient__step__recipe=makenow_recipe.id).first()
|
||||
food = Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id).first()
|
||||
onhand_user = food.onhand_users.first()
|
||||
food.onhand_users.clear()
|
||||
food.substitute_children = True
|
||||
food.save()
|
||||
assert search.get_queryset(Recipe.objects.all()).count() == 0
|
||||
new_food = FoodFactory.create(space=space_1, onhand_users=[onhand_user])
|
||||
new_food.move(food, 'first-child')
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, numchild__gt=0).count() == 1
|
||||
new_food = FoodFactory.create(
|
||||
space=space_1, onhand_users=[onhand_user])
|
||||
new_food.move(food, node_location)
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, numchild__gt=0).count() == 1
|
||||
search = search.get_queryset(Recipe.objects.all())
|
||||
assert search.count() == 1
|
||||
assert search.first().id == makenow_recipe.id
|
||||
@ -116,18 +133,22 @@ def test_makenow_sibling_substitute(recipes, makenow_recipe, user1, space_1):
|
||||
request = type('', (object,), {'space': space_1, 'user': user1})()
|
||||
search = RecipeSearch(request, makenow='true')
|
||||
with scope(space=space_1):
|
||||
food = Food.objects.filter(ingredient__step__recipe=makenow_recipe.id).first()
|
||||
food = Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id).first()
|
||||
onhand_user = food.onhand_users.first()
|
||||
food.onhand_users.clear()
|
||||
food.substitute_siblings = True
|
||||
food.save()
|
||||
assert search.get_queryset(Recipe.objects.all()).count() == 0
|
||||
new_parent = FoodFactory.create(space=space_1)
|
||||
new_sibling = FoodFactory.create(space=space_1, onhand_users=[onhand_user])
|
||||
new_sibling.move(new_parent, 'first-child')
|
||||
food.move(new_parent, 'first-child')
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(ingredient__step__recipe=makenow_recipe.id, depth=2).count() == 1
|
||||
new_sibling = FoodFactory.create(
|
||||
space=space_1, onhand_users=[onhand_user])
|
||||
new_sibling.move(new_parent, node_location)
|
||||
food.move(new_parent, node_location)
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, onhand_users__isnull=False).count() == 9
|
||||
assert Food.objects.filter(
|
||||
ingredient__step__recipe=makenow_recipe.id, depth=2).count() == 1
|
||||
search = search.get_queryset(Recipe.objects.all())
|
||||
assert search.count() == 1
|
||||
assert search.first().id == makenow_recipe.id
|
||||
|
@ -7,9 +7,9 @@ from django.conf import settings
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from django_scopes import scope
|
||||
|
||||
from cookbook.models import Food, Recipe, SearchFields
|
||||
from cookbook.models import Recipe, SearchFields
|
||||
from cookbook.tests.conftest import transpose
|
||||
from cookbook.tests.factories import (CookLogFactory, FoodFactory, IngredientFactory,
|
||||
KeywordFactory, RecipeBookEntryFactory, RecipeFactory,
|
||||
@ -23,7 +23,8 @@ from cookbook.tests.factories import (CookLogFactory, FoodFactory, IngredientFac
|
||||
# TODO makenow with above filters
|
||||
# TODO test search food/keywords including/excluding children
|
||||
LIST_URL = 'api:recipe-list'
|
||||
sqlite = settings.DATABASES['default']['ENGINE'] not in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']
|
||||
sqlite = settings.DATABASES['default']['ENGINE'] not in [
|
||||
'django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -50,26 +51,43 @@ def user1(request, space_1, u1_s1, unaccent):
|
||||
if params.get('fuzzy_lookups', False):
|
||||
user.searchpreference.lookup = True
|
||||
misspelled_result = 1
|
||||
else:
|
||||
user.searchpreference.lookup = False
|
||||
|
||||
if params.get('fuzzy_search', False):
|
||||
user.searchpreference.trigram.set(SearchFields.objects.all())
|
||||
misspelled_result = 1
|
||||
else:
|
||||
user.searchpreference.trigram.set([])
|
||||
|
||||
if params.get('icontains', False):
|
||||
user.searchpreference.icontains.set(SearchFields.objects.all())
|
||||
search_term = 'ghijklmn'
|
||||
else:
|
||||
user.searchpreference.icontains.set([])
|
||||
|
||||
if params.get('istartswith', False):
|
||||
user.searchpreference.istartswith.set(SearchFields.objects.all())
|
||||
search_term = 'abcdef'
|
||||
else:
|
||||
user.searchpreference.istartswith.set([])
|
||||
|
||||
if params.get('unaccent', False):
|
||||
user.searchpreference.unaccent.set(SearchFields.objects.all())
|
||||
misspelled_result *= 2
|
||||
result *= 2
|
||||
else:
|
||||
user.searchpreference.unaccent.set([])
|
||||
|
||||
# full text vectors are hard coded to use unaccent - put this after unaccent to override result
|
||||
if params.get('fulltext', False):
|
||||
user.searchpreference.fulltext.set(SearchFields.objects.all())
|
||||
# user.searchpreference.search = 'websearch'
|
||||
search_term = 'ghijklmn uvwxyz'
|
||||
result = 2
|
||||
else:
|
||||
user.searchpreference.fulltext.set([])
|
||||
|
||||
user.searchpreference.save()
|
||||
misspelled_term = transpose(search_term, number=3)
|
||||
return (u1_s1, result, misspelled_result, search_term, misspelled_term, params)
|
||||
@ -104,7 +122,8 @@ def found_recipe(request, space_1, accent, unaccent, u1_s1, u2_s1):
|
||||
obj2 = FoodFactory.create(name=accent, space=space_1)
|
||||
recipe1.steps.first().ingredients.add(IngredientFactory.create(food=obj1))
|
||||
recipe2.steps.first().ingredients.add(IngredientFactory.create(food=obj2))
|
||||
recipe3.steps.first().ingredients.add(IngredientFactory.create(food=obj1), IngredientFactory.create(food=obj2))
|
||||
recipe3.steps.first().ingredients.add(IngredientFactory.create(
|
||||
food=obj1), IngredientFactory.create(food=obj2))
|
||||
if request.param.get('keyword', None):
|
||||
obj1 = KeywordFactory.create(name=unaccent, space=space_1)
|
||||
obj2 = KeywordFactory.create(name=accent, space=space_1)
|
||||
@ -125,7 +144,8 @@ def found_recipe(request, space_1, accent, unaccent, u1_s1, u2_s1):
|
||||
obj2 = UnitFactory.create(name=accent, space=space_1)
|
||||
recipe1.steps.first().ingredients.add(IngredientFactory.create(unit=obj1))
|
||||
recipe2.steps.first().ingredients.add(IngredientFactory.create(unit=obj2))
|
||||
recipe3.steps.first().ingredients.add(IngredientFactory.create(unit=obj1), IngredientFactory.create(unit=obj2))
|
||||
recipe3.steps.first().ingredients.add(IngredientFactory.create(
|
||||
unit=obj1), IngredientFactory.create(unit=obj2))
|
||||
if request.param.get('name', None):
|
||||
recipe1.name = unaccent
|
||||
recipe2.name = accent
|
||||
@ -145,21 +165,32 @@ def found_recipe(request, space_1, accent, unaccent, u1_s1, u2_s1):
|
||||
i2.save()
|
||||
|
||||
if request.param.get('viewedon', None):
|
||||
ViewLogFactory.create(recipe=recipe1, created_by=user1, created_at=days_3, space=space_1)
|
||||
ViewLogFactory.create(recipe=recipe2, created_by=user1, created_at=days_30, space=space_1)
|
||||
ViewLogFactory.create(recipe=recipe3, created_by=user2, created_at=days_15, space=space_1)
|
||||
ViewLogFactory.create(recipe=recipe1, created_by=user1,
|
||||
created_at=days_3, space=space_1)
|
||||
ViewLogFactory.create(recipe=recipe2, created_by=user1,
|
||||
created_at=days_30, space=space_1)
|
||||
ViewLogFactory.create(recipe=recipe3, created_by=user2,
|
||||
created_at=days_15, space=space_1)
|
||||
if request.param.get('cookedon', None):
|
||||
CookLogFactory.create(recipe=recipe1, created_by=user1, created_at=days_3, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe2, created_by=user1, created_at=days_30, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe3, created_by=user2, created_at=days_15, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe1, created_by=user1,
|
||||
created_at=days_3, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe2, created_by=user1,
|
||||
created_at=days_30, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe3, created_by=user2,
|
||||
created_at=days_15, space=space_1)
|
||||
if request.param.get('timescooked', None):
|
||||
CookLogFactory.create_batch(5, recipe=recipe1, created_by=user1, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe2, created_by=user1, space=space_1)
|
||||
CookLogFactory.create_batch(3, recipe=recipe3, created_by=user2, space=space_1)
|
||||
CookLogFactory.create_batch(
|
||||
5, recipe=recipe1, created_by=user1, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe2, created_by=user1, space=space_1)
|
||||
CookLogFactory.create_batch(
|
||||
3, recipe=recipe3, created_by=user2, space=space_1)
|
||||
if request.param.get('rating', None):
|
||||
CookLogFactory.create(recipe=recipe1, created_by=user1, rating=5.0, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe2, created_by=user1, rating=1.0, space=space_1)
|
||||
CookLogFactory.create(recipe=recipe3, created_by=user2, rating=3.0, space=space_1)
|
||||
CookLogFactory.create(
|
||||
recipe=recipe1, created_by=user1, rating=5.0, space=space_1)
|
||||
CookLogFactory.create(
|
||||
recipe=recipe2, created_by=user1, rating=1.0, space=space_1)
|
||||
CookLogFactory.create(
|
||||
recipe=recipe3, created_by=user2, rating=3.0, space=space_1)
|
||||
|
||||
return (recipe1, recipe2, recipe3, obj1, obj2, request.param)
|
||||
|
||||
@ -188,7 +219,8 @@ def test_search_or_and_not(found_recipe, param_type, operator, recipes, u1_s1, s
|
||||
assert found_recipe[1].id in [x['id'] for x in r['results']]
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) + f'?{param1}&{param2}').content)
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) +
|
||||
f'?{param1}&{param2}').content)
|
||||
assert r['count'] == operator[1]
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
||||
@ -203,7 +235,8 @@ def test_search_or_and_not(found_recipe, param_type, operator, recipes, u1_s1, s
|
||||
assert found_recipe[1].id not in [x['id'] for x in r['results']]
|
||||
assert found_recipe[2].id not in [x['id'] for x in r['results']]
|
||||
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) + f'?{param1_not}&{param2_not}').content)
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) +
|
||||
f'?{param1_not}&{param2_not}').content)
|
||||
assert r['count'] == 10 + operator[2]
|
||||
assert found_recipe[2].id not in [x['id'] for x in r['results']]
|
||||
|
||||
@ -227,13 +260,14 @@ def test_search_units(found_recipe, recipes, u1_s1, space_1):
|
||||
assert found_recipe[1].id in [x['id'] for x in r['results']]
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) + f'?{param1}&{param2}').content)
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) +
|
||||
f'?{param1}&{param2}').content)
|
||||
assert r['count'] == 3
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sqlite, reason="requires PostgreSQL")
|
||||
@pytest.mark.parametrize("user1", itertools.product(
|
||||
@pytest.mark.parametrize("user1", itertools.product(
|
||||
[
|
||||
('fuzzy_search', True), ('fuzzy_search', False),
|
||||
('fuzzy_lookups', True), ('fuzzy_lookups', False)
|
||||
@ -245,22 +279,26 @@ def test_search_units(found_recipe, recipes, u1_s1, space_1):
|
||||
({'keyword': True}, 'keyword'),
|
||||
({'food': True}, 'food'),
|
||||
], indirect=['found_recipe'])
|
||||
def test_fuzzy_lookup(found_recipe, recipes, param_type, user1, space_1):
|
||||
def test_fuzzy_lookup(found_recipe, recipes, param_type, user1, space_1):
|
||||
with scope(space=space_1):
|
||||
list_url = f'api:{param_type}-list'
|
||||
param1 = f"query={user1[3]}"
|
||||
param2 = f"query={user1[4]}"
|
||||
|
||||
r = json.loads(user1[0].get(reverse(list_url) + f'?{param1}&limit=2').content)
|
||||
assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[3].id, found_recipe[4].id]]) == user1[1]
|
||||
r = json.loads(user1[0].get(reverse(list_url) +
|
||||
f'?{param1}&limit=2').content)
|
||||
assert len([x['id'] for x in r['results'] if x['id'] in [
|
||||
found_recipe[3].id, found_recipe[4].id]]) == user1[1]
|
||||
|
||||
r = json.loads(user1[0].get(reverse(list_url) + f'?{param2}&limit=10').content)
|
||||
assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[3].id, found_recipe[4].id]]) == user1[2]
|
||||
r = json.loads(user1[0].get(reverse(list_url) +
|
||||
f'?{param2}&limit=10').content)
|
||||
assert len([x['id'] for x in r['results'] if x['id'] in [
|
||||
found_recipe[3].id, found_recipe[4].id]]) == user1[2]
|
||||
|
||||
# commenting this out for general use - it is really slow
|
||||
# it should be run on occasion to ensure everything still works
|
||||
# @pytest.mark.skipif(sqlite and True, reason="requires PostgreSQL")
|
||||
# @pytest.mark.parametrize("user1", itertools.product(
|
||||
# @pytest.mark.parametrize("user1", itertools.product(
|
||||
# [
|
||||
# ('fuzzy_search', True), ('fuzzy_search', False),
|
||||
# ('fulltext', True), ('fulltext', False),
|
||||
@ -276,29 +314,35 @@ def test_fuzzy_lookup(found_recipe, recipes, param_type, user1, space_1):
|
||||
# ({'keyword': True}),
|
||||
# ({'food': True}),
|
||||
# ], indirect=['found_recipe'])
|
||||
# def test_search_string(found_recipe, recipes, user1, space_1):
|
||||
# # user array contains: user client, expected count of search, expected count of mispelled search, search string, mispelled search string, user search preferences
|
||||
# def test_search_string(found_recipe, recipes, user1, space_1):
|
||||
# with scope(space=space_1):
|
||||
# param1 = f"query={user1[3]}"
|
||||
# param2 = f"query={user1[4]}"
|
||||
|
||||
# r = json.loads(user1[0].get(reverse(LIST_URL) + f'?{param1}').content)
|
||||
# assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[0].id, found_recipe[1].id]]) == user1[1]
|
||||
# assert len([x['id'] for x in r['results'] if x['id'] in [
|
||||
# found_recipe[0].id, found_recipe[1].id]]) == user1[1]
|
||||
|
||||
# r = json.loads(user1[0].get(reverse(LIST_URL) + f'?{param2}').content)
|
||||
# assert len([x['id'] for x in r['results'] if x['id'] in [found_recipe[0].id, found_recipe[1].id]]) == user1[2]
|
||||
# assert len([x['id'] for x in r['results'] if x['id'] in [
|
||||
# found_recipe[0].id, found_recipe[1].id]]) == user1[2]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("found_recipe, param_type, result", [
|
||||
({'viewedon': True}, 'viewedon', (1, 1)),
|
||||
({'cookedon': True}, 'cookedon', (1, 1)),
|
||||
({'createdon': True}, 'createdon', (2, 12)), # created dates are not filtered by user
|
||||
({'createdon': True}, 'updatedon', (2, 12)), # updated dates are not filtered by user
|
||||
# created dates are not filtered by user
|
||||
({'createdon': True}, 'createdon', (2, 12)),
|
||||
# updated dates are not filtered by user
|
||||
({'createdon': True}, 'updatedon', (2, 12)),
|
||||
], indirect=['found_recipe'])
|
||||
def test_search_date(found_recipe, recipes, param_type, result, u1_s1, u2_s1, space_1):
|
||||
# force updated_at to equal created_at datetime
|
||||
with scope(space=space_1):
|
||||
for recipe in Recipe.objects.all():
|
||||
Recipe.objects.filter(id=recipe.id).update(updated_at=recipe.created_at)
|
||||
Recipe.objects.filter(id=recipe.id).update(
|
||||
updated_at=recipe.created_at)
|
||||
|
||||
date = (timezone.now() - timedelta(days=15)).strftime("%Y-%m-%d")
|
||||
param1 = f"?{param_type}={date}"
|
||||
@ -321,34 +365,34 @@ def test_search_date(found_recipe, recipes, param_type, result, u1_s1, u2_s1, sp
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
||||
|
||||
# TODO this is somehow screwed, probably the search itself, dont want to fix it for now
|
||||
# @pytest.mark.parametrize("found_recipe, param_type", [
|
||||
# ({'rating': True}, 'rating'),
|
||||
# ({'timescooked': True}, 'timescooked'),
|
||||
# ], indirect=['found_recipe'])
|
||||
# def test_search_count(found_recipe, recipes, param_type, u1_s1, u2_s1, space_1):
|
||||
# param1 = f'?{param_type}=3'
|
||||
# param2 = f'?{param_type}=-3'
|
||||
# param3 = f'?{param_type}=0'
|
||||
#
|
||||
# r = json.loads(u1_s1.get(reverse(LIST_URL) + param1).content)
|
||||
# assert r['count'] == 1
|
||||
# assert found_recipe[0].id in [x['id'] for x in r['results']]
|
||||
#
|
||||
# r = json.loads(u1_s1.get(reverse(LIST_URL) + param2).content)
|
||||
# assert r['count'] == 1
|
||||
# assert found_recipe[1].id in [x['id'] for x in r['results']]
|
||||
#
|
||||
# # test search for not rated/cooked
|
||||
# r = json.loads(u1_s1.get(reverse(LIST_URL) + param3).content)
|
||||
# assert r['count'] == 11
|
||||
# assert (found_recipe[0].id or found_recipe[1].id) not in [x['id'] for x in r['results']]
|
||||
#
|
||||
# # test matched returns for lte and gte searches
|
||||
# r = json.loads(u2_s1.get(reverse(LIST_URL) + param1).content)
|
||||
# assert r['count'] == 1
|
||||
# assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
#
|
||||
# r = json.loads(u2_s1.get(reverse(LIST_URL) + param2).content)
|
||||
# assert r['count'] == 1
|
||||
# assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
@pytest.mark.parametrize("found_recipe, param_type", [
|
||||
({'rating': True}, 'rating'),
|
||||
({'timescooked': True}, 'timescooked'),
|
||||
], indirect=['found_recipe'])
|
||||
def test_search_count(found_recipe, recipes, param_type, u1_s1, u2_s1, space_1):
|
||||
param1 = f'?{param_type}=3'
|
||||
param2 = f'?{param_type}=-3'
|
||||
param3 = f'?{param_type}=0'
|
||||
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) + param1).content)
|
||||
assert r['count'] == 1
|
||||
assert found_recipe[0].id in [x['id'] for x in r['results']]
|
||||
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) + param2).content)
|
||||
assert r['count'] == 1
|
||||
assert found_recipe[1].id in [x['id'] for x in r['results']]
|
||||
|
||||
# test search for not rated/cooked
|
||||
r = json.loads(u1_s1.get(reverse(LIST_URL) + param3).content)
|
||||
assert r['count'] == 11
|
||||
assert (found_recipe[0].id or found_recipe[1].id) not in [
|
||||
x['id'] for x in r['results']]
|
||||
|
||||
# test matched returns for lte and gte searches
|
||||
r = json.loads(u2_s1.get(reverse(LIST_URL) + param1).content)
|
||||
assert r['count'] == 1
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
||||
r = json.loads(u2_s1.get(reverse(LIST_URL) + param2).content)
|
||||
assert r['count'] == 1
|
||||
assert found_recipe[2].id in [x['id'] for x in r['results']]
|
||||
|
Reference in New Issue
Block a user