Completed
Push — 3.7 ( 81b2d8...ef0909 )
by
unknown
09:42
created

FieldListTest   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 996
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 14

Importance

Changes 0
Metric Value
dl 0
loc 996
rs 9.124
c 0
b 0
f 0
wmc 36
lcom 0
cbo 14

35 Methods

Rating   Name   Duplication   Size   Complexity  
A testAddFieldToTab() 0 25 1
A testFieldgroup() 0 33 1
A testRemoveSingleFieldFromTab() 0 17 1
A testRemoveTab() 0 13 1
A testHasTabSet() 0 13 1
A testRemoveMultipleFieldsFromTab() 0 25 1
A testRemoveFieldByName() 0 13 1
A testDataFieldByName() 0 8 1
A testRemoveFieldsByName() 0 16 1
A testReplaceField() 0 22 1
A testRenameField() 0 17 1
A testReplaceAFieldInADifferentTab() 0 20 1
A testNestedTabsFindingFieldByName() 0 31 1
A testTabTitles() 0 37 1
A testPushFieldToSet() 0 23 1
A testPushFieldToBeginningOfSet() 0 25 1
A testInsertBeforeFieldToSet() 0 35 1
A testInsertBeforeMultipleFields() 0 22 1
A testInsertAfterFieldToSet() 0 35 1
A testrootFieldList() 0 28 1
A testAddingDuplicateReplacesOldField() 0 33 1
A testAddingFieldToNonExistentTabCreatesThatTab() 0 14 1
A testAddingFieldToATabWithTheSameNameAsTheField() 0 15 1
A testInsertBeforeWithNestedCompositeFields() 0 47 1
B testInsertBeforeWithNestedTabsets() 0 56 1
A testInsertAfterWithNestedCompositeFields() 0 47 1
B testInsertAfterWithNestedTabsets() 0 55 1
A testChangeFieldOrder() 0 25 2
A testFieldPosition() 0 19 1
A testForTemplate() 0 8 1
A testForTemplateForActionList() 0 8 1
A testMakeFieldReadonly() 0 14 1
A testVisibleAndHiddenFields() 0 29 1
A testRewriteTabPath() 0 37 1
A testRewriteTabPathFindOrMakeTab() 0 33 1
1
<?php
2
3
/**
4
 * Tests for FieldList
5
 *
6
 * @package framework
7
 * @subpackage tests
8
 *
9
 * @todo test for {@link FieldList->setValues()}. Need to check
10
 * 	that the values that were set are the correct ones given back.
11
 * @todo test for {@link FieldList->transform()} and {@link FieldList->makeReadonly()}.
12
 *  Need to ensure that it correctly transforms the FieldList object.
13
 * @todo test for {@link FieldList->HiddenFields()}. Need to check
14
 * 	the fields returned are the correct HiddenField objects for a
15
 * 	given FieldList instance.
16
 * @todo test for {@link FieldList->dataFields()}.
17
 * @todo test for {@link FieldList->findOrMakeTab()}.
18
 * @todo the same as above with insertBefore() and insertAfter()
19
 *
20
 */
21
class FieldListTest extends SapphireTest {
22
23
	/**
24
	 * Test adding a field to a tab in a set.
25
	 */
26
	public function testAddFieldToTab() {
27
		$fields = new FieldList();
28
		$tab = new Tab('Root');
29
		$fields->push($tab);
30
31
		/* We add field objects to the FieldList, using two different methods */
32
		$fields->addFieldToTab('Root', new TextField('Country'));
33
		$fields->addFieldsToTab('Root', array(
34
			new EmailField('Email'),
35
			new TextField('Name'),
36
		));
37
38
		/* Check that the field objects were created */
39
		$this->assertNotNull($fields->dataFieldByName('Country'));
40
		$this->assertNotNull($fields->dataFieldByName('Email'));
41
		$this->assertNotNull($fields->dataFieldByName('Name'));
42
43
		/* The field objects in the set should be the same as the ones we created */
44
		$this->assertSame($fields->dataFieldByName('Country'), $tab->fieldByName('Country'));
45
		$this->assertSame($fields->dataFieldByName('Email'), $tab->fieldByName('Email'));
46
		$this->assertSame($fields->dataFieldByName('Name'), $tab->fieldByName('Name'));
47
48
		/* We'll have 3 fields inside the tab */
49
		$this->assertEquals(3, $tab->Fields()->Count());
50
	}
51
52
	/**
53
	 * Test that groups can be added to a fieldlist
54
	 */
55
	public function testFieldgroup() {
56
		$fields = new FieldList();
57
		$tab = new Tab('Root');
58
		$fields->push($tab);
59
60
		$fields->addFieldsToTab('Root', array(
61
			$group1 = new FieldGroup(
62
				new TextField('Name'),
63
				new EmailField('Email')
64
			),
65
			$group2 = new FieldGroup(
66
				new TextField('Company'),
67
				new TextareaField('Address')
68
			)
69
		));
70
71
		/* Check that the field objects were created */
72
		$this->assertNotNull($fields->dataFieldByName('Name'));
73
		$this->assertNotNull($fields->dataFieldByName('Email'));
74
		$this->assertNotNull($fields->dataFieldByName('Company'));
75
		$this->assertNotNull($fields->dataFieldByName('Address'));
76
77
		/* The field objects in the set should be the same as the ones we created */
78
		$this->assertSame($fields->dataFieldByName('Name'), $group1->fieldByName('Name'));
79
		$this->assertSame($fields->dataFieldByName('Email'), $group1->fieldByName('Email'));
80
		$this->assertSame($fields->dataFieldByName('Company'), $group2->fieldByName('Company'));
81
		$this->assertSame($fields->dataFieldByName('Address'), $group2->fieldByName('Address'));
82
83
		/* We'll have 2 fields directly inside the tab */
84
		$this->assertEquals(2, $tab->Fields()->Count());
85
86
87
	}
88
89
	/**
90
	 * Test removing a single field from a tab in a set.
91
	 */
92
	public function testRemoveSingleFieldFromTab() {
93
		$fields = new FieldList();
94
		$tab = new Tab('Root');
95
		$fields->push($tab);
96
97
		/* We add a field to the "Root" tab */
98
		$fields->addFieldToTab('Root', new TextField('Country'));
99
100
		/* We have 1 field inside the tab, which is the field we just created */
101
		$this->assertEquals(1, $tab->Fields()->Count());
102
103
		/* We remove the field from the tab */
104
		$fields->removeFieldFromTab('Root', 'Country');
105
106
		/* We'll have no fields in the tab now */
107
		$this->assertEquals(0, $tab->Fields()->Count());
108
	}
109
110
	public function testRemoveTab() {
111
		$fields = new FieldList(new TabSet(
112
			'Root',
113
			$tab1 = new Tab('Tab1'),
114
			$tab2 = new Tab('Tab2'),
115
			$tab3 = new Tab('Tab3')
116
		));
117
118
		$fields->removeByName('Tab2');
119
		$this->assertNull($fields->fieldByName('Root')->fieldByName('Tab2'));
120
121
		$this->assertEquals($tab1, $fields->fieldByName('Root')->fieldByName('Tab1'));
122
	}
123
124
	public function testHasTabSet() {
125
		$untabbedFields = new FieldList(
126
			new TextField('Field1')
127
		);
128
		$this->assertFalse($untabbedFields->hasTabSet());
129
130
		$tabbedFields = new FieldList(
131
			new TabSet('Root',
132
				new Tab('Tab1')
133
			)
134
		);
135
		$this->assertTrue($tabbedFields->hasTabSet());
136
	}
137
138
	/**
139
	 * Test removing an array of fields from a tab in a set.
140
	 */
141
	public function testRemoveMultipleFieldsFromTab() {
142
		$fields = new FieldList();
143
		$tab = new Tab('Root');
144
		$fields->push($tab);
145
146
		/* We add an array of fields, using addFieldsToTab() */
147
		$fields->addFieldsToTab('Root', array(
148
			new TextField('Name', 'Your name'),
149
			new EmailField('Email', 'Email address'),
150
			new NumericField('Number', 'Insert a number')
151
		));
152
153
		/* We have 3 fields inside the tab, which we just created */
154
		$this->assertEquals(3, $tab->Fields()->Count());
155
156
		/* We remove the 3 fields from the tab */
157
		$fields->removeFieldsFromTab('Root', array(
158
			'Name',
159
			'Email',
160
			'Number'
161
		));
162
163
		/* We have no fields in the tab now */
164
		$this->assertEquals(0, $tab->Fields()->Count());
165
	}
166
167
	public function testRemoveFieldByName() {
168
		$fields = new FieldList();
169
		$fields->push(new TextField('Name', 'Your name'));
170
171
		$this->assertEquals(1, $fields->Count());
172
		$fields->removeByName('Name');
173
		$this->assertEquals(0, $fields->Count());
174
175
		$fields->push(new TextField('Name[Field]', 'Your name'));
176
		$this->assertEquals(1, $fields->Count());
177
		$fields->removeByName('Name[Field]');
178
		$this->assertEquals(0, $fields->Count());
179
	}
180
181
	public function testDataFieldByName() {
182
		$fields = new FieldList();
183
		$fields->push($basic = new TextField('Name', 'Your name'));
184
		$fields->push($brack = new TextField('Name[Field]', 'Your name'));
185
186
		$this->assertEquals($basic, $fields->dataFieldByName('Name'));
187
		$this->assertEquals($brack, $fields->dataFieldByName('Name[Field]'));
188
	}
189
190
	/**
191
	 * Test removing multiple fields from a set by their names in an array.
192
	 */
193
	public function testRemoveFieldsByName() {
194
		$fields = new FieldList();
195
196
		/* First of all, we add some fields into our FieldList object */
197
		$fields->push(new TextField('Name', 'Your name'));
198
		$fields->push(new TextField('Email', 'Your email'));
199
200
		/* We have 2 fields in our set now */
201
		$this->assertEquals(2, $fields->Count());
202
203
		/* Then, we call up removeByName() to take it out again */
204
		$fields->removeByName(array('Name', 'Email'));
205
206
		/* We have 0 fields in our set now, as we've just removed the one we added */
207
		$this->assertEquals(0, $fields->Count());
208
	}
209
210
	/**
211
	 * Test replacing a field with another one.
212
	 */
213
	public function testReplaceField() {
214
		$fields = new FieldList();
215
		$tab = new Tab('Root');
216
		$fields->push($tab);
217
218
		/* A field gets added to the set */
219
		$fields->addFieldToTab('Root', new TextField('Country'));
220
221
		$this->assertSame($fields->dataFieldByName('Country'), $tab->fieldByName('Country'));
222
223
		$fields->replaceField('Country', new EmailField('Email'));
224
		$this->assertEquals(1, $tab->Fields()->Count());
225
226
		$fields = new FieldList();
227
		$fields->push(new TextField('Name', 'Your name'));
228
		$brack = new TextField('Name[Field]', 'Your name');
229
230
		$fields->replaceField('Name', $brack);
231
		$this->assertEquals(1, $fields->Count());
232
233
		$this->assertEquals('Name[Field]', $fields->first()->getName());
234
	}
235
236
	public function testRenameField() {
237
		$fields = new FieldList();
238
		$nameField = new TextField('Name', 'Before title');
239
		$fields->push($nameField);
240
241
		/* The title of the field object is the same as what we put in */
242
		$this->assertSame('Before title', $nameField->Title());
243
244
		/* The field gets renamed to a different title */
245
		$fields->renameField('Name', 'After title');
246
247
		/* The title of the field object is the title we renamed to, this
248
			includes the original object we created ($nameField), and getting
249
			the field back out of the set */
250
		$this->assertSame('After title', $nameField->Title());
251
		$this->assertSame('After title', $fields->dataFieldByName('Name')->Title());
252
	}
253
254
	public function testReplaceAFieldInADifferentTab() {
255
		/* A FieldList gets created with a TabSet and some field objects */
256
		$FieldList = new FieldList(
257
			new TabSet('Root', $main = new Tab('Main',
258
				new TextField('A'),
259
				new TextField('B')
260
			), $other = new Tab('Other',
261
				new TextField('C'),
262
				new TextField('D')
263
			))
264
		);
265
266
		/* The field "A" gets added to the FieldList we just created created */
267
		$FieldList->addFieldToTab('Root.Other', $newA = new TextField('A', 'New Title'));
268
269
		/* The field named "A" has been removed from the Main tab to make way for our new field named "A" in
270
		 * Other tab. */
271
		$this->assertEquals(1, $main->Fields()->Count());
272
		$this->assertEquals(3, $other->Fields()->Count());
273
	}
274
275
	/**
276
	 * Test finding a field that's inside a tabset, within another tab.
277
	 */
278
	public function testNestedTabsFindingFieldByName() {
279
		$fields = new FieldList();
280
281
		/* 2 tabs get created within a TabSet inside our set */
282
		$tab = new TabSet('Root',
283
			new TabSet('MyContent',
284
				$mainTab = new Tab('Main'),
285
				$otherTab = new Tab('Others')
286
			)
287
		);
288
		$fields->push($tab);
289
290
		/* Some fields get added to the 2 tabs we just created */
291
		$fields->addFieldToTab('Root.MyContent.Main', new TextField('Country'));
292
		$fields->addFieldToTab('Root.MyContent.Others', new TextField('Email'));
293
294
		/* The fields we just added actually exists in the set */
295
		$this->assertNotNull($fields->dataFieldByName('Country'));
296
		$this->assertNotNull($fields->dataFieldByName('Email'));
297
298
		/* The fields we just added actually exist in the tabs */
299
		$this->assertNotNull($mainTab->fieldByName('Country'));
300
		$this->assertNotNull($otherTab->fieldByName('Email'));
301
302
		/* We have 1 field for each of the tabs */
303
		$this->assertEquals(1, $mainTab->Fields()->Count());
304
		$this->assertEquals(1, $otherTab->Fields()->Count());
305
306
		$this->assertNotNull($fields->fieldByName('Root.MyContent'));
307
		$this->assertNotNull($fields->fieldByName('Root.MyContent'));
308
	}
309
310
	public function testTabTitles() {
311
		$set = new FieldList(
312
			$rootTabSet = new TabSet('Root',
313
				$tabSetWithoutTitle = new TabSet('TabSetWithoutTitle'),
314
				$tabSetWithTitle = new TabSet('TabSetWithTitle', 'My TabSet Title',
315
					new Tab('ExistingChildTab')
316
				)
317
			)
318
		);
319
320
		$this->assertEquals(
321
			$tabSetWithTitle->Title(),
322
			'My TabSet Title',
323
			'Automatic conversion of tab identifiers through findOrMakeTab() with FormField::name_to_label()'
324
		);
325
326
		$tabWithoutTitle = $set->findOrMakeTab('Root.TabWithoutTitle');
327
		$this->assertEquals(
328
			$tabWithoutTitle->Title(),
329
			'Tab Without Title',
330
			'Automatic conversion of tab identifiers through findOrMakeTab() with FormField::name_to_label()'
331
		);
332
333
		$tabWithTitle = $set->findOrMakeTab('Root.TabWithTitle', 'My Tab with Title');
334
		$this->assertEquals(
335
			$tabWithTitle->Title(),
336
			'My Tab with Title',
337
			'Setting of simple tab titles through findOrMakeTab()'
338
		);
339
340
		$childTabWithTitle = $set->findOrMakeTab('Root.TabSetWithoutTitle.NewChildTab', 'My Child Tab Title');
341
		$this->assertEquals(
342
			$childTabWithTitle->Title(),
343
			'My Child Tab Title',
344
			'Setting of nested tab titles through findOrMakeTab() works on last child tab'
345
		);
346
	}
347
348
	/**
349
	 * Test pushing a field to a set.
350
	 *
351
	 * This tests {@link FieldList->push()}.
352
	 */
353
	public function testPushFieldToSet() {
354
		$fields = new FieldList();
355
356
		/* A field named Country is added to the set */
357
		$fields->push(new TextField('Country'));
358
359
		/* We only have 1 field in the set */
360
		$this->assertEquals(1, $fields->Count());
361
362
		/* Another field called Email is added to the set */
363
		$fields->push(new EmailField('Email'));
364
365
		/* There are now 2 fields in the set */
366
		$this->assertEquals(2, $fields->Count());
367
368
		// Test that pushing a composite field without a name onto the set works
369
		// See ticket #2932
370
		$fields->push(new CompositeField(
371
			new TextField('Test1'),
372
			new TextField('Test2')
373
		));
374
		$this->assertEquals(3, $fields->Count());
375
	}
376
377
	/**
378
	 * Test pushing a field to the beginning of a set.
379
	 *
380
	 * This tests {@link FieldList->unshift()}.
381
	 */
382
	public function testPushFieldToBeginningOfSet() {
383
		$fields = new FieldList();
384
385
		/* A field named Country is added to the set */
386
		$fields->unshift(new TextField('Country'));
387
388
		/* We only have 1 field in the set */
389
		$this->assertEquals(1, $fields->Count());
390
391
		/* Another field called Email is added to the set */
392
		$fields->unshift(new EmailField('Email'));
393
394
		/* There are now 2 fields in the set */
395
		$this->assertEquals(2, $fields->Count());
396
397
		/* The most recently added field is at the beginning of the set */
398
		$this->assertEquals('Email', $fields->First()->getName());
399
400
		// Test that pushing a composite field without a name onto the set works
401
		$fields->unshift(new CompositeField(
402
			new TextField('Test1'),
403
			new TextField('Test2')
404
		));
405
		$this->assertEquals(3, $fields->Count());
406
	}
407
408
	/**
409
	 * Test inserting a field before another in a set.
410
	 *
411
	 * This tests {@link FieldList->insertBefore()}.
412
	 */
413
	public function testInsertBeforeFieldToSet() {
414
		$fields = new FieldList();
415
416
		/* 3 fields are added to the set */
417
		$fields->push(new TextField('Country'));
418
		$fields->push(new TextField('Email'));
419
		$fields->push(new TextField('FirstName'));
420
421
		/* We now have 3 fields in the set */
422
		$this->assertEquals(3, $fields->Count());
423
424
		/* We insert another field called Title before the FirstName field */
425
		$fields->insertBefore(new TextField('Title'), 'FirstName');
426
427
		/* The field we just added actually exists in the set */
428
		$this->assertNotNull($fields->dataFieldByName('Title'));
429
430
		/* We now have 4 fields in the set */
431
		$this->assertEquals(4, $fields->Count());
432
433
		/* The position of the Title field is at number 3 */
434
		$this->assertEquals('Title', $fields[2]->getName());
435
436
		/* Test arguments are accepted in either order */
437
		$fields->insertBefore('FirstName', new TextField('Surname'));
438
439
		/* The field we just added actually exists in the set */
440
		$this->assertNotNull($fields->dataFieldByName('Surname'));
441
442
		/* We now have 5 fields in the set */
443
		$this->assertEquals(5, $fields->Count());
444
445
		/* The position of the Surname field is at number 4 */
446
		$this->assertEquals('Surname', $fields[3]->getName());
447
	}
448
449
	public function testInsertBeforeMultipleFields() {
450
		$fields = new FieldList(
451
			$root = new TabSet("Root",
452
				$main = new Tab("Main",
453
					$a = new TextField("A"),
454
					$b = new TextField("B")
455
				)
456
			)
457
		);
458
459
		$fields->addFieldsToTab('Root.Main', array(
460
			new TextField('NewField1'),
461
			new TextField('NewField2')
462
		), 'B');
463
464
		$this->assertEquals(array_keys($fields->dataFields()), array(
465
			'A',
466
			'NewField1',
467
			'NewField2',
468
			'B'
469
		));
470
	}
471
472
	/**
473
	 * Test inserting a field after another in a set.
474
	 */
475
	public function testInsertAfterFieldToSet() {
476
		$fields = new FieldList();
477
478
		/* 3 fields are added to the set */
479
		$fields->push(new TextField('Country'));
480
		$fields->push(new TextField('Email'));
481
		$fields->push(new TextField('FirstName'));
482
483
		/* We now have 3 fields in the set */
484
		$this->assertEquals(3, $fields->Count());
485
486
		/* A field called Title is inserted after the Country field */
487
		$fields->insertAfter(new TextField('Title'), 'Country');
488
489
		/* The field we just added actually exists in the set */
490
		$this->assertNotNull($fields->dataFieldByName('Title'));
491
492
		/* We now have 4 fields in the FieldList */
493
		$this->assertEquals(4, $fields->Count());
494
495
		/* The position of the Title field should be at number 2 */
496
		$this->assertEquals('Title', $fields[1]->getName());
497
498
		/* Test arguments are accepted in either order */
499
		$fields->insertAfter('FirstName', new TextField('Surname'));
500
501
		/* The field we just added actually exists in the set */
502
		$this->assertNotNull($fields->dataFieldByName('Surname'));
503
504
		/* We now have 5 fields in the set */
505
		$this->assertEquals(5, $fields->Count());
506
507
		/* The position of the Surname field is at number 5 */
508
		$this->assertEquals('Surname', $fields[4]->getName());
509
	}
510
511
	public function testrootFieldList() {
512
		/* Given a nested set of FormField, CompositeField, and FieldList objects */
513
		$FieldList = new FieldList(
514
			$root = new TabSet("Root",
515
				$main = new Tab("Main",
516
					$a = new TextField("A"),
517
					$b = new TextField("B")
518
				)
519
			)
520
		);
521
522
		/* rootFieldList() should always evaluate to the same object: the topmost FieldList */
523
		$this->assertSame($FieldList, $FieldList->rootFieldList());
524
		$this->assertSame($FieldList, $root->rootFieldList());
525
		$this->assertSame($FieldList, $main->rootFieldList());
526
		$this->assertSame($FieldList, $a->rootFieldList());
527
		$this->assertSame($FieldList, $b->rootFieldList());
528
529
		/* If we push additional fields, they should also have the same rootFieldList() */
530
		$root->push($other = new Tab("Other"));
531
		$other->push($c = new TextField("C"));
532
		$root->push($third = new Tab("Third", $d = new TextField("D")));
533
534
		$this->assertSame($FieldList, $other->rootFieldList());
535
		$this->assertSame($FieldList, $third->rootFieldList());
536
		$this->assertSame($FieldList, $c->rootFieldList());
537
		$this->assertSame($FieldList, $d->rootFieldList());
538
	}
539
540
	public function testAddingDuplicateReplacesOldField() {
541
		/* Given a nested set of FormField, CompositeField, and FieldList objects */
542
		$FieldList = new FieldList(
543
			$root = new TabSet("Root",
544
				$main = new Tab("Main",
545
					$a = new TextField("A"),
546
					$b = new TextField("B")
547
				)
548
			)
549
		);
550
551
		/* Adding new fields of the same names should replace the original fields */
552
		$newA = new TextField("A", "New A");
553
		$newB = new TextField("B", "New B");
554
555
		$FieldList->addFieldToTab("Root.Main", $newA);
556
		$FieldList->addFieldToTab("Root.Other", $newB);
557
558
		$this->assertSame($newA, $FieldList->dataFieldByName("A"));
559
		$this->assertSame($newB, $FieldList->dataFieldByName("B"));
560
		$this->assertEquals(1, $main->Fields()->Count());
561
562
		/* Pushing fields on the end of the field set should remove them from the tab */
563
		$thirdA = new TextField("A", "Third A");
564
		$thirdB = new TextField("B", "Third B");
565
		$FieldList->push($thirdA);
566
		$FieldList->push($thirdB);
567
568
		$this->assertSame($thirdA, $FieldList->fieldByName("A"));
569
		$this->assertSame($thirdB, $FieldList->fieldByName("B"));
570
571
		$this->assertEquals(0, $main->Fields()->Count());
572
	}
573
574
	public function testAddingFieldToNonExistentTabCreatesThatTab() {
575
		$FieldList = new FieldList(
576
			$root = new TabSet("Root",
577
				$main = new Tab("Main",
578
					$a = new TextField("A")
579
				)
580
			)
581
		);
582
583
		/* Add a field to a non-existent tab, and it will be created */
584
		$FieldList->addFieldToTab("Root.Other", $b = new TextField("B"));
585
		$this->assertNotNull($FieldList->fieldByName('Root')->fieldByName('Other'));
586
		$this->assertSame($b, $FieldList->fieldByName('Root')->fieldByName('Other')->Fields()->First());
587
	}
588
589
	public function testAddingFieldToATabWithTheSameNameAsTheField() {
590
		$FieldList = new FieldList(
591
			$root = new TabSet("Root",
592
				$main = new Tab("Main",
593
					$a = new TextField("A")
594
				)
595
			)
596
		);
597
598
		/* If you have a tab with the same name as the field, then technically it's a duplicate. However, it's
599
		 * allowed because tab isn't a data field.  Only duplicate data fields are problematic */
600
		$FieldList->addFieldToTab("Root.MyName", $myName = new TextField("MyName"));
601
		$this->assertNotNull($FieldList->fieldByName('Root')->fieldByName('MyName'));
602
		$this->assertSame($myName, $FieldList->fieldByName('Root')->fieldByName('MyName')->Fields()->First());
603
	}
604
605
	public function testInsertBeforeWithNestedCompositeFields() {
606
		$FieldList = new FieldList(
607
			new TextField('A_pre'),
608
			new TextField('A'),
609
			new TextField('A_post'),
610
			$compositeA = new CompositeField(
611
				new TextField('B_pre'),
612
				new TextField('B'),
613
				new TextField('B_post'),
614
				$compositeB = new CompositeField(
615
					new TextField('C_pre'),
616
					new TextField('C'),
617
					new TextField('C_post')
618
				)
619
			)
620
		);
621
622
		$FieldList->insertBefore(
623
			$A_insertbefore = new TextField('A_insertbefore'),
624
			'A'
625
		);
626
		$this->assertSame(
627
			$A_insertbefore,
628
			$FieldList->dataFieldByName('A_insertbefore'),
629
			'Field on toplevel FieldList can be inserted'
630
		);
631
632
		$FieldList->insertBefore(
633
			$B_insertbefore = new TextField('B_insertbefore'),
634
			'B'
635
		);
636
		$this->assertSame(
637
			$FieldList->dataFieldByName('B_insertbefore'),
638
			$B_insertbefore,
639
			'Field on one nesting level FieldList can be inserted'
640
		);
641
642
		$FieldList->insertBefore(
643
			$C_insertbefore = new TextField('C_insertbefore'),
644
			'C'
645
		);
646
		$this->assertSame(
647
			$FieldList->dataFieldByName('C_insertbefore'),
648
			$C_insertbefore,
649
			'Field on two nesting levels FieldList can be inserted'
650
		);
651
	}
652
653
	/**
654
	 * @todo check actual placement of fields
655
	 */
656
	public function testInsertBeforeWithNestedTabsets() {
657
		$FieldListA = new FieldList(
658
			$tabSetA = new TabSet('TabSet_A',
659
				$tabA1 = new Tab('Tab_A1',
660
					new TextField('A_pre'),
661
					new TextField('A'),
662
					new TextField('A_post')
663
				),
664
				$tabB1 = new Tab('Tab_B1',
665
					new TextField('B')
666
				)
667
			)
668
		);
669
		$tabSetA->insertBefore(
670
			$A_insertbefore = new TextField('A_insertbefore'),
671
			'A'
672
		);
673
		$this->assertEquals(
674
			$FieldListA->dataFieldByName('A_insertbefore'),
675
			$A_insertbefore,
676
			'Field on toplevel tab can be inserted'
677
		);
678
679
		$this->assertEquals(0, $tabA1->fieldPosition('A_pre'));
680
		$this->assertEquals(1, $tabA1->fieldPosition('A_insertbefore'));
681
		$this->assertEquals(2, $tabA1->fieldPosition('A'));
682
		$this->assertEquals(3, $tabA1->fieldPosition('A_post'));
683
684
		$FieldListB = new FieldList(
685
			new TabSet('TabSet_A',
686
				$tabsetB = new TabSet('TabSet_B',
687
					$tabB1 = new Tab('Tab_B1',
688
						new TextField('C')
689
					),
690
					$tabB2 = new Tab('Tab_B2',
691
						new TextField('B_pre'),
692
						new TextField('B'),
693
						new TextField('B_post')
694
					)
695
				)
696
			)
697
		);
698
		$FieldListB->insertBefore(
699
			$B_insertbefore = new TextField('B_insertbefore'),
700
			'B'
701
		);
702
		$this->assertSame(
703
			$FieldListB->dataFieldByName('B_insertbefore'),
704
			$B_insertbefore,
705
			'Field on nested tab can be inserted'
706
		);
707
		$this->assertEquals(0, $tabB2->fieldPosition('B_pre'));
708
		$this->assertEquals(1, $tabB2->fieldPosition('B_insertbefore'));
709
		$this->assertEquals(2, $tabB2->fieldPosition('B'));
710
		$this->assertEquals(3, $tabB2->fieldPosition('B_post'));
711
	}
712
713
	public function testInsertAfterWithNestedCompositeFields() {
714
		$FieldList = new FieldList(
715
			new TextField('A_pre'),
716
			new TextField('A'),
717
			new TextField('A_post'),
718
			$compositeA = new CompositeField(
719
				new TextField('B_pre'),
720
				new TextField('B'),
721
				new TextField('B_post'),
722
				$compositeB = new CompositeField(
723
					new TextField('C_pre'),
724
					new TextField('C'),
725
					new TextField('C_post')
726
				)
727
			)
728
		);
729
730
		$FieldList->insertAfter(
731
			$A_insertafter = new TextField('A_insertafter'),
732
			'A'
733
		);
734
		$this->assertSame(
735
			$A_insertafter,
736
			$FieldList->dataFieldByName('A_insertafter'),
737
			'Field on toplevel FieldList can be inserted after'
738
		);
739
740
		$FieldList->insertAfter(
741
			$B_insertafter = new TextField('B_insertafter'),
742
			'B'
743
		);
744
		$this->assertSame(
745
			$FieldList->dataFieldByName('B_insertafter'),
746
			$B_insertafter,
747
			'Field on one nesting level FieldList can be inserted after'
748
		);
749
750
		$FieldList->insertAfter(
751
			$C_insertafter = new TextField('C_insertafter'),
752
			'C'
753
		);
754
		$this->assertSame(
755
			$FieldList->dataFieldByName('C_insertafter'),
756
			$C_insertafter,
757
			'Field on two nesting levels FieldList can be inserted after'
758
		);
759
	}
760
761
	/**
762
	 * @todo check actual placement of fields
763
	 */
764
	public function testInsertAfterWithNestedTabsets() {
765
		$FieldListA = new FieldList(
766
			$tabSetA = new TabSet('TabSet_A',
767
				$tabA1 = new Tab('Tab_A1',
768
					new TextField('A_pre'),
769
					new TextField('A'),
770
					new TextField('A_post')
771
				),
772
				$tabB1 = new Tab('Tab_B1',
773
					new TextField('B')
774
				)
775
			)
776
		);
777
		$tabSetA->insertAfter(
778
			$A_insertafter = new TextField('A_insertafter'),
779
			'A'
780
		);
781
		$this->assertEquals(
782
			$FieldListA->dataFieldByName('A_insertafter'),
783
			$A_insertafter,
784
			'Field on toplevel tab can be inserted after'
785
		);
786
		$this->assertEquals(0, $tabA1->fieldPosition('A_pre'));
787
		$this->assertEquals(1, $tabA1->fieldPosition('A'));
788
		$this->assertEquals(2, $tabA1->fieldPosition('A_insertafter'));
789
		$this->assertEquals(3, $tabA1->fieldPosition('A_post'));
790
791
		$FieldListB = new FieldList(
792
			new TabSet('TabSet_A',
793
				$tabsetB = new TabSet('TabSet_B',
794
					$tabB1 = new Tab('Tab_B1',
795
						new TextField('C')
796
					),
797
					$tabB2 = new Tab('Tab_B2',
798
						new TextField('B_pre'),
799
						new TextField('B'),
800
						new TextField('B_post')
801
					)
802
				)
803
			)
804
		);
805
		$FieldListB->insertAfter(
806
			$B_insertafter = new TextField('B_insertafter'),
807
			'B'
808
		);
809
		$this->assertSame(
810
			$FieldListB->dataFieldByName('B_insertafter'),
811
			$B_insertafter,
812
			'Field on nested tab can be inserted after'
813
		);
814
		$this->assertEquals(0, $tabB2->fieldPosition('B_pre'));
815
		$this->assertEquals(1, $tabB2->fieldPosition('B'));
816
		$this->assertEquals(2, $tabB2->fieldPosition('B_insertafter'));
817
		$this->assertEquals(3, $tabB2->fieldPosition('B_post'));
818
	}
819
	/**
820
	 * FieldList::changeFieldOrder() should place specified fields in given
821
	 * order then add any unspecified remainders at the end. Can be given an
822
	 * array or list of arguments.
823
	 */
824
	public function testChangeFieldOrder() {
825
		$fieldNames = array('A','B','C','D','E');
826
		$setArray = new FieldList();
827
		$setArgs = new FieldList();
828
		foreach ($fieldNames as $fN) {
829
			$setArray->push(new TextField($fN));
830
			$setArgs->push(new TextField($fN));
831
		}
832
833
		$setArray->changeFieldOrder(array('D','B','E'));
834
		$this->assertEquals(0, $setArray->fieldPosition('D'));
835
		$this->assertEquals(1, $setArray->fieldPosition('B'));
836
		$this->assertEquals(2, $setArray->fieldPosition('E'));
837
		$this->assertEquals(3, $setArray->fieldPosition('A'));
838
		$this->assertEquals(4, $setArray->fieldPosition('C'));
839
840
		$setArgs->changeFieldOrder('D','B','E');
841
		$this->assertEquals(0, $setArgs->fieldPosition('D'));
842
		$this->assertEquals(1, $setArgs->fieldPosition('B'));
843
		$this->assertEquals(2, $setArgs->fieldPosition('E'));
844
		$this->assertEquals(3, $setArgs->fieldPosition('A'));
845
		$this->assertEquals(4, $setArgs->fieldPosition('C'));
846
847
		unset($setArray, $setArgs);
848
	}
849
850
	public function testFieldPosition() {
851
		$set = new FieldList(
852
			new TextField('A'),
853
			new TextField('B'),
854
			new TextField('C')
855
		);
856
857
		$this->assertEquals(0, $set->fieldPosition('A'));
858
		$this->assertEquals(1, $set->fieldPosition('B'));
859
		$this->assertEquals(2, $set->fieldPosition('C'));
860
861
		$set->insertBefore(new TextField('AB'), 'B');
862
		$this->assertEquals(0, $set->fieldPosition('A'));
863
		$this->assertEquals(1, $set->fieldPosition('AB'));
864
		$this->assertEquals(2, $set->fieldPosition('B'));
865
		$this->assertEquals(3, $set->fieldPosition('C'));
866
867
		unset($set);
868
	}
869
870
	/**
871
	 * FieldList::forTemplate() returns a concatenation of FieldHolder values.
872
	 */
873
	public function testForTemplate() {
874
		$set = new FieldList(
875
			$a = new TextField('A'),
876
			$b = new TextField('B')
877
		);
878
879
		$this->assertEquals($a->FieldHolder() . $b->FieldHolder(), $set->forTemplate());
880
	}
881
882
	/**
883
	 * FieldList::forTemplate() for an action list returns a concatenation of Field values.
884
	 * Internally, this works by having FormAction::FieldHolder return just the field, but it's an important
885
	 * use-case to test.
886
	 */
887
	public function testForTemplateForActionList() {
888
		$set = new FieldList(
889
			$a = new FormAction('A'),
890
			$b = new FormAction('B')
891
		);
892
893
		$this->assertEquals($a->Field() . $b->Field(), $set->forTemplate());
894
	}
895
896
	public function testMakeFieldReadonly() {
897
		$FieldList = new FieldList(
898
			new TabSet('Root', new Tab('Main',
899
				new TextField('A'),
900
				new TextField('B')
901
			)
902
		));
903
904
		$FieldList->makeFieldReadonly('A');
905
		$this->assertTrue(
906
			$FieldList->dataFieldByName('A')->isReadonly(),
907
			'Field nested inside a TabSet and FieldList can be marked readonly by FieldList->makeFieldReadonly()'
908
		);
909
	}
910
911
	/**
912
	 * Test VisibleFields and HiddenFields
913
	 */
914
	public function testVisibleAndHiddenFields() {
915
		$fields = new FieldList(
916
			new TextField("A"),
917
			new TextField("B"),
918
			new HiddenField("C"),
919
			new Tabset("Root",
920
				new Tab("D",
921
					new TextField("D1"),
922
					new HiddenField("D2")
923
				)
924
			)
925
		);
926
927
		$hidden = $fields->HiddenFields();
928
		// Inside hidden fields, all HiddenField objects are included, even nested ones
929
		$this->assertNotNull($hidden->dataFieldByName('C'));
930
		$this->assertNotNull($hidden->dataFieldByName('D2'));
931
		// Visible fields are not
932
		$this->assertNull($hidden->dataFieldByName('B'));
933
		$this->assertNull($hidden->dataFieldByName('D1'));
934
935
		$visible = $fields->VisibleFields();
936
		// Visible fields exclude top level HiddenField objects
937
		$this->assertNotNull($visible->dataFieldByName('A'));
938
		$this->assertNull($visible->dataFieldByName('C'));
939
		// But they don't exclude nested HiddenField objects.  This is a limitation; you should
940
		// put all your HiddenFields at the top level.
941
		$this->assertNotNull($visible->dataFieldByName('D2'));
942
	}
943
944
	public function testRewriteTabPath() {
945
		$originalDeprecation = Deprecation::dump_settings();
946
		Deprecation::notification_version('2.4');
947
948
		$fields = new FieldList(
949
			new Tabset("Root",
950
				$tab1Level1 = new Tab("Tab1Level1",
951
					$tab1Level2 = new Tab("Tab1Level2"),
952
					$tab2Level2 = new Tab("Tab2Level2")
953
				),
954
				$tab2Level1 = new Tab("Tab2Level1")
955
			)
956
		);
957
		$fields->setTabPathRewrites(array(
958
			'/Root\.Tab1Level1\.([^.]+)$/' => 'Root.Tab1Level1Renamed.\\1',
959
			'/Root\.Tab1Level1$/' => 'Root.Tab1Level1Renamed',
960
		));
961
		$method = new ReflectionMethod($fields, 'rewriteTabPath');
962
		$method->setAccessible(true);
963
		$this->assertEquals(
964
			'Root.Tab1Level1Renamed',
965
			$method->invoke($fields, 'Root.Tab1Level1Renamed'),
966
			"Doesn't rewrite new name"
967
		);
968
		$this->assertEquals(
969
			'Root.Tab1Level1Renamed',
970
			$method->invoke($fields, 'Root.Tab1Level1'),
971
			'Direct aliasing on toplevel'
972
		);
973
		$this->assertEquals(
974
			'Root.Tab1Level1Renamed.Tab1Level2',
975
			$method->invoke($fields, 'Root.Tab1Level1.Tab1Level2'),
976
			'Indirect aliasing on toplevel'
977
		);
978
979
		Deprecation::restore_settings($originalDeprecation);
980
	}
981
982
	public function testRewriteTabPathFindOrMakeTab() {
983
		$originalDeprecation = Deprecation::dump_settings();
984
		Deprecation::notification_version('2.4');
985
986
		$fields = new FieldList(
987
			new Tabset("Root",
988
				$tab1Level1 = new Tab("Tab1Level1Renamed",
989
					$tab1Level2 = new Tab("Tab1Level2"),
990
					$tab2Level2 = new Tab("Tab2Level2")
991
				),
992
				$tab2Level1 = new Tab("Tab2Level1")
993
			)
994
		);
995
		$fields->setTabPathRewrites(array(
996
			'/Root\.Tab1Level1\.([^.]+)$/' => 'Root.Tab1Level1Renamed.\\1',
997
			'/Root\.Tab1Level1$/' => 'Root.Tab1Level1Renamed',
998
		));
999
1000
		$this->assertEquals($tab1Level1, $fields->findOrMakeTab('Root.Tab1Level1'),
1001
			'findOrMakeTab() with toplevel tab under old name'
1002
		);
1003
		$this->assertEquals($tab1Level1, $fields->findOrMakeTab('Root.Tab1Level1Renamed'),
1004
			'findOrMakeTab() with toplevel tab under new name'
1005
		);
1006
		$this->assertEquals($tab1Level2, $fields->findOrMakeTab('Root.Tab1Level1.Tab1Level2'),
1007
			'findOrMakeTab() with nested tab under old parent tab name'
1008
		);
1009
		$this->assertEquals($tab1Level2, $fields->findOrMakeTab('Root.Tab1Level1Renamed.Tab1Level2'),
1010
			'findOrMakeTab() with nested tab under new parent tab name'
1011
		);
1012
1013
		Deprecation::restore_settings($originalDeprecation);
1014
	}
1015
1016
}
1017