Completed
Pull Request — 3.4 (#6168)
by Damian
10:25
created

CheckboxSetFieldTest::testValidationWithDataList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 71
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 52
nc 1
nop 0
dl 0
loc 71
rs 9.1369
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package framework
5
 * @subpackage tests
6
 */
7
class CheckboxSetFieldTest extends SapphireTest {
8
9
	protected static $fixture_file = 'CheckboxSetFieldTest.yml';
10
11
	protected $extraDataObjects = array(
12
		'CheckboxSetFieldTest_Article',
13
		'CheckboxSetFieldTest_Tag',
14
	);
15
16
	public function testSetDefaultItems() {
17
		$f = new CheckboxSetField(
18
			'Test',
19
			false,
20
			array(0 => 'Zero', 1 => 'One', 2 => 'Two', 3 => 'Three')
21
		);
22
23
		$f->setValue(array(0,1));
24
		$f->setDefaultItems(array(2));
25
		$p = new CSSContentParser($f->Field());
26
		$item0 = $p->getBySelector('#Test_0');
27
		$item1 = $p->getBySelector('#Test_1');
28
		$item2 = $p->getBySelector('#Test_2');
29
		$item3 = $p->getBySelector('#Test_3');
30
		$this->assertEquals(
31
			(string)$item0[0]['checked'],
32
			'checked',
33
			'Selected through value'
34
		);
35
		$this->assertEquals(
36
			(string)$item1[0]['checked'],
37
			'checked',
38
			'Selected through value'
39
		);
40
		$this->assertEquals(
41
			(string)$item2[0]['checked'],
42
			'checked',
43
			'Selected through default items'
44
		);
45
		$this->assertEquals(
46
			(string)$item3[0]['checked'],
47
			'',
48
			'Not selected by either value or default items'
49
		);
50
	}
51
52
	public function testSaveWithNothingSelected() {
53
		$article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags');
54
55
		/* Create a CheckboxSetField with nothing selected */
56
		$field = new CheckboxSetField("Tags", "Test field", DataObject::get("CheckboxSetFieldTest_Tag")->map());
57
58
		/* Saving should work */
59
		$field->saveInto($article);
0 ignored issues
show
Bug introduced by
It seems like $article defined by $this->objFromFixture('C..., 'articlewithouttags') on line 53 can be null; however, CheckboxSetField::saveInto() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
60
61
		$this->assertNull(
62
			DB::prepared_query("SELECT *
63
				FROM \"CheckboxSetFieldTest_Article_Tags\"
64
				WHERE \"CheckboxSetFieldTest_Article_Tags\".\"CheckboxSetFieldTest_ArticleID\" = ?", array($article->ID)
65
			)->value(),
66
			'Nothing should go into manymany join table for a saved field without any ticked boxes'
67
		);
68
	}
69
70
	public function testSaveWithArrayValueSet() {
71
		$article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags');
72
		$articleWithTags = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithtags');
73
		$tag1 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag1');
74
		$tag2 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag2');
75
76
		/* Create a CheckboxSetField with 2 items selected.  Note that the array is in the format (key) => (selected) */
77
		$field = new CheckboxSetField("Tags", "Test field", DataObject::get("CheckboxSetFieldTest_Tag")->map());
78
		$field->setValue(array(
79
			$tag1->ID => true,
80
			$tag2->ID => true
81
		));
82
83
		/* Saving should work */
84
		$field->saveInto($article);
0 ignored issues
show
Bug introduced by
It seems like $article defined by $this->objFromFixture('C..., 'articlewithouttags') on line 71 can be null; however, CheckboxSetField::saveInto() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
85
86
		$this->assertEquals(
87
			array($tag1->ID,$tag2->ID),
88
			DB::prepared_query("SELECT \"CheckboxSetFieldTest_TagID\"
89
				FROM \"CheckboxSetFieldTest_Article_Tags\"
90
				WHERE \"CheckboxSetFieldTest_Article_Tags\".\"CheckboxSetFieldTest_ArticleID\" = ?", array($article->ID)
91
			)->column(),
92
			'Data shold be saved into CheckboxSetField manymany relation table on the "right end"'
93
		);
94
		$this->assertEquals(
95
			array($articleWithTags->ID,$article->ID),
96
			DB::query("SELECT \"CheckboxSetFieldTest_ArticleID\"
97
				FROM \"CheckboxSetFieldTest_Article_Tags\"
98
				WHERE \"CheckboxSetFieldTest_Article_Tags\".\"CheckboxSetFieldTest_TagID\" = $tag1->ID
99
			")->column(),
100
			'Data shold be saved into CheckboxSetField manymany relation table on the "left end"'
101
		);
102
	}
103
104
	public function testLoadDataFromObject() {
105
		$article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags');
106
		$articleWithTags = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithtags');
107
		$tag1 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag1');
108
		$tag2 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag2');
109
110
		$field = new CheckboxSetField("Tags", "Test field", DataObject::get("CheckboxSetFieldTest_Tag")->map());
111
		$form = new Form(
112
			new Controller(),
113
			'Form',
114
			new FieldList($field),
115
			new FieldList()
116
		);
117
		$form->loadDataFrom($articleWithTags);
0 ignored issues
show
Bug introduced by
It seems like $articleWithTags defined by $this->objFromFixture('C...le', 'articlewithtags') on line 106 can be null; however, Form::loadDataFrom() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
118
		$this->assertEquals(
119
			array(
120
				$tag1->ID => $tag1->ID,
121
				$tag2->ID => $tag2->ID
122
			),
123
			$field->Value(),
124
			'CheckboxSetField loads data from a manymany relationship in an object through Form->loadDataFrom()'
125
		);
126
	}
127
128
	public function testSavingIntoTextField() {
129
		$field = new CheckboxSetField('Content', 'Content', array(
130
			'Test' => 'Test',
131
			'Another' => 'Another',
132
			'Something' => 'Something'
133
		));
134
		$article = new CheckboxSetFieldTest_Article();
135
		$field->setValue(array('Test' => 'Test', 'Another' => 'Another'));
136
		$field->saveInto($article);
137
		$article->write();
138
139
		$dbValue = DB::query(sprintf(
140
			'SELECT "Content" FROM "CheckboxSetFieldTest_Article" WHERE "ID" = %s',
141
			$article->ID
142
		))->value();
143
144
		$this->assertEquals('Test,Another', $dbValue);
145
	}
146
147
	public function testValidationWithArray() {
148
		//test with array input
149
		$field = CheckboxSetField::create('Test', 'Testing', array(
150
			"One" => "One",
151
			"Two" => "Two",
152
			"Three" => "Three"
153
		));
154
		$validator = new RequiredFields();
155
		$field->setValue(array("One" => "One", "Two" => "Two"));
156
		$this->assertTrue(
157
			$field->validate($validator),
158
			'Field validates values within source array'
159
		);
160
		//non valid value should fail
161
		$field->setValue(array("Four" => "Four"));
162
		$this->assertFalse(
163
			$field->validate($validator),
164
			'Field does not validate values outside of source array'
165
		);
166
		//non valid value included with valid options should succeed
167
		$field->setValue(array("One" => "One", "Two" => "Two", "Four" => "Four"));
168
		$this->assertTrue(
169
			$field->validate($validator),
170
			'Field validates when presented with mixed valid and invalid values'
171
		);
172
	}
173
174
	public function testValidationWithDataList() {
175
		//test with datalist input
176
		$checkboxTestArticle = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithtags');
177
		$tag1 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag1');
178
		$tag2 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag2');
179
		$tag3 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag3');
180
		$field = CheckboxSetField::create('Test', 'Testing', $checkboxTestArticle->Tags());
181
		$validator = new RequiredFields();
182
		$field->setValue(array( $tag1->ID, $tag2->ID ));
183
		$isValid = $field->validate($validator);
184
		$this->assertTrue(
185
			$isValid,
186
			'Validates values in source map'
187
		);
188
189
		// Invalid value should fail
190
		$validator = new RequiredFields();
191
		$fakeID = CheckboxSetFieldTest_Tag::get()->max('ID') + 1;
192
		$field->setValue(array($fakeID));
193
		$this->assertFalse(
194
			$field->validate($validator),
195
			'Field does not valid values outside of source map'
196
		);
197
		$errors = $validator->getErrors();
198
		$error = reset($errors);
199
		$this->assertEquals(
200
			"Please select a value within the list provided. '$fakeID' is not a valid option",
201
			$error['message']
202
		);
203
204
		// Multiple invalid values should fail
205
		$validator = new RequiredFields();
206
		$fakeID = CheckboxSetFieldTest_Tag::get()->max('ID') + 1;
207
		$field->setValue(array($fakeID, $tag3->ID));
208
		$this->assertFalse(
209
			$field->validate($validator),
210
			'Field does not valid values outside of source map'
211
		);
212
		$errors = $validator->getErrors();
213
		$error = reset($errors);
214
		$this->assertEquals(
215
			"Please select a value within the list provided. '{$fakeID} and {$tag3->ID}' is not a valid option",
216
			$error['message']
217
		);
218
219
		// Invalid value with non-array value
220
		$validator = new RequiredFields();
221
		$field->setValue($fakeID);
222
		$this->assertFalse(
223
			$field->validate($validator),
224
			'Field does not valid values outside of source map'
225
		);
226
		$errors = $validator->getErrors();
227
		$error = reset($errors);
228
		$this->assertEquals(
229
			"Please select a value within the list provided. '{$fakeID}' is not a valid option",
230
			$error['message']
231
		);
232
233
		// non valid value included with valid options should succeed
234
		$validator = new RequiredFields();
235
		$field->setValue(array(
236
			$tag1->ID,
237
			$tag2->ID,
238
			$tag3->ID
239
		));
240
		$this->assertTrue(
241
			$field->validate($validator),
242
			'Validates when presented with mixed valid and invalid values'
243
		);
244
	}
245
246
	public function testSafelyCast() {
247
		$member = new Member();
248
		$member->FirstName = '<firstname>';
249
		$member->Surname = '<surname>';
250
		$member->write();
251
		$field1 = new CheckboxSetField('Options', 'Options', array(
252
			'one' => 'One',
253
			'two' => 'Two & Three',
254
			'three' => DBField::create_field('HTMLText', 'Four &amp; Five &amp; Six'),
255
			$member
256
		));
257
		$fieldHTML = (string)$field1->Field();
258
		$this->assertContains('One', $fieldHTML);
259
		$this->assertContains('Two &amp; Three', $fieldHTML);
260
		$this->assertNotContains('Two & Three', $fieldHTML);
261
		$this->assertContains('Four &amp; Five &amp; Six', $fieldHTML);
262
		$this->assertNotContains('Four & Five & Six', $fieldHTML);
263
		$this->assertContains('&lt;firstname&gt;', $fieldHTML);
264
		$this->assertNotContains('<firstname>', $fieldHTML);
265
	}
266
267
}
268
269
/**
270
 * @package framework
271
 * @subpackage tests
272
 */
273
274
class CheckboxSetFieldTest_Article extends DataObject implements TestOnly {
275
276
	private static $db = array(
277
		"Content" => "Text",
278
	);
279
280
	private static $many_many = array(
281
		"Tags" => "CheckboxSetFieldTest_Tag",
282
	);
283
284
}
285
286
/**
287
 * @package framework
288
 * @subpackage tests
289
 */
290
class CheckboxSetFieldTest_Tag extends DataObject implements TestOnly {
291
292
	private static $belongs_many_many = array(
293
		'Articles' => 'CheckboxSetFieldTest_Article'
294
	);
295
}
296