fa5fd1c9b780f4edb5cfb1d5af7c97f921ff8df0
[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) {
185         return TRUE;
186       },
187       // Alternated field values: only the even ones are equal.
188       function ($delta) {
189         return $delta % 2 !== 0;
190       },
191       // Sparse field values: only the "middle" ones are equal.
192       function ($delta) {
193         return $delta === 1 || $delta === 2;
194       },
195       // Sparse field values: only the "extreme" ones are equal.
196       function ($delta) {
197         return $delta === 0 || $delta === 3;
198       },
199     ];
200
201     foreach ($delta_callbacks as $delta_callback) {
202       $field_values = $this->unchangedFieldValues;
203
204       for ($delta = 0; $delta < $this->cardinality; $delta++) {
205         if ($delta_callback($delta)) {
206           foreach ($this->columns as $column) {
207             if (in_array($column, $this->synchronized)) {
208               $field_values[$sync_langcode][$delta][$column] = $field_values[$sync_langcode][0][$column];
209             }
210           }
211         }
212       }
213
214       $changed_items = $field_values[$sync_langcode];
215       $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
216
217       foreach ($this->unchangedFieldValues as $langcode => $unchanged_items) {
218         for ($delta = 0; $delta < $this->cardinality; $delta++) {
219           foreach ($this->columns as $column) {
220             // The first item is always unchanged hence it is retained by the
221             // synchronization process. The other ones are retained or synced
222             // depending on the logic implemented by the delta callback and
223             // whether it is a sync column or not.
224             $value = $delta > 0 && $delta_callback($delta) && in_array($column, $this->synchronized) ? $changed_items[0][$column] : $unchanged_items[$delta][$column];
225             $this->assertEqual($field_values[$langcode][$delta][$column], $value, "Item $delta column $column for langcode $langcode synced correctly");
226           }
227         }
228       }
229     }
230   }
231
232   /**
233    * Tests that one change in a synchronized column triggers a change in all columns.
234    */
235   public function testDifferingSyncedColumns() {
236     $sync_langcode = $this->langcodes[2];
237     $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
238     $field_values = $this->unchangedFieldValues;
239
240     for ($delta = 0; $delta < $this->cardinality; $delta++) {
241       $index = ($delta % 2) + 1;
242       $field_values[$sync_langcode][$delta]['sync' . $index] .= '-updated';
243     }
244
245     $changed_items = $field_values[$sync_langcode];
246     $this->synchronizer->synchronizeItems($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
247
248     foreach ($this->unchangedFieldValues as $langcode => $unchanged_items) {
249       for ($delta = 0; $delta < $this->cardinality; $delta++) {
250         foreach ($this->columns as $column) {
251           // If the column is synchronized, the value should have been synced,
252           // for unsychronized columns, the value must not change.
253           $expected_value = in_array($column, $this->synchronized) ? $changed_items[$delta][$column] : $this->unchangedFieldValues[$langcode][$delta][$column];
254           $this->assertEqual($field_values[$langcode][$delta][$column], $expected_value, "Differing Item $delta column $column for langcode $langcode synced correctly");
255         }
256       }
257     }
258   }
259
260 }