~launchpad-pqm/launchpad/devel

14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
1
# Copyright 2011 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
__metaclass__ = type
5
14400.2.17 by Curtis Hovey
Added tests for call.
6
import re
7
8
from BeautifulSoup import BeautifulSoup
14550.1.1 by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad
9
from lazr.restful.fields import Reference
10
from zope.app.form.browser.interfaces import IBrowserWidget
11
from zope.app.form.interfaces import IInputWidget
14400.2.6 by Curtis Hovey
Added test to verify that the DistributionSourcePackageVocabulary is used
12
from zope.interface import (
13
    implements,
14
    Interface,
15
    )
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
16
14550.1.1 by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad
17
from lp.app.validators import LaunchpadValidationError
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
18
from lp.app.widgets.launchpadtarget import LaunchpadTargetWidget
14400.2.4 by Curtis Hovey
Verify the subwidgets are setup.
19
from lp.registry.vocabularies import (
14550.1.1 by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad
20
    DistributionSourcePackageVocabulary,
14400.2.4 by Curtis Hovey
Verify the subwidgets are setup.
21
    DistributionVocabulary,
22
    ProductVocabulary,
23
    )
14400.2.6 by Curtis Hovey
Added test to verify that the DistributionSourcePackageVocabulary is used
24
from lp.services.features.testing import FeatureFixture
14612.2.1 by William Grant
format-imports on lib/. So many imports.
25
from lp.services.webapp.servers import LaunchpadTestRequest
26
from lp.services.webapp.testing import verifyObject
14400.2.4 by Curtis Hovey
Verify the subwidgets are setup.
27
from lp.soyuz.model.binaryandsourcepackagename import (
28
    BinaryAndSourcePackageNameVocabulary,
29
    )
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
30
from lp.testing import TestCaseWithFactory
14612.2.1 by William Grant
format-imports on lib/. So many imports.
31
from lp.testing.layers import DatabaseFunctionalLayer
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
32
33
14400.2.6 by Curtis Hovey
Added test to verify that the DistributionSourcePackageVocabulary is used
34
class IThing(Interface):
35
    target = Reference(schema=Interface)
36
37
38
class Thing:
39
    implements(IThing)
40
    target = None
41
42
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
43
class LaunchpadTargetWidgetTestCase(TestCaseWithFactory):
44
    """Test the LaunchpadTargetWidget class."""
45
46
    layer = DatabaseFunctionalLayer
47
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
48
    @property
49
    def form(self):
50
        return {
51
        'field.target': 'package',
52
        'field.target.distribution': 'fnord',
53
        'field.target.package': 'snarf',
54
        'field.target.product': 'pting',
55
        }
56
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
57
    def setUp(self):
58
        super(LaunchpadTargetWidgetTestCase, self).setUp()
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
59
        self.distribution, self.package = self.factory.makeDSPCache(
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
60
            distro_name='fnord', package_name='snarf')
61
        self.project = self.factory.makeProduct('pting')
14400.2.8 by Curtis Hovey
Added test coverage for hasInput.
62
        field = Reference(
63
            __name__='target', schema=Interface, title=u'target')
64
        field = field.bind(Thing())
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
65
        request = LaunchpadTestRequest()
66
        self.widget = LaunchpadTargetWidget(field, request)
67
14400.2.17 by Curtis Hovey
Added tests for call.
68
    def test_implements(self):
69
        self.assertTrue(verifyObject(IBrowserWidget, self.widget))
70
        self.assertTrue(verifyObject(IInputWidget, self.widget))
71
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
72
    def test_template(self):
73
        # The render template is setup.
74
        self.assertTrue(
75
            self.widget.template.filename.endswith('launchpad-target.pt'),
76
            'Template was not setup.')
77
78
    def test_default_option(self):
14400.2.7 by Curtis Hovey
Added test coverage for getDistributionVocabulary.
79
        # This package field is the default option.
14400.2.3 by Curtis Hovey
Assembled a rudimentary unittest for LaunchpadTargetWidget.
80
        self.assertEqual('package', self.widget.default_option)
14400.2.4 by Curtis Hovey
Verify the subwidgets are setup.
81
14400.2.7 by Curtis Hovey
Added test coverage for getDistributionVocabulary.
82
    def test_getDistributionVocabulary(self):
83
        # The vocabulary is always "Distribution".
84
        self.assertEqual(
85
            'Distribution', self.widget.getDistributionVocabulary())
86
14400.2.8 by Curtis Hovey
Added test coverage for hasInput.
87
    def test_hasInput_false(self):
88
        # hasInput is false when the widget's name is not in the form data.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
89
        self.widget.request = LaunchpadTestRequest(form={})
14400.2.8 by Curtis Hovey
Added test coverage for hasInput.
90
        self.assertEqual('field.target', self.widget.name)
91
        self.assertFalse(self.widget.hasInput())
92
93
    def test_hasInput_true(self):
94
        # hasInput is true is the widget's name in the form data.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
95
        self.widget.request = LaunchpadTestRequest(form=self.form)
14400.2.8 by Curtis Hovey
Added test coverage for hasInput.
96
        self.assertEqual('field.target', self.widget.name)
97
        self.assertTrue(self.widget.hasInput())
98
14400.2.4 by Curtis Hovey
Verify the subwidgets are setup.
99
    def test_setUpSubWidgets_first_call(self):
100
        # The subwidgets are setup and a flag is set.
101
        self.widget.setUpSubWidgets()
102
        self.assertTrue(self.widget._widgets_set_up)
103
        self.assertIsInstance(
104
            self.widget.distribution_widget.context.vocabulary,
105
            DistributionVocabulary)
106
        self.assertIsInstance(
14400.2.9 by Curtis Hovey
Added tests for setUpOptions.
107
            self.widget.package_widget.context.vocabulary,
108
            BinaryAndSourcePackageNameVocabulary)
109
        self.assertIsInstance(
14400.2.4 by Curtis Hovey
Verify the subwidgets are setup.
110
            self.widget.product_widget.context.vocabulary,
111
            ProductVocabulary)
14400.2.5 by Curtis Hovey
Added test for setUpSubWidgets's early exit rule.
112
113
    def test_setUpSubWidgets_second_call(self):
114
        # The setUpSubWidgets method exits early if a flag is set to
115
        # indicate that the widgets were setup.
116
        self.widget._widgets_set_up = True
117
        self.widget.setUpSubWidgets()
118
        self.assertIs(None, getattr(self.widget, 'distribution_widget', None))
119
        self.assertIs(None, getattr(self.widget, 'package_widget', None))
120
        self.assertIs(None, getattr(self.widget, 'product_widget', None))
14400.2.6 by Curtis Hovey
Added test to verify that the DistributionSourcePackageVocabulary is used
121
122
    def test_setUpSubWidgets_dsp_picker_feature_flag(self):
123
        # The DistributionSourcePackageVocabulary is used when the
124
        # disclosure.dsp_picker.enabled is true.
125
        with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
126
            self.widget.setUpSubWidgets()
127
        self.assertIsInstance(
128
            self.widget.package_widget.context.vocabulary,
129
            DistributionSourcePackageVocabulary)
14400.2.9 by Curtis Hovey
Added tests for setUpOptions.
130
131
    def test_setUpOptions_default_package_checked(self):
132
        # The radio button options are composed of the setup widgets with
133
        # the package widget set as the default.
134
        self.widget.setUpSubWidgets()
135
        self.widget.setUpOptions()
136
        self.assertEqual(
137
            "selectWidget('field.target.option.package', event)",
138
            self.widget.package_widget.onKeyPress)
139
        self.assertEqual(
140
            "selectWidget('field.target.option.product', event)",
141
            self.widget.product_widget.onKeyPress)
142
        self.assertEqual(
143
            '<input class="radioType" checked="checked" '
144
            'id="field.target.option.package" name="field.target" '
145
            'type="radio" value="package" />',
146
            self.widget.options['package'])
147
        self.assertEqual(
148
            '<input class="radioType" '
149
            'id="field.target.option.product" name="field.target" '
150
            'type="radio" value="product" />',
151
            self.widget.options['product'])
152
153
    def test_setUpOptions_product_checked(self):
154
        # The product radio button is selected when the form is submitted
14400.2.10 by Curtis Hovey
Added test coverage for hasValidInput.
155
        # when the target field's value is 'product'.
14400.2.9 by Curtis Hovey
Added tests for setUpOptions.
156
        form = {
157
            'field.target': 'product',
158
            }
159
        self.widget.request = LaunchpadTestRequest(form=form)
160
        self.widget.setUpSubWidgets()
161
        self.widget.setUpOptions()
162
        self.assertEqual(
163
            '<input class="radioType" '
164
            'id="field.target.option.package" name="field.target" '
165
            'type="radio" value="package" />',
166
            self.widget.options['package'])
167
        self.assertEqual(
168
            '<input class="radioType" checked="checked" '
169
            'id="field.target.option.product" name="field.target" '
170
            'type="radio" value="product" />',
171
            self.widget.options['product'])
14400.2.10 by Curtis Hovey
Added test coverage for hasValidInput.
172
173
    def test_hasValidInput_true(self):
174
        # The field input is valid when all submitted parts are valid.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
175
        self.widget.request = LaunchpadTestRequest(form=self.form)
14400.2.10 by Curtis Hovey
Added test coverage for hasValidInput.
176
        self.assertTrue(self.widget.hasValidInput())
177
178
    def test_hasValidInput_false(self):
179
        # The field input is invalid if any of the submitted parts are
180
        # invalid.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
181
        form = self.form
14400.2.17 by Curtis Hovey
Added tests for call.
182
        form['field.target.package'] = 'non-existent'
14400.2.10 by Curtis Hovey
Added test coverage for hasValidInput.
183
        self.widget.request = LaunchpadTestRequest(form=form)
184
        self.assertFalse(self.widget.hasValidInput())
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
185
14400.2.21 by Curtis Hovey
Fixed case where package_name is already a dsp.
186
    def test_getInputValue_package_spn(self):
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
187
        # The field value is the package when the package radio button
14400.2.26 by Curtis Hovey
Fixed comments and documentation.
188
        # is selected and the package sub field has official spn.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
189
        self.widget.request = LaunchpadTestRequest(form=self.form)
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
190
        self.assertEqual(self.package, self.widget.getInputValue())
191
14400.2.22 by Curtis Hovey
Added setDistribution() so that the LaunchpadTargetWidget can pass the
192
    def test_getInputValue_package_spn_dsp_picker_feature_flag(self):
14400.2.21 by Curtis Hovey
Fixed case where package_name is already a dsp.
193
        # The field value is the package when the package radio button
14400.2.26 by Curtis Hovey
Fixed comments and documentation.
194
        # is selected and the package sub field has a official dsp.
14400.2.21 by Curtis Hovey
Fixed case where package_name is already a dsp.
195
        self.widget.request = LaunchpadTestRequest(form=self.form)
196
        with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
197
            self.widget.setUpSubWidgets()
198
            self.assertEqual(self.package, self.widget.getInputValue())
199
200
    def test_getInputValue_package_dsp_dsp_picker_feature_flag(self):
201
        # The field value is the package when the package radio button
202
        # is selected and the package sub field has valid input.
203
        form = self.form
204
        form['field.target.package'] = 'fnord/snarf'
205
        self.widget.request = LaunchpadTestRequest(form=form)
206
        with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
207
            self.widget.setUpSubWidgets()
208
            self.assertEqual(self.package, self.widget.getInputValue())
209
14400.2.15 by Curtis Hovey
Added test for invalid package.
210
    def test_getInputValue_package_invalid(self):
14400.2.17 by Curtis Hovey
Added tests for call.
211
        # An error is raised when the package is not published in the distro.
14400.2.15 by Curtis Hovey
Added test for invalid package.
212
        form = self.form
14400.2.17 by Curtis Hovey
Added tests for call.
213
        form['field.target.package'] = 'non-existent'
14400.2.15 by Curtis Hovey
Added test for invalid package.
214
        self.widget.request = LaunchpadTestRequest(form=form)
215
        message = (
14400.2.17 by Curtis Hovey
Added tests for call.
216
            "There is no package name 'non-existent' published in Fnord")
14400.2.15 by Curtis Hovey
Added test for invalid package.
217
        self.assertRaisesWithContent(
218
            LaunchpadValidationError, message, self.widget.getInputValue)
14400.2.17 by Curtis Hovey
Added tests for call.
219
        self.assertEqual(message, self.widget.error())
14400.2.15 by Curtis Hovey
Added test for invalid package.
220
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
221
    def test_getInputValue_distribution(self):
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
222
        # The field value is the distribution when the package radio button
223
        # is selected and the package sub field empty.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
224
        form = self.form
225
        form['field.target.package'] = ''
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
226
        self.widget.request = LaunchpadTestRequest(form=form)
227
        self.assertEqual(self.distribution, self.widget.getInputValue())
228
14400.2.13 by Curtis Hovey
Added a test for invalid distros.
229
    def test_getInputValue_distribution_invalid(self):
14400.2.15 by Curtis Hovey
Added test for invalid package.
230
        # An error is raised when the distribution is invalid.
14400.2.13 by Curtis Hovey
Added a test for invalid distros.
231
        form = self.form
232
        form['field.target.package'] = ''
14400.2.17 by Curtis Hovey
Added tests for call.
233
        form['field.target.distribution'] = 'non-existent'
14400.2.13 by Curtis Hovey
Added a test for invalid distros.
234
        self.widget.request = LaunchpadTestRequest(form=form)
235
        message = (
14400.2.17 by Curtis Hovey
Added tests for call.
236
            "There is no distribution named 'non-existent' registered in "
14400.2.13 by Curtis Hovey
Added a test for invalid distros.
237
            "Launchpad")
238
        self.assertRaisesWithContent(
239
            LaunchpadValidationError, message, self.widget.getInputValue)
14400.2.17 by Curtis Hovey
Added tests for call.
240
        self.assertEqual(message, self.widget.error())
14400.2.13 by Curtis Hovey
Added a test for invalid distros.
241
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
242
    def test_getInputValue_product(self):
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
243
        # The field value is the product when the project radio button
244
        # is selected and the project sub field is valid.
14400.2.12 by Curtis Hovey
Refactored common code to a property. Removed unneeded setup.
245
        form = self.form
246
        form['field.target'] = 'product'
14400.2.11 by Curtis Hovey
Added optimistic tests for getInputValue.
247
        self.widget.request = LaunchpadTestRequest(form=form)
248
        self.assertEqual(self.project, self.widget.getInputValue())
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
249
14400.2.15 by Curtis Hovey
Added test for invalid package.
250
    def test_getInputValue_product_missing(self):
251
        # An error is raised when the product field is missing.
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
252
        form = self.form
253
        form['field.target'] = 'product'
254
        del form['field.target.product']
255
        self.widget.request = LaunchpadTestRequest(form=form)
256
        message = 'Please enter a project name'
257
        self.assertRaisesWithContent(
258
            LaunchpadValidationError, message, self.widget.getInputValue)
14400.2.17 by Curtis Hovey
Added tests for call.
259
        self.assertEqual(message, self.widget.error())
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
260
261
    def test_getInputValue_product_invalid(self):
14400.2.15 by Curtis Hovey
Added test for invalid package.
262
        # An error is raised when the product is not valid.
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
263
        form = self.form
264
        form['field.target'] = 'product'
14400.2.17 by Curtis Hovey
Added tests for call.
265
        form['field.target.product'] = 'non-existent'
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
266
        self.widget.request = LaunchpadTestRequest(form=form)
267
        message = (
14400.2.17 by Curtis Hovey
Added tests for call.
268
            "There is no project named 'non-existent' registered in "
14400.2.14 by Curtis Hovey
Added tests for invalid product targets.
269
            "Launchpad")
270
        self.assertRaisesWithContent(
271
            LaunchpadValidationError, message, self.widget.getInputValue)
14400.2.17 by Curtis Hovey
Added tests for call.
272
        self.assertEqual(message, self.widget.error())
14400.2.16 by Curtis Hovey
Added tests for setRenderedValue.
273
274
    def test_setRenderedValue_product(self):
275
        # Passing a product will set the widget's render state to 'product'.
276
        self.widget.setUpSubWidgets()
277
        self.widget.setRenderedValue(self.project)
278
        self.assertEqual('product', self.widget.default_option)
279
        self.assertEqual(
280
            self.project, self.widget.product_widget._getCurrentValue())
281
282
    def test_setRenderedValue_distribution(self):
283
        # Passing a distribution will set the widget's render state to
284
        # 'package', but only the distribution widget is set.
285
        self.widget.setUpSubWidgets()
286
        self.widget.setRenderedValue(self.distribution)
287
        self.assertEqual('package', self.widget.default_option)
288
        self.assertEqual(
289
            self.distribution,
290
            self.widget.distribution_widget._getCurrentValue())
291
        self.assertEqual(
292
            None, self.widget.package_widget._getCurrentValue())
293
294
    def test_setRenderedValue_package(self):
295
        # Passing a package will set the widget's render state to
296
        # 'package'.
297
        self.widget.setUpSubWidgets()
298
        self.widget.setRenderedValue(self.package)
299
        self.assertEqual('package', self.widget.default_option)
300
        self.assertEqual(
301
            self.distribution,
302
            self.widget.distribution_widget._getCurrentValue())
303
        self.assertEqual(
304
            self.package.sourcepackagename,
305
            self.widget.package_widget._getCurrentValue())
14400.2.17 by Curtis Hovey
Added tests for call.
306
307
    def test_call(self):
308
        # The __call__ method setups the widgets and the options.
309
        markup = self.widget()
310
        self.assertIsNot(None, self.widget.package_widget)
311
        self.assertTrue('package' in self.widget.options)
312
        expected_ids = [
313
            'field.target.distribution',
314
            'field.target.option.package',
315
            'field.target.option.product',
316
            'field.target.package',
317
            'field.target.product',
318
            ]
319
        soup = BeautifulSoup(markup)
320
        fields = soup.findAll(['input', 'select'], {'id': re.compile('.*')})
321
        ids = [field['id'] for field in fields]
322
        self.assertContentEqual(expected_ids, ids)