def test_selected_existing_already_in_active_item(self, charity, user): """Tests no new WantedItems are created if the item is already in WantedItem for the entity. """ items = ItemFactory.create_batch(11) items_conditions = [randint(0, 3) for _ in range(len(items))] WantedItem.objects.bulk_create( [ WantedItem(charity=charity, item=item, condition=condition) for item, condition in zip(items, items_conditions) ] ) assert WantedItem.objects.count() == 11 # Add lingering Item that isn't a part of entity yet random_item = ItemFactory.create() items.append(random_item) items_conditions.append(randint(0, 3)) # Create proposed item proposed = ProposedItem.objects.create( entity=charity, user=user, item=[item.id for item in items], item_condition=items_conditions, ) merge(charity, proposed) assert WantedItem.objects.count() == 12, "Only one item should've been added" assert WantedItem.objects.get(item=random_item) assert WantedItem.objects.distinct("item", "charity").count() == 12 for item, condition in zip(items, items_conditions): assert WantedItem.objects.filter( item=item, condition=condition, charity=charity ).exists() assert WantedItem.objects.filter(charity=charity, item=random_item).exists()
def test_dissimilar_item_names(self, rf): query = "chair" ItemFactory.create(name="blah blah") # DONATABLE BTW target = ItemFactory.create(name=query) request = rf.get("item/api/v1/item-autocomplete/", {"q": query}) response = search_item_autocomplete(request) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 1, f"Response {data}" assert data["data"][0] == [target.id, target.name, target.image]
def test_no_children(self, rf, user): parent = ItemFactory.create() progeny = ItemFactory.create_batch(9, parent=parent) request = rf.get("blah/") request.user = user response = item_children(request, progeny[0].id) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 0 assert data["data"] == []
def test_show_only_appropriate(self, rf): # Remember, "name" is unique. ItemFactory.create(name="chai", is_appropriate=False) ItemFactory.create(name="hair", is_appropriate=False) # DONATABLE BTW target = ItemFactory.create(name="chair", is_appropriate=True) request = rf.get("item/api/v1/item-autocomplete/", {"q": "chair"}) response = search_item_autocomplete(request) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 1 assert data["data"][0] == [target.id, target.name, target.image]
def test_children_level_1(self, rf, user): parent = ItemFactory.create() progeny = ItemFactory.create_batch(9, parent=parent) request = rf.get("blah/") request.user = user response = item_children(request, parent.id) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 9 assert sorted(data["data"], key=lambda x: x[0]) == [ [x.id, x.name] for x in progeny ]
def test_recursion(self, rf, user): item1 = ItemFactory.create() item2 = ItemFactory.create(parent=item1) item1.parent = item2 item1.save(update_fields=["parent"]) request = rf.get("blah/") request.user = user response = item_children(request, item1.id) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 1 assert sorted(data["data"], key=lambda x: x[0]) == [[item2.id, item2.name]]
def test_return_closest_exact_matching(self, rf): """Tests closest matching in terms of number of letters close to the query. "Three-ring binder shows up before binder... """ target1 = ItemFactory.create(name="three-ring binder") target2 = ItemFactory.create(name="binder") request = rf.get("blah/", {"q": "binder"}) response = search_item_autocomplete(request) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 2 assert data["data"][0] == [target2.id, target2.name, target2.image] assert data["data"][1] == [target1.id, target1.name, target1.image]
def test_children_multi_level(self, rf, user): item1 = ItemFactory.create() item2a = ItemFactory.create(parent=item1) item3a = ItemFactory.create_batch(3, parent=item2a) item2b = ItemFactory.create(parent=item1) item3b = ItemFactory.create_batch(6, parent=item2b) request = rf.get("blah/") request.user = user response = item_children(request, item1.id) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 11 assert sorted(data["data"], key=lambda x: x[0]) == [ [x.id, x.name] for x in sorted((item2a, item2b, *item3a, *item3b), key=lambda x: x.id) ]
def test_non_existing_already_in_active_item(self, charity, user): """Tests if an item that exists in Item but user thought it didn't (so it's in the names list) will NOT create a new Item object but use the existing one to create the WantedItem. """ items = ItemFactory.create_batch(9) assert Item.objects.count() == 9 item_conditions = [randint(0, 3) for _ in range(len(items))] WantedItem.objects.bulk_create( [ WantedItem(charity=charity, item=item, condition=condition) for item, condition in zip(items, item_conditions) ] ) proposed = ProposedItem.objects.create( entity=charity, user=user, names=[item.name.lower() for item in items], # Different conditions names_condition=[randint(0, 3) for _ in range(len(items))], ) merge(charity, proposed) assert Item.objects.count() == 9 assert WantedItem.objects.count() == 9 for item, condition in zip(items, item_conditions): assert WantedItem.objects.filter( item=item, condition=condition, charity=charity ).exists()
def test_merge(self, charity, user): # Assuming names attribute are of names that aren't in Item list already. items = ItemFactory.create_batch(10) item_conditions = [randint(0, 3) for _ in range(len(items))] names = [("".join(sample(ascii_letters, 50))).lower() for _ in range(10)] names_condition = [randint(0, 3) for _ in range(len(names))] proposed = ProposedItem.objects.create( entity=charity, user=user, item=[item.id for item in items], item_condition=item_conditions, names=names, names_condition=names_condition, ) assert ProposedItem.objects.get(id=proposed.id).closed is False merge(charity, proposed) assert Item.objects.count() == 20, "Names list should've created 10 Item objs" for x in names: assert Item.objects.filter(name=x).exists() assert WantedItem.objects.filter(charity=charity).count() == 20 for item, condition in zip(items, item_conditions): assert WantedItem.objects.filter( item=item, condition=condition, charity=charity ).exists() for name, condition in zip(names, names_condition): assert WantedItem.objects.filter( item__name=name, condition=condition, charity=charity ).exists() assert ProposedItem.objects.get(id=proposed.id).closed is True
def test_search_multiple_items(self, client, charity): # Create the items chair = ItemFactory.create(name="chair") pan = ItemFactory.create(name="pan") jeans = ItemFactory.create(name="jeans") # Create items organizations wants # All items are created with condition 3: Brand New WantedItemFactory.create_batch(3, item=chair) # 3 WantedItemFactory.create(item=chair, charity=charity) # 4 WantedItemFactory.create(item=pan, charity=charity) # 4 since same charity WantedItemFactory.create_batch(2, item=pan) # 6 WantedItemFactory.create(item=jeans) # 7 WantedItemFactory.create_batch(25, item=jeans) response = client.get( f"/item/multi-lookup/?" f"q={item_encode_b64(chair.id, 3)}&" f"q={item_encode_b64(pan.id, 3)}&" f"q={item_encode_b64(jeans.id, 3)}" ) assert response.status_code == 200 data: dict = response.context["data"] assert len(data) == 25, f"Supposed to show 25 max pagination.\n{data}" assert response.context["page_obj"].has_next() is True assert response.context["page_obj"].has_previous() is False first_key = list(data.keys())[0] assert first_key == charity.id, ( "Target charity, which supports the most items " "out of the searched, should be the first result." ) assert ( len(data[first_key][:-2]) == WantedItem.objects.filter( item_id__in=[chair.id, pan.id, jeans.id], charity=charity, ).count() ), ( "Assuming the additional information is only name and description" "of the organization, hence -2 in the test, then you're missing items." ) charities_seen = [] for k in data.keys(): # Check the rest isn't the exact same charity assert k not in charities_seen, "Charities shown must be distinct" charities_seen.append(k)
def test_create_thread_proposed_item(charity, user): item = ItemFactory.create() ProposedItem.objects.create(entity=charity, user=user, item=[item.id]) assert Thread.objects.count() == 1 assert Message.objects.count() == 1 thread = Thread.objects.first() assert thread.type == 4 message = Message.objects.first() assert message.thread == thread
def test_remove_duplicate_items(self, charity, user): item = ItemFactory.create() # What happens when a duplicate like this appears? First or second? First :) proposed = ProposedItem.objects.create( entity=charity, user=user, item=[item.id, item.id], item_condition=[2, 1] ) merge(charity, proposed) assert Item.objects.count() == 1 assert WantedItem.objects.count() == 1 assert WantedItem.objects.first().condition == 2
def test_item_missing_condition(self, client, user, charity): item = ItemFactory.create(is_appropriate=False) client.force_login(user) response = client.post( self.view_url, data={"entity": charity.id, "item": str(item.id)}, ) assert response.status_code == 400 errors = json.loads(response.content)["errors"] assert "item" in errors
def test_item_condition_incorrect_length(self, client, user, charity, neg): item = ItemFactory.create(is_appropriate=False) client.force_login(user) response = client.post( self.view_url, data={ "entity": charity.id, "item": str(item.id), "item_condition": [1] * (1 - neg), }, ) assert response.status_code == 400 errors = json.loads(response.content)["errors"] assert "item" in errors
def setup_thread(thread, entity): thread.type = 4 user = UserFactory.create() items = [x.id for x in ItemFactory.create_batch(10)] proposed = ProposedItem.objects.create(user_id=user.id, entity=entity, item=items, item_condition=[2] * len(items)) thread.extra = { "OP_id": user.id, "entity_id": entity.id, "proposed_item_id": proposed.id, } thread.save()
def test_list_active_entity_items(self, rf, charity, user, django_assert_max_num_queries): # Create test data item_a = WantedItemFactory.create(item=ItemFactory.create(name="a"), charity=charity, condition=randint(0, 3)) item_k = WantedItemFactory.create(item=ItemFactory.create(name="k"), charity=charity, condition=randint(0, 3)) item_z = WantedItemFactory.create(item=ItemFactory.create(name="z"), charity=charity, condition=randint(0, 3)) request = rf.get("blah/") with django_assert_max_num_queries(3): response = views.list_active_entity_items(request, charity_id=charity.id) assert response.status_code == 200 data = json.loads(response.content)["data"] assert data[0][0] == item_a.item.name assert data[0][1] == item_a.condition assert data[1][0] == item_k.item.name assert data[1][1] == item_k.condition assert data[2][0] == item_z.item.name assert data[2][1] == item_z.condition
def test_typeahead(self, rf): query = "an" ItemFactory.create(name="pan") ItemFactory.create(name="canned food") ItemFactory.create(name="blah") request = rf.get("item/api/v1/item-autocomplete/", {"q": query}) response = search_item_autocomplete(request) assert response.status_code == 200 data = json.loads(response.content) assert len(data["data"]) == 2, f"Response {data}" assert query in data["data"][0][1] assert query in data["data"][1][1]
def test_list_proposed_existing_item(self, rf, user, charity): items = sorted(ItemFactory.create_batch(10), key=lambda x: x.id) item_condition = [randint(0, 3) for _ in range(len(items))] proposed = ProposedItem.objects.create( user=user, entity=charity, item=[x.id for x in items], item_condition=item_condition, ) request = rf.get("blah") response = views.list_proposed_existing_item(request, proposed.id) assert response.status_code == 200 data = json.loads(response.content) for d, item in zip(data["data"], items): # Should be in the same order assert d == [item.id, item.name] for condition, item_condition in zip(data["condition"], item_condition): assert item_condition == condition
def test_duplicate_name_and_item(self, charity, user): """Tests that a duplicate listed name and listed item don't create two WantedItems. """ item = ItemFactory.create() proposed = ProposedItem.objects.create( entity=charity, user=user, item=[item.id], item_condition=[1], names=[item.name.lower()], names_condition=[2], ) merge(charity, proposed) assert Item.objects.get(name=item.name) assert WantedItem.objects.count() == 1 wanted_item = WantedItem.objects.first() assert wanted_item.item == item assert wanted_item.condition == 1
def test_attribute_and_condition_not_equal_in_length( self, attribute_name, client, user, charity, neg): # Doesn't matter since we're stringifying everything array = [x.id for x in ItemFactory.create_batch(3)] array_condition = _format_list_to_str( [randint(0, 3) for _ in range((len(array) - neg))]) client.force_login(user) response = client.post( self.view_url, data={ "entity": charity.id, attribute_name: _format_list_to_str(array), attribute_name + "_condition": array_condition, }, ) assert response.status_code == 400 errors = json.loads(response.content)["errors"] assert attribute_name in errors assert attribute_name + "_condition" in errors
def test_proposed_item_form_create(self, client, user, charity): item = [x.id for x in ItemFactory.create_batch(3)] item_condition = [randint(0, 3) for _ in range(len(item))] name = [_random_string() for _ in range(3)] names_condition = [randint(0, 3) for _ in range(len(name))] client.force_login(user) response = client.post( self.view_url, data={ "entity": charity.id, "item": _format_list_to_str(item), "item_condition": _format_list_to_str(item_condition), "names": _format_list_to_str(name), "names_condition": _format_list_to_str(names_condition), }, ) _assert_response_form_create_update(response, user, charity, item, item_condition, name, names_condition)
def test_non_existing_already_in_item(self, charity, user): """Tests if an item that exists in Item but user thought it didn't (so it's in the names list) will NOT create a new Item object but will create a new WantedItem. """ items = ItemFactory.create_batch(9) assert Item.objects.count() == 9 names_condition = [randint(0, 3) for _ in range(9)] proposed = ProposedItem.objects.create( entity=charity, user=user, names=[item.name.lower() for item in items], names_condition=names_condition, ) merge(charity, proposed) assert Item.objects.count() == 9 assert WantedItem.objects.count() == 9 for name, condition in zip(items, names_condition): assert WantedItem.objects.filter( item__name=name, condition=condition, charity=charity )
def test_form_not_update_for_wrong_user(self, client, user, charity): item = [x.id for x in ItemFactory.create_batch(3)] name = [_random_string() for _ in range(3)] obj = ProposedItem.objects.create( user=user, entity=charity, item=item[:2], names=name[:2] ) client.force_login(UserFactory.create()) response = client.post( self.view_url, data={ "id": obj.id, "item": _format_list_to_str(item), "item_condition": _format_list_to_str([3] * len(item)), "names": _format_list_to_str(name), "names_condition": _format_list_to_str([3] * len(name)), }, ) assert response.status_code == 200 assert ProposedItem.objects.count() == 1 obj = ProposedItem.objects.first() assert obj.item == item[:2] assert obj.names == name[:2]
def test_proposed_item_form_update(self, client, user, charity): """The updating of the form""" item = [x.id for x in ItemFactory.create_batch(10)] item_condition = [3] * len(item) name = [_random_string() for _ in range(10)] names_condition = [3] * len(name) obj = ProposedItem.objects.create( user=user, entity=charity, item=item[:5], names=name[:5] ) client.force_login(user) response = client.post( self.view_url, data={ "id": obj.id, "item": _format_list_to_str(item), "item_condition": _format_list_to_str(item_condition), "names": _format_list_to_str(name), "names_condition": _format_list_to_str(names_condition), }, ) _assert_response_form_create_update( response, user, charity, item, item_condition, name, names_condition )
def item() -> Item: return ItemFactory()
def handle(self, *args, **options): if not settings.DEBUG: raise Exception("You cannot use this command in production.") print("Creating Item app data.") org_1 = Charity.objects.create( name="Org 1", link="https://google.com/", description="Desc.", how_to_donate="Address", ) org_2 = Charity.objects.create( name="Org 2", link="https://google.com/", description="Desc.", how_to_donate="Address", ) org_3 = Charity.objects.create( name="Org 3", link="https://google.com/", description="Desc.", how_to_donate="Address", ) item_1 = Item.objects.create(name="pan") item_2 = Item.objects.create(name="canned food") Item.objects.create(name="chair") item_3 = Item.objects.create(name="fork") item_4 = Item.objects.create(name="blood") WantedItem.objects.create(item=item_1, charity=org_1) # 3 orgs WantedItem.objects.create(item=item_2, charity=org_1) # 2 orgs WantedItem.objects.create(item=item_3, charity=org_1) # 2 orgs WantedItem.objects.create(item=item_4, charity=org_1) # 1 org WantedItem.objects.create(item=item_1, charity=org_2) WantedItem.objects.create(item=item_2, charity=org_2) WantedItem.objects.create(item=item_1, charity=org_3) WantedItem.objects.create(item=item_3, charity=org_3) ProposedItem.objects.create( entity=org_1, user=UserFactory.create(), item=[item_1.id] + [x.id for x in ItemFactory.create_batch(10)], names=[Faker().bs() for _ in range(50)], ) ProposedItem.objects.create( entity=org_2, user=UserFactory.create(), item=[item_3.id] + [x.id for x in ItemFactory.create_batch(10)], names=[Faker().bs() for _ in range(50)], ) # For testing pagination - change to 1 in paginating WantedItemFactory.create_batch(25, item=item_1) # For testing proposed item, if user selects a generic # item, then all of its children are added as well. # If no parent, then select that only. GH #3 parent = Item.objects.create(name="parent1") [ Item.objects.create(parent=parent, name=f"child{x}") for x in range(7) ] # Also, during searching, if a generic item appears # we warn the user that they should check the list beforehand. print("Finished creating Item app data.")