text.test

Tests for text.module.

File

drupal-7.x/modules/field/modules/text/text.test
View source
  1. <?php
  2. /**
  3. * @file
  4. * Tests for text.module.
  5. */
  6. class TextFieldTestCase extends DrupalWebTestCase {
  7. protected $instance;
  8. protected $admin_user;
  9. protected $web_user;
  10. public static function getInfo() {
  11. return array(
  12. 'name' => 'Text field',
  13. 'description' => "Test the creation of text fields.",
  14. 'group' => 'Field types'
  15. );
  16. }
  17. function setUp() {
  18. parent::setUp('field_test');
  19. $this->admin_user = $this->drupalCreateUser(array('administer filters'));
  20. $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
  21. $this->drupalLogin($this->web_user);
  22. }
  23. // Test fields.
  24. /**
  25. * Test text field validation.
  26. */
  27. function testTextFieldValidation() {
  28. // Create a field with settings to validate.
  29. $max_length = 3;
  30. $this->field = array(
  31. 'field_name' => drupal_strtolower($this->randomName()),
  32. 'type' => 'text',
  33. 'settings' => array(
  34. 'max_length' => $max_length,
  35. )
  36. );
  37. field_create_field($this->field);
  38. $this->instance = array(
  39. 'field_name' => $this->field['field_name'],
  40. 'entity_type' => 'test_entity',
  41. 'bundle' => 'test_bundle',
  42. 'widget' => array(
  43. 'type' => 'text_textfield',
  44. ),
  45. 'display' => array(
  46. 'default' => array(
  47. 'type' => 'text_default',
  48. ),
  49. ),
  50. );
  51. field_create_instance($this->instance);
  52. // Test valid and invalid values with field_attach_validate().
  53. $entity = field_test_create_stub_entity();
  54. $langcode = LANGUAGE_NONE;
  55. for ($i = 0; $i <= $max_length + 2; $i++) {
  56. $entity->{$this->field['field_name']}[$langcode][0]['value'] = str_repeat('x', $i);
  57. try {
  58. field_attach_validate('test_entity', $entity);
  59. $this->assertTrue($i <= $max_length, "Length $i does not cause validation error when max_length is $max_length");
  60. }
  61. catch (FieldValidationException $e) {
  62. $this->assertTrue($i > $max_length, "Length $i causes validation error when max_length is $max_length");
  63. }
  64. }
  65. }
  66. /**
  67. * Test widgets.
  68. */
  69. function testTextfieldWidgets() {
  70. $this->_testTextfieldWidgets('text', 'text_textfield');
  71. $this->_testTextfieldWidgets('text_long', 'text_textarea');
  72. }
  73. /**
  74. * Helper function for testTextfieldWidgets().
  75. */
  76. function _testTextfieldWidgets($field_type, $widget_type) {
  77. // Setup a field and instance
  78. $entity_type = 'test_entity';
  79. $this->field_name = drupal_strtolower($this->randomName());
  80. $this->field = array('field_name' => $this->field_name, 'type' => $field_type);
  81. field_create_field($this->field);
  82. $this->instance = array(
  83. 'field_name' => $this->field_name,
  84. 'entity_type' => 'test_entity',
  85. 'bundle' => 'test_bundle',
  86. 'label' => $this->randomName() . '_label',
  87. 'settings' => array(
  88. 'text_processing' => TRUE,
  89. ),
  90. 'widget' => array(
  91. 'type' => $widget_type,
  92. ),
  93. 'display' => array(
  94. 'full' => array(
  95. 'type' => 'text_default',
  96. ),
  97. ),
  98. );
  99. field_create_instance($this->instance);
  100. $langcode = LANGUAGE_NONE;
  101. // Display creation form.
  102. $this->drupalGet('test-entity/add/test-bundle');
  103. $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed');
  104. $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '1', 'Format selector is not displayed');
  105. // Submit with some value.
  106. $value = $this->randomName();
  107. $edit = array(
  108. "{$this->field_name}[$langcode][0][value]" => $value,
  109. );
  110. $this->drupalPost(NULL, $edit, t('Save'));
  111. preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
  112. $id = $match[1];
  113. $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
  114. // Display the entity.
  115. $entity = field_test_entity_test_load($id);
  116. $entity->content = field_attach_view($entity_type, $entity, 'full');
  117. $this->content = drupal_render($entity->content);
  118. $this->assertText($value, 'Filtered tags are not displayed');
  119. }
  120. /**
  121. * Test widgets + 'formatted_text' setting.
  122. */
  123. function testTextfieldWidgetsFormatted() {
  124. $this->_testTextfieldWidgetsFormatted('text', 'text_textfield');
  125. $this->_testTextfieldWidgetsFormatted('text_long', 'text_textarea');
  126. }
  127. /**
  128. * Helper function for testTextfieldWidgetsFormatted().
  129. */
  130. function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
  131. // Setup a field and instance
  132. $entity_type = 'test_entity';
  133. $this->field_name = drupal_strtolower($this->randomName());
  134. $this->field = array('field_name' => $this->field_name, 'type' => $field_type);
  135. field_create_field($this->field);
  136. $this->instance = array(
  137. 'field_name' => $this->field_name,
  138. 'entity_type' => 'test_entity',
  139. 'bundle' => 'test_bundle',
  140. 'label' => $this->randomName() . '_label',
  141. 'settings' => array(
  142. 'text_processing' => TRUE,
  143. ),
  144. 'widget' => array(
  145. 'type' => $widget_type,
  146. ),
  147. 'display' => array(
  148. 'full' => array(
  149. 'type' => 'text_default',
  150. ),
  151. ),
  152. );
  153. field_create_instance($this->instance);
  154. $langcode = LANGUAGE_NONE;
  155. // Disable all text formats besides the plain text fallback format.
  156. $this->drupalLogin($this->admin_user);
  157. foreach (filter_formats() as $format) {
  158. if ($format->format != filter_fallback_format()) {
  159. $this->drupalPost('admin/config/content/formats/' . $format->format . '/disable', array(), t('Disable'));
  160. }
  161. }
  162. $this->drupalLogin($this->web_user);
  163. // Display the creation form. Since the user only has access to one format,
  164. // no format selector will be displayed.
  165. $this->drupalGet('test-entity/add/test-bundle');
  166. $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed');
  167. $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '', 'Format selector is not displayed');
  168. // Submit with data that should be filtered.
  169. $value = '<em>' . $this->randomName() . '</em>';
  170. $edit = array(
  171. "{$this->field_name}[$langcode][0][value]" => $value,
  172. );
  173. $this->drupalPost(NULL, $edit, t('Save'));
  174. preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
  175. $id = $match[1];
  176. $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
  177. // Display the entity.
  178. $entity = field_test_entity_test_load($id);
  179. $entity->content = field_attach_view($entity_type, $entity, 'full');
  180. $this->content = drupal_render($entity->content);
  181. $this->assertNoRaw($value, 'HTML tags are not displayed.');
  182. $this->assertRaw(check_plain($value), 'Escaped HTML is displayed correctly.');
  183. // Create a new text format that does not escape HTML, and grant the user
  184. // access to it.
  185. $this->drupalLogin($this->admin_user);
  186. $edit = array(
  187. 'format' => drupal_strtolower($this->randomName()),
  188. 'name' => $this->randomName(),
  189. );
  190. $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
  191. filter_formats_reset();
  192. $this->checkPermissions(array(), TRUE);
  193. $format = filter_format_load($edit['format']);
  194. $format_id = $format->format;
  195. $permission = filter_permission_name($format);
  196. $rid = max(array_keys($this->web_user->roles));
  197. user_role_grant_permissions($rid, array($permission));
  198. $this->drupalLogin($this->web_user);
  199. // Display edition form.
  200. // We should now have a 'text format' selector.
  201. $this->drupalGet('test-entity/manage/' . $id . '/edit');
  202. $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", NULL, 'Widget is displayed');
  203. $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", NULL, 'Format selector is displayed');
  204. // Edit and change the text format to the new one that was created.
  205. $edit = array(
  206. "{$this->field_name}[$langcode][0][format]" => $format_id,
  207. );
  208. $this->drupalPost(NULL, $edit, t('Save'));
  209. $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
  210. // Display the entity.
  211. $entity = field_test_entity_test_load($id);
  212. $entity->content = field_attach_view($entity_type, $entity, 'full');
  213. $this->content = drupal_render($entity->content);
  214. $this->assertRaw($value, 'Value is displayed unfiltered');
  215. }
  216. }
  217. class TextSummaryTestCase extends DrupalWebTestCase {
  218. public static function getInfo() {
  219. return array(
  220. 'name' => 'Text summary',
  221. 'description' => 'Test text_summary() with different strings and lengths.',
  222. 'group' => 'Field types',
  223. );
  224. }
  225. function setUp() {
  226. parent::setUp();
  227. $this->article_creator = $this->drupalCreateUser(array('create article content', 'edit own article content'));
  228. }
  229. /**
  230. * Tests an edge case where the first sentence is a question and
  231. * subsequent sentences are not. This edge case is documented at
  232. * http://drupal.org/node/180425.
  233. */
  234. function testFirstSentenceQuestion() {
  235. $text = 'A question? A sentence. Another sentence.';
  236. $expected = 'A question? A sentence.';
  237. $this->callTextSummary($text, $expected, NULL, 30);
  238. }
  239. /**
  240. * Test summary with long example.
  241. */
  242. function testLongSentence() {
  243. $text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' . // 125
  244. 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' . // 108
  245. 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ' . // 103
  246. 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; // 110
  247. $expected = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' .
  248. 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' .
  249. 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.';
  250. // First three sentences add up to: 336, so add one for space and then 3 to get half-way into next word.
  251. $this->callTextSummary($text, $expected, NULL, 340);
  252. }
  253. /**
  254. * Test various summary length edge cases.
  255. */
  256. function testLength() {
  257. // This string tests a number of edge cases.
  258. $text = "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>";
  259. // The summaries we expect text_summary() to return when $size is the index
  260. // of each array item.
  261. // Using no text format:
  262. $expected = array(
  263. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  264. "<",
  265. "<p",
  266. "<p>",
  267. "<p>\n",
  268. "<p>\nH",
  269. "<p>\nHi",
  270. "<p>\nHi\n",
  271. "<p>\nHi\n<",
  272. "<p>\nHi\n</",
  273. "<p>\nHi\n</p",
  274. "<p>\nHi\n</p>",
  275. "<p>\nHi\n</p>",
  276. "<p>\nHi\n</p>",
  277. "<p>\nHi\n</p>",
  278. "<p>\nHi\n</p>",
  279. "<p>\nHi\n</p>",
  280. "<p>\nHi\n</p>",
  281. "<p>\nHi\n</p>",
  282. "<p>\nHi\n</p>",
  283. "<p>\nHi\n</p>",
  284. "<p>\nHi\n</p>",
  285. "<p>\nHi\n</p>",
  286. "<p>\nHi\n</p>",
  287. "<p>\nHi\n</p>",
  288. "<p>\nHi\n</p>",
  289. "<p>\nHi\n</p>",
  290. "<p>\nHi\n</p>",
  291. "<p>\nHi\n</p>",
  292. "<p>\nHi\n</p>",
  293. "<p>\nHi\n</p>",
  294. "<p>\nHi\n</p>",
  295. "<p>\nHi\n</p>",
  296. "<p>\nHi\n</p>",
  297. "<p>\nHi\n</p>",
  298. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  299. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  300. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  301. );
  302. // And using a text format WITH the line-break and htmlcorrector filters.
  303. $expected_lb = array(
  304. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  305. "",
  306. "<p></p>",
  307. "<p></p>",
  308. "<p></p>",
  309. "<p></p>",
  310. "<p></p>",
  311. "<p>\nHi</p>",
  312. "<p>\nHi</p>",
  313. "<p>\nHi</p>",
  314. "<p>\nHi</p>",
  315. "<p>\nHi\n</p>",
  316. "<p>\nHi\n</p>",
  317. "<p>\nHi\n</p>",
  318. "<p>\nHi\n</p>",
  319. "<p>\nHi\n</p>",
  320. "<p>\nHi\n</p>",
  321. "<p>\nHi\n</p>",
  322. "<p>\nHi\n</p>",
  323. "<p>\nHi\n</p>",
  324. "<p>\nHi\n</p>",
  325. "<p>\nHi\n</p>",
  326. "<p>\nHi\n</p>",
  327. "<p>\nHi\n</p>",
  328. "<p>\nHi\n</p>",
  329. "<p>\nHi\n</p>",
  330. "<p>\nHi\n</p>",
  331. "<p>\nHi\n</p>",
  332. "<p>\nHi\n</p>",
  333. "<p>\nHi\n</p>",
  334. "<p>\nHi\n</p>",
  335. "<p>\nHi\n</p>",
  336. "<p>\nHi\n</p>",
  337. "<p>\nHi\n</p>",
  338. "<p>\nHi\n</p>",
  339. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  340. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  341. "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
  342. );
  343. // Test text_summary() for different sizes.
  344. for ($i = 0; $i <= 37; $i++) {
  345. $this->callTextSummary($text, $expected[$i], NULL, $i);
  346. $this->callTextSummary($text, $expected_lb[$i], 'plain_text', $i);
  347. $this->callTextSummary($text, $expected_lb[$i], 'filtered_html', $i);
  348. }
  349. }
  350. /**
  351. * Calls text_summary() and asserts that the expected teaser is returned.
  352. */
  353. function callTextSummary($text, $expected, $format = NULL, $size = NULL) {
  354. $summary = text_summary($text, $format, $size);
  355. $this->assertIdentical($summary, $expected, format_string('Generated summary "@summary" matches expected "@expected".', array('@summary' => $summary, '@expected' => $expected)));
  356. }
  357. /**
  358. * Test sending only summary.
  359. */
  360. function testOnlyTextSummary() {
  361. // Login as article creator.
  362. $this->drupalLogin($this->article_creator);
  363. // Create article with summary but empty body.
  364. $summary = $this->randomName();
  365. $edit = array(
  366. "title" => $this->randomName(),
  367. "body[und][0][summary]" => $summary,
  368. );
  369. $this->drupalPost('node/add/article', $edit, t('Save'));
  370. $node = $this->drupalGetNodeByTitle($edit['title']);
  371. $this->assertIdentical($node->body['und'][0]['summary'], $summary, 'Article with with summary and no body has been submitted.');
  372. }
  373. }
  374. class TextTranslationTestCase extends DrupalWebTestCase {
  375. public static function getInfo() {
  376. return array(
  377. 'name' => 'Text translation',
  378. 'description' => 'Check if the text field is correctly prepared for translation.',
  379. 'group' => 'Field types',
  380. );
  381. }
  382. function setUp() {
  383. parent::setUp('locale', 'translation');
  384. $full_html_format = filter_format_load('full_html');
  385. $this->format = $full_html_format->format;
  386. $this->admin = $this->drupalCreateUser(array(
  387. 'administer languages',
  388. 'administer content types',
  389. 'access administration pages',
  390. 'bypass node access',
  391. filter_permission_name($full_html_format),
  392. ));
  393. $this->translator = $this->drupalCreateUser(array('create article content', 'edit own article content', 'translate content'));
  394. // Enable an additional language.
  395. $this->drupalLogin($this->admin);
  396. $edit = array('langcode' => 'fr');
  397. $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
  398. // Set "Article" content type to use multilingual support with translation.
  399. $edit = array('language_content_type' => 2);
  400. $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
  401. $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Article')), 'Article content type has been updated.');
  402. }
  403. /**
  404. * Test that a plaintext textfield widget is correctly populated.
  405. */
  406. function testTextField() {
  407. // Disable text processing for body.
  408. $edit = array('instance[settings][text_processing]' => 0);
  409. $this->drupalPost('admin/structure/types/manage/article/fields/body', $edit, t('Save settings'));
  410. // Login as translator.
  411. $this->drupalLogin($this->translator);
  412. // Create content.
  413. $langcode = LANGUAGE_NONE;
  414. $body = $this->randomName();
  415. $edit = array(
  416. "title" => $this->randomName(),
  417. "language" => 'en',
  418. "body[$langcode][0][value]" => $body,
  419. );
  420. // Translate the article in french.
  421. $this->drupalPost('node/add/article', $edit, t('Save'));
  422. $node = $this->drupalGetNodeByTitle($edit['title']);
  423. $this->drupalGet("node/$node->nid/translate");
  424. $this->clickLink(t('add translation'));
  425. $this->assertFieldByXPath("//textarea[@name='body[$langcode][0][value]']", $body, 'The textfield widget is populated.');
  426. }
  427. /**
  428. * Check that user that does not have access the field format cannot see the
  429. * source value when creating a translation.
  430. */
  431. function testTextFieldFormatted() {
  432. // Make node body multiple.
  433. $edit = array('field[cardinality]' => -1);
  434. $this->drupalPost('admin/structure/types/manage/article/fields/body', $edit, t('Save settings'));
  435. $this->drupalGet('node/add/article');
  436. $this->assertFieldByXPath("//input[@name='body_add_more']", t('Add another item'), 'Body field cardinality set to multiple.');
  437. $body = array(
  438. $this->randomName(),
  439. $this->randomName(),
  440. );
  441. // Create an article with the first body input format set to "Full HTML".
  442. $title = $this->randomName();
  443. $edit = array(
  444. 'title' => $title,
  445. 'language' => 'en',
  446. );
  447. $this->drupalPost('node/add/article', $edit, t('Save'));
  448. // Populate the body field: the first item gets the "Full HTML" input
  449. // format, the second one "Filtered HTML".
  450. $formats = array('full_html', 'filtered_html');
  451. $langcode = LANGUAGE_NONE;
  452. foreach ($body as $delta => $value) {
  453. $edit = array(
  454. "body[$langcode][$delta][value]" => $value,
  455. "body[$langcode][$delta][format]" => array_shift($formats),
  456. );
  457. $this->drupalPost('node/1/edit', $edit, t('Save'));
  458. $this->assertText($body[$delta], format_string('The body field with delta @delta has been saved.', array('@delta' => $delta)));
  459. }
  460. // Login as translator.
  461. $this->drupalLogin($this->translator);
  462. // Translate the article in french.
  463. $node = $this->drupalGetNodeByTitle($title);
  464. $this->drupalGet("node/$node->nid/translate");
  465. $this->clickLink(t('add translation'));
  466. $this->assertNoText($body[0], format_string('The body field with delta @delta is hidden.', array('@delta' => 0)));
  467. $this->assertText($body[1], format_string('The body field with delta @delta is shown.', array('@delta' => 1)));
  468. }
  469. }