Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
6 | class ElasticsearchBaseTest extends SapphireTest { |
||
7 | |||
8 | public static $ignoreFixtureFileFor = array(); |
||
9 | |||
10 | protected $extraDataObjects = array( |
||
11 | 'SearchableTestPage','FlickrPhotoTO','FlickrAuthorTO','FlickrSetTO','FlickrTagTO', |
||
12 | 'SearchableTestFatherPage','SearchableTestGrandFatherPage','AutoCompleteOption' |
||
13 | ); |
||
14 | |||
15 | |||
16 | public function setUpOnce() { |
||
17 | ElasticaUtil::setPrinterOutput(false); |
||
18 | |||
19 | // add Searchable extension where appropriate |
||
20 | FlickrSetTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
21 | FlickrPhotoTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
22 | FlickrTagTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
23 | FlickrAuthorTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
24 | SearchableTestPage::add_extension('SilverStripe\Elastica\Searchable'); |
||
25 | |||
26 | |||
27 | $config = Config::inst(); |
||
28 | $config->remove('Injector', 'SilverStripe\Elastica\ElasticaService'); |
||
29 | $constructor = array('constructor' => array('%$Elastica\Client', 'elastica_ss_module_test')); |
||
30 | $config->update('Injector', 'SilverStripe\Elastica\ElasticaService', $constructor); |
||
31 | parent::setUpOnce(); |
||
32 | } |
||
33 | |||
34 | |||
35 | 1 | public function setUp() { |
|
36 | // no need to index here as it's done when fixtures are loaded during setup method |
||
37 | 1 | $cache = SS_Cache::factory('elasticsearch'); |
|
38 | 1 | $cache->clean(Zend_Cache::CLEANING_MODE_ALL); |
|
39 | 1 | SS_Cache::set_cache_lifetime('elasticsearch', 3600, 1000); |
|
40 | |||
41 | // this needs to be called in order to create the list of searchable |
||
42 | // classes and fields that are available. Simulates part of a build |
||
43 | 1 | $classes = array('SearchableTestPage','SiteTree','Page','FlickrPhotoTO','FlickrSetTO', |
|
44 | 1 | 'FlickrTagTO', 'FlickrAuthorTO'); |
|
45 | 1 | $this->requireDefaultRecordsFrom = $classes; |
|
46 | |||
47 | |||
48 | // clear the index |
||
49 | 1 | $this->service = Injector::inst()->create('SilverStripe\Elastica\ElasticaService'); |
|
50 | 1 | $this->service->setTestMode(true); |
|
51 | |||
52 | // A previous test may have deleted the index and then failed, so check for this |
||
53 | 1 | if (!$this->service->getIndex()->exists()) { |
|
54 | 1 | $this->service->getIndex()->create(); |
|
55 | 1 | } |
|
56 | 1 | $this->service->reset(); |
|
57 | |||
58 | // FIXME - use request getVar instead? |
||
59 | 1 | $_GET['progress'] = 20; |
|
60 | // load fixtures |
||
61 | |||
62 | 1 | $orig_fixture_file = static::$fixture_file; |
|
63 | |||
64 | 1 | foreach (static::$ignoreFixtureFileFor as $testPattern) { |
|
65 | $pattern = '/'.$testPattern.'/'; |
||
66 | if (preg_match($pattern, $this->getName())) { |
||
67 | static::$fixture_file = null; |
||
68 | } |
||
69 | 1 | } |
|
70 | |||
71 | 1 | parent::setUp(); |
|
72 | 1 | static::$fixture_file = $orig_fixture_file; |
|
73 | |||
74 | 1 | $this->publishSiteTree(); |
|
75 | |||
76 | 1 | $this->service->reset(); |
|
77 | |||
78 | // index loaded fixtures |
||
79 | 1 | $task = new ReindexTask($this->service); |
|
80 | // null request is fine as no parameters used |
||
81 | |||
82 | 1 | $task->run(null); |
|
83 | |||
84 | 1 | } |
|
85 | |||
86 | |||
87 | protected function devBuild() { |
||
88 | $task = new \BuildTask(); |
||
89 | // null request is fine as no parameters used |
||
90 | $task->run(null); |
||
91 | } |
||
92 | |||
93 | |||
94 | 1 | private function publishSiteTree() { |
|
95 | 1 | foreach (SiteTree::get()->getIterator() as $page) { |
|
96 | // temporarily disable Elasticsearch indexing, it will be done in a batch |
||
97 | 1 | $page->IndexingOff = true; |
|
98 | 1 | $page->publish('Stage','Live'); |
|
99 | 1 | } |
|
100 | 1 | } |
|
101 | |||
102 | |||
103 | public function generateAssertionsFromArray($toAssert) { |
||
104 | echo '$expected = array('."\n"; |
||
105 | foreach ($toAssert as $key => $value) { |
||
106 | $escValue = str_replace("'", '\\\'', $value); |
||
107 | echo "'$key' => '$escValue',\n"; |
||
108 | } |
||
109 | echo ");\n"; |
||
110 | echo '$this->assertEquals($expected, $somevar);'."\n"; |
||
111 | } |
||
112 | |||
113 | |||
114 | public function generateAssertionsFromArray1D($toAssert) { |
||
115 | echo '$expected = array('."\n"; |
||
116 | foreach ($toAssert as $key => $value) { |
||
117 | $escValue = str_replace("'", '\\\'', $value); |
||
118 | echo "'$escValue',"; |
||
119 | } |
||
120 | echo ");\n"; |
||
121 | echo '$this->assertEquals($expected, $somevar);'."\n"; |
||
122 | } |
||
123 | |||
124 | |||
125 | public function generateAssertionsFromArrayRecurse($toAssert) { |
||
126 | echo '$expected = '; |
||
127 | $this->recurseArrayAssertion($toAssert,1, 'FIXME'); |
||
128 | echo '$this->assertEquals($expected, $somevar);'."\n"; |
||
129 | } |
||
130 | |||
131 | |||
132 | private function recurseArrayAssertion($toAssert, $depth, $parentKey) { |
||
133 | $prefix = str_repeat("\t",$depth); |
||
134 | echo "\t{$prefix}'$parentKey' => array(\n"; |
||
135 | $ctr = 0; |
||
136 | $len = sizeof(array_keys($toAssert)); |
||
137 | foreach ($toAssert as $key => $value) { |
||
138 | if (is_array($value)) { |
||
139 | $this->recurseArrayAssertion($value, $depth+1, $key); |
||
140 | } else { |
||
141 | $escValue = str_replace("'", '\\\'', $value); |
||
142 | $comma = ','; |
||
143 | if ($ctr == $len-1) { |
||
144 | $comma = ''; |
||
145 | } |
||
146 | echo "\t\t$prefix'$key' => '$escValue'$comma\n"; |
||
147 | } |
||
148 | |||
149 | $ctr++; |
||
150 | |||
151 | } |
||
152 | echo "\t$prefix),\n"; |
||
153 | |||
154 | } |
||
155 | |||
156 | |||
157 | /* |
||
158 | Helper methods for testing CMS fields |
||
159 | */ |
||
160 | public function checkTabExists($fields, $tabName) { |
||
161 | $tab = $fields->findOrMakeTab("Root.{$tabName}"); |
||
162 | $actualTabName = $tab->getName(); |
||
163 | $splits = explode('.', $tabName); |
||
164 | $size = sizeof($splits); |
||
165 | $nameToCheck = end($splits); |
||
166 | $this->assertEquals($actualTabName, $nameToCheck); |
||
167 | if ($size == 1) { |
||
168 | $this->assertEquals("Root_${tabName}", $tab->id()); |
||
169 | } else { |
||
170 | $expected = "Root_{$splits[0]}_set_{$splits[1]}"; |
||
171 | $this->assertEquals($expected, $tab->id()); |
||
172 | } |
||
173 | |||
174 | return $tab; |
||
175 | } |
||
176 | |||
177 | |||
178 | public function checkFieldExists($tab,$fieldName) { |
||
179 | $fields = $tab->Fields(); |
||
180 | $field = $tab->fieldByName($fieldName); |
||
181 | $this->assertTrue($field != null); |
||
182 | return $field; |
||
183 | } |
||
184 | |||
185 | |||
186 | /** |
||
187 | * From https://jtreminio.com/2013/03/unit-testing-tutorial-part-3-testing-protected-private-methods-coverage-reports-and-crap/ |
||
188 | * Call protected/private method of a class. |
||
189 | * |
||
190 | * @param object &$object Instantiated object that we will run method on. |
||
191 | * @param string $methodName Method name to call |
||
192 | * @param array $parameters Array of parameters to pass into method. |
||
193 | * |
||
194 | * @return mixed Method return. |
||
195 | */ |
||
196 | public function invokeMethod(&$object, $methodName, array $parameters = array()) |
||
197 | { |
||
198 | $reflection = new \ReflectionClass(get_class($object)); |
||
199 | 1 | $method = $reflection->getMethod($methodName); |
|
200 | $method->setAccessible(true); |
||
201 | |||
202 | return $method->invokeArgs($object, $parameters); |
||
203 | } |
||
204 | |||
205 | |||
206 | public function checkNumberOfIndexedDocuments($expectedAmount) { |
||
207 | 1 | $index = $this->service->getIndex(); |
|
208 | 1 | $status = $index->getStatus()->getData(); |
|
209 | |||
210 | 1 | $numberDocsInIndex = -1; // flag value for not yet indexed |
|
211 | 1 | if (isset($status['indices']['elastica_ss_module_test_en_us']['docs'])) { |
|
212 | 1 | error_log('CHECKING NUMBER OF INDEXED DOCUMENTS, SHOULD BE ' . $expectedAmount); |
|
213 | 1 | error_log(print_r($status,1)); |
|
214 | $numberDocsInIndex = $status['indices']['elastica_ss_module_test_en_us']['docs']['num_docs']; |
||
215 | 1 | error_log('DOCUMENTS FOUND:'.$numberDocsInIndex) |
|
216 | 1 | } |
|
|
|||
217 | |||
218 | $this->assertEquals($expectedAmount,$numberDocsInIndex); |
||
219 | } |
||
220 | |||
221 | /* |
||
222 | 1 | Get the number of documents in an index. It is assumed the index exists, if not the test will fail |
|
223 | 1 | */ |
|
224 | public function getNumberOfIndexedDocuments() { |
||
225 | 1 | $index = $this->service->getIndex(); |
|
226 | 1 | $status = $index->getStatus()->getData(); |
|
227 | 1 | ||
228 | 1 | $numberDocsInIndex = -1; // flag value for not yet indexed |
|
229 | if (isset($status['indices']['elastica_ss_module_test_en_us']['docs'])) { |
||
230 | 1 | $numberDocsInIndex = $status['indices']['elastica_ss_module_test_en_us']['docs']['num_docs']; |
|
231 | 1 | } |
|
232 | |||
233 | $this->assertGreaterThan(-1, $numberDocsInIndex); |
||
234 | return $numberDocsInIndex; |
||
237 |