• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 755

14 Feb 2026 07:14PM UTC coverage: 80.526%. Remained the same
755

push

github

hazendaz
[ci] Fix badge

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8245 of 10124 relevant lines covered (81.44%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.65
/src/main/java/com/meterware/httpunit/FormControl.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2000-2026 Russell Gold
6
 * Copyright 2021-2000 hazendaz
7
 */
8
package com.meterware.httpunit;
9

10
import com.meterware.httpunit.controls.SelectionFormControl;
11
import com.meterware.httpunit.dom.HTMLControl;
12
import com.meterware.httpunit.dom.HTMLInputElementImpl;
13
import com.meterware.httpunit.dom.HTMLSelectElementImpl;
14
import com.meterware.httpunit.dom.HTMLTextAreaElementImpl;
15
import com.meterware.httpunit.protocol.ParameterProcessor;
16
import com.meterware.httpunit.protocol.UploadFileSpec;
17
import com.meterware.httpunit.scripting.Input;
18
import com.meterware.httpunit.scripting.ScriptableDelegate;
19

20
import java.io.IOException;
21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Set;
24

25
import org.w3c.dom.Node;
26
import org.xml.sax.SAXException;
27

28
/**
29
 * Represents a control in an HTML form.
30
 **/
31
public abstract class FormControl extends HTMLElementBase {
32

33
    /** The Constant NO_VALUE. */
34
    static final String[] NO_VALUE = {};
1✔
35

36
    /** The form. */
37
    private final WebForm _form;
38

39
    /** The control. */
40
    private HTMLControl _control;
41

42
    /** The Constant UNDEFINED_TYPE. */
43
    public static final String UNDEFINED_TYPE = "undefined";
44

45
    /** The Constant BUTTON_TYPE. */
46
    public static final String BUTTON_TYPE = "button";
47

48
    /** The Constant RESET_BUTTON_TYPE. */
49
    public static final String RESET_BUTTON_TYPE = "reset";
50

51
    /** The Constant SUBMIT_BUTTON_TYPE. */
52
    public static final String SUBMIT_BUTTON_TYPE = "submit";
53

54
    /** The Constant IMAGE_BUTTON_TYPE. */
55
    public static final String IMAGE_BUTTON_TYPE = "image";
56

57
    /** The Constant RADIO_BUTTON_TYPE. */
58
    public static final String RADIO_BUTTON_TYPE = "radio";
59

60
    /** The Constant CHECKBOX_TYPE. */
61
    public static final String CHECKBOX_TYPE = "checkbox";
62

63
    /** The Constant TEXT_TYPE. */
64
    public static final String TEXT_TYPE = "text";
65

66
    /** The Constant PASSWORD_TYPE. */
67
    public static final String PASSWORD_TYPE = "password";
68

69
    /** The Constant HIDDEN_TYPE. */
70
    public static final String HIDDEN_TYPE = "hidden";
71

72
    /** The Constant TEXTAREA_TYPE. */
73
    public static final String TEXTAREA_TYPE = "textarea";
74

75
    /** The Constant FILE_TYPE. */
76
    public static final String FILE_TYPE = "file";
77

78
    /** The Constant SINGLE_TYPE. */
79
    public static final String SINGLE_TYPE = "select-one";
80

81
    /** The Constant MULTIPLE_TYPE. */
82
    public static final String MULTIPLE_TYPE = "select-multiple";
83

84
    /**
85
     * Return the type of the control, as seen from JavaScript.
86
     *
87
     * @return the type
88
     */
89
    public abstract String getType();
90

91
    /**
92
     * New selection option.
93
     *
94
     * @return the scriptable delegate
95
     */
96
    static ScriptableDelegate newSelectionOption() {
97
        return new SelectionFormControl.Option();
1✔
98
    }
99

100
    /**
101
     * Instantiates a new form control.
102
     *
103
     * @param form
104
     *            the form
105
     */
106
    FormControl(WebForm form) {
107
        this(form, newEmptyControlElement(form));
1✔
108
    }
1✔
109

110
    /**
111
     * New empty control element.
112
     *
113
     * @param form
114
     *            the form
115
     *
116
     * @return the HTML control
117
     */
118
    private static HTMLControl newEmptyControlElement(WebForm form) {
119
        return (HTMLControl) form.getElement().getOwnerDocument().createElement("input");
1✔
120
    }
121

122
    /**
123
     * initialize the given form control from a Webform and a HTMLControl.
124
     *
125
     * @param form
126
     *            the form
127
     * @param control
128
     *            the control
129
     */
130
    protected FormControl(WebForm form, HTMLControl control) {
131
        super(control);
1✔
132
        _control = control;
1✔
133
        _form = form;
1✔
134
        supportAttribute("tabindex");
1✔
135
        supportAttribute("disabled");
1✔
136
        // Add all custom attributes
137
        Set customAttributes = HttpUnitOptions.getCustomAttributes();
1✔
138
        if (customAttributes != null) {
1✔
139
            for (Iterator iter = customAttributes.iterator(); iter.hasNext();) {
1✔
140
                supportAttribute((String) iter.next());
1✔
141
            }
142
        }
143
    }
1✔
144

145
    /**
146
     * Returns the current value(s) associated with this control. These values will be transmitted to the server if the
147
     * control is 'successful'.
148
     *
149
     * @return the values
150
     */
151
    protected abstract String[] getValues();
152

153
    /**
154
     * Returns either a single delegate object or potentially an array of delegates as needed, given the form control.
155
     * This default implementation returns the scriptable delegate for the control.
156
     *
157
     * @return the delegate
158
     */
159
    Object getDelegate() {
160
        return getScriptingHandler();
1✔
161
    }
162

163
    /**
164
     * Gets the form.
165
     *
166
     * @return the form
167
     */
168
    protected final WebForm getForm() {
169
        return _form;
1✔
170
    }
171

172
    @Override
173
    public ScriptableDelegate getParentDelegate() {
174
        return (ScriptableDelegate) getForm().getScriptingHandler();
1✔
175
    }
176

177
    /**
178
     * Returns the values permitted in this control. Does not apply to text or file controls.
179
     *
180
     * @return the option values
181
     */
182
    public String[] getOptionValues() {
183
        return NO_VALUE;
×
184
    }
185

186
    /**
187
     * Returns the list of values displayed by this control, if any.
188
     *
189
     * @return the displayed options
190
     */
191
    protected String[] getDisplayedOptions() {
192
        return NO_VALUE;
×
193
    }
194

195
    /**
196
     * Returns true if this control is read-only.
197
     *
198
     * @return true, if is read only
199
     */
200
    protected boolean isReadOnly() {
201
        return isDisabled() || _control.getReadOnly();
1✔
202
    }
203

204
    /**
205
     * Returns true if this control is hidden.
206
     *
207
     * @return true, if is hidden
208
     */
209
    public boolean isHidden() {
210
        return false;
1✔
211
    }
212

213
    /**
214
     * Sets the disabled.
215
     *
216
     * @param disabled
217
     *            the new disabled
218
     */
219
    void setDisabled(boolean disabled) {
220
        _control.setDisabled(disabled);
1✔
221
    }
1✔
222

223
    /**
224
     * Returns true if this control is disabled, meaning that it will not send a value to the server as part of a
225
     * request.
226
     *
227
     * @return true, if is disabled
228
     */
229
    public boolean isDisabled() {
230
        return _control.getDisabled();
1✔
231
    }
232

233
    /**
234
     * Returns true if this control accepts free-form text.
235
     *
236
     * @return true, if is text control
237
     */
238
    boolean isTextControl() {
239
        return false;
×
240
    }
241

242
    /**
243
     * Returns true if only one control of this kind with this name can have a value. This is true for radio buttons.
244
     *
245
     * @return true, if is exclusive
246
     */
247
    boolean isExclusive() {
248
        return false;
1✔
249
    }
250

251
    /**
252
     * Returns true if a single control can have multiple values.
253
     *
254
     * @return true, if is multi valued
255
     */
256
    protected boolean isMultiValued() {
257
        return false;
×
258
    }
259

260
    /**
261
     * Returns true if this control accepts a file for upload.
262
     *
263
     * @return true, if is file parameter
264
     */
265
    boolean isFileParameter() {
266
        return false;
1✔
267
    }
268

269
    /**
270
     * Adds the values.
271
     *
272
     * @param processor
273
     *            the processor
274
     * @param characterSet
275
     *            the character set
276
     *
277
     * @throws IOException
278
     *             Signals that an I/O exception has occurred.
279
     */
280
    protected abstract void addValues(ParameterProcessor processor, String characterSet) throws IOException;
281

282
    /**
283
     * Remove any required values for this control from the list, throwing an exception if they are missing.
284
     *
285
     * @param values
286
     *            the values
287
     */
288
    void claimRequiredValues(List values) {
289
    }
1✔
290

291
    /**
292
     * Sets this control to the next compatible value from the list, removing it from the list.
293
     *
294
     * @param values
295
     *            the values
296
     */
297
    void claimValue(List values) {
298
    }
1✔
299

300
    /**
301
     * Sets this control to the next compatible value from the list, removing it from the list.
302
     *
303
     * @param values
304
     *            the values
305
     */
306
    protected void claimUniqueValue(List values) {
307
    }
1✔
308

309
    /**
310
     * Specifies a file to be uploaded via this control.
311
     *
312
     * @param files
313
     *            the files
314
     */
315
    void claimUploadSpecification(List files) {
316
    }
×
317

318
    /**
319
     * Resets this control to its initial value.
320
     **/
321
    protected void reset() {
322
        _control.reset();
1✔
323
    }
1✔
324

325
    /**
326
     * Toggles the value of this control.
327
     */
328
    public void toggle() {
329
        throw new FormParameter.IllegalCheckboxParameterException(getName(), "toggleCheckbox");
1✔
330
    }
331

332
    /**
333
     * Sets the state of this boolean control.
334
     *
335
     * @param state
336
     *            the new state
337
     */
338
    public void setState(boolean state) {
339
        throw new FormParameter.IllegalCheckboxParameterException(getName(), "setCheckbox");
×
340
    }
341

342
    /**
343
     * Performs the 'onChange' event defined for this control.
344
     *
345
     * @deprecated since 1.7 use doOnChangeEvent instead
346
     */
347
    @Deprecated
348
    protected void sendOnChangeEvent() {
349
        doOnChangeEvent();
1✔
350
    }
1✔
351

352
    /**
353
     * Performs the 'onchange' event defined for this control.
354
     *
355
     * @return true, if successful
356
     */
357
    protected boolean doOnChangeEvent() {
358
        return handleEvent("onchange");
1✔
359
    }
360

361
    /**
362
     * Performs the 'onClick' event defined for this control.
363
     *
364
     * @deprecated since 1.7 use doOnClickEvent instead
365
     */
366
    @Deprecated
367
    protected void sendOnClickEvent() {
368
        doOnClickEvent();
1✔
369
    }
1✔
370

371
    /**
372
     * Performs the 'onClick' event defined for this control.
373
     *
374
     * @return true, if successful
375
     */
376
    protected boolean doOnClickEvent() {
377
        return handleEvent("onclick");
1✔
378
    }
379

380
    /**
381
     * Performs the 'onMouseUp' event defined for this control.
382
     *
383
     * @deprecated since 1.7 use doOnMouseUpEvent instead
384
     */
385
    @Deprecated
386
    protected void sendOnMouseUpEvent() {
387
        doOnMouseUpEvent();
×
388
    }
×
389

390
    /**
391
     * Performs the 'onMouseUp' event defined for this control.
392
     *
393
     * @return true, if successful
394
     */
395
    protected boolean doOnMouseUpEvent() {
396
        return handleEvent("onmouseup");
×
397
    }
398

399
    /**
400
     * Performs the 'onMouseDown' event defined for this control.
401
     *
402
     * @deprecated since 1.7 use doOnMouseDownEvent instead
403
     */
404
    @Deprecated
405
    protected void sendOnMouseDownEvent() {
406
        doOnMouseDownEvent();
×
407
    }
×
408

409
    /**
410
     * Performs the 'onMouseDown' event defined for this control.
411
     *
412
     * @return true, if successful
413
     */
414
    protected boolean doOnMouseDownEvent() {
415
        return handleEvent("onmousedown");
×
416
    }
417

418
    /**
419
     * Creates and returns a scriptable object for this control. Subclasses should override this if they use a different
420
     * implementation of Scriptable.
421
     */
422
    @Override
423
    public ScriptableDelegate newScriptable() {
424
        return new Scriptable();
×
425
    }
426

427
    /**
428
     * Returns the value of this control in the form. If no value is specified, defaults to the empty string.
429
     *
430
     * @return the value attribute
431
     */
432
    protected String getValueAttribute() {
433
        return "";
×
434
    }
435

436
    /**
437
     * Sets the value of this control in the form.
438
     *
439
     * @param value
440
     *            the new value attribute
441
     */
442
    protected void setValueAttribute(String value) {
443
    }
×
444

445
    /**
446
     * Removes the specified required value from the list of values, throwing an exception if it is missing.
447
     *
448
     * @param values
449
     *            the values
450
     * @param value
451
     *            the value
452
     */
453
    protected final void claimValueIsRequired(List values, final String value) {
454
        if (!values.contains(value)) {
1✔
455
            throw new MissingParameterValueException(getName(), value,
1✔
456
                    (String[]) values.toArray(new String[values.size()]));
1✔
457
        }
458
        values.remove(value);
1✔
459
    }
1✔
460

461
    /**
462
     * Gets the control element tags.
463
     *
464
     * @return the control element tags
465
     */
466
    static String[] getControlElementTags() {
467
        return new String[] { "textarea", "select", "button", "input" };
1✔
468
    }
469

470
    /**
471
     * return the FormControl for the given parameter node in a form.
472
     *
473
     * @param form
474
     *            - the form in which the parameter is defined
475
     * @param node
476
     *            - the node in which the parameter is defined
477
     *
478
     * @return the form control
479
     */
480
    static FormControl newFormParameter(WebForm form, Node node) {
481
        if (node.getNodeType() != Node.ELEMENT_NODE) {
1!
482
            return null;
×
483
        }
484
        if (node.getNodeName().equalsIgnoreCase("textarea")) {
1✔
485
            return new TextAreaFormControl(form, (HTMLTextAreaElementImpl) node);
1✔
486
        }
487
        if (node.getNodeName().equalsIgnoreCase("select")) {
1✔
488
            return new SelectionFormControl(form, (HTMLSelectElementImpl) node);
1✔
489
        }
490
        if (node.getNodeName().equalsIgnoreCase("button")) {
1✔
491
            HTMLControl control = (HTMLControl) node;
1✔
492
            final String type = control.getType();
1✔
493
            if (type.equalsIgnoreCase(SUBMIT_BUTTON_TYPE)) {
1✔
494
                return new SubmitButton(form, control);
1✔
495
            }
496
            if (type.equalsIgnoreCase(RESET_BUTTON_TYPE)) {
1✔
497
                return new ResetButton(form, control);
1✔
498
            }
499
            return new Button(form, control);
1✔
500
        }
501
        if (!node.getNodeName().equalsIgnoreCase("input")) {
1!
502
            return null;
×
503
        }
504
        HTMLInputElementImpl element = (HTMLInputElementImpl) node;
1✔
505
        final String type = element.getType();
1✔
506
        if (type.equalsIgnoreCase(TEXT_TYPE)) {
1✔
507
            return new TextFieldFormControl(form, element);
1✔
508
        }
509
        if (type.equalsIgnoreCase(PASSWORD_TYPE)) {
1✔
510
            return new PasswordFieldFormControl(form, element);
1✔
511
        }
512
        if (type.equalsIgnoreCase(HIDDEN_TYPE)) {
1✔
513
            return new HiddenFieldFormControl(form, element);
1✔
514
        }
515
        if (type.equalsIgnoreCase(RADIO_BUTTON_TYPE)) {
1✔
516
            return new RadioButtonFormControl(form, element);
1✔
517
        }
518
        if (type.equalsIgnoreCase(CHECKBOX_TYPE)) {
1✔
519
            return new CheckboxFormControl(form, element);
1✔
520
        }
521
        if (type.equalsIgnoreCase(SUBMIT_BUTTON_TYPE) || type.equalsIgnoreCase(IMAGE_BUTTON_TYPE)) {
1✔
522
            return new SubmitButton(form, element);
1✔
523
        }
524
        if (type.equalsIgnoreCase(BUTTON_TYPE)) {
1✔
525
            return new Button(form, (HTMLControl) node);
1✔
526
        }
527
        if (type.equalsIgnoreCase(RESET_BUTTON_TYPE)) {
1✔
528
            return new ResetButton(form, (HTMLControl) node);
1✔
529
        }
530
        if (type.equalsIgnoreCase(FILE_TYPE)) {
1✔
531
            return new FileSubmitFormControl(form, element);
1✔
532
        }
533
        return new TextFieldFormControl(form, element);
1✔
534
    }
535

536
    /**
537
     * Empty if null.
538
     *
539
     * @param value
540
     *            the value
541
     *
542
     * @return the string
543
     */
544
    protected String emptyIfNull(String value) {
545
        return value == null ? "" : value;
1✔
546
    }
547

548
    /**
549
     * implementation of Scriptable input elements.
550
     */
551
    public class Scriptable extends HTMLElementScriptable implements Input {
552

553
        /**
554
         * get my Name
555
         *
556
         * @return the name of this scriptable
557
         */
558
        @Override
559
        public String getName() {
560
            return FormControl.this.getName();
1✔
561
        }
562

563
        /**
564
         * get my ID
565
         *
566
         * @return the id of this scriptable
567
         */
568
        @Override
569
        public String getID() {
570
            return FormControl.this.getID();
1✔
571
        }
572

573
        /**
574
         * construct a Scriptable.
575
         */
576
        public Scriptable() {
1✔
577
            super(FormControl.this);
1✔
578
        }
1✔
579

580
        /**
581
         * get the given property
582
         *
583
         * @param propertyName
584
         *            - the name of the property to get
585
         */
586
        @Override
587
        public Object get(String propertyName) {
588
            if (propertyName.equalsIgnoreCase("name")) {
1✔
589
                return FormControl.this.getName();
1✔
590
            }
591
            if (propertyName.equalsIgnoreCase("type")) {
1✔
592
                return FormControl.this.getType();
1✔
593
            }
594
            return super.get(propertyName);
1✔
595
        }
596

597
        /**
598
         * set the given property to the given value
599
         *
600
         * @param propertyName
601
         *            - the property to set
602
         * @param value
603
         *            - the value to use
604
         */
605
        @Override
606
        public void set(String propertyName, Object value) {
607
            if (propertyName.equalsIgnoreCase("value")) {
1✔
608
                setValueAttribute(value.toString());
1✔
609
            } else if (propertyName.equalsIgnoreCase("disabled")) {
1!
610
                setDisabled(value instanceof Boolean && ((Boolean) value).booleanValue());
1!
611
            } else {
612
                super.set(propertyName, value);
×
613
            }
614
        }
1✔
615

616
        /**
617
         * set the given attribute to the given value
618
         *
619
         * @param attributeName
620
         *            - the name of the attribute to set
621
         * @param value
622
         *            - the value to use
623
         */
624
        @Override
625
        public void setAttribute(String attributeName, Object value) {
626
            // Value set by JavaScript, make sure attribute is supported
627
            supportAttribute(attributeName);
1✔
628
            super.setAttribute(attributeName, value);
1✔
629
        }
1✔
630

631
        /**
632
         * allow calling click for this control
633
         */
634
        @Override
635
        public void click() throws IOException, SAXException {
636
            // TODO check whether the empty body of this method was correct
637
            // call onclick event handler
638
            HTMLElement element = this.get_element();
×
639
            if (element instanceof FormControl) {
×
640
                FormControl control = (FormControl) element;
×
641
                control.sendOnClickEvent();
×
642
            }
643
        }
×
644

645
        /**
646
         * simulate blur.
647
         */
648
        public void blur() {
649
            handleEvent("onblur");
×
650
        }
×
651

652
        /**
653
         * simulate focus;.
654
         */
655
        public void focus() {
656
            handleEvent("onfocus");
×
657
        }
×
658

659
        /**
660
         * allow firing a sendOnChangeEvent
661
         */
662
        @Override
663
        public void sendOnChangeEvent() {
664
            // TODO check why the test for this does not work although
665
            // the javascript function call is done in the corresponding testcase
666
            // testCallOnChange()
667
            HTMLElement element = this.get_element();
1✔
668
            if (element instanceof FormControl) {
1!
669
                FormControl control = (FormControl) element;
1✔
670
                control.sendOnChangeEvent();
1✔
671
            }
672
        }
1✔
673

674
    }
675

676
}
677

678
abstract class BooleanFormControl extends FormControl {
679

680
    private String[] _displayedValue;
681

682
    private HTMLInputElementImpl _element;
683

684
    @Override
685
    public ScriptableDelegate newScriptable() {
686
        return new Scriptable();
1✔
687
    }
688

689
    class Scriptable extends FormControl.Scriptable {
1✔
690

691
        @Override
692
        public Object get(String propertyName) {
693
            if (propertyName.equalsIgnoreCase("value")) {
1✔
694
                return getQueryValue();
1✔
695
            }
696
            if (propertyName.equalsIgnoreCase("checked")) {
1✔
697
                return isChecked() ? Boolean.TRUE : Boolean.FALSE;
1✔
698
            }
699
            if (propertyName.equalsIgnoreCase("defaultchecked")) {
1✔
700
                return _element.getDefaultChecked() ? Boolean.TRUE : Boolean.FALSE;
1✔
701
            }
702
            return super.get(propertyName);
1✔
703
        }
704

705
        @Override
706
        public void set(String propertyName, Object value) {
707
            if (propertyName.equalsIgnoreCase("checked")) {
1✔
708
                setChecked(value instanceof Boolean && ((Boolean) value).booleanValue());
1!
709
            } else {
710
                super.set(propertyName, value);
1✔
711
            }
712
        }
1✔
713
    }
714

715
    public BooleanFormControl(WebForm form, HTMLInputElementImpl element) {
716
        super(form, element);
1✔
717
        _element = element;
1✔
718
        _displayedValue = new String[] { readDisplayedValue(element) };
1✔
719
    }
1✔
720

721
    private String readDisplayedValue(Node node) {
722
        Node nextSibling = node.getNextSibling();
1✔
723
        while (nextSibling != null && nextSibling.getNodeType() != Node.TEXT_NODE
1✔
724
                && nextSibling.getNodeType() != Node.ELEMENT_NODE) {
1!
725
            nextSibling = nextSibling.getNextSibling();
×
726
        }
727
        if (nextSibling == null || nextSibling.getNodeType() != Node.TEXT_NODE) {
1✔
728
            return "";
1✔
729
        }
730
        return nextSibling.getNodeValue();
1✔
731
    }
732

733
    boolean isChecked() {
734
        return _element.getChecked();
1✔
735
    }
736

737
    @Override
738
    protected String getValueAttribute() {
739
        return emptyIfNull(_element.getValue());
1✔
740
    }
741

742
    @Override
743
    protected void setValueAttribute(String value) {
744
        _element.setValue(value);
1✔
745
    }
1✔
746

747
    /**
748
     * Sets the checked.
749
     *
750
     * @param checked
751
     *            the new checked
752
     */
753
    public void setChecked(boolean checked) {
754
        _element.setChecked(checked);
1✔
755
    }
1✔
756

757
    /**
758
     * Returns the current value(s) associated with this control. These values will be transmitted to the server if the
759
     * control is 'successful'.
760
     **/
761
    @Override
762
    public String[] getValues() {
763
        return isChecked() ? toArray(getQueryValue()) : NO_VALUE;
1✔
764
    }
765

766
    /**
767
     * Returns the values permitted in this control.
768
     **/
769
    @Override
770
    public String[] getOptionValues() {
771
        return isReadOnly() && !isChecked() ? NO_VALUE : toArray(getQueryValue());
1✔
772
    }
773

774
    @Override
775
    protected String[] getDisplayedOptions() {
776
        return _displayedValue;
1✔
777
    }
778

779
    @Override
780
    protected void addValues(ParameterProcessor processor, String characterSet) throws IOException {
781
        if (isChecked() && !isDisabled()) {
1✔
782
            processor.addParameter(getName(), getQueryValue(), characterSet);
1✔
783
        }
784
    }
1✔
785

786
    /**
787
     * Remove any required values for this control from the list, throwing an exception if they are missing.
788
     **/
789
    @Override
790
    void claimRequiredValues(List values) {
791
        if (isValueRequired()) {
1✔
792
            claimValueIsRequired(values, getQueryValue());
1✔
793
        }
794
    }
1✔
795

796
    /**
797
     * Checks if is value required.
798
     *
799
     * @return true, if is value required
800
     */
801
    protected boolean isValueRequired() {
802
        return isReadOnly() && isChecked();
1✔
803
    }
804

805
    abstract String getQueryValue();
806

807
    private String[] toArray(String value) {
808
        return new String[] { value };
1✔
809
    }
810
}
811

812
class CheckboxFormControl extends BooleanFormControl {
813

814
    @Override
815
    public String getType() {
816
        return CHECKBOX_TYPE;
1✔
817
    }
818

819
    public CheckboxFormControl(WebForm form, HTMLInputElementImpl element) {
820
        super(form, element);
1✔
821
    }
1✔
822

823
    @Override
824
    protected void claimUniqueValue(List values) {
825
        if (isValueRequired()) {
1✔
826
            return;
1✔
827
        }
828
        setState(values.contains(getQueryValue()));
1✔
829
        if (isChecked()) {
1✔
830
            values.remove(getQueryValue());
1✔
831
        }
832
    }
1✔
833

834
    @Override
835
    String getQueryValue() {
836
        final String value = getValueAttribute();
1✔
837
        return value.isEmpty() ? "on" : value;
1✔
838
    }
839

840
    /**
841
     * Toggles the value of this control.
842
     */
843
    @Override
844
    public void toggle() {
845
        setState(!isChecked());
1!
846
    }
1✔
847

848
    /**
849
     * Sets the state of this boolean control. Triggers the 'onclick' event if the state has changed.
850
     */
851
    @Override
852
    public void setState(boolean state) {
853
        boolean wasChecked = isChecked();
1✔
854
        setChecked(state);
1✔
855
        if (isChecked() != wasChecked) {
1✔
856
            sendOnClickEvent();
1✔
857
        }
858
    }
1✔
859
}
860

861
abstract class TextFormControl extends FormControl {
862

863
    public TextFormControl(WebForm form, HTMLControl control) {
864
        super(form, control);
1✔
865
    }
1✔
866

867
    /**
868
     * Returns the current value(s) associated with this control. These values will be transmitted to the server if the
869
     * control is 'successful'.
870
     **/
871
    @Override
872
    public String[] getValues() {
873
        return new String[] { getValue() };
1✔
874
    }
875

876
    abstract protected String getDefaultValue();
877

878
    abstract protected String getValue();
879

880
    abstract protected void setValue(String value);
881

882
    /**
883
     * Returns true to indicate that this control accepts free-form text.
884
     **/
885
    @Override
886
    public boolean isTextControl() {
887
        return true;
1✔
888
    }
889

890
    @Override
891
    public ScriptableDelegate newScriptable() {
892
        return new Scriptable();
1✔
893
    }
894

895
    @Override
896
    protected void addValues(ParameterProcessor processor, String characterSet) throws IOException {
897
        if (!isDisabled() && getName().length() > 0) {
1✔
898
            processor.addParameter(getName(), getValues()[0], characterSet);
1✔
899
        }
900
    }
1✔
901

902
    /**
903
     * claim values and fire onChange Event if a change occured
904
     *
905
     * @param values
906
     *            - the list of values
907
     */
908
    @Override
909
    void claimValue(List values) {
910
        if (isReadOnly()) {
1✔
911
            return;
1✔
912
        }
913

914
        String oldValue = getValue();
1✔
915
        if (values.isEmpty()) {
1✔
916
            setValue("");
1✔
917
        } else {
918
            setValue((String) values.get(0));
1✔
919
            values.remove(0);
1✔
920
        }
921
        boolean same = oldValue == null && getValue() == null;
1!
922
        if (oldValue != null) {
1!
923
            same = oldValue.equals(getValue());
1✔
924
        }
925
        if (!same) {
1✔
926
            sendOnChangeEvent();
1✔
927
        }
928
    }
1✔
929

930
    @Override
931
    void claimRequiredValues(List values) {
932
        if (isReadOnly()) {
1✔
933
            claimValueIsRequired(values);
1✔
934
        }
935
    }
1✔
936

937
    protected void claimValueIsRequired(List values) {
938
        claimValueIsRequired(values, getDefaultValue());
1✔
939
    }
1✔
940

941
    class Scriptable extends FormControl.Scriptable {
1✔
942

943
        @Override
944
        public Object get(String propertyName) {
945
            if (propertyName.equalsIgnoreCase("value")) {
1✔
946
                return getValue();
1✔
947
            }
948
            if (propertyName.equalsIgnoreCase("defaultValue")) {
1✔
949
                return getDefaultValue();
1✔
950
            }
951
            return super.get(propertyName);
1✔
952
        }
953

954
        @Override
955
        public void set(String propertyName, Object value) {
956
            if (!propertyName.equalsIgnoreCase("value")) {
1!
957
                super.set(propertyName, value);
×
958
            } else if (value instanceof Number) {
1✔
959
                setValue(HttpUnitUtils.trimmedValue((Number) value));
1✔
960
            } else {
961
                setValue(value == null ? null : value.toString());
1✔
962
            }
963
        }
1✔
964
    }
965
}
966

967
class TextFieldFormControl extends TextFormControl {
968

969
    private HTMLInputElementImpl _element;
970

971
    @Override
972
    public String getType() {
973
        return TEXT_TYPE;
1✔
974
    }
975

976
    public TextFieldFormControl(WebForm form, HTMLInputElementImpl element) {
977
        super(form, element);
1✔
978
        _element = element;
1✔
979
        supportAttribute("maxlength");
1✔
980
    }
1✔
981

982
    @Override
983
    protected String getDefaultValue() {
984
        return _element.getDefaultValue();
1✔
985
    }
986

987
    @Override
988
    protected String getValue() {
989
        return emptyIfNull(_element.getValue());
1✔
990
    }
991

992
    @Override
993
    protected void setValue(String value) {
994
        _element.setValue(value);
1✔
995
    }
1✔
996
}
997

998
class PasswordFieldFormControl extends TextFieldFormControl {
999

1000
    @Override
1001
    public String getType() {
1002
        return PASSWORD_TYPE;
1✔
1003
    }
1004

1005
    public PasswordFieldFormControl(WebForm form, HTMLInputElementImpl element) {
1006
        super(form, element);
1✔
1007
    }
1✔
1008
}
1009

1010
/**
1011
 * a hidden text field
1012
 */
1013
class HiddenFieldFormControl extends TextFieldFormControl {
1014

1015
    @Override
1016
    public String getType() {
1017
        return HIDDEN_TYPE;
1✔
1018
    }
1019

1020
    public HiddenFieldFormControl(WebForm form, HTMLInputElementImpl element) {
1021
        super(form, element);
1✔
1022
    }
1✔
1023

1024
    @Override
1025
    void claimRequiredValues(List values) {
1026
        claimValueIsRequired(values);
1✔
1027
    }
1✔
1028

1029
    @Override
1030
    void claimValue(List values) {
1031
    }
1✔
1032

1033
    @Override
1034
    public boolean isHidden() {
1035
        return true;
1✔
1036
    }
1037
}
1038

1039
class TextAreaFormControl extends TextFormControl {
1040

1041
    private HTMLTextAreaElementImpl _element;
1042

1043
    public TextAreaFormControl(WebForm form, HTMLTextAreaElementImpl element) {
1044
        super(form, element);
1✔
1045
        _element = element;
1✔
1046
    }
1✔
1047

1048
    @Override
1049
    public String getType() {
1050
        return TEXTAREA_TYPE;
1✔
1051
    }
1052

1053
    @Override
1054
    protected String getDefaultValue() {
1055
        return _element.getDefaultValue();
1✔
1056
    }
1057

1058
    @Override
1059
    protected String getValue() {
1060
        return _element.getValue();
1✔
1061
    }
1062

1063
    @Override
1064
    protected void setValue(String value) {
1065
        _element.setValue(value);
1✔
1066
    }
1✔
1067

1068
}
1069

1070
/**
1071
 * a control for File submit
1072
 */
1073
class FileSubmitFormControl extends FormControl {
1074

1075
    /**
1076
     * accessor for the type
1077
     *
1078
     * @return the constant FILE_TYPE
1079
     */
1080
    @Override
1081
    public String getType() {
1082
        return FILE_TYPE;
1✔
1083
    }
1084

1085
    private UploadFileSpec _fileToUpload;
1086

1087
    @Override
1088
    public ScriptableDelegate newScriptable() {
1089
        return new Scriptable();
1✔
1090
    }
1091

1092
    class Scriptable extends FormControl.Scriptable {
1✔
1093

1094
        @Override
1095
        public Object get(String propertyName) {
1096
            if (propertyName.equalsIgnoreCase("value")) {
1✔
1097
                return getSelectedName();
1✔
1098
            }
1099
            return super.get(propertyName);
1✔
1100
        }
1101

1102
    }
1103

1104
    public FileSubmitFormControl(WebForm form, HTMLInputElementImpl node) {
1105
        super(form, node);
1✔
1106
    }
1✔
1107

1108
    /**
1109
     * Returns true if this control accepts a file for upload.
1110
     **/
1111
    @Override
1112
    public boolean isFileParameter() {
1113
        return true;
1✔
1114
    }
1115

1116
    /**
1117
     * Returns the name of the selected file, if any.
1118
     */
1119
    @Override
1120
    public String[] getValues() {
1121
        return new String[] { getSelectedName() };
1✔
1122
    }
1123

1124
    private String getSelectedName() {
1125
        return _fileToUpload == null ? "" : _fileToUpload.getFileName();
1✔
1126
    }
1127

1128
    /**
1129
     * Specifies a number of file upload specifications for this control.
1130
     **/
1131
    @Override
1132
    void claimUploadSpecification(List files) {
1133
        if (files.isEmpty()) {
1✔
1134
            _fileToUpload = null;
1✔
1135
        } else {
1136
            _fileToUpload = (UploadFileSpec) files.get(0);
1✔
1137
            files.remove(0);
1✔
1138
        }
1139
    }
1✔
1140

1141
    @Override
1142
    protected void addValues(ParameterProcessor processor, String characterSet) throws IOException {
1143
        if (!isDisabled() && _fileToUpload != null) {
1!
1144
            processor.addFile(getName(), _fileToUpload);
1✔
1145
        }
1146
    }
1✔
1147
}
1148

1149
// ============================= exception class MissingParameterValueException ======================================
1150

1151
/**
1152
 * This exception is thrown on an attempt to remove a required value from a form parameter.
1153
 **/
1154
class MissingParameterValueException extends IllegalRequestParameterException {
1155

1156
    private static final long serialVersionUID = 1L;
1157

1158
    MissingParameterValueException(String parameterName, String missingValue, String[] proposed) {
1✔
1159
        _parameterName = parameterName;
1✔
1160
        _missingValue = missingValue;
1✔
1161
        _proposedValues = proposed;
1✔
1162
    }
1✔
1163

1164
    @Override
1165
    public String getMessage() {
1166
        StringBuilder sb = new StringBuilder(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
×
1167
        sb.append("Parameter '").append(_parameterName).append("' must have the value '");
×
1168
        sb.append(_missingValue).append("'. Attempted to set it to: { ");
×
1169
        for (int i = 0; i < _proposedValues.length; i++) {
×
1170
            if (i != 0) {
×
1171
                sb.append(", ");
×
1172
            }
1173
            sb.append(_proposedValues[i]);
×
1174
        }
1175
        sb.append(" }");
×
1176
        return sb.toString();
×
1177
    }
1178

1179
    private String _parameterName;
1180
    private String _missingValue;
1181
    private String[] _proposedValues;
1182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc