field_permission_example.test 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. <?php
  2. /**
  3. * @file
  4. * Tests for Field Permission Example.
  5. *
  6. * @ingroup field_permission_example
  7. */
  8. /**
  9. * A generic field testing class.
  10. *
  11. * Subclass this one to test your specific field type
  12. * and get some basic unit testing for free.
  13. *
  14. * Since Simpletest only looks through one class definition
  15. * to find test functions, we define generic tests as
  16. * 'code_testWhatever' or 'form_testWhatever'. Subclasses
  17. * can then implement shim test methods that just call the
  18. * generic tests.
  19. *
  20. * 'code_' and 'form_' prefixes denote the type of test:
  21. * using code only, or through Drupal page forms.
  22. *
  23. * @ingroup field_permission_example
  24. */
  25. class GenericFieldTest extends DrupalWebTestCase {
  26. // Our tests will generate some random field instance
  27. // names. We store them here so many functions can act on them.
  28. protected $instanceNames;
  29. /**
  30. * {@inheritdoc}
  31. */
  32. public static function getInfo() {
  33. return array(
  34. 'name' => 'Generic Field Test',
  35. 'description' => 'Someone neglected to override GenericFieldTest::getInfo().',
  36. 'group' => 'Examples',
  37. );
  38. }
  39. /**
  40. * Supply the field types we wish to test.
  41. *
  42. * Return an array of field types to instantiate and test.
  43. *
  44. * @return array
  45. * The field types we wish to use.
  46. */
  47. protected function getFieldTypes() {
  48. return array('these_are_not', 'valid_field_types', 'please_override');
  49. }
  50. /**
  51. * The module to enable.
  52. *
  53. * @return string
  54. * Module machine name.
  55. */
  56. protected function getModule() {
  57. return 'this-is-not-a-module-name-please-override';
  58. }
  59. /**
  60. * Simpletest's setUp().
  61. *
  62. * We want to be able to subclass this class, so we jump
  63. * through a few hoops in order to get the modules from args
  64. * and add our own.
  65. */
  66. public function setUp() {
  67. $this->instanceNames = array();
  68. $modules = func_get_args();
  69. if (isset($modules[0]) && is_array($modules[0])) {
  70. $modules = $modules[0];
  71. }
  72. $modules[] = 'node';
  73. $modules[] = 'field_ui';
  74. parent::setUp($modules);
  75. }
  76. /**
  77. * Verify that all required fields are specified in hook_field_info().
  78. *
  79. * The full list is label, description, settings, instance_settings,
  80. * default_widget, default_formatter, no_ui.
  81. *
  82. * Some are optional, and we won't check for those.
  83. *
  84. * In a sane world, this would be a unit test, rather than a
  85. * web test, but module_implements is unavailable to us
  86. * in unit tests.
  87. *
  88. * @see hook_field_info()
  89. */
  90. public function runTestGenericFieldInfo() {
  91. $field_types = $this->getFieldTypes();
  92. $module = $this->getModule();
  93. $info_keys = array(
  94. 'label',
  95. 'description',
  96. 'default_widget',
  97. 'default_formatter',
  98. );
  99. // We don't want to use field_info_field_types()
  100. // because there is a hook_field_info_alter().
  101. // We're testing the module here, not the rest of
  102. // the system. So invoke hook_field_info() ourselves.
  103. $modules = module_implements('field_info');
  104. $this->assertTrue(in_array($module, $modules),
  105. 'Module ' . $module . ' implements hook_field_info()');
  106. foreach ($field_types as $field_type) {
  107. $field_info = module_invoke($module, 'field_info');
  108. $this->assertTrue(isset($field_info[$field_type]),
  109. 'Module ' . $module . ' defines field type ' . $field_type);
  110. $field_info = $field_info[$field_type];
  111. foreach ($info_keys as $key) {
  112. $this->assertTrue(
  113. isset($field_info[$key]),
  114. $field_type . "'s " . $key . ' is set.'
  115. );
  116. }
  117. }
  118. }
  119. /**
  120. * Add all testable fields as instances to a content type.
  121. *
  122. * As a side-effect: Store the names of the instances created
  123. * in $this->$instance_names.
  124. *
  125. * @param object $node_type
  126. * A content type object. If none is provided, one will be generated.
  127. *
  128. * @return object
  129. * The content type object that has the fields attached.
  130. */
  131. public function codeTestGenericAddAllFields($node_type = NULL) {
  132. $this->instanceNames = array();
  133. if (!$node_type) {
  134. $node_type = $this->drupalCreateContentType();
  135. }
  136. foreach ($this->getFieldTypes() as $field_type) {
  137. $instance_name = drupal_strtolower($this->randomName(32));
  138. $field = array(
  139. 'field_name' => $instance_name,
  140. 'type' => $field_type,
  141. );
  142. $field = field_create_field($field);
  143. $instance = array(
  144. 'field_name' => $instance_name,
  145. 'entity_type' => 'node',
  146. 'bundle' => $node_type->name,
  147. 'label' => drupal_strtolower($this->randomName(20)),
  148. );
  149. // Finally create the instance.
  150. $instance = field_create_instance($instance);
  151. // Reset the caches...
  152. _field_info_collate_fields(TRUE);
  153. // Grab this instance.
  154. $verify_instance = field_info_instance('node', $instance_name, $node_type->name);
  155. $this->assertTrue($verify_instance, 'Instance object exists.');
  156. $this->assertTrue(
  157. $verify_instance != NULL,
  158. 'field_info_instance() says ' . $instance_name . ' (' . $node_type->name . ') was created.'
  159. );
  160. $this->instanceNames[] = $instance_name;
  161. }
  162. return $node_type;
  163. }
  164. /**
  165. * Remove all fields in $this->field_names.
  166. *
  167. * @param mixed $node_type
  168. * A content type object. If none is specified,
  169. * the test fails.
  170. */
  171. public function codeTestGenericRemoveAllFields($node_type = NULL) {
  172. if (!$node_type) {
  173. $this->fail('No node type.');
  174. }
  175. if (count($this->instanceNames) < 1) {
  176. $this->fail('There are no instances to remove.');
  177. return;
  178. }
  179. foreach ($this->instanceNames as $instance_name) {
  180. $instance = field_info_instance('node', $instance_name, $node_type->name);
  181. $this->assertTrue($instance, "Instance exists, now we'll delete it.");
  182. field_delete_field($instance_name);
  183. $instance = field_info_instance('node', $instance_name, $node_type->name);
  184. $this->assertFalse($instance, 'Instance was deleted.');
  185. }
  186. $this->instanceNames = array();
  187. }
  188. /**
  189. * Add and delete all field types through Form API.
  190. *
  191. * @access public
  192. */
  193. public function formTestGenericFieldNodeAddDeleteForm() {
  194. // Create and login user.
  195. $account = $this->drupalCreateUser(array(
  196. 'administer content types',
  197. 'administer fields',
  198. ));
  199. $this->drupalLogin($account);
  200. // Add a content type.
  201. $node_type = $this->drupalCreateContentType();
  202. // Add all our testable fields.
  203. $field_names = $this->formAddAllFields($node_type);
  204. // Now let's delete all the fields.
  205. foreach ($field_names as $field_name) {
  206. // This is the path for the 'delete' link on field admin page.
  207. $this->drupalGet('admin/structure/types/manage/' .
  208. $node_type->name . '/fields/field_' . $field_name . '/delete');
  209. // Click the 'delete' button.
  210. $this->drupalPost(NULL, array(), t('Delete'));
  211. $this->assertText(t('The field @field has been deleted from the @type content type.',
  212. array('@field' => $field_name, '@type' => $node_type->name)));
  213. }
  214. }
  215. /**
  216. * Add all fields using Form API.
  217. *
  218. * @param mixed $node_type
  219. * A content type object. If none is specified,
  220. * the test fails.
  221. */
  222. protected function formAddAllFields($node_type = NULL) {
  223. if (!$node_type) {
  224. $this->fail('No content type specified.');
  225. }
  226. // Get all our field types.
  227. $field_types = $this->getFieldTypes();
  228. // Keep a list of no_ui fields so we can tell the user.
  229. $unsafe_field_types = array();
  230. $field_names = array();
  231. $manage_path = 'admin/structure/types/manage/' . $node_type->name . '/fields';
  232. foreach ($field_types as $field_type) {
  233. // Get the field info.
  234. $field_info = field_info_field_types($field_type);
  235. // Exclude no_ui field types.
  236. if (isset($field_info['no_ui']) && $field_info['no_ui']) {
  237. $unsafe_field_types[] = $field_type;
  238. }
  239. else {
  240. // Generate a name for our field.
  241. // 26 is max length for field name.
  242. $field_name = drupal_strtolower($this->randomName(26));
  243. $field_names[$field_type] = $field_name;
  244. // Create the field through Form API.
  245. $this->formCreateField($manage_path, $field_type, $field_name,
  246. $field_info['default_widget'], 1);
  247. }
  248. }
  249. // Tell the user which fields we couldn't test.
  250. if (!empty($unsafe_field_types)) {
  251. debug(
  252. 'Unable to attach these no_ui fields: ' .
  253. implode(', ', $unsafe_field_types)
  254. );
  255. }
  256. // Somehow clicking "save" isn't enough, and we have to
  257. // rebuild a few caches.
  258. node_types_rebuild();
  259. menu_rebuild();
  260. return $field_names;
  261. }
  262. /**
  263. * Create a field using the content type management form.
  264. *
  265. * @param mixed $manage_path
  266. * Path to our content type management form.
  267. * @param mixed $field_type
  268. * The type of field we're adding.
  269. * @param mixed $field_name
  270. * The name of the field instance we want.
  271. * @param mixed $widget_type
  272. * Which widget would we like?
  273. * @param mixed $cardinality
  274. * Cardinality for this field instance.
  275. */
  276. protected function formCreateField($manage_path, $field_type, $field_name, $widget_type, $cardinality) {
  277. // $manage_path is the field edit form for our content type.
  278. $this->drupalGet($manage_path);
  279. $edit = array(
  280. 'fields[_add_new_field][label]' => $field_name,
  281. 'fields[_add_new_field][field_name]' => $field_name,
  282. 'fields[_add_new_field][type]' => $field_type,
  283. 'fields[_add_new_field][widget_type]' => $widget_type,
  284. );
  285. $this->drupalPost(NULL, $edit, t('Save'));
  286. // Assume there are no settings for this,
  287. // so just press the button.
  288. $this->drupalPost(NULL, array(), t('Save field settings'));
  289. $edit = array('field[cardinality]' => (string) $cardinality);
  290. $this->drupalPost(NULL, $edit, t('Save settings'));
  291. debug(
  292. t('Saved settings for field !field_name with widget !widget_type and cardinality !cardinality',
  293. array(
  294. '!field_name' => $field_name,
  295. '!widget_type' => $widget_type,
  296. '!cardinality' => $cardinality,
  297. )
  298. )
  299. );
  300. $this->assertText(t('Saved @name configuration.', array('@name' => $field_name)));
  301. }
  302. /**
  303. * Create a node with some field content.
  304. *
  305. * @return object
  306. * Node object for the created node.
  307. */
  308. public function createFieldContentForUser(
  309. $account = NULL,
  310. $content = 'testable_content',
  311. $node_type = NULL,
  312. $instance_name = '',
  313. $column = NULL
  314. ) {
  315. if (!$column) {
  316. $this->fail('No column name given.');
  317. return NULL;
  318. }
  319. if (!$account) {
  320. $account = $this->drupalCreateUser(array(
  321. 'bypass node access',
  322. 'administer content types',
  323. ));
  324. }
  325. $this->drupalLogin($account);
  326. if (!$node_type) {
  327. $node_type = $this->codeTestGenericAddAllFields();
  328. }
  329. if (!$instance_name) {
  330. $instance_name = reset($this->instanceNames);
  331. }
  332. $field = array();
  333. $field[LANGUAGE_NONE][0][$column] = $content;
  334. $settings = array(
  335. 'type' => $node_type->name,
  336. $instance_name => $field,
  337. );
  338. $node = $this->drupalCreateNode($settings);
  339. $this->assertTrue($node, 'Node of type ' . $node->type . ' allegedly created.');
  340. $node = node_load($node->nid);
  341. debug('Loaded node id: ' . $node->nid);
  342. $this->assertTrue($node->$instance_name, 'Field actually created.');
  343. $field = $node->$instance_name;
  344. $this->assertTrue($field[LANGUAGE_NONE][0][$column] == $content,
  345. 'Content was stored properly on the field.');
  346. return $node;
  347. }
  348. }
  349. class FieldTestPermissionsExample extends GenericFieldTest {
  350. /**
  351. * {@inheritdoc}
  352. */
  353. public function setUp() {
  354. parent::setUp(array('field_permission_example'));
  355. }
  356. /**
  357. * {@inheritdoc}
  358. */
  359. public static function getInfo() {
  360. return array(
  361. 'name' => 'Field Permission Example',
  362. 'description' => 'Various tests on the functionality of the Fieldnote field.',
  363. 'group' => 'Examples',
  364. );
  365. }
  366. /**
  367. * {@inheritdoc}
  368. */
  369. protected function getFieldTypes() {
  370. return array('field_permission_example_fieldnote');
  371. }
  372. /**
  373. * {@inheritdoc}
  374. */
  375. protected function getModule() {
  376. return 'field_permission_example';
  377. }
  378. /**
  379. * Override createFieldContentForUser().
  380. *
  381. * We override so we can make sure $column is set to 'notes'.
  382. */
  383. public function createFieldContentForUser(
  384. $account = NULL,
  385. $content = 'fieldnote_testable_content',
  386. $node_type = NULL,
  387. $instance_name = '',
  388. $column = 'notes'
  389. ) {
  390. return parent::createFieldContentForUser($account, $content, $node_type, $instance_name, $column);
  391. }
  392. /**
  393. * Test of hook_field_info() and other implementation requirements.
  394. *
  395. * @see GenericFieldTest::runTestGenericFieldInfo()
  396. */
  397. public function testFieldnoteInfo() {
  398. $this->runTestGenericFieldInfo();
  399. }
  400. /**
  401. * Add and remove the field through Form API.
  402. */
  403. public function testAddRemoveFieldnoteForm() {
  404. $this->formTestGenericFieldNodeAddDeleteForm();
  405. }
  406. /**
  407. * Add and remove the field through code.
  408. */
  409. public function testAddRemoveFieldnoteCode() {
  410. $node_type = $this->codeTestGenericAddAllFields();
  411. $this->codeTestGenericRemoveAllFields($node_type);
  412. }
  413. /**
  414. * Test view permissions.
  415. */
  416. public function testFieldnoteViewPerms() {
  417. // We create two sets of content so we can get a few
  418. // test cases out of the way.
  419. $view_own_content = $this->randomName(23);
  420. $view_any_content = $this->randomName(23);
  421. $view_own_node = $this->createFieldContentForUser(NULL, $view_own_content);
  422. // Get the type of the node so we can create another one.
  423. $node_type = node_type_load($view_own_node->type);
  424. $view_any_node = $this->createFieldContentForUser(NULL, $view_any_content, $node_type);
  425. // There should be a node now, with some lovely content, but it's the wrong
  426. // user for the view-own test.
  427. $view_own_account = $this->drupalCreateUser(array(
  428. 'view own fieldnote',
  429. ));
  430. debug("Created user with 'view own fieldnote' permission.");
  431. // Now change the user id for the test node.
  432. $view_own_node = node_load($view_own_node->nid);
  433. $view_own_node->uid = $view_own_account->uid;
  434. node_save($view_own_node);
  435. $view_own_node = node_load($view_own_node->nid);
  436. $this->assertTrue($view_own_node->uid == $view_own_account->uid, 'New user assigned to node.');
  437. // Now we want to look at the page with the field and
  438. // check that we can see it.
  439. $this->drupalLogin($view_own_account);
  440. $this->drupalGet('node/' . $view_own_node->nid);
  441. // Check that the field content is present.
  442. $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()");
  443. $this->assertEqual((string) reset($output_strings), $view_own_content);
  444. debug("'view own fieldnote' can view own field.");
  445. // This account shouldn't be able to see the field on the
  446. // 'view any' node.
  447. $this->drupalGet('node/' . $view_any_node->nid);
  448. // Check that the field content is not present.
  449. $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()");
  450. $this->assertNotEqual((string) reset($output_strings), $view_any_content);
  451. debug("'view own fieldnote' cannot view other field.");
  452. // Now, to test for 'view any fieldnote' we create another user
  453. // with that permission, and try to look at the same node.
  454. $view_any_account = $this->drupalCreateUser(array(
  455. 'view any fieldnote',
  456. ));
  457. debug("Created user with 'view any fieldnote' permission.");
  458. $this->drupalLogin($view_any_account);
  459. // This account should be able to see the field on the
  460. // 'view any' node.
  461. $this->drupalGet('node/' . $view_any_node->nid);
  462. // Check that the field content is present.
  463. $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()");
  464. $this->assertEqual((string) reset($output_strings), $view_any_content);
  465. debug("'view any fieldnote' can view other field.");
  466. }
  467. /**
  468. * Test edit permissions.
  469. *
  470. * Note that this is mostly identical to testFieldnoteViewPerms() and could
  471. * probably be refactored.
  472. */
  473. public function testFieldnoteEditPerms() {
  474. // We create two sets of content so we can get a few
  475. // test cases out of the way.
  476. $edit_own_content = $this->randomName(23);
  477. $edit_any_content = $this->randomName(23);
  478. $edit_own_node = $this->createFieldContentForUser(NULL, $edit_own_content);
  479. // Get the type of the node so we can create another one.
  480. $node_type = node_type_load($edit_own_node->type);
  481. $edit_any_node = $this->createFieldContentForUser(NULL, $edit_any_content, $node_type);
  482. $edit_own_account = $this->drupalCreateUser(array(
  483. 'edit own ' . $node_type->name . ' content',
  484. 'edit own fieldnote',
  485. ));
  486. debug("Created user with 'edit own fieldnote' permission.");
  487. // Now change the user id for the test node.
  488. $edit_own_node = node_load($edit_own_node->nid);
  489. $edit_own_node->uid = $edit_own_account->uid;
  490. node_save($edit_own_node);
  491. $edit_own_node = node_load($edit_own_node->nid);
  492. $this->assertTrue($edit_own_node->uid == $edit_own_account->uid, 'New edit test user assigned to node.');
  493. // Now we want to look at the page with the field and
  494. // check that we can see it.
  495. $this->drupalLogin($edit_own_account);
  496. $this->drupalGet('node/' . $edit_own_node->nid . '/edit');
  497. $this->assertText($edit_own_content, "'edit own fieldnote' can edit own fieldnote.");
  498. // This account shouldn't be able to edit the field on the
  499. // 'edit any' node.
  500. $this->drupalGet('node/' . $edit_any_node->nid . '/edit');
  501. $this->assertNoText($edit_any_content, "'edit own fieldnote' can not edit any fieldnote.");
  502. // Now, to test for 'edit any fieldnote' we create another user
  503. // with that permission, and try to edit at the same node.
  504. // We have to add the ability to edit any node content, as well
  505. // or Drupal will deny us access to the page.
  506. $edit_any_account = $this->drupalCreateUser(array(
  507. 'edit any ' . $node_type->name . ' content',
  508. 'edit any fieldnote',
  509. ));
  510. debug("Created user with 'edit any fieldnote' permission.");
  511. $this->drupalLogin($edit_any_account);
  512. // This account should be able to see the field on the
  513. // 'edit any' node.
  514. $this->drupalGet('node/' . $edit_any_node->nid . '/edit');
  515. $this->assertText($edit_any_content, "'edit any fieldnote' can edit any fieldnote.");
  516. }
  517. }