Version 1
[yaffs-website] / web / core / modules / content_translation / tests / src / Kernel / ContentTranslationSyncUnitTest.php
1 <?php
2
3 namespace Drupal\Tests\content_translation\Kernel;
4
5 use Drupal\content_translation\FieldTranslationSynchronizer;
6 use Drupal\KernelTests\KernelTestBase;
7
8 /**
9  * Tests the field synchronization logic.
10  *
11  * @group content_translation
12  */
13 class ContentTranslationSyncUnitTest extends KernelTestBase {
14
15   /**
16    * The synchronizer class to be tested.
17    *
18    * @var \Drupal\content_translation\FieldTranslationSynchronizer
19    */
20   protected $synchronizer;
21
22   /**
23    * The columns to be synchronized.
24    *
25    * @var array
26    */
27   protected $synchronized;
28
29   /**
30    * All the field columns.
31    *
32    * @var array
33    */
34   protected $columns;
35
36   /**
37    * The available language codes.
38    *
39    * @var array
40    */
41   protected $langcodes;
42
43   /**
44    * The field cardinality.
45    *
46    * @var int
47    */
48   protected $cardinality;
49
50   /**
51    * The unchanged field values.
52    *
53    * @var array
54    */
55   protected $unchangedFieldValues;
56
57   public static $modules = ['language', 'content_translation'];
58
59   protected function setUp() {
60     parent::setUp();
61
62     $this->synchronizer = new FieldTranslationSynchronizer($this->container->get('entity.manager'));
63     $this->synchronized = ['sync1', 'sync2'];
64     $this->columns = array_merge($this->synchronized, ['var1', 'var2']);
65     $this->langcodes = ['en', 'it', 'fr', 'de', 'es'];
66     $this->cardinality = 4;
67     $this->unchangedFieldValues = [];
68
69     // Set up an initial set of values in the correct state, that is with
70     // "synchronized" values being equal.
71     foreach ($this->langcodes as $langcode) {
72       for ($delta = 0; $delta < $this->cardinality; $delta++) {
73         foreach ($this->columns as $column) {
74           $sync = in_array($column, $this->synchronized) && $langcode != $this->langcodes[0];
75           $value = $sync ? $this->unchangedFieldValues[$this->langcodes[0]][$delta][$column] : $langcode . '-' . $delta . '-' . $column;
76           $this->unchangedFieldValues[$langcode][$delta][$column] = $value;
77         }
78       }
79     }
80   }
81
82   /**
83    * Tests the field synchronization algorithm.
84    */
85   public function testFieldSync() {
86     // Add a new item to the source items and check that its added to all the
87     // translations.
88     $sync_langcode = $this->langcodes[2];
89     $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
90     $field_values = $this->unchangedFieldValues;
91     $item = [];
92     foreach ($this->columns as $column) {
93       $item[$column] = $this->randomMachineName();
94     }
95     $field_values[$sync_langcode][] = $item;
96     $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
97     $result = TRUE;
98     foreach ($this->unchangedFieldValues as $langcode => $items) {
99       // Check that the old values are still in place.
100       for ($delta = 0; $delta < $this->cardinality; $delta++) {
101         foreach ($this->columns as $column) {
102           $result = $result && ($this->unchangedFieldValues[$langcode][$delta][$column] == $field_values[$langcode][$delta][$column]);
103         }
104       }
105       // Check that the new item is available in all languages.
106       foreach ($this->columns as $column) {
107         $result = $result && ($field_values[$langcode][$delta][$column] == $field_values[$sync_langcode][$delta][$column]);
108       }
109     }
110     $this->assertTrue($result, 'A new item has been correctly synchronized.');
111
112     // Remove an item from the source items and check that its removed from all
113     // the translations.
114     $sync_langcode = $this->langcodes[1];
115     $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
116     $field_values = $this->unchangedFieldValues;
117     $sync_delta = mt_rand(0, count($field_values[$sync_langcode]) - 1);
118     unset($field_values[$sync_langcode][$sync_delta]);
119     // Renumber deltas to start from 0.
120     $field_values[$sync_langcode] = array_values($field_values[$sync_langcode]);
121     $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
122     $result = TRUE;
123     foreach ($this->unchangedFieldValues as $langcode => $items) {
124       $new_delta = 0;
125       // Check that the old values are still in place.
126       for ($delta = 0; $delta < $this->cardinality; $delta++) {
127         // Skip the removed item.
128         if ($delta != $sync_delta) {
129           foreach ($this->columns as $column) {
130             $result = $result && ($this->unchangedFieldValues[$langcode][$delta][$column] == $field_values[$langcode][$new_delta][$column]);
131           }
132           $new_delta++;
133         }
134       }
135     }
136     $this->assertTrue($result, 'A removed item has been correctly synchronized.');
137
138     // Move the items around in the source items and check that they are moved
139     // in all the translations.
140     $sync_langcode = $this->langcodes[3];
141     $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
142     $field_values = $this->unchangedFieldValues;
143     $field_values[$sync_langcode] = [];
144     // Scramble the items.
145     foreach ($unchanged_items as $delta => $item) {
146       $new_delta = ($delta + 1) % $this->cardinality;
147       $field_values[$sync_langcode][$new_delta] = $item;
148     }
149     // Renumber deltas to start from 0.
150     ksort($field_values[$sync_langcode]);
151     $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
152     $result = TRUE;
153     foreach ($field_values as $langcode => $items) {
154       for ($delta = 0; $delta < $this->cardinality; $delta++) {
155         foreach ($this->columns as $column) {
156           $value = $field_values[$langcode][$delta][$column];
157           if (in_array($column, $this->synchronized)) {
158             // If we are dealing with a synchronize column the current value is
159             // supposed to be the same of the source items.
160             $result = $result && $field_values[$sync_langcode][$delta][$column] == $value;
161           }
162           else {
163             // Otherwise the values should be unchanged.
164             $old_delta = ($delta > 0 ? $delta : $this->cardinality) - 1;
165             $result = $result && $this->unchangedFieldValues[$langcode][$old_delta][$column] == $value;
166           }
167         }
168       }
169     }
170     $this->assertTrue($result, 'Scrambled items have been correctly synchronized.');
171   }
172
173   /**
174    * Tests that items holding the same values are correctly synchronized.
175    */
176   public function testMultipleSyncedValues() {
177     $sync_langcode = $this->langcodes[1];
178     $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
179
180     // Determine whether the unchanged values should be altered depending on
181     // their delta.
182     $delta_callbacks = [
183       // Continuous field values: all values are equal.
184       function($delta) { return TRUE; },
185       // Alternated field values: only the even ones are equal.
186       function($delta) { return $delta % 2 !== 0; },
187       // Sparse field values: only the "middle" ones are equal.
188       function($delta) { return $delta === 1 || $delta === 2; },
189       // Sparse field values: only the "extreme" ones are equal.
190       function($delta) { return $delta === 0 || $delta === 3; },
191     ];
192
193     foreach ($delta_callbacks as $delta_callback) {
194       $field_values = $this->unchangedFieldValues;
195
196       for ($delta = 0; $delta < $this->cardinality; $delta++) {
197         if ($delta_callback($delta)) {
198           foreach ($this->columns as $column) {
199             if (in_array($column, $this->synchronized)) {
200               $field_values[$sync_langcode][$delta][$column] = $field_values[$sync_langcode][0][$column];
201             }
202           }
203         }
204       }
205
206       $changed_items = $field_values[$sync_langcode];
207       $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
208
209       foreach ($this->unchangedFieldValues as $langcode => $unchanged_items) {
210         for ($delta = 0; $delta < $this->cardinality; $delta++) {
211           foreach ($this->columns as $column) {
212             // The first item is always unchanged hence it is retained by the
213             // synchronization process. The other ones are retained or synced
214             // depending on the logic implemented by the delta callback and
215             // whether it is a sync column or not.
216             $value = $delta > 0 && $delta_callback($delta) && in_array($column, $this->synchronized) ? $changed_items[0][$column] : $unchanged_items[$delta][$column];
217             $this->assertEqual($field_values[$langcode][$delta][$column], $value, "Item $delta column $column for langcode $langcode synced correctly");
218           }
219         }
220       }
221     }
222   }
223
224   /**
225    * Tests that one change in a synchronized column triggers a change in all columns.
226    */
227   public function testDifferingSyncedColumns() {
228     $sync_langcode = $this->langcodes[2];
229     $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
230     $field_values = $this->unchangedFieldValues;
231
232     for ($delta = 0; $delta < $this->cardinality; $delta++) {
233       $index = ($delta % 2) + 1;
234       $field_values[$sync_langcode][$delta]['sync' . $index] .= '-updated';
235     }
236
237     $changed_items = $field_values[$sync_langcode];
238     $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
239
240     foreach ($this->unchangedFieldValues as $langcode => $unchanged_items) {
241       for ($delta = 0; $delta < $this->cardinality; $delta++) {
242         foreach ($this->columns as $column) {
243           // If the column is synchronized, the value should have been synced,
244           // for unsychronized columns, the value must not change.
245           $expected_value = in_array($column, $this->synchronized) ? $changed_items[$delta][$column] : $this->unchangedFieldValues[$langcode][$delta][$column];
246           $this->assertEqual($field_values[$langcode][$delta][$column], $expected_value, "Differing Item $delta column $column for langcode $langcode synced correctly");
247         }
248       }
249     }
250   }
251
252 }