synonyms.test 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  1. <?php
  2. /**
  3. * @file
  4. * Tests for the Synonyms module.
  5. */
  6. /**
  7. * Base class for all Synonyms web test cases.
  8. */
  9. abstract class SynonymsWebTestCase extends DrupalWebTestCase {
  10. /**
  11. * Fully loaded user object of an admin user that has required access rights.
  12. *
  13. * @var object
  14. */
  15. protected $admin;
  16. /**
  17. * SetUp method.
  18. */
  19. public function setUp() {
  20. parent::setUp(array('synonyms'));
  21. $this->admin = $this->drupalCreateUser(array(
  22. 'administer taxonomy',
  23. 'administer content types',
  24. 'bypass node access',
  25. 'search content',
  26. ));
  27. }
  28. /**
  29. * Return last inserted term into the specified vocabulary.
  30. *
  31. * @param object $vocabulary
  32. * Fully loaded taxonomy vocabulary object
  33. *
  34. * @return object
  35. * Fully loaded taxonomy term object of the last inserted term into
  36. * the specified vocabulary
  37. */
  38. protected function getLastTerm($vocabulary) {
  39. drupal_static_reset();
  40. $tree = taxonomy_get_tree($vocabulary->vid);
  41. $max = 0;
  42. $term = NULL;
  43. foreach ($tree as $v) {
  44. if ($v->tid > $max) {
  45. $max = $v->tid;
  46. $term = $v;
  47. }
  48. }
  49. $term = entity_load_unchanged('taxonomy_term', $term->tid);
  50. return $term;
  51. }
  52. }
  53. /**
  54. * Test Synonyms functionality of synonyms module.
  55. */
  56. class SynonymsSynonymsWebTestCase extends SynonymsWebTestCase {
  57. protected $vocabularies = array(
  58. 'enabled' => TRUE,
  59. 'disabled' => FALSE,
  60. );
  61. /**
  62. * GetInfo method.
  63. */
  64. public function getInfo() {
  65. return array(
  66. 'name' => 'Taxonomy synonyms',
  67. 'description' => 'Ensure that the feature "synonyms" works correctly with taxonomy terms.',
  68. 'group' => 'Synonyms',
  69. );
  70. }
  71. /**
  72. * SetUp method.
  73. */
  74. public function setUp() {
  75. parent::setUp();
  76. // Creating vocabularies.
  77. $this->drupalLogin($this->admin);
  78. foreach ($this->vocabularies as $k => $v) {
  79. $name = $this->randomName();
  80. $this->drupalPost('admin/structure/taxonomy/add', array(
  81. 'name' => $name,
  82. 'machine_name' => $k,
  83. 'description' => $this->randomName(),
  84. 'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => $v,
  85. ), 'Save');
  86. $this->vocabularies[$k] = taxonomy_vocabulary_machine_name_load($k);
  87. }
  88. // Flushing cache.
  89. _field_info_collate_fields(TRUE);
  90. }
  91. /**
  92. * Test the disabled taxonomy synonyms feature.
  93. */
  94. public function testSynonymsDisabled() {
  95. $this->drupalGet('admin/structure/taxonomy/disabled/add');
  96. $this->assertNoFieldById('edit-synonyms-synonyms-und-0-value');
  97. $this->drupalGet('admin/structure/taxonomy/enabled/add');
  98. $this->assertFieldById('edit-synonyms-synonyms-und-0-value');
  99. // Making sure that after disabling "synonyms" the synonyms field
  100. // is no longer available on taxonomy term add page.
  101. $this->drupalPost('admin/structure/taxonomy/enabled/edit', array(
  102. 'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => FALSE,
  103. ), 'Save');
  104. $this->drupalGet('admin/structure/taxonomy/enabled/add');
  105. $this->assertNoFieldById('edit-synonyms-synonyms-und-0-value');
  106. }
  107. /**
  108. * Test the functionality of synonyms.
  109. */
  110. public function testSynonyms() {
  111. $name = $this->randomName();
  112. $synonym = $this->randomName();
  113. $parent_synonym = $this->randomName();
  114. // Creating terms for testing synonyms_get_term_synonyms().
  115. $synonym1 = $this->randomName();
  116. $synonym2 = $this->randomName();
  117. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  118. 'name' => $this->randomName(),
  119. 'description[value]' => $this->randomName(),
  120. ), 'Save');
  121. $no_synonyms_term = $this->getLastTerm($this->vocabularies['enabled']);
  122. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  123. 'name' => $this->randomName(),
  124. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $synonym1,
  125. ), 'Save');
  126. $one_synonym_term = $this->getLastTerm($this->vocabularies['enabled']);
  127. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  128. 'name' => $this->randomName(),
  129. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $synonym1,
  130. ), 'Add another item');
  131. $this->drupalPost(NULL, array(
  132. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][1][value]' => $synonym2,
  133. ), 'Save');
  134. $two_synonyms_term = $this->getLastTerm($this->vocabularies['enabled']);
  135. // Creating an identical parent term in order to test
  136. // $parent parameter in our functions.
  137. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  138. 'name' => $name,
  139. 'description[value]' => $this->randomName(),
  140. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $synonym,
  141. ), 'Add another item');
  142. $this->drupalPost(NULL, array(
  143. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][1][value]' => $parent_synonym,
  144. ), 'Save');
  145. $term_parent = $this->getLastTerm($this->vocabularies['enabled']);
  146. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  147. 'name' => $name,
  148. 'description[value]' => $this->randomName(),
  149. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $synonym,
  150. 'parent[]' => array($term_parent->tid),
  151. ), 'Save');
  152. $term = $this->getLastTerm($this->vocabularies['enabled']);
  153. $this->drupalGet('taxonomy/term/' . $term->tid);
  154. // Asserting the presence of synonym string.
  155. $this->assertText($synonym, 'The synonym string is present on taxonomy term view page');
  156. // Testing the 'synonyms' property of 'taxonomy_term' entity.
  157. $synonyms = synonyms_get_sanitized($no_synonyms_term);
  158. $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() for a term without synonyms.');
  159. $synonyms = synonyms_get_sanitized($one_synonym_term);
  160. $this->assertTrue(count($synonyms) == 1 && $synonyms[0] == $synonym1, 'Successfully retrieved synonyms_get_sanitized() for a term with a single synonym.');
  161. $synonyms = synonyms_get_sanitized($two_synonyms_term);
  162. $this->assertTrue(count($synonyms) == 2 && $synonyms[0] == $synonym1 && $synonyms[1] == $synonym2, 'Successfully retrieved synonyms_get_sanitized() for a term with 2 synonyms.');
  163. // Testing the function synonyms_get_term_by_synonym().
  164. $tid = synonyms_get_term_by_synonym(drupal_strtoupper($synonym), $this->vocabularies['enabled'], $term_parent->tid);
  165. $this->assertEqual($tid, $term->tid, 'Successfully looked up term by its synonym.');
  166. $tid = synonyms_get_term_by_synonym(drupal_strtoupper($name), $this->vocabularies['enabled'], $term_parent->tid);
  167. $this->assertEqual($tid, $term->tid, 'Successfully looked up term by its name.');
  168. // Now submitting a non-existing name.
  169. $tid = synonyms_get_term_by_synonym($parent_synonym, $this->vocabularies['enabled'], $term_parent->tid);
  170. $this->assertEqual($tid, 0, 'synonyms_get_term_by_synonym() returns 0 if the term is not found (considering $parent parameter).');
  171. // Testing the function synonyms_add_term_by_synonym().
  172. $tid = synonyms_add_term_by_synonym(drupal_strtolower($name), $this->vocabularies['enabled'], $term_parent->tid);
  173. $this->assertEqual($tid, $term->tid, 'Successfully called synonyms_add_term_by_synonym() on an existing title and no new term was created.');
  174. $tid = synonyms_add_term_by_synonym(drupal_strtolower($synonym), $this->vocabularies['enabled'], $term_parent->tid);
  175. $this->assertEqual($tid, $term->tid, 'Successfully called synonyms_add_term_by_synonym() on an existing synonym and no new term was created.');
  176. drupal_static_reset();
  177. $tid = synonyms_add_term_by_synonym($parent_synonym, $this->vocabularies['enabled'], $term_parent->tid);
  178. $new_term = taxonomy_term_load($tid);
  179. $new_term_parents = array_keys(taxonomy_get_parents($new_term->tid));
  180. $this->assertEqual($parent_synonym, $new_term->name, 'Successfully called synonyms_add_term_by_synonym() on a new title and a new term was created.');
  181. $this->assertNotEqual($new_term->tid, $term_parent->tid, 'Successfully called synonyms_add_term_by_synonym() on a synonym of $parent. New term was created instead of returning $parent\'s tid.');
  182. $this->assertTrue(in_array($term_parent->tid, $new_term_parents), 'Successfully called synonyms_add_term_by_synonym(). New term is assigned as a child to supplied $parent parameter.');
  183. // Disabling functionality of synonyms for "enabled" vocabulary
  184. // and making sure it has cleaned up all its functionality.
  185. $this->drupalPost('admin/structure/taxonomy/enabled/edit', array(
  186. 'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => FALSE,
  187. ), 'Save');
  188. $this->drupalGet('taxonomy/term/' . $term->tid);
  189. // Asserting the absence of synonym string.
  190. $this->assertNoText($synonym, 'The synonym string is no longer present on taxonomy term view page after disabling "synonyms" feature for a vocabulary');
  191. $term = array_pop(entity_load('taxonomy_term', array($term->tid), array(), TRUE));
  192. $this->assertFalse(isset($term->{SYNONYMS_DEFAULT_FIELD_NAME}), 'The term no longer has synonyms field after disabling "synonyms" feature for a vocabulary');
  193. // Testing the 'synonyms' property of 'taxonomy_term' entity.
  194. $synonyms = synonyms_get_sanitized($no_synonyms_term);
  195. $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() on a term without synonyms after disabling "synonyms" feature');
  196. $synonyms = synonyms_get_sanitized($one_synonym_term);
  197. $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() on a term with a single synonym after disabling "synonyms" feature');
  198. $synonyms = synonyms_get_sanitized($two_synonyms_term);
  199. $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() on a term with 2 synonyms after disabling "synonyms" feature');
  200. $tid = synonyms_get_term_by_synonym(drupal_strtoupper($synonym), $this->vocabularies['enabled']);
  201. $this->assertEqual($tid, 0, 'synonyms_get_term_by_synonym() returns 0 after disabling "synonyms" feature for a vocabulary');
  202. $tid = synonyms_get_term_by_synonym(drupal_strtoupper($name), $this->vocabularies['enabled'], $term_parent->tid);
  203. $this->assertEqual($tid, $term->tid, 'synonyms_get_term_by_synonym() returns $term->tid even after disabling "synonyms" feature if looking up by term title');
  204. // Testing synonyms_add_term_by_synonym() function.
  205. $tid = synonyms_add_term_by_synonym(drupal_strtolower($name), $this->vocabularies['enabled'], $term_parent->tid);
  206. $this->assertEqual($tid, $term->tid, 'Successfully called synonyms_add_term_by_synonym() on an existing title and no new term was created after disabling "synonyms" feature.');
  207. $tid = synonyms_add_term_by_synonym(drupal_strtolower($synonym), $this->vocabularies['enabled'], $term_parent->tid);
  208. $new_term = taxonomy_term_load($tid);
  209. $new_term_parents = array_keys(taxonomy_get_parents($new_term->tid));
  210. $this->assertFalse(in_array($new_term->tid, array($term->tid, $term_parent->tid)), 'Successfully called synonyms_add_term_by_synonym() using previous synonym and a new term was created (because the vocabulary has disabled "synonyms" feature)');
  211. $this->assertTrue(in_array($term_parent->tid, $new_term_parents), 'Successfully called synonyms_add_term_by_synonym(). New term is assigned as a child to supplied $parent parameter with disabled "synonyms" feature.');
  212. $tid = synonyms_add_term_by_synonym($parent_synonym, $this->vocabularies['enabled']);
  213. $new_term = array_pop(entity_load('taxonomy_term', array($tid), array(), TRUE));
  214. $this->assertEqual($parent_synonym, $new_term->name, 'Successfully called synonyms_add_term_by_synonym() on an new title and a new term was created.');
  215. $this->assertFalse(in_array($new_term->tid, array($term->tid, $term_parent->tid)), 'Successfully called synonyms_add_term_by_synonym() on the synonyn of parent term. New term was created (because the vocabulary has disabled "synonyms" feature)');
  216. }
  217. }
  218. /**
  219. * Test "Synonyms friendly autocomplete" widget of Synonyms module.
  220. */
  221. class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
  222. /**
  223. * Array of fully loaded vocabulary entities to be used in this test.
  224. *
  225. * Array is keyed by the corresponding vocabulary's machine name.
  226. *
  227. * @var array
  228. */
  229. protected $vocabularies = array(
  230. 'enabled' => TRUE,
  231. 'disabled' => FALSE,
  232. );
  233. /**
  234. * Array of fully loaded taxonomy term entities to be used in this test.
  235. *
  236. * Term entities are grouped by machine name of the vocabulary to which they
  237. * belong.
  238. *
  239. * @var array
  240. */
  241. protected $terms = array(
  242. 'enabled' => array(),
  243. 'disabled' => array(),
  244. );
  245. /**
  246. * Entity type to which a term reference field with tested widget is attached.
  247. *
  248. * @var string
  249. */
  250. protected $entity_type = 'node';
  251. /**
  252. * Bundle to which a term reference field with tested widget is attached.
  253. *
  254. * @var string
  255. */
  256. protected $bundle = 'synonyms_test_content';
  257. /**
  258. * GetInfo method.
  259. */
  260. public function getInfo() {
  261. return array(
  262. 'name' => 'Taxonomy synonyms autocomplete',
  263. 'description' => 'Ensure that the "synonym friendly autocomplete" widget works correctly with taxonomy terms.',
  264. 'group' => 'Synonyms',
  265. );
  266. }
  267. /**
  268. * SetUp method.
  269. */
  270. public function setUp() {
  271. parent::setUp();
  272. // Creating vocabularies.
  273. $this->drupalLogin($this->admin);
  274. foreach ($this->vocabularies as $k => $v) {
  275. $name = $this->randomName();
  276. $this->drupalPost('admin/structure/taxonomy/add', array(
  277. 'name' => $name,
  278. 'machine_name' => $k,
  279. 'description' => $this->randomName(),
  280. 'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => $v,
  281. ), 'Save');
  282. $this->vocabularies[$k] = taxonomy_vocabulary_machine_name_load($k);
  283. }
  284. // Creating a test content type.
  285. $this->drupalPost('admin/structure/types/add', array(
  286. 'name' => 'Synonyms Test Content',
  287. 'type' => $this->bundle,
  288. ), 'Save content type');
  289. // Attaching each vocabulary term reference field to the new content type.
  290. foreach ($this->vocabularies as $k => $v) {
  291. $this->drupalPost('admin/structure/types/manage/synonyms_test_content/fields', array(
  292. 'fields[_add_new_field][label]' => 'Synonym Terms ' . $k,
  293. 'fields[_add_new_field][field_name]' => 'synonyms_term_' . $k,
  294. 'fields[_add_new_field][type]' => 'taxonomy_term_reference',
  295. 'fields[_add_new_field][widget_type]' => 'synonyms_autocomplete',
  296. ), 'Save');
  297. $this->drupalPost(NULL, array(
  298. 'field[settings][allowed_values][0][vocabulary]' => $v->machine_name,
  299. ), 'Save field settings');
  300. $this->drupalPost(NULL, array(
  301. 'field[cardinality]' => FIELD_CARDINALITY_UNLIMITED,
  302. ), 'Save settings');
  303. }
  304. // Flushing static cache.
  305. _field_info_collate_fields(TRUE);
  306. // Now creating taxonomy tree for each vocabulary.
  307. // For synonym-disabled vocabulary just a few terms is good enough.
  308. $name = $this->randomName();
  309. $this->drupalPost('admin/structure/taxonomy/disabled/add', array(
  310. 'name' => $name,
  311. ), 'Save');
  312. $this->terms['disabled']['term1'] = $this->getLastTerm($this->vocabularies['disabled']);
  313. $name .= $this->randomName();
  314. $this->drupalPost('admin/structure/taxonomy/disabled/add', array(
  315. 'name' => $name,
  316. ), 'Save');
  317. $this->terms['disabled']['term1_longer_name'] = $this->getLastTerm($this->vocabularies['disabled']);
  318. $this->drupalPost('admin/structure/taxonomy/disabled/add', array(
  319. 'name' => $this->randomName(),
  320. ), 'Save');
  321. $this->terms['disabled']['term2'] = $this->getLastTerm($this->vocabularies['disabled']);
  322. // For synonym-enabled vocabulary we have to create such a set of input,
  323. // that would cover all possible branches of the autocomplete callback.
  324. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  325. 'name' => $this->randomName(),
  326. ), 'Save');
  327. $this->terms['enabled']['no_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
  328. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  329. 'name' => $this->randomName(),
  330. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(),
  331. ), 'Save');
  332. $this->terms['enabled']['one_synonym'] = $this->getLastTerm($this->vocabularies['enabled']);
  333. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  334. 'name' => $this->randomName(),
  335. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(),
  336. ), 'Add another item');
  337. $this->drupalPost(NULL, array(
  338. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][1][value]' => $this->randomName(),
  339. ), 'Save');
  340. $this->terms['enabled']['two_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
  341. $name = $this->randomName();
  342. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  343. 'name' => $name,
  344. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $name . $this->randomName(),
  345. ), 'Save');
  346. $this->terms['enabled']['name_similar_synonym'] = $this->getLastTerm($this->vocabularies['enabled']);
  347. $name = 'similar_synonyms_';
  348. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  349. 'name' => $this->randomName(),
  350. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $name . $this->randomName(),
  351. ), 'Add another item');
  352. $this->drupalPost(NULL, array(
  353. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][1][value]' => $name . $this->randomName(),
  354. ), 'Save');
  355. $this->terms['enabled']['similar_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
  356. $name = 'one_term_name_another_synonym_';
  357. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  358. 'name' => $name . $this->randomName(),
  359. ), 'Save');
  360. $this->terms['enabled']['name_another_synonym'] = $this->getLastTerm($this->vocabularies['enabled']);
  361. $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
  362. 'name' => $this->randomName(),
  363. SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $name . $this->randomName(),
  364. ), 'Save');
  365. $this->terms['enabled']['synonym_another_name'] = $this->getLastTerm($this->vocabularies['enabled']);
  366. }
  367. /**
  368. * Test auto-creation functionality.
  369. *
  370. * Test the auto-creation functionality of the synonym friendly autocomplete
  371. * widget type. Along the way it tests whether synonyms, submitted into the
  372. * widget's textfield are converted into the terms, synonyms of which they
  373. * are.
  374. */
  375. public function testAutoCreation() {
  376. // Trying enabled auto creation.
  377. $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
  378. 'instance[widget][settings][auto_creation]' => TRUE,
  379. ), 'Save settings');
  380. $new_term_name = $this->randomName();
  381. $this->drupalPost('node/add/synonyms-test-content', array(
  382. 'title' => $this->randomName(),
  383. 'field_synonyms_term_enabled[' . LANGUAGE_NONE . ']' => $this->terms['enabled']['no_synonyms']->name . ', ' . $new_term_name . ', ' . $this->terms['enabled']['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'],
  384. ), 'Save');
  385. $this->assertText($this->terms['enabled']['no_synonyms']->name, 'Existing term was assigned to the new node');
  386. $this->assertText($new_term_name, 'Auto created term was assigned to the new node when Auto creation is on.');
  387. $this->assertText($this->terms['enabled']['one_synonym']->name, 'Submitting a synonym into autocomplete widget results in the term, to which the synonym belongs, being assigned to the just created entity (when Auto creation is on).');
  388. $term = $this->getLastTerm($this->vocabularies['enabled']);
  389. $this->assertEqual($term->name, $new_term_name, 'The auto created term has been created when Auto creation is on.');
  390. // Trying disabled auto creation.
  391. $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
  392. 'instance[widget][settings][auto_creation]' => FALSE,
  393. ), 'Save settings');
  394. $new_term_name = $this->randomName();
  395. $this->drupalPost('node/add/synonyms-test-content', array(
  396. 'title' => $this->randomName(),
  397. 'field_synonyms_term_enabled[' . LANGUAGE_NONE . ']' => $this->terms['enabled']['no_synonyms']->name . ', ' . $new_term_name . ', ' . $this->terms['enabled']['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'],
  398. ), 'Save');
  399. $this->assertText($this->terms['enabled']['no_synonyms']->name, 'Existing term was assigned to the new node');
  400. $this->assertNoText($new_term_name, 'Auto created term was not assigned to the new node when Auto creation is off.');
  401. $this->assertText($this->terms['enabled']['one_synonym']->name, 'Submitting a synonym into autocomplete widget results in the term, to which the synonym belongs, being assigned to the just created entity (when Auto creation is off).');
  402. $term = $this->getLastTerm($this->vocabularies['enabled']);
  403. $this->assertNotEqual($term->name, $new_term_name, 'The auto created term has not been created when Auto creation is off.');
  404. }
  405. /**
  406. * Test autocomplete menu path.
  407. *
  408. * Feed all known "buggy" input to synonym friendly autocomplete menu path,
  409. * in order to test its performance.
  410. */
  411. public function testAutocompleteMenuPath() {
  412. $assertions = array();
  413. // Testing empty and non-existing name arguments.
  414. foreach ($this->vocabularies as $v) {
  415. $assertions[] = array(
  416. 'vocabulary' => $v->machine_name,
  417. 'input' => '',
  418. 'response' => array(),
  419. 'message' => 'Submitting empty string into a ' . $v->machine_name . ' synonyms vocabulary',
  420. );
  421. $assertions[] = array(
  422. 'vocabulary' => $v->machine_name,
  423. 'input' => $this->randomName(),
  424. 'response' => array(),
  425. 'message' => 'Submitting non existing name into a ' . $v->machine_name . ' synonyms vocabulary',
  426. );
  427. }
  428. // Testing the synonym-disabled vocabulary.
  429. $terms = $this->terms['disabled'];
  430. $assertions[] = array(
  431. 'vocabulary' => 'disabled',
  432. 'input' => drupal_strtoupper(drupal_substr($terms['term1']->name, 1, -1)),
  433. 'response' => array($terms['term1']->name => $terms['term1']->name, $terms['term1_longer_name']->name => $terms['term1_longer_name']->name),
  434. 'message' => 'Submitting a name similar to 2 existing term names into a disabled synonyms vocabulary',
  435. );
  436. $assertions[] = array(
  437. 'vocabulary' => 'disabled',
  438. 'input' => $terms['term1']->name . ',' . drupal_strtoupper(drupal_substr($terms['term1']->name, 1, -1)),
  439. 'response' => array($terms['term1']->name . ', ' . $terms['term1_longer_name']->name => $terms['term1_longer_name']->name),
  440. 'message' => 'Submitting one term already chosen along with a name similar to 2 existing term names into a disabled synonyms vocabulary',
  441. );
  442. $assertions[] = array(
  443. 'vocabulary' => 'disabled',
  444. 'input' => drupal_strtoupper(drupal_substr($terms['term2']->name, 1, -1)),
  445. 'response' => array($terms['term2']->name => $terms['term2']->name),
  446. 'message' => 'Submitting a name similar to one existing term name into a disabled synonyms vocabulary',
  447. );
  448. $assertions[] = array(
  449. 'vocabulary' => 'disabled',
  450. 'input' => drupal_strtolower($terms['term2']->name) . ',' . drupal_strtoupper(drupal_substr($terms['term2']->name, 1, -1)),
  451. 'response' => array(),
  452. 'message' => 'Submitting the same term over again into a disabled synonyms vocabulary',
  453. );
  454. // Testing the synonym-enabled vocabulary.
  455. $terms = $this->terms['enabled'];
  456. $assertions[] = array(
  457. 'vocabulary' => 'enabled',
  458. 'input' => drupal_strtoupper($terms['no_synonyms']->name) . ',' . drupal_strtolower(drupal_substr($terms['no_synonyms']->name, 1, -1)),
  459. 'response' => array(),
  460. 'message' => 'Submitting the same term over again into an enabled synonyms vocabulary',
  461. );
  462. $assertions[] = array(
  463. 'vocabulary' => 'enabled',
  464. 'input' => $terms['one_synonym']->name . ',' . $terms['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['safe_value'],
  465. 'response' => array(),
  466. 'message' => 'Submitting a synonym of a term over again into an enabled synonyms vocabulary',
  467. );
  468. foreach (array('no_synonyms', 'one_synonym', 'two_synonyms') as $k) {
  469. $assertions[] = array(
  470. 'vocabulary' => 'enabled',
  471. 'input' => drupal_strtolower(drupal_substr($terms[$k]->name, 1, -1)),
  472. 'response' => array($terms[$k]->name => $terms[$k]->name),
  473. 'message' => 'Submitting a name similar to ' . $k . ' term into an enabled synonyms vocabulary',
  474. );
  475. $synonyms = field_get_items('taxonomy_term', $terms[$k], SYNONYMS_DEFAULT_FIELD_NAME);
  476. if (is_array($synonyms)) {
  477. foreach ($synonyms as $delta => $item) {
  478. $assertions[] = array(
  479. 'vocabulary' => 'enabled',
  480. 'input' => drupal_strtolower(drupal_substr($item['safe_value'], 1, -1)),
  481. 'response' => array($terms[$k]->name => $this->synonymAutocompleteResult($terms[$k], $item['safe_value'])),
  482. 'message' => 'Submitting a name similar to synonym#' . $delta . ' of the term ' . $k . ' into an enabled synonyms vocabulary',
  483. );
  484. }
  485. }
  486. }
  487. $assertions[] = array(
  488. 'vocabulary' => 'enabled',
  489. 'input' => 'one_term_name_another_synonym_',
  490. 'response' => array(
  491. $terms['name_another_synonym']->name => $terms['name_another_synonym']->name,
  492. $terms['synonym_another_name']->name => $this->synonymAutocompleteResult($terms['synonym_another_name'], $terms['synonym_another_name']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['safe_value']),
  493. ),
  494. 'message' => 'Submitting a keyword similar to name of one term and synonym of another into an enabled synonyms vocabulary yields both included in the results',
  495. );
  496. foreach ($assertions as $v) {
  497. $this->assertAutocompleteMenuPath($v);
  498. }
  499. }
  500. /**
  501. * Test 'Suggestions Size' setting of synonyms-friendly autocomplete widget.
  502. */
  503. function testWidgetSettingsSuggestionSize() {
  504. $suggestion_size = 1;
  505. $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_disabled', array(
  506. 'instance[widget][settings][suggestion_size]' => $suggestion_size,
  507. ), 'Save settings');
  508. $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
  509. 'instance[widget][settings][suggestion_size]' => $suggestion_size,
  510. ), 'Save settings');
  511. $assertions = array();
  512. // If size was bigger than 1, we'd get suggested 2 terms: 'term1' and
  513. // 'term1_longer_name'.
  514. $assertions[] = array(
  515. 'vocabulary' => 'disabled',
  516. 'input' => $this->terms['disabled']['term1']->name,
  517. 'response' => array($this->terms['disabled']['term1']->name => $this->terms['disabled']['term1']->name),
  518. 'message' => 'Suggestions Size option is respected in autocomplete widget for term suggestion entries.',
  519. );
  520. $assertions[] = array(
  521. 'vocabulary' => 'enabled',
  522. 'input' => $this->terms['enabled']['name_similar_synonym']->name,
  523. 'response' => array($this->terms['enabled']['name_similar_synonym']->name => $this->terms['enabled']['name_similar_synonym']->name),
  524. 'message' => 'Suggestions Size option is respected in autocomplete widget for term and synonym suggestion entries.'
  525. );
  526. $assertions[] = array(
  527. 'vocabulary' => 'enabled',
  528. 'input' => drupal_substr($this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'], 0, 8),
  529. 'response' => array($this->terms['enabled']['similar_synonyms']->name => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'])),
  530. 'message' => 'Suggestions Size option is respected in autocomplete widget for synonyms suggestion entries.'
  531. );
  532. foreach ($assertions as $assertion) {
  533. $this->assertAutocompleteMenuPath($assertion);
  534. }
  535. }
  536. /**
  537. * Test 'Suggest only one entry per term' setting of autocomplete widget.
  538. */
  539. function testWidgetSettingsSuggestOnlyUnique() {
  540. $assertions = array();
  541. // Testing disabled "Suggest only one entry per term" setting.
  542. $assertions[] = array(
  543. 'vocabulary' => 'enabled',
  544. 'input' => $this->terms['enabled']['name_similar_synonym']->name,
  545. 'response' => array(
  546. $this->terms['enabled']['name_similar_synonym']->name => $this->terms['enabled']['name_similar_synonym']->name,
  547. $this->terms['enabled']['name_similar_synonym']->name . ' ' => $this->synonymAutocompleteResult($this->terms['enabled']['name_similar_synonym'], $this->terms['enabled']['name_similar_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value']),
  548. ),
  549. 'message' => 'Both term and its synonym are shown when "Suggest only one entry per term" is off.'
  550. );
  551. $assertions[] = array(
  552. 'vocabulary' => 'enabled',
  553. 'input' => drupal_substr($this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'], 0, 8),
  554. 'response' => array(
  555. $this->terms['enabled']['similar_synonyms']->name => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value']),
  556. $this->terms['enabled']['similar_synonyms']->name . ' ' => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][1]['value']),
  557. ),
  558. 'message' => 'Multiple synonyms are shown when "Suggest only one entry per term" is off.'
  559. );
  560. foreach ($assertions as $assertion) {
  561. $this->assertAutocompleteMenuPath($assertion);
  562. }
  563. // Testing enabled "Suggest only one entry per term" setting.
  564. $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_disabled', array(
  565. 'instance[widget][settings][suggest_only_unique]' => TRUE,
  566. ), 'Save settings');
  567. $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
  568. 'instance[widget][settings][suggest_only_unique]' => TRUE,
  569. ), 'Save settings');
  570. $assertions = array();
  571. $assertions[] = array(
  572. 'vocabulary' => 'enabled',
  573. 'input' => $this->terms['enabled']['name_similar_synonym']->name,
  574. 'response' => array(
  575. $this->terms['enabled']['name_similar_synonym']->name => $this->terms['enabled']['name_similar_synonym']->name,
  576. ),
  577. 'message' => 'Only term is shown and synonym is not shown when "Suggest only one entry per term" is on.'
  578. );
  579. $assertions[] = array(
  580. 'vocabulary' => 'enabled',
  581. 'input' => drupal_substr($this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'], 0, 8),
  582. 'response' => array(
  583. $this->terms['enabled']['similar_synonyms']->name => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value']),
  584. ),
  585. 'message' => 'Only single synonym is shown when "Suggest only one entry per term" is on.'
  586. );
  587. foreach ($assertions as $assertion) {
  588. $this->assertAutocompleteMenuPath($assertion);
  589. }
  590. }
  591. /**
  592. * Assert output of synonym friendly autocomplete path.
  593. *
  594. * @param array $assertion
  595. * Specially encoded array of assertion. Should include the following keys:
  596. * vocabulary - machine name of vocabulary whose field is asserted
  597. * input - input string to be fed to autocomplete menu path
  598. * response - JSON decoded expected response of autocomplete menu path
  599. * message - Drupal assertion message to be displayed on test results
  600. * page
  601. */
  602. protected function assertAutocompleteMenuPath($assertion) {
  603. $response = $this->drupalGet('synonyms/autocomplete/field_synonyms_term_' . $assertion['vocabulary'] . '/' . $this->entity_type . '/' . $this->bundle . '/' . $assertion['input']);
  604. if (!$response) {
  605. $this->fail($assertion['message'], 'Autocomplete Menu Path');
  606. return;
  607. }
  608. $response = (array) json_decode($response);
  609. $is_the_same = count($response) == count($assertion['response']);
  610. $is_the_same = $is_the_same && count(array_intersect_assoc($response, $assertion['response'])) == count($assertion['response']);
  611. $this->assertTrue($is_the_same, $assertion['message'], 'Autocomplete Menu Path');
  612. }
  613. /**
  614. * Return expected autocomplete menu path result.
  615. *
  616. * The result is prepared as if the term was found by the supplied synonym.
  617. *
  618. * @param object $term
  619. * Fully loaded taxonomy term object for which the result is generated.
  620. * @param string $synonym
  621. * Synonym by which the term was hit in the search
  622. *
  623. * @return string
  624. * Formatted autocomplete result
  625. */
  626. protected function synonymAutocompleteResult($term, $synonym) {
  627. return t('@synonym, synonym of %term', array('@synonym' => $synonym, '%term' => $term->name));
  628. }
  629. }
  630. /**
  631. * Test Synonyms module integration with Drupal search functionality.
  632. */
  633. class SearchIndexSynonymsWebTestCase extends SynonymsWebTestCase {
  634. protected $vocabularies = array(
  635. 'enabled' => TRUE,
  636. );
  637. /**
  638. * GetInfo method.
  639. */
  640. public function getInfo() {
  641. return array(
  642. 'name' => 'Synonyms search integration',
  643. 'description' => 'Ensure that Synonyms module correctly integrates with the Drupal search functionality.',
  644. 'group' => 'Synonyms',
  645. );
  646. }
  647. /**
  648. * SetUp method.
  649. */
  650. public function setUp() {
  651. parent::setUp();
  652. // Creating vocabularies.
  653. $this->drupalLogin($this->admin);
  654. foreach ($this->vocabularies as $k => $v) {
  655. $name = $this->randomName();
  656. $this->drupalPost('admin/structure/taxonomy/add', array(
  657. 'name' => $name,
  658. 'machine_name' => $k,
  659. 'description' => $this->randomName(),
  660. 'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => $v,
  661. ), 'Save');
  662. $this->vocabularies[$k] = taxonomy_vocabulary_machine_name_load($k);
  663. }
  664. // Creating a test content type.
  665. $this->drupalPost('admin/structure/types/add', array(
  666. 'name' => 'Synonyms Test Content',
  667. 'type' => 'synonyms_test_content',
  668. ), 'Save content type');
  669. // Attaching each vocabulary term reference field to the new content type.
  670. foreach ($this->vocabularies as $k => $v) {
  671. $this->drupalPost('admin/structure/types/manage/synonyms_test_content/fields', array(
  672. 'fields[_add_new_field][label]' => 'Synonym Terms ' . $k,
  673. 'fields[_add_new_field][field_name]' => 'synonyms_term_' . $k,
  674. 'fields[_add_new_field][type]' => 'taxonomy_term_reference',
  675. 'fields[_add_new_field][widget_type]' => 'synonyms_autocomplete',
  676. ), 'Save');
  677. $this->drupalPost(NULL, array(
  678. 'field[settings][allowed_values][0][vocabulary]' => $v->machine_name,
  679. ), 'Save field settings');
  680. $this->drupalPost(NULL, array(
  681. 'field[cardinality]' => FIELD_CARDINALITY_UNLIMITED,
  682. ), 'Save settings');
  683. }
  684. // Flushing static cache.
  685. _field_info_collate_fields(TRUE);
  686. }
  687. /**
  688. * Test searching by a term synonym.
  689. *
  690. * Since logically term and its synonyms represent the same entity, the idea
  691. * is that searching by a term synonym should trigger all content referencing
  692. * that term to be included in search results. Additionally we test that when
  693. * a synonym is deleted/edited in a term, corresponding content is no longer
  694. * encountered when searched by ex-synonym.
  695. */
  696. public function testSearchTermSynonym() {
  697. // Create a few terms and synonyms.
  698. $terms = array();
  699. $term = (object) array(
  700. 'vid' => $this->vocabularies['enabled']->vid,
  701. 'name' => $this->randomName(),
  702. );
  703. taxonomy_term_save($term);
  704. $terms['no_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
  705. $term = (object) array(
  706. 'vid' => $this->vocabularies['enabled']->vid,
  707. 'name' => $this->randomName(),
  708. SYNONYMS_DEFAULT_FIELD_NAME => array(
  709. LANGUAGE_NONE => array(
  710. array('value' => $this->randomName()),
  711. ),
  712. )
  713. );
  714. taxonomy_term_save($term);
  715. $terms['one_synonym'] = $this->getLastTerm($this->vocabularies['enabled']);
  716. $term = (object) array(
  717. 'vid' => $this->vocabularies['enabled']->vid,
  718. 'name' => $this->randomName(),
  719. SYNONYMS_DEFAULT_FIELD_NAME => array(
  720. LANGUAGE_NONE => array(
  721. array('value' => $this->randomName()),
  722. array('value' => $this->randomName()),
  723. ),
  724. )
  725. );
  726. taxonomy_term_save($term);
  727. $terms['two_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
  728. // Creating a node, which references to all the terms we have.
  729. $title = $this->randomName();
  730. $this->drupalPost('node/add/synonyms-test-content', array(
  731. 'title' => $title,
  732. 'field_synonyms_term_enabled[' . LANGUAGE_NONE . ']' => $terms['no_synonyms']->name . ', ' . $terms['one_synonym']->name . ', ' . $terms['two_synonyms']->name,
  733. ), 'Save');
  734. $node = $this->drupalGetNodeByTitle($title);
  735. // Rebuilding Search index.
  736. $this->cronRun();
  737. foreach ($terms as $k => $term) {
  738. $this->assertSearchResults($term->name, array($node), 'Searching by name of the term ' . $k);
  739. foreach (synonyms_get_sanitized($term) as $delta => $synonym) {
  740. $this->assertSearchResults($synonym, array($node), 'Searching by synonym #' . $delta . ' of the term ' . $k);
  741. }
  742. }
  743. // Removing a synonym from the term. Then asserting node got re-indexed
  744. // with new values of synonyms.
  745. $deleted_synonym = array_pop($terms['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE]);
  746. taxonomy_term_save($terms['one_synonym']);
  747. $this->cronRun();
  748. $this->assertSearchResults($deleted_synonym['value'], array(), 'Searching by recently deleted synonym of a taxonomy term yields no results.');
  749. // Editing a synonym in a term. Then asserting node got re-indexed with new
  750. // values of synonyms.
  751. $ex_synonym = $terms['two_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'];
  752. $terms['two_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'] = $this->randomName();
  753. taxonomy_term_save($terms['two_synonyms']);
  754. $this->cronRun();
  755. $this->assertSearchResults($ex_synonym, array(), 'Searching by recently changed synonym of a taxonomy term yields no results.');
  756. // We disable entire field from being source of synonyms and make sure for
  757. // all synonyms search results are empty.
  758. $this->drupalPost('admin/structure/taxonomy/enabled/edit', array(
  759. 'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => FALSE,
  760. ), 'Save');
  761. $this->cronRun();
  762. foreach ($terms as $k => $term) {
  763. $items = field_get_items('taxonomy_term', $term, SYNONYMS_DEFAULT_FIELD_NAME);
  764. if (is_array($items)) {
  765. foreach ($items as $synonym) {
  766. $this->assertSearchResults($synonym['value'], array(), 'Searching by ' . $k . ' term synonym, which field was recently disabled as source of synonyms in vocabulary yields no results.');
  767. }
  768. }
  769. }
  770. }
  771. /**
  772. * Assert search results.
  773. *
  774. * @param $keyword string
  775. * Keyword to supply to the search mechanism
  776. * @param $results array
  777. * Array of fully loaded nodes that are expected to be on search results
  778. * @param $message string
  779. * Drupal assertion message to display on test results page
  780. */
  781. protected function assertSearchResults($keyword, $results, $message) {
  782. $response = $this->drupalGet('search/node/' . $keyword);
  783. $matches = array();
  784. preg_match_all('#\<li[^>]+class="search-result"[^>]*\>(.*?)\</li\>#si', $response, $matches);
  785. $matches = $matches[1];
  786. if (count($matches) != count($results)) {
  787. $this->fail($message);
  788. return;
  789. }
  790. $matches = implode('', $matches);
  791. foreach ($results as $node) {
  792. if (strpos($matches, 'node/' . $node->nid) === FALSE) {
  793. $this->fail($message);
  794. return;
  795. }
  796. }
  797. $this->pass($message);
  798. }
  799. }
  800. /**
  801. * Base class for all test cases that test Synonyms Extractor classes.
  802. */
  803. abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
  804. /**
  805. * Taxonomy vocabulary object on whose term all synonyms extracting tests will
  806. * occur.
  807. *
  808. * @var object
  809. */
  810. protected $vocabulary;
  811. /**
  812. * Class name of a synonyms extractor that is being tested.
  813. *
  814. * @var string
  815. */
  816. protected $extractor;
  817. /**
  818. * Field API field definition array of the field that is tested right now.
  819. *
  820. * @var array
  821. */
  822. protected $field;
  823. /**
  824. * Field API instance definition array of the instance that is tested now.
  825. *
  826. * @var array
  827. */
  828. protected $instance;
  829. /**
  830. * SetUp method.
  831. *
  832. * @param string $class
  833. * Name of class that is being tested
  834. * @param array $modules
  835. * Array of extra modules to install for testing a particular synonyms
  836. * extractor
  837. */
  838. public function setUp($class, $modules = array()) {
  839. array_unshift($modules, 'synonyms');
  840. parent::setUp($modules);
  841. $this->vocabulary = (object) array(
  842. 'name' => 'Test Synonyms Extractor',
  843. 'machine_name' => 'synonyms_extractor',
  844. );
  845. taxonomy_vocabulary_save($this->vocabulary);
  846. $this->extractor = $class;
  847. }
  848. /**
  849. * Completely set field in the tested vocabulary.
  850. *
  851. * Create a field in Field API (if does not exist yet), then create an
  852. * instance and relate it to our tested vocabulary. Lastly enable this field
  853. * as a source of synonyms for our tested vocabulary.
  854. *
  855. * @param array $field
  856. * Field definition array as expected by Field API
  857. * @param array $instance
  858. * Instance definition array as expected by Field API
  859. */
  860. protected function addFieldInstance($field, $instance) {
  861. $field = field_create_field($field);
  862. $instance['entity_type'] = 'taxonomy_term';
  863. $instance['bundle'] = field_extract_bundle('taxonomy_term', $this->vocabulary);
  864. field_create_instance($instance);
  865. $settings = synonyms_vocabulary_settings($this->vocabulary);
  866. $settings['synonyms'][] = $field['field_name'];
  867. synonyms_vocabulary_settings_save($this->vocabulary, $settings);
  868. $this->field = $field;
  869. $this->instance = $instance;
  870. }
  871. /**
  872. * Test synonymsExtract() method of class.
  873. *
  874. * @param array $items
  875. * Array of field items to be saved in tested term
  876. * @param array $etalon
  877. * Expected return of synonymsExtract() method of class
  878. * @param string $message
  879. * Any custom message to be added to the standard one and passed to
  880. * SimpleTest assertion method
  881. */
  882. protected function assertSynonymsExtract($items, $etalon, $message = '') {
  883. $term = (object) array(
  884. 'name' => $this->randomName(),
  885. 'vid' => $this->vocabulary->vid,
  886. );
  887. $term->{$this->field['field_name']} = $items;
  888. taxonomy_term_save($term);
  889. $items = field_get_items('taxonomy_term', $term, $this->field['field_name']);
  890. $synonyms = is_array($items) ? call_user_func(array($this->extractor, 'synonymsExtract'), $items, $this->field, $this->instance, $term, 'taxonomy_term') : array();
  891. $this->assertTrue(count(array_intersect($etalon, $synonyms)) == count($etalon), 'Synonyms Extractor ' . $this->extractor . ' passed synonymsExtract() method: ' . $message);
  892. // Cleaning up.
  893. taxonomy_term_delete($term->tid);
  894. }
  895. /**
  896. * Test processEntityFieldQuery method of class.
  897. *
  898. * @param array $meta_data
  899. * Array of meta data. Each subarray represents a single term and whether it
  900. * is expected to be included in the results of EntityFieldQuery. Should
  901. * have the following structure:
  902. * items - array of field items. Terms will be automatically created with
  903. * those items
  904. * expected - bool, whether the created term should be expected in the
  905. * results of EntityFieldQuery
  906. * @param string $tag
  907. * Corresponding parameter to be passed to processEntityFieldQuery() method
  908. * @param string $message
  909. * Any custom message to be added to the standard one and passed to
  910. * SimpleTest assertion method
  911. */
  912. protected function assertProcessEntityFieldQuery($meta_data, $tag, $message = '') {
  913. // Creating taxonomy terms according to the meta data.
  914. $terms = array();
  915. foreach ($meta_data as $v) {
  916. $term = (object) array(
  917. 'name' => $this->randomName(),
  918. 'vid' => $this->vocabulary->vid,
  919. );
  920. taxonomy_term_save($term);
  921. $term->{$this->field['field_name']} = $v['items'];
  922. taxonomy_term_save($term);
  923. $term->expected = $v['expected'];
  924. $terms[] = $term;
  925. }
  926. // Preparing and running EntityFieldQuery.
  927. $efq = new EntityFieldQuery();
  928. $efq->entityCondition('entity_type', 'taxonomy_term')
  929. ->entityCondition('bundle', $this->vocabulary->machine_name);
  930. call_user_func(array($this->extractor, 'processEntityFieldQuery'), $tag, $efq, $this->field, $this->instance);
  931. $result = $efq->execute();
  932. $result = isset($result['taxonomy_term']) ? array_keys($result['taxonomy_term']) : array();
  933. // Asserting results of EntityFieldQuery.
  934. $pass = TRUE;
  935. foreach ($terms as $term) {
  936. $tmp = $term->expected ? in_array($term->tid, $result) : !in_array($term->tid, $result);
  937. $pass = $pass && $tmp;
  938. }
  939. $this->assertTrue($pass, 'Synonyms Extractor ' . $this->extractor . ' passed processEntityFieldQuery() method: ' . $message);
  940. // Cleaning up.
  941. foreach ($terms as $term) {
  942. taxonomy_term_delete($term->tid);
  943. }
  944. }
  945. /**
  946. * Test mergeEntityAsSynonym method of class.
  947. *
  948. * @param array $items
  949. * Parameter will be passed directly to the extractor class method
  950. * @param object $synonym_entity
  951. * Parameter will be passed directly to the extractor class method
  952. * @param string $synonym_entity_type
  953. * Parameter will be passed directly to the extractor class method
  954. * @param array $etalon
  955. * Array that is expected to be returned by the tested method
  956. * @param string $message
  957. * Any custom message to be added to the standard one and passed to
  958. * SimpleTest assertion method
  959. */
  960. protected function assertMergeEntityAsSynonym($items, $synonym_entity, $synonym_entity_type, $etalon, $message = '') {
  961. $extra_items = call_user_func(array($this->extractor, 'mergeEntityAsSynonym'), $items, $this->field, $this->instance, $synonym_entity, $synonym_entity_type);
  962. foreach ($etalon as $k => $v) {
  963. if (count(array_intersect($etalon[$k], $extra_items[$k])) != count($etalon[$k])) {
  964. $this->fail('Synonyms Extractor ' . $this->extractor . ' passed mergeEntityAsSynonym() method: ' . $message);
  965. return;
  966. }
  967. }
  968. $this->pass('Synonyms Extractor ' . $this->extractor . ' passed mergeEntityAsSynonym() method: ' . $message);
  969. }
  970. }
  971. /**
  972. * Test SynonymsSynonymsExtractor class.
  973. */
  974. class SynonymsSynonymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
  975. /**
  976. * GetInfo method.
  977. */
  978. public function getInfo() {
  979. return array(
  980. 'name' => 'SynonymsSynonymsExtractor',
  981. 'description' => 'Ensure that the synonyms module extracts synonyms from text and number fields correctly.',
  982. 'group' => 'Synonyms',
  983. );
  984. }
  985. /**
  986. * SetUp method.
  987. */
  988. public function setUp() {
  989. parent::setUp('SynonymsSynonymsExtractor');
  990. }
  991. /**
  992. * Test synonyms extraction for 'text' field type.
  993. */
  994. public function testText() {
  995. $this->addFieldInstance(array(
  996. 'field_name' => 'text',
  997. 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  998. 'type' => 'text',
  999. ), array(
  1000. 'field_name' => 'text',
  1001. 'entity_type' => 'taxonomy_term',
  1002. 'bundle' => $this->vocabulary->machine_name,
  1003. 'label' => $this->randomName(),
  1004. ));
  1005. // Testing synonymsExtract().
  1006. $this->assertSynonymsExtract(array(), array(), 'on empty field.');
  1007. $synonym = $this->randomName();
  1008. $this->assertSynonymsExtract(array(
  1009. LANGUAGE_NONE => array(
  1010. 0 => array('value' => $synonym),
  1011. ),
  1012. ), array($synonym), 'on a field that holds one value.');
  1013. // Testing processEntityFieldQuery().
  1014. $this->assertProcessEntityFieldQuery(array(), $this->randomName(), 'on empty field.');
  1015. $tag = $this->randomName();
  1016. $meta_data = array();
  1017. $meta_data[] = array(
  1018. 'items' => array(
  1019. LANGUAGE_NONE => array(
  1020. 0 => array('value' => $tag . $this->randomName()),
  1021. 1 => array('value' => $this->randomName()),
  1022. ),
  1023. ),
  1024. 'expected' => TRUE,
  1025. );
  1026. $meta_data[] = array(
  1027. 'items' => array(
  1028. LANGUAGE_NONE => array(
  1029. 0 => array('value' => $this->randomName()),
  1030. ),
  1031. ),
  1032. 'expected' => FALSE,
  1033. );
  1034. $meta_data[] = array(
  1035. 'items' => array(),
  1036. 'expected' => FALSE,
  1037. );
  1038. $this->assertProcessEntityFieldQuery($meta_data, $tag, 'on a field with values.');
  1039. // Testing mergeEntityAsSynonym() method.
  1040. $node = (object) array(
  1041. 'title' => $this->randomName(),
  1042. 'type' => 'page',
  1043. );
  1044. node_save($node);
  1045. $this->assertMergeEntityAsSynonym(array(), $node, 'node', array(array('value' => $node->title)), 'on a node entity.');
  1046. }
  1047. }
  1048. /**
  1049. * Test TaxonomySynonymsExtractor class.
  1050. */
  1051. class TaxonomySynonymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
  1052. /**
  1053. * Taxonomy vocabulary object terms.
  1054. *
  1055. * Terms of this vocabulary are synonyms of the main vocabulary terms.
  1056. *
  1057. * @var object
  1058. */
  1059. protected $vocabularySource;
  1060. /**
  1061. * GetInfo method.
  1062. */
  1063. public function getInfo() {
  1064. return array(
  1065. 'name' => 'TaxonomySynonymsExtractor',
  1066. 'description' => 'Ensure that the synonyms module extracts synonyms from taxonomy term reference fields correctly.',
  1067. 'group' => 'Synonyms',
  1068. );
  1069. }
  1070. /**
  1071. * SetUp method.
  1072. */
  1073. public function setUp() {
  1074. parent::setUp('TaxonomySynonymsExtractor');
  1075. $this->vocabularySource = (object) array(
  1076. 'name' => $this->randomName(),
  1077. 'machine_name' => 'source_vocabulary',
  1078. );
  1079. taxonomy_vocabulary_save($this->vocabularySource);
  1080. }
  1081. /**
  1082. * Test synonyms extraction for 'taxonomy_term_reference' field type.
  1083. */
  1084. public function testTaxonomyTermReference() {
  1085. $this->addFieldInstance(array(
  1086. 'field_name' => 'term',
  1087. 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  1088. 'type' => 'taxonomy_term_reference',
  1089. 'settings' => array(
  1090. 'allowed_values' => array(
  1091. array(
  1092. 'vocabulary' => $this->vocabularySource->machine_name,
  1093. 'parent' => 0,
  1094. ),
  1095. ),
  1096. ),
  1097. ), array(
  1098. 'field_name' => 'term',
  1099. 'entity_type' => 'taxonomy_term',
  1100. 'bundle' => $this->vocabulary->machine_name,
  1101. 'label' => $this->randomName(),
  1102. ));
  1103. // Testing synonymsExtract().
  1104. $this->assertSynonymsExtract(array(), array(), 'on empty field.');
  1105. $synonym_term = $this->createSynonymTerm();
  1106. $this->assertSynonymsExtract(array(
  1107. LANGUAGE_NONE => array(
  1108. 0 => array(
  1109. 'tid' => $synonym_term->tid,
  1110. ),
  1111. ),
  1112. ), array($synonym_term->name), 'on a field that holds one value.');
  1113. // Testing processEntityFieldQuery().
  1114. $this->assertProcessEntityFieldQuery(array(), $this->randomName(), 'on empty field.');
  1115. $tag = $this->randomName();
  1116. $meta_data = array();
  1117. $meta_data[] = array(
  1118. 'items' => array(
  1119. LANGUAGE_NONE => array(
  1120. array('tid' => $this->createSynonymTerm($tag . $this->randomName())->tid),
  1121. array('tid' => $this->createSynonymTerm()->tid),
  1122. ),
  1123. ),
  1124. 'expected' => TRUE,
  1125. );
  1126. $meta_data[] = array(
  1127. 'items' => array(
  1128. LANGUAGE_NONE => array(
  1129. array('tid' => $this->createSynonymTerm()->tid),
  1130. ),
  1131. ),
  1132. 'expected' => FALSE,
  1133. );
  1134. $meta_data[] = array(
  1135. 'items' => array(),
  1136. 'expected' => FALSE,
  1137. );
  1138. $this->assertProcessEntityFieldQuery($meta_data, $tag, 'on a field with values.');
  1139. // Testing mergeEntityAsSynonym() method.
  1140. $synonym_term = $this->createSynonymTerm();
  1141. $this->assertMergeEntityAsSynonym(array(), $synonym_term, 'taxonomy_term', array(array('tid' => $synonym_term->tid)), 'on a term from referenced vocabulary.');
  1142. }
  1143. /**
  1144. * Supportive function.
  1145. *
  1146. * Create a taxonomy term in the synonyms source vocabulary with the specified
  1147. * name.
  1148. *
  1149. * @param string $name
  1150. * Name of the term to be created. If nothing is supplied a random string
  1151. * is used
  1152. *
  1153. * @return object
  1154. * Fully loaded taxonomy term object of the just created term
  1155. */
  1156. protected function createSynonymTerm($name = NULL) {
  1157. if (is_null($name)) {
  1158. $name = $this->randomName();
  1159. }
  1160. $synonym_term = (object) array(
  1161. 'name' => $name,
  1162. 'vid' => $this->vocabularySource->vid,
  1163. );
  1164. taxonomy_term_save($synonym_term);
  1165. return $synonym_term;
  1166. }
  1167. }
  1168. /**
  1169. * Test EntityReferenceSynonymsExtractor class.
  1170. */
  1171. class EntityReferenceSynonymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
  1172. /**
  1173. * GetInfo method.
  1174. */
  1175. public function getInfo() {
  1176. return array(
  1177. 'name' => 'EntityReferenceSynonymsExtractor',
  1178. 'description' => 'Ensure that the synonyms module extracts synonyms from entity reference fields correctly.',
  1179. 'group' => 'Synonyms',
  1180. );
  1181. }
  1182. /**
  1183. * SetUp method.
  1184. */
  1185. public function setUp() {
  1186. parent::setUp('EntityReferenceSynonymsExtractor', array('entityreference'));
  1187. }
  1188. /**
  1189. * Test synonyms extraction for 'entityreference' field type.
  1190. */
  1191. public function testEntityReference() {
  1192. $this->addFieldInstance(array(
  1193. 'field_name' => 'reference',
  1194. 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  1195. 'type' => 'entityreference',
  1196. // For the sake of experiment we use entityreference field that references
  1197. // nodes of a Drupal standard type to make things easier.
  1198. 'settings' => array(
  1199. 'target_type' => 'node',
  1200. 'handler' => 'base',
  1201. 'handler_settings' => array(
  1202. 'target_bundles' => array('page' => 'page'),
  1203. 'sort' => array('type' => 'none'),
  1204. ),
  1205. ),
  1206. ), array(
  1207. 'field_name' => 'reference',
  1208. 'entity_type' => 'taxonomy_term',
  1209. 'bundle' => $this->vocabulary->machine_name,
  1210. 'label' => $this->randomName(),
  1211. ));
  1212. // Testing synonymsExtract().
  1213. $this->assertSynonymsExtract(array(), array(), 'on empty field.');
  1214. $synonym_entity = $this->createNode();
  1215. $this->assertSynonymsExtract(array(
  1216. LANGUAGE_NONE => array(
  1217. 0 => array(
  1218. 'target_id' => entity_id('node', $synonym_entity),
  1219. ),
  1220. ),
  1221. ), array(entity_label('node', $synonym_entity)), 'on a field that holds one value.');
  1222. // Testing processEntityFieldQuery().
  1223. $this->assertProcessEntityFieldQuery(array(), $this->randomName(), 'on empty field.');
  1224. $tag = $this->randomName();
  1225. $meta_data = array();
  1226. $meta_data[] = array(
  1227. 'items' => array(
  1228. LANGUAGE_NONE => array(
  1229. array(
  1230. 'target_id' => entity_id('node', $this->createNode($tag . $this->randomName())),
  1231. ),
  1232. array(
  1233. 'target_id' => entity_id('node', $this->createNode()),
  1234. ),
  1235. ),
  1236. ),
  1237. 'expected' => TRUE,
  1238. );
  1239. $meta_data[] = array(
  1240. 'items' => array(
  1241. LANGUAGE_NONE => array(
  1242. array('target_id' => entity_id('node', $this->createNode())),
  1243. ),
  1244. ),
  1245. 'expected' => FALSE,
  1246. );
  1247. $meta_data[] = array(
  1248. 'items' => array(),
  1249. 'expected' => FALSE,
  1250. );
  1251. $this->assertProcessEntityFieldQuery($meta_data, $tag, 'on a field with values.');
  1252. // Testing mergeEntityAsSynonym() method.
  1253. $node = $this->createNode();
  1254. $this->assertMergeEntityAsSynonym(array(), $node, 'node', array(array('target_id' => $node->nid)), 'on a node.');
  1255. }
  1256. /**
  1257. * Supportive function.
  1258. *
  1259. * Create an entity of necessary entity type (in our test it's node).
  1260. *
  1261. * @param string $label
  1262. * Label to use for the entity that is about to be created
  1263. * @param string $bundle
  1264. * Bundle to use for the entity that is about to be created
  1265. *
  1266. * @return object
  1267. * Fully loaded entity object of the just created entity
  1268. */
  1269. protected function createNode($label = NULL, $bundle = 'page') {
  1270. if (is_null($label)) {
  1271. $label = $this->randomName();
  1272. }
  1273. $entity = (object) array(
  1274. 'type' => $bundle,
  1275. 'title' => $label,
  1276. );
  1277. node_save($entity);
  1278. return $entity;
  1279. }
  1280. }