1<?php
2/**
3 * Unit tests for HTML_QuickForm2 package
4 *
5 * PHP version 5
6 *
7 * LICENSE
8 *
9 * This source file is subject to BSD 3-Clause License that is bundled
10 * with this package in the file LICENSE and available at the URL
11 * https://raw.githubusercontent.com/pear/HTML_QuickForm2/trunk/docs/LICENSE
12 *
13 * @category  HTML
14 * @package   HTML_QuickForm2
15 * @author    Alexey Borzov <avb@php.net>
16 * @author    Bertrand Mansion <golgote@mamasam.com>
17 * @copyright 2006-2021 Alexey Borzov <avb@php.net>, Bertrand Mansion <golgote@mamasam.com>
18 * @license   https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
19 * @link      https://pear.php.net/package/HTML_QuickForm2
20 */
21
22/** Sets up includes */
23require_once dirname(__DIR__) . '/TestHelper.php';
24
25/**
26 * The non-abstract subclass of Rule
27 */
28class HTML_QuickForm2_Rule_ImplConst extends HTML_QuickForm2_Rule
29{
30    protected function validateOwner()
31    {
32        // It just returns whatever value was passed to setConfig()
33        return $this->config;
34    }
35}
36
37/**
38 * Unit test for HTML_QuickForm2_Rule class
39 */
40class HTML_QuickForm2_RuleTest extends PHPUnit_Framework_TestCase
41{
42    public function testSetAndGetOptions()
43    {
44        $rule = new HTML_QuickForm2_Rule_ImplConst(
45            new HTML_QuickForm2_Element_InputText('foo'), 'a message', 'bar'
46        );
47        $this->assertEquals('bar', $rule->getConfig());
48
49        $this->assertSame($rule, $rule->setConfig('baz'));
50        $this->assertEquals('baz', $rule->getConfig());
51    }
52
53    public function testSetAndGetMessage()
54    {
55        $rule = new HTML_QuickForm2_Rule_ImplConst(
56            new HTML_QuickForm2_Element_InputText('foo'), 'a message', 'bar'
57        );
58        $this->assertEquals('a message', $rule->getMessage());
59
60        $this->assertSame($rule, $rule->setMessage('another message'));
61        $this->assertEquals('another message', $rule->getMessage());
62    }
63
64    public function testValidateSingle()
65    {
66        $ruleTrue = new HTML_QuickForm2_Rule_ImplConst(
67            new HTML_QuickForm2_Element_InputText('ruleTrue'), 'a message', true
68        );
69        $this->assertTrue($ruleTrue->validate());
70
71        $ruleFalse = new HTML_QuickForm2_Rule_ImplConst(
72            new HTML_QuickForm2_Element_InputText('ruleFalse'), 'a message', false
73        );
74        $this->assertFalse($ruleFalse->validate());
75    }
76
77    public function testValidateChained()
78    {
79        $elTest = new HTML_QuickForm2_Element_InputText('testAndOr');
80        $ruleAnd = new HTML_QuickForm2_Rule_ImplConst($elTest, 'a message', true);
81        $ruleAnd->and_(new HTML_QuickForm2_Rule_ImplConst($elTest, 'a message', false));
82        $this->assertFalse($ruleAnd->validate());
83
84        $ruleOr = new HTML_QuickForm2_Rule_ImplConst($elTest, 'a message', false);
85        $ruleOr->or_(new HTML_QuickForm2_Rule_ImplConst($elTest, 'a message', true));
86        $this->assertTrue($ruleOr->validate());
87    }
88
89    public function testOperatorPrecedence()
90    {
91        // true = true or true and false != ((true or true) and false) = false
92        $elTest = new HTML_QuickForm2_Element_InputText('testPrecedence');
93        $ruleTrue = new HTML_QuickForm2_Rule_ImplConst($elTest, 'a message', true);
94        $ruleFalse = new HTML_QuickForm2_Rule_ImplConst($elTest, 'a message', false);
95
96        $ruleTrue->or_(clone $ruleTrue)->and_($ruleFalse);
97        $this->assertTrue($ruleTrue->validate());
98    }
99
100    public function testShortCircuitedEvaluationAnd()
101    {
102        $elTest = new HTML_QuickForm2_Element_InputText('testShortCircuitedAnd');
103        $ruleTrue = new HTML_QuickForm2_Rule_ImplConst($elTest, '...', true);
104        $ruleFalse = new HTML_QuickForm2_Rule_ImplConst($elTest, '...', false);
105
106        $ruleAndTrue = $this->getMockBuilder('HTML_QuickForm2_Rule')
107            ->setMethods(['validateOwner'])
108            ->setConstructorArgs([$elTest])
109            ->getMock();
110        $ruleAndTrue->expects($this->once())->method('validateOwner');
111        $ruleTrue->and_($ruleAndTrue);
112        $ruleTrue->validate();
113
114        $ruleAndFalse = $this->getMockBuilder('HTML_QuickForm2_Rule')
115            ->setMethods(['validateOwner'])
116            ->setConstructorArgs([$elTest])
117            ->getMock();
118        $ruleAndFalse->expects($this->never())->method('validateOwner');
119        $ruleFalse->and_($ruleAndFalse);
120        $ruleFalse->validate();
121    }
122
123    public function testShortCircuitedEvaluationOr()
124    {
125        $elTest = new HTML_QuickForm2_Element_InputText('testShortCircuitedOr');
126        $ruleTrue = new HTML_QuickForm2_Rule_ImplConst($elTest, '...', true);
127        $ruleFalse = new HTML_QuickForm2_Rule_ImplConst($elTest, '...', false);
128
129        $ruleOrTrue = $this->getMockBuilder('HTML_QuickForm2_Rule')
130            ->setMethods(['validateOwner'])
131            ->setConstructorArgs([$elTest])
132            ->getMock();
133        $ruleOrTrue->expects($this->never())->method('validateOwner');
134        $ruleTrue->or_($ruleOrTrue);
135        $ruleTrue->validate();
136
137        $ruleOrFalse = $this->getMockBuilder('HTML_QuickForm2_Rule')
138            ->setMethods(['validateOwner'])
139            ->setConstructorArgs([$elTest])
140            ->getMock();
141        $ruleOrFalse->expects($this->once())->method('validateOwner');
142        $ruleFalse->or_($ruleOrFalse);
143        $ruleFalse->validate();
144    }
145
146    public function testSetErrorOnlyOnChainFailure()
147    {
148        $elTest = new HTML_QuickForm2_Element_InputText('valid');
149        $chain  = new HTML_QuickForm2_Rule_ImplConst($elTest, 'bogus error', false);
150        $chain->or_(new HTML_QuickForm2_Rule_ImplConst($elTest, '', true));
151
152        $this->assertTrue($chain->validate());
153        $this->assertEquals('', $elTest->getError());
154
155        $chain2 = new HTML_QuickForm2_Rule_ImplConst($elTest, 'genuine error', false);
156        $chain2->or_(new HTML_QuickForm2_Rule_ImplConst($elTest, '', false));
157
158        $this->assertFalse($chain2->validate());
159        $this->assertEquals('genuine error', $elTest->getError());
160    }
161
162    public function testDefaultConfigMerging()
163    {
164        $this->assertEquals('foo', HTML_QuickForm2_Rule::mergeConfig('foo', null));
165        $this->assertEquals('bar', HTML_QuickForm2_Rule::mergeConfig('foo', 'bar'));
166
167        HTML_QuickForm2_Factory::registerRule('no-config', 'HTML_QuickForm2_Rule_ImplConst');
168        HTML_QuickForm2_Factory::registerRule('with-config', 'HTML_QuickForm2_Rule_ImplConst',
169                                              null, 'bar');
170        $el = new HTML_QuickForm2_Element_InputText();
171        $this->assertEquals('foo', $el->createRule('no-config', '', 'foo')->getConfig());
172        $this->assertEquals('bar', $el->createRule('with-config', '', 'foo')->getConfig());
173    }
174
175    public function testValidationTriggers()
176    {
177        $el = new HTML_QuickForm2_Element_InputText('foo', ['id' => 'foo']);
178        $rule = $this->getMockBuilder('HTML_QuickForm2_Rule')
179            ->setMethods(['validateOwner', 'getJavascriptCallback'])
180            ->setConstructorArgs([$el])
181            ->getMock();
182        $rule->expects($this->any())->method('getJavascriptCallback')
183             ->will($this->returnValue('a callback'));
184
185        $this->assertContains('qf.LiveRule', $rule->getJavascript());
186        $this->assertContains('["foo"]', $rule->getJavascript());
187        $this->assertNotContains('qf.LiveRule', $rule->getJavascript(false));
188    }
189
190    public function testChainedValidationTriggers()
191    {
192        $foo = new HTML_QuickForm2_Element_InputText('foo', ['id' => 'foo']);
193        $bar = new HTML_QuickForm2_Element_InputText('bar', ['id' => 'bar']);
194        $baz = new HTML_QuickForm2_Element_InputText('baz', ['id' => 'baz']);
195
196        $ruleFoo = $this->getMockBuilder('HTML_QuickForm2_Rule')
197            ->setMethods(['validateOwner', 'getJavascriptCallback'])
198            ->setConstructorArgs([$foo])
199            ->getMock();
200        $ruleBar = $this->getMockBuilder('HTML_QuickForm2_Rule')
201            ->setMethods(['validateOwner', 'getJavascriptCallback'])
202            ->setConstructorArgs([$bar])
203            ->getMock();
204        $ruleBaz = $this->getMockBuilder('HTML_QuickForm2_Rule')
205            ->setMethods(['validateOwner', 'getJavascriptCallback'])
206            ->setConstructorArgs([$baz])
207            ->getMock();
208        $ruleFoo->expects($this->once())->method('getJavascriptCallback')
209                ->will($this->returnValue('a callback'));
210        $ruleBar->expects($this->once())->method('getJavascriptCallback')
211                ->will($this->returnValue('a callback'));
212        $ruleBar->expects($this->once())->method('getJavascriptCallback')
213                ->will($this->returnValue('a callback'));
214
215        $script = $ruleFoo->and_($ruleBar->and_($ruleBaz))->getJavascript();
216        preg_match('/\[\S+\]/', $script, $m);
217        $this->assertContains('foo', $m[0]);
218        $this->assertContains('bar', $m[0]);
219        $this->assertContains('baz', $m[0]);
220    }
221
222    public function testCannotSetErrorsOnHiddenElements()
223    {
224        $hidden = new HTML_QuickForm2_Element_InputHidden('noError');
225        $text   = new HTML_QuickForm2_Element_InputText('canHaveError');
226
227        try {
228            $rule = $this->getMockBuilder('HTML_QuickForm2_Rule')
229                ->setMethods(['validateOwner'])
230                ->setConstructorArgs([$hidden, 'an error message'])
231                ->getMock();
232            $this->fail('Expected HTML_QuickForm2_InvalidArgumentException was not thrown');
233        } catch (HTML_QuickForm2_InvalidArgumentException $e) {}
234
235        try {
236            $rule = $this->getMockBuilder('HTML_QuickForm2_Rule')
237                ->setMethods(['validateOwner'])
238                ->setConstructorArgs([$text, 'an error message'])
239                ->getMock();
240            $rule->setOwner($hidden);
241            $this->fail('Expected HTML_QuickForm2_InvalidArgumentException was not thrown');
242        } catch (HTML_QuickForm2_InvalidArgumentException $e) {}
243    }
244}
245?>
246