Completed
Push — new-committers ( 29cb6f...bcba16 )
by Sam
12:18 queued 33s
created

CheckboxSetFieldTest   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 203
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13
Metric Value
wmc 7
lcom 1
cbo 13
dl 0
loc 203
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
B testSetDefaultItems() 0 35 1
A testSaveWithNothingSelected() 0 17 1
B testSaveWithArrayValueSet() 0 33 1
A testLoadDataFromObject() 0 23 1
A testSavingIntoTextField() 0 18 1
B testValidationWithArray() 0 26 1
B testValidationWithDataList() 0 34 1
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,
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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');
0 ignored issues
show
Unused Code introduced by
$article is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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()	->map());
181
		$validator = new RequiredFields();
182
		$field->setValue(array(
183
			$tag1->ID => $tag1->ID,
184
			$tag2->ID => $tag2->ID
185
		));
186
		$this->assertTrue(
187
			$field->validate($validator),
188
			'Validates values in source map'
189
		);
190
		//invalid value should fail
191
		$fakeID = CheckboxSetFieldTest_Tag::get()->max('ID') + 1;
192
		$field->setValue(array($fakeID => $fakeID));
193
		$this->assertFalse(
194
			$field->validate($validator),
195
			'Field does not valid values outside of source map'
196
		);
197
		//non valid value included with valid options should succeed
198
		$field->setValue(array(
199
			$tag1->ID => $tag1->ID,
200
			$tag2->ID => $tag2->ID,
201
			$tag3->ID => $tag3->ID
202
		));
203
		$this->assertTrue(
204
			$field->validate($validator),
205
			'Validates when presented with mixed valid and invalid values'
206
		);
207
	}
208
209
}
210
211
/**
212
 * @package framework
213
 * @subpackage tests
214
 */
215
216
class CheckboxSetFieldTest_Article extends DataObject implements TestOnly {
217
218
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
219
		"Content" => "Text",
220
	);
221
222
	private static $many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
223
		"Tags" => "CheckboxSetFieldTest_Tag",
224
	);
225
226
}
227
228
/**
229
 * @package framework
230
 * @subpackage tests
231
 */
232
class CheckboxSetFieldTest_Tag extends DataObject implements TestOnly {
233
234
	private static $belongs_many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
235
		'Articles' => 'CheckboxSetFieldTest_Article'
236
	);
237
}
238