Merge lp:~abentley/launchpad/product-specifications-tests into lp:launchpad

Proposed by Aaron Bentley on 2012-10-16
Status: Merged
Merged at revision: 16167
Proposed branch: lp:~abentley/launchpad/product-specifications-tests
Merge into: lp:launchpad
Prerequisite: lp:~abentley/launchpad/user-blueprints-privacy
Diff against target: 197 lines (+180/-0)
1 file modified
lib/lp/registry/tests/test_product.py (+180/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/product-specifications-tests
Reviewer Review Type Date Requested Status
Deryck Hodge (community) 2012-10-16 Approve on 2012-10-17
Review via email: mp+130000@code.launchpad.net

Commit Message

Add unit tests for Product.specifications.

Description of the Change

= Summary =
Make it safe to reimplement Product.specifications

== Proposed fix ==
Add unit tests for Product.specifications.

== Pre-implementation notes ==
None

== LOC Rationale ==
Part of Private Projects

== Implementation details ==
Tests copied from test_person.TestSpecifications. This implementation of specifications does not filter out inactive products, but AFAICT, it does not guarantee that it will include inactive products.

== Tests ==
bin/test test_product.py -t TestSpecifications

== Demo and Q/A ==
None

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/testing/factory.py
  lib/lp/blueprints/model/specification.py
  lib/lp/blueprints/model/sprint.py
  lib/lp/registry/model/person.py
  lib/lp/registry/tests/test_person.py
  lib/lp/registry/tests/test_product.py

To post a comment you must log in.
Deryck Hodge (deryck) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/tests/test_product.py'
2--- lib/lp/registry/tests/test_product.py 2012-10-16 00:57:45 +0000
3+++ lib/lp/registry/tests/test_product.py 2012-10-16 22:23:52 +0000
4@@ -41,6 +41,15 @@
5 )
6 from lp.app.interfaces.informationtype import IInformationType
7 from lp.app.interfaces.services import IService
8+from lp.blueprints.enums import (
9+ NewSpecificationDefinitionStatus,
10+ SpecificationDefinitionStatus,
11+ SpecificationFilter,
12+ SpecificationImplementationStatus,
13+ SpecificationPriority,
14+ SpecificationSort,
15+ )
16+
17 from lp.bugs.interfaces.bugsummary import IBugSummaryDimension
18 from lp.bugs.interfaces.bugsupervisor import IHasBugSupervisor
19 from lp.registry.enums import (
20@@ -1579,6 +1588,177 @@
21 product.translationpermission = TranslationPermission.CLOSED
22
23
24+def list_result(product, filter=None, user=None):
25+ result = product.specifications(
26+ user, SpecificationSort.DATE, filter=filter)
27+ return list(result)
28+
29+
30+class TestSpecifications(TestCaseWithFactory):
31+
32+ layer = DatabaseFunctionalLayer
33+
34+ def setUp(self):
35+ super(TestSpecifications, self).setUp()
36+ self.date_created = datetime.now(pytz.utc)
37+
38+ def makeSpec(self, product=None, date_created=0, title=None,
39+ status=NewSpecificationDefinitionStatus.NEW,
40+ name=None, priority=None, information_type=None):
41+ blueprint = self.factory.makeSpecification(
42+ title=title, status=status, name=name, priority=priority,
43+ information_type=information_type, product=product,
44+ )
45+ removeSecurityProxy(blueprint).datecreated = (
46+ self.date_created + timedelta(date_created))
47+ return blueprint
48+
49+ def test_specifications_quantity(self):
50+ # Ensure the quantity controls the maximum number of entries.
51+ product = self.factory.makeProduct()
52+ for count in range(10):
53+ self.factory.makeSpecification(product=product)
54+ self.assertEqual(10, product.specifications(None).count())
55+ result = product.specifications(None, quantity=None).count()
56+ self.assertEqual(10, result)
57+ self.assertEqual(8, product.specifications(None, quantity=8).count())
58+ self.assertEqual(10, product.specifications(None, quantity=11).count())
59+
60+ def test_date_sort(self):
61+ # Sort on date_created.
62+ product = self.factory.makeProduct()
63+ blueprint1 = self.makeSpec(product, date_created=0)
64+ blueprint2 = self.makeSpec(product, date_created=-1)
65+ blueprint3 = self.makeSpec(product, date_created=1)
66+ result = list_result(product)
67+ self.assertEqual([blueprint3, blueprint1, blueprint2], result)
68+
69+ def test_date_sort_id(self):
70+ # date-sorting when no date varies uses object id.
71+ product = self.factory.makeProduct()
72+ blueprint1 = self.makeSpec(product)
73+ blueprint2 = self.makeSpec(product)
74+ blueprint3 = self.makeSpec(product)
75+ result = list_result(product)
76+ self.assertEqual([blueprint1, blueprint2, blueprint3], result)
77+
78+ def test_priority_sort(self):
79+ # Sorting by priority works and is the default.
80+ # When priority is supplied, status is ignored.
81+ blueprint1 = self.makeSpec(priority=SpecificationPriority.UNDEFINED,
82+ status=SpecificationDefinitionStatus.NEW)
83+ product = blueprint1.product
84+ blueprint2 = self.makeSpec(
85+ product, priority=SpecificationPriority.NOTFORUS,
86+ status=SpecificationDefinitionStatus.APPROVED)
87+ blueprint3 = self.makeSpec(
88+ product, priority=SpecificationPriority.LOW,
89+ status=SpecificationDefinitionStatus.NEW)
90+ result = product.specifications(None)
91+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
92+ result = product.specifications(None, sort=SpecificationSort.PRIORITY)
93+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
94+
95+ def test_priority_sort_fallback_status(self):
96+ # Sorting by priority falls back to defintion_status.
97+ # When status is supplied, name is ignored.
98+ blueprint1 = self.makeSpec(
99+ status=SpecificationDefinitionStatus.NEW, name='a')
100+ product = blueprint1.product
101+ blueprint2 = self.makeSpec(
102+ product, status=SpecificationDefinitionStatus.APPROVED, name='c')
103+ blueprint3 = self.makeSpec(
104+ product, status=SpecificationDefinitionStatus.DISCUSSION, name='b')
105+ result = product.specifications(None)
106+ self.assertEqual([blueprint2, blueprint3, blueprint1], list(result))
107+ result = product.specifications(None, sort=SpecificationSort.PRIORITY)
108+ self.assertEqual([blueprint2, blueprint3, blueprint1], list(result))
109+
110+ def test_priority_sort_fallback_name(self):
111+ # Sorting by priority falls back to name.
112+ blueprint1 = self.makeSpec(name='b')
113+ product = blueprint1.product
114+ blueprint2 = self.makeSpec(product, name='c')
115+ blueprint3 = self.makeSpec(product, name='a')
116+ result = product.specifications(None)
117+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
118+ result = product.specifications(None, sort=SpecificationSort.PRIORITY)
119+ self.assertEqual([blueprint3, blueprint1, blueprint2], list(result))
120+
121+ def test_informational(self):
122+ # INFORMATIONAL causes only informational specs to be shown.
123+ enum = SpecificationImplementationStatus
124+ informational = self.factory.makeSpecification(
125+ implementation_status=enum.INFORMATIONAL)
126+ product = informational.product
127+ plain = self.factory.makeSpecification(product=product)
128+ result = product.specifications(None)
129+ self.assertIn(informational, result)
130+ self.assertIn(plain, result)
131+ result = product.specifications(
132+ None, filter=[SpecificationFilter.INFORMATIONAL])
133+ self.assertIn(informational, result)
134+ self.assertNotIn(plain, result)
135+
136+ def test_completeness(self):
137+ # If COMPLETE is specified, completed specs are listed. If INCOMPLETE
138+ # is specified or neither is specified, only incomplete specs are
139+ # listed.
140+ enum = SpecificationImplementationStatus
141+ implemented = self.factory.makeSpecification(
142+ implementation_status=enum.IMPLEMENTED)
143+ product = implemented.product
144+ non_implemented = self.factory.makeSpecification(product=product)
145+ result = product.specifications(
146+ None, filter=[SpecificationFilter.COMPLETE])
147+ self.assertIn(implemented, result)
148+ self.assertNotIn(non_implemented, result)
149+
150+ result = product.specifications(
151+ None, filter=[SpecificationFilter.INCOMPLETE])
152+ self.assertNotIn(implemented, result)
153+ self.assertIn(non_implemented, result)
154+ result = product.specifications(
155+ None)
156+ self.assertNotIn(implemented, result)
157+ self.assertIn(non_implemented, result)
158+
159+ def test_all(self):
160+ # ALL causes both complete and incomplete to be listed.
161+ enum = SpecificationImplementationStatus
162+ implemented = self.factory.makeSpecification(
163+ implementation_status=enum.IMPLEMENTED)
164+ product = implemented.product
165+ non_implemented = self.factory.makeSpecification(product=product)
166+ result = product.specifications(None, filter=[SpecificationFilter.ALL])
167+ self.assertContentEqual([implemented, non_implemented], result)
168+
169+ def test_valid(self):
170+ # VALID adjusts COMPLETE to exclude OBSOLETE and SUPERSEDED specs.
171+ # (INCOMPLETE already excludes OBSOLETE and SUPERSEDED.)
172+ i_enum = SpecificationImplementationStatus
173+ d_enum = SpecificationDefinitionStatus
174+ implemented = self.factory.makeSpecification(
175+ implementation_status=i_enum.IMPLEMENTED)
176+ product = implemented.product
177+ self.factory.makeSpecification(product=product,
178+ status=d_enum.SUPERSEDED)
179+ self.factory.makeSpecification(product=product, status=d_enum.OBSOLETE)
180+ filter = [SpecificationFilter.VALID, SpecificationFilter.COMPLETE]
181+ results = product.specifications(None, filter=filter)
182+ self.assertContentEqual([implemented], results)
183+
184+ def test_text_search(self):
185+ # Text searches work.
186+ blueprint1 = self.makeSpec(title='abc')
187+ product = blueprint1.product
188+ blueprint2 = self.makeSpec(product, title='def')
189+ result = list_result(product, ['abc'])
190+ self.assertEqual([blueprint1], result)
191+ result = list_result(product, ['def'])
192+ self.assertEqual([blueprint2], result)
193+
194+
195 class TestWebService(WebServiceTestCase):
196
197 def test_translations_usage(self):