|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+from django.core.exceptions import ValidationError
|
|
|
2
|
+from django.test import TestCase
|
|
|
3
|
+
|
|
|
4
|
+from oscar.core.loading import get_model
|
|
|
5
|
+from oscar.test.factories import (
|
|
|
6
|
+ ProductAttributeFactory, ProductClassFactory, ProductFactory)
|
|
|
7
|
+
|
|
|
8
|
+Product = get_model("catalogue", "Product")
|
|
|
9
|
+ProductAttribute = get_model("catalogue", "ProductAttribute")
|
|
|
10
|
+ProductAttributeValue = get_model("catalogue", "ProductAttributeValue")
|
|
|
11
|
+
|
|
|
12
|
+
|
|
|
13
|
+class ProductAttributeTest(TestCase):
|
|
|
14
|
+
|
|
|
15
|
+ def setUp(self):
|
|
|
16
|
+ super().setUp()
|
|
|
17
|
+
|
|
|
18
|
+ # setup the productclass
|
|
|
19
|
+ self.product_class = product_class = ProductClassFactory(name='Cows', slug='cows')
|
|
|
20
|
+ self.name_attr = ProductAttributeFactory(
|
|
|
21
|
+ type=ProductAttribute.TEXT, product_class=product_class, name="name", code="name")
|
|
|
22
|
+ self.weight_attrs = ProductAttributeFactory(
|
|
|
23
|
+ type=ProductAttribute.INTEGER, name="weight", code="weight", product_class=product_class)
|
|
|
24
|
+
|
|
|
25
|
+ # create the parent product
|
|
|
26
|
+ self.product = product = ProductFactory(
|
|
|
27
|
+ title="I am your father", stockrecords=None, product_class=product_class, structure="parent", upc="1234")
|
|
|
28
|
+ product.attr.weight = 3
|
|
|
29
|
+ product.full_clean()
|
|
|
30
|
+ product.save()
|
|
|
31
|
+
|
|
|
32
|
+ # create the child product
|
|
|
33
|
+ self.child_product = ProductFactory(
|
|
|
34
|
+ parent=product, structure="child", categories=None, product_class=None,
|
|
|
35
|
+ title="You are my father", upc="child-1234")
|
|
|
36
|
+ self.child_product.full_clean()
|
|
|
37
|
+
|
|
|
38
|
+ def test_update_child_with_attributes(self):
|
|
|
39
|
+ "Attributes preseent on the parent should not be copied to the child "
|
|
|
40
|
+ "when title of the child is modified"
|
|
|
41
|
+ self.assertEqual(
|
|
|
42
|
+ ProductAttributeValue.objects.filter(product_id=self.product.pk).count(),
|
|
|
43
|
+ 1,
|
|
|
44
|
+ "The parent has 1 attributes",
|
|
|
45
|
+ )
|
|
|
46
|
+
|
|
|
47
|
+ # establish baseline
|
|
|
48
|
+ self.assertEqual(
|
|
|
49
|
+ ProductAttributeValue.objects.filter(product=self.child_product).count(),
|
|
|
50
|
+ 0,
|
|
|
51
|
+ "The child has no attributes",
|
|
|
52
|
+ )
|
|
|
53
|
+ self.assertEqual(self.child_product.parent_id, self.product.pk)
|
|
|
54
|
+ self.assertIsNone(self.child_product.product_class)
|
|
|
55
|
+ self.assertEqual(self.child_product.upc, "child-1234")
|
|
|
56
|
+ self.assertEqual(self.child_product.slug, "you-are-my-father")
|
|
|
57
|
+ self.assertNotEqual(self.child_product.title, "Klaas is my real father")
|
|
|
58
|
+
|
|
|
59
|
+ self.child_product.title = "Klaas is my real father"
|
|
|
60
|
+ self.child_product.save()
|
|
|
61
|
+
|
|
|
62
|
+ self.child_product.refresh_from_db()
|
|
|
63
|
+ self.assertEqual(self.child_product.title, "Klaas is my real father")
|
|
|
64
|
+ self.assertEqual(
|
|
|
65
|
+ ProductAttributeValue.objects.filter(product=self.child_product).count(),
|
|
|
66
|
+ 0,
|
|
|
67
|
+ "The child has no attributes",
|
|
|
68
|
+ )
|
|
|
69
|
+
|
|
|
70
|
+ def test_update_child_attributes(self):
|
|
|
71
|
+ "Attributes preseent on the parent should not be copied to the child "
|
|
|
72
|
+ "when the child attributes are modified"
|
|
|
73
|
+ self.assertEqual(
|
|
|
74
|
+ ProductAttributeValue.objects.filter(product_id=self.product.pk).count(),
|
|
|
75
|
+ 1,
|
|
|
76
|
+ "The parent has 1 attributes",
|
|
|
77
|
+ )
|
|
|
78
|
+
|
|
|
79
|
+ # establish baseline
|
|
|
80
|
+ self.assertEqual(
|
|
|
81
|
+ ProductAttributeValue.objects.filter(product=self.child_product).count(),
|
|
|
82
|
+ 0,
|
|
|
83
|
+ "The child has no attributes",
|
|
|
84
|
+ )
|
|
|
85
|
+ self.assertEqual(self.child_product.parent_id, self.product.pk)
|
|
|
86
|
+ self.assertIsNone(self.child_product.product_class)
|
|
|
87
|
+ self.assertEqual(self.child_product.upc, "child-1234")
|
|
|
88
|
+ self.assertEqual(self.child_product.slug, "you-are-my-father")
|
|
|
89
|
+ self.assertNotEqual(self.child_product.title, "Klaas is my real father")
|
|
|
90
|
+
|
|
|
91
|
+ self.child_product.title = "Klaas is my real father"
|
|
|
92
|
+ self.child_product.attr.name = "Berta"
|
|
|
93
|
+ self.child_product.save()
|
|
|
94
|
+
|
|
|
95
|
+ self.child_product.refresh_from_db()
|
|
|
96
|
+ self.assertEqual(self.child_product.title, "Klaas is my real father")
|
|
|
97
|
+ self.assertEqual(
|
|
|
98
|
+ ProductAttributeValue.objects.filter(product=self.child_product).count(),
|
|
|
99
|
+ 1,
|
|
|
100
|
+ "The child now has 1 attribute",
|
|
|
101
|
+ )
|
|
|
102
|
+
|
|
|
103
|
+ def test_update_attributes_to_parent_and_child(self):
|
|
|
104
|
+ "Attributes present on the parent should not be copied to the child "
|
|
|
105
|
+ "ever, not even newly added attributes"
|
|
|
106
|
+ self.assertEqual(
|
|
|
107
|
+ ProductAttributeValue.objects.filter(product_id=self.product.pk).count(),
|
|
|
108
|
+ 1,
|
|
|
109
|
+ "The parent has 1 attributes",
|
|
|
110
|
+ )
|
|
|
111
|
+ self.product.attr.name = "Greta"
|
|
|
112
|
+ self.product.save()
|
|
|
113
|
+ self.product.refresh_from_db()
|
|
|
114
|
+ self.product.attr.refresh()
|
|
|
115
|
+
|
|
|
116
|
+ self.assertEqual(
|
|
|
117
|
+ ProductAttributeValue.objects.filter(product_id=self.product.pk).count(),
|
|
|
118
|
+ 2,
|
|
|
119
|
+ "The parent now has 2 attributes",
|
|
|
120
|
+ )
|
|
|
121
|
+
|
|
|
122
|
+ # establish baseline
|
|
|
123
|
+ self.assertEqual(
|
|
|
124
|
+ ProductAttributeValue.objects.filter(product=self.child_product).count(),
|
|
|
125
|
+ 0,
|
|
|
126
|
+ "The child has no attributes",
|
|
|
127
|
+ )
|
|
|
128
|
+ self.assertEqual(self.child_product.parent_id, self.product.pk)
|
|
|
129
|
+ self.assertIsNone(self.child_product.product_class)
|
|
|
130
|
+ self.assertEqual(self.child_product.upc, "child-1234")
|
|
|
131
|
+ self.assertEqual(self.child_product.slug, "you-are-my-father")
|
|
|
132
|
+ self.assertNotEqual(self.child_product.title, "Klaas is my real father")
|
|
|
133
|
+
|
|
|
134
|
+ self.child_product.title = "Klaas is my real father"
|
|
|
135
|
+ self.child_product.attr.name = "Berta"
|
|
|
136
|
+ self.child_product.save()
|
|
|
137
|
+
|
|
|
138
|
+ self.child_product.refresh_from_db()
|
|
|
139
|
+ self.assertEqual(self.child_product.title, "Klaas is my real father")
|
|
|
140
|
+ self.assertEqual(
|
|
|
141
|
+ ProductAttributeValue.objects.filter(product=self.child_product).count(),
|
|
|
142
|
+ 1,
|
|
|
143
|
+ "The child now has 1 attribute",
|
|
|
144
|
+ )
|
|
|
145
|
+
|
|
|
146
|
+
|
|
|
147
|
+class ProductAttributeQuerysetTest(TestCase):
|
|
|
148
|
+ fixtures = ["productattributes"]
|
|
|
149
|
+
|
|
|
150
|
+ def test_query_multiple_producttypes(self):
|
|
|
151
|
+ "We should be able to query over multiple product classes"
|
|
|
152
|
+ result = Product.objects.filter_by_attributes(henkie="bah bah")
|
|
|
153
|
+ self.assertEqual(result.count(), 2)
|
|
|
154
|
+ result1, result2 = list(result)
|
|
|
155
|
+
|
|
|
156
|
+ self.assertNotEqual(result1.product_class, result2.product_class)
|
|
|
157
|
+ self.assertEqual(result1.attr.henkie, result2.attr.henkie)
|
|
|
158
|
+
|
|
|
159
|
+ def test_further_filtering(self):
|
|
|
160
|
+ "The returned queryset should be ready for further filtering"
|
|
|
161
|
+ result = Product.objects.filter_by_attributes(henkie="bah bah")
|
|
|
162
|
+ photo = result.filter(title__contains="Photo")
|
|
|
163
|
+ self.assertEqual(photo.count(), 1)
|
|
|
164
|
+
|
|
|
165
|
+ def test_empty_results(self):
|
|
|
166
|
+ "Empty results are possible without errors"
|
|
|
167
|
+ result = Product.objects.filter_by_attributes(doesnotexist=True)
|
|
|
168
|
+ self.assertFalse(result.exists(), "querying with bulshit attributes should give no results")
|
|
|
169
|
+ result = Product.objects.filter_by_attributes(henkie="zulthoofd")
|
|
|
170
|
+ self.assertFalse(result.exists(), "querying with non existing values should give no results")
|
|
|
171
|
+ result = Product.objects.filter_by_attributes(henkie=True)
|
|
|
172
|
+ self.assertFalse(result.exists(), "querying with wring value type should give no results")
|
|
|
173
|
+
|
|
|
174
|
+ def test_text_value(self):
|
|
|
175
|
+ result = Product.objects.filter_by_attributes(subtitle="superhenk")
|
|
|
176
|
+ self.assertTrue(result.exists())
|
|
|
177
|
+ result = Product.objects.filter_by_attributes(subtitle="kekjo")
|
|
|
178
|
+ self.assertTrue(result.exists())
|
|
|
179
|
+ result = Product.objects.filter_by_attributes(subtitle=True)
|
|
|
180
|
+ self.assertFalse(result.exists())
|
|
|
181
|
+
|
|
|
182
|
+ def test_formatted_text(self):
|
|
|
183
|
+ html = "<p style=\"margin: 0px; font-stretch: normal; font-size: 12px; line-height: normal; font-family: Helvetica;\">Vivamus auctor leo vel dui. Aliquam erat volutpat. Phasellus nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras tempor. Morbi egestas, <em>urna</em> non consequat tempus, <strong>nunc</strong> arcu mollis enim, eu aliquam erat nulla non nibh. Duis consectetuer malesuada velit. Nam ante nulla, interdum vel, tristique ac, condimentum non, tellus. Proin ornare feugiat nisl. Suspendisse dolor nisl, ultrices at, eleifend vel, consequat at, dolor.</p>" # noqa
|
|
|
184
|
+ result = Product.objects.filter_by_attributes(additional_info=html)
|
|
|
185
|
+ self.assertTrue(result.exists())
|
|
|
186
|
+
|
|
|
187
|
+ def test_boolean(self):
|
|
|
188
|
+ result = Product.objects.filter_by_attributes(available=True)
|
|
|
189
|
+ self.assertTrue(result.exists())
|
|
|
190
|
+ result = Product.objects.filter_by_attributes(available=0)
|
|
|
191
|
+ self.assertTrue(result.exists())
|
|
|
192
|
+ with self.assertRaises(ValidationError):
|
|
|
193
|
+ result = Product.objects.filter_by_attributes(available="henk")
|
|
|
194
|
+
|
|
|
195
|
+ def test_number(self):
|
|
|
196
|
+ result = Product.objects.filter_by_attributes(facets=4)
|
|
|
197
|
+ self.assertTrue(result.exists())
|
|
|
198
|
+ with self.assertRaises(ValueError):
|
|
|
199
|
+ result = Product.objects.filter_by_attributes(facets="four")
|
|
|
200
|
+
|
|
|
201
|
+ result = Product.objects.filter_by_attributes(facets=1)
|
|
|
202
|
+ self.assertFalse(result.exists())
|
|
|
203
|
+
|
|
|
204
|
+ def test_float(self):
|
|
|
205
|
+ result = Product.objects.filter_by_attributes(hypothenusa=1.25)
|
|
|
206
|
+ self.assertTrue(result.exists())
|
|
|
207
|
+ with self.assertRaises(ValueError):
|
|
|
208
|
+ result = Product.objects.filter_by_attributes(facets="four")
|
|
|
209
|
+
|
|
|
210
|
+ result = Product.objects.filter_by_attributes(hypothenusa=1)
|
|
|
211
|
+ self.assertFalse(result.exists())
|
|
|
212
|
+
|
|
|
213
|
+ def test_option(self):
|
|
|
214
|
+ result = Product.objects.filter_by_attributes(kind="totalitarian")
|
|
|
215
|
+ self.assertTrue(result.exists())
|
|
|
216
|
+ result = Product.objects.filter_by_attributes(kind=True)
|
|
|
217
|
+ self.assertFalse(result.exists())
|
|
|
218
|
+
|
|
|
219
|
+ result = Product.objects.filter_by_attributes(kind="omnimous")
|
|
|
220
|
+ self.assertFalse(result.exists())
|
|
|
221
|
+
|
|
|
222
|
+ def test_multi_option(self):
|
|
|
223
|
+ result = Product.objects.filter_by_attributes(subkinds="megalomane")
|
|
|
224
|
+ self.assertTrue(result.exists())
|
|
|
225
|
+ self.assertEqual(result.count(), 2)
|
|
|
226
|
+ result = Product.objects.filter_by_attributes(subkinds=True)
|
|
|
227
|
+ self.assertFalse(result.exists())
|
|
|
228
|
+
|
|
|
229
|
+ result = Product.objects.filter_by_attributes(subkinds="omnimous")
|
|
|
230
|
+ self.assertFalse(result.exists())
|
|
|
231
|
+
|
|
|
232
|
+ result = Product.objects.filter_by_attributes(subkinds__contains="om")
|
|
|
233
|
+ self.assertTrue(result.exists(), "megalomane conains om")
|
|
|
234
|
+ self.assertEqual(result.count(), 2)
|
|
|
235
|
+
|
|
|
236
|
+ def test_multiple_attributes(self):
|
|
|
237
|
+ result = Product.objects.filter_by_attributes(subkinds="megalomane", available=True)
|
|
|
238
|
+ self.assertTrue(result.exists())
|
|
|
239
|
+
|
|
|
240
|
+ result = Product.objects.filter_by_attributes(
|
|
|
241
|
+ kind="totalitarian",
|
|
|
242
|
+ hypothenusa=1.25,
|
|
|
243
|
+ facets=8,
|
|
|
244
|
+ subtitle="superhenk",
|
|
|
245
|
+ subkinds="megalomane",
|
|
|
246
|
+ available=False
|
|
|
247
|
+ )
|
|
|
248
|
+ self.assertTrue(result.exists())
|
|
|
249
|
+
|
|
|
250
|
+ def test_lookups(self):
|
|
|
251
|
+ result = Product.objects.filter_by_attributes(facets__lte=4)
|
|
|
252
|
+ self.assertEqual(result.count(), 1)
|
|
|
253
|
+
|
|
|
254
|
+ result = Product.objects.filter_by_attributes(facets__lte=8)
|
|
|
255
|
+ self.assertEqual(result.count(), 2)
|
|
|
256
|
+
|
|
|
257
|
+ result = Product.objects.filter_by_attributes(facets__lt=8)
|
|
|
258
|
+ self.assertEqual(result.count(), 1)
|