MDL-69068 behat: New step to support singular generators
authorAndrew Nicols <andrew@nicols.co.uk>
Sun, 5 Jan 2020 11:51:18 +0000 (19:51 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Wed, 15 Jul 2020 07:27:31 +0000 (15:27 +0800)
lib/behat/classes/behat_core_generator.php
lib/behat/classes/behat_generator_base.php
lib/tests/behat/behat_data_generators.php
mod/quiz/accessrule/seb/tests/generator/behat_quizaccess_seb_generator.php
mod/quiz/tests/generator/behat_mod_quiz_generator.php
question/tests/generator/behat_core_question_generator.php

index 6e2dd2d..f36955c 100644 (file)
@@ -39,99 +39,119 @@ defined('MOODLE_INTERNAL') || die();
 class behat_core_generator extends behat_generator_base {
 
     protected function get_creatable_entities(): array {
 class behat_core_generator extends behat_generator_base {
 
     protected function get_creatable_entities(): array {
-        return [
+        $entities = [
             'users' => [
             'users' => [
+                'singular' => 'user',
                 'datagenerator' => 'user',
                 'required' => ['username'],
             ],
             'categories' => [
                 'datagenerator' => 'user',
                 'required' => ['username'],
             ],
             'categories' => [
+                'singular' => 'category',
                 'datagenerator' => 'category',
                 'required' => ['idnumber'],
                 'switchids' => ['category' => 'parent'],
             ],
             'courses' => [
                 'datagenerator' => 'category',
                 'required' => ['idnumber'],
                 'switchids' => ['category' => 'parent'],
             ],
             'courses' => [
+                'singular' => 'course',
                 'datagenerator' => 'course',
                 'required' => ['shortname'],
                 'switchids' => ['category' => 'category'],
             ],
             'groups' => [
                 'datagenerator' => 'course',
                 'required' => ['shortname'],
                 'switchids' => ['category' => 'category'],
             ],
             'groups' => [
+                'singular' => 'group',
                 'datagenerator' => 'group',
                 'required' => ['idnumber', 'course'],
                 'switchids' => ['course' => 'courseid'],
             ],
             'groupings' => [
                 'datagenerator' => 'group',
                 'required' => ['idnumber', 'course'],
                 'switchids' => ['course' => 'courseid'],
             ],
             'groupings' => [
+                'singular' => 'grouping',
                 'datagenerator' => 'grouping',
                 'required' => ['idnumber', 'course'],
                 'switchids' => ['course' => 'courseid'],
             ],
             'course enrolments' => [
                 'datagenerator' => 'grouping',
                 'required' => ['idnumber', 'course'],
                 'switchids' => ['course' => 'courseid'],
             ],
             'course enrolments' => [
+                'singular' => 'course enrolment',
                 'datagenerator' => 'enrol_user',
                 'required' => ['user', 'course', 'role'],
                 'switchids' => ['user' => 'userid', 'course' => 'courseid', 'role' => 'roleid'],
             ],
             'custom field categories' => [
                 'datagenerator' => 'enrol_user',
                 'required' => ['user', 'course', 'role'],
                 'switchids' => ['user' => 'userid', 'course' => 'courseid', 'role' => 'roleid'],
             ],
             'custom field categories' => [
+                'singular' => 'custom field category',
                 'datagenerator' => 'custom_field_category',
                 'required' => ['name', 'component', 'area', 'itemid'],
                 'switchids' => [],
             ],
             'custom fields' => [
                 'datagenerator' => 'custom_field_category',
                 'required' => ['name', 'component', 'area', 'itemid'],
                 'switchids' => [],
             ],
             'custom fields' => [
+                'singular' => 'custom field',
                 'datagenerator' => 'custom_field',
                 'required' => ['name', 'category', 'type', 'shortname'],
                 'switchids' => [],
             ],
             'permission overrides' => [
                 'datagenerator' => 'custom_field',
                 'required' => ['name', 'category', 'type', 'shortname'],
                 'switchids' => [],
             ],
             'permission overrides' => [
+                'singular' => 'permission override',
                 'datagenerator' => 'permission_override',
                 'required' => ['capability', 'permission', 'role', 'contextlevel', 'reference'],
                 'switchids' => ['role' => 'roleid'],
             ],
             'system role assigns' => [
                 'datagenerator' => 'permission_override',
                 'required' => ['capability', 'permission', 'role', 'contextlevel', 'reference'],
                 'switchids' => ['role' => 'roleid'],
             ],
             'system role assigns' => [
+                'singular' => 'system role assignment',
                 'datagenerator' => 'system_role_assign',
                 'required' => ['user', 'role'],
                 'switchids' => ['user' => 'userid', 'role' => 'roleid'],
             ],
             'role assigns' => [
                 'datagenerator' => 'system_role_assign',
                 'required' => ['user', 'role'],
                 'switchids' => ['user' => 'userid', 'role' => 'roleid'],
             ],
             'role assigns' => [
+                'singular' => 'role assignment',
                 'datagenerator' => 'role_assign',
                 'required' => ['user', 'role', 'contextlevel', 'reference'],
                 'switchids' => ['user' => 'userid', 'role' => 'roleid'],
             ],
             'activities' => [
                 'datagenerator' => 'role_assign',
                 'required' => ['user', 'role', 'contextlevel', 'reference'],
                 'switchids' => ['user' => 'userid', 'role' => 'roleid'],
             ],
             'activities' => [
+                'singular' => 'activity',
                 'datagenerator' => 'activity',
                 'required' => ['activity', 'idnumber', 'course'],
                 'switchids' => ['course' => 'course', 'gradecategory' => 'gradecat', 'grouping' => 'groupingid'],
             ],
             'blocks' => [
                 'datagenerator' => 'activity',
                 'required' => ['activity', 'idnumber', 'course'],
                 'switchids' => ['course' => 'course', 'gradecategory' => 'gradecat', 'grouping' => 'groupingid'],
             ],
             'blocks' => [
+                'singular' => 'block',
                 'datagenerator' => 'block_instance',
                 'required' => ['blockname', 'contextlevel', 'reference'],
             ],
             'group members' => [
                 'datagenerator' => 'block_instance',
                 'required' => ['blockname', 'contextlevel', 'reference'],
             ],
             'group members' => [
+                'singular' => 'group member',
                 'datagenerator' => 'group_member',
                 'required' => ['user', 'group'],
                 'switchids' => ['user' => 'userid', 'group' => 'groupid'],
             ],
             'grouping groups' => [
                 'datagenerator' => 'group_member',
                 'required' => ['user', 'group'],
                 'switchids' => ['user' => 'userid', 'group' => 'groupid'],
             ],
             'grouping groups' => [
+                'singular' => 'grouping group',
                 'datagenerator' => 'grouping_group',
                 'required' => ['grouping', 'group'],
                 'switchids' => ['grouping' => 'groupingid', 'group' => 'groupid'],
             ],
             'cohorts' => [
                 'datagenerator' => 'grouping_group',
                 'required' => ['grouping', 'group'],
                 'switchids' => ['grouping' => 'groupingid', 'group' => 'groupid'],
             ],
             'cohorts' => [
+                'singular' => 'cohort',
                 'datagenerator' => 'cohort',
                 'required' => ['idnumber'],
             ],
             'cohort members' => [
                 'datagenerator' => 'cohort',
                 'required' => ['idnumber'],
             ],
             'cohort members' => [
+                'singular' => 'cohort member',
                 'datagenerator' => 'cohort_member',
                 'required' => ['user', 'cohort'],
                 'switchids' => ['user' => 'userid', 'cohort' => 'cohortid'],
             ],
             'roles' => [
                 'datagenerator' => 'cohort_member',
                 'required' => ['user', 'cohort'],
                 'switchids' => ['user' => 'userid', 'cohort' => 'cohortid'],
             ],
             'roles' => [
+                'singular' => 'role',
                 'datagenerator' => 'role',
                 'required' => ['shortname'],
             ],
             'grade categories' => [
                 'datagenerator' => 'role',
                 'required' => ['shortname'],
             ],
             'grade categories' => [
+                'singular' => 'grade category',
                 'datagenerator' => 'grade_category',
                 'required' => ['fullname', 'course'],
                 'switchids' => ['course' => 'courseid', 'gradecategory' => 'parent'],
             ],
             'grade items' => [
                 'datagenerator' => 'grade_category',
                 'required' => ['fullname', 'course'],
                 'switchids' => ['course' => 'courseid', 'gradecategory' => 'parent'],
             ],
             'grade items' => [
+                'singular' => 'grade item',
                 'datagenerator' => 'grade_item',
                 'required' => ['course'],
                 'switchids' => [
                 'datagenerator' => 'grade_item',
                 'required' => ['course'],
                 'switchids' => [
@@ -142,30 +162,36 @@ class behat_core_generator extends behat_generator_base {
                 ],
             ],
             'grade outcomes' => [
                 ],
             ],
             'grade outcomes' => [
+                'singular' => 'grade outcome',
                 'datagenerator' => 'grade_outcome',
                 'required' => ['shortname', 'scale'],
                 'switchids' => ['course' => 'courseid', 'gradecategory' => 'categoryid', 'scale' => 'scaleid'],
             ],
             'scales' => [
                 'datagenerator' => 'grade_outcome',
                 'required' => ['shortname', 'scale'],
                 'switchids' => ['course' => 'courseid', 'gradecategory' => 'categoryid', 'scale' => 'scaleid'],
             ],
             'scales' => [
+                'singular' => 'scale',
                 'datagenerator' => 'scale',
                 'required' => ['name', 'scale'],
                 'switchids' => ['course' => 'courseid'],
             ],
             'question categories' => [
                 'datagenerator' => 'scale',
                 'required' => ['name', 'scale'],
                 'switchids' => ['course' => 'courseid'],
             ],
             'question categories' => [
+                'singular' => 'question category',
                 'datagenerator' => 'question_category',
                 'required' => ['name', 'contextlevel', 'reference'],
                 'switchids' => ['questioncategory' => 'parent'],
             ],
             'questions' => [
                 'datagenerator' => 'question_category',
                 'required' => ['name', 'contextlevel', 'reference'],
                 'switchids' => ['questioncategory' => 'parent'],
             ],
             'questions' => [
+                'singular' => 'question',
                 'datagenerator' => 'question',
                 'required' => ['qtype', 'questioncategory', 'name'],
                 'switchids' => ['questioncategory' => 'category', 'user' => 'createdby'],
             ],
             'tags' => [
                 'datagenerator' => 'question',
                 'required' => ['qtype', 'questioncategory', 'name'],
                 'switchids' => ['questioncategory' => 'category', 'user' => 'createdby'],
             ],
             'tags' => [
+                'singular' => 'tag',
                 'datagenerator' => 'tag',
                 'required' => ['name'],
             ],
             'events' => [
                 'datagenerator' => 'tag',
                 'required' => ['name'],
             ],
             'events' => [
+                'singular' => 'event',
                 'datagenerator' => 'event',
                 'required' => ['name', 'eventtype'],
                 'switchids' => [
                 'datagenerator' => 'event',
                 'required' => ['name', 'eventtype'],
                 'switchids' => [
@@ -175,68 +201,83 @@ class behat_core_generator extends behat_generator_base {
                 ],
             ],
             'message contacts' => [
                 ],
             ],
             'message contacts' => [
+                'singular' => 'message contact',
                 'datagenerator' => 'message_contacts',
                 'required' => ['user', 'contact'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'private messages' => [
                 'datagenerator' => 'message_contacts',
                 'required' => ['user', 'contact'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'private messages' => [
+                'singular' => 'private message',
                 'datagenerator' => 'private_messages',
                 'required' => ['user', 'contact', 'message'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'favourite conversations' => [
                 'datagenerator' => 'private_messages',
                 'required' => ['user', 'contact', 'message'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'favourite conversations' => [
+                'singular' => 'favourite conversation',
                 'datagenerator' => 'favourite_conversations',
                 'required' => ['user', 'contact'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'group messages' => [
                 'datagenerator' => 'favourite_conversations',
                 'required' => ['user', 'contact'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'group messages' => [
+                'singular' => 'group message',
                 'datagenerator' => 'group_messages',
                 'required' => ['user', 'group', 'message'],
                 'switchids' => ['user' => 'userid', 'group' => 'groupid'],
             ],
             'muted group conversations' => [
                 'datagenerator' => 'group_messages',
                 'required' => ['user', 'group', 'message'],
                 'switchids' => ['user' => 'userid', 'group' => 'groupid'],
             ],
             'muted group conversations' => [
+                'singular' => 'muted group conversation',
                 'datagenerator' => 'mute_group_conversations',
                 'required' => ['user', 'group', 'course'],
                 'switchids' => ['user' => 'userid', 'group' => 'groupid', 'course' => 'courseid'],
             ],
             'muted private conversations' => [
                 'datagenerator' => 'mute_group_conversations',
                 'required' => ['user', 'group', 'course'],
                 'switchids' => ['user' => 'userid', 'group' => 'groupid', 'course' => 'courseid'],
             ],
             'muted private conversations' => [
+                'singular' => 'muted private conversation',
                 'datagenerator' => 'mute_private_conversations',
                 'required' => ['user', 'contact'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'language customisations' => [
                 'datagenerator' => 'mute_private_conversations',
                 'required' => ['user', 'contact'],
                 'switchids' => ['user' => 'userid', 'contact' => 'contactid'],
             ],
             'language customisations' => [
+                'singular' => 'language customisation',
                 'datagenerator' => 'customlang',
                 'required' => ['component', 'stringid', 'value'],
             ],
                 'datagenerator' => 'customlang',
                 'required' => ['component', 'stringid', 'value'],
             ],
-            'analytics model' => [
+            'analytics models' => [
+                'singular' => 'analytics model',
                 'datagenerator' => 'analytics_model',
                 'required' => ['target', 'indicators', 'timesplitting', 'enabled'],
             ],
             'user preferences' => [
                 'datagenerator' => 'analytics_model',
                 'required' => ['target', 'indicators', 'timesplitting', 'enabled'],
             ],
             'user preferences' => [
+                'singular' => 'user preference',
                 'datagenerator' => 'user_preferences',
                 'required' => array('user', 'preference', 'value'),
                 'datagenerator' => 'user_preferences',
                 'required' => array('user', 'preference', 'value'),
-                'switchids' => array('user' => 'userid')
+                'switchids' => array('user' => 'userid'),
             ],
             ],
-            'contentbank content' => [
+            'contentbank contents' => [
+                'singular' => 'contentbank content',
                 'datagenerator' => 'contentbank_content',
                 'required' => array('contextlevel', 'reference', 'contenttype', 'user', 'contentname'),
                 'switchids' => array('user' => 'userid')
             ],
                 'datagenerator' => 'contentbank_content',
                 'required' => array('contextlevel', 'reference', 'contenttype', 'user', 'contentname'),
                 'switchids' => array('user' => 'userid')
             ],
-            'badge external backpack' => [
+            'badge external backpacks' => [
+                'singular' => 'badge external backpack',
                 'datagenerator' => 'badge_external_backpack',
                 'required' => ['backpackapiurl', 'backpackweburl', 'apiversion']
             ],
                 'datagenerator' => 'badge_external_backpack',
                 'required' => ['backpackapiurl', 'backpackweburl', 'apiversion']
             ],
-            'setup backpack connected' => [
+            'setup backpacks connected' => [
+                'singular' => 'setup backpack connected',
                 'datagenerator' => 'setup_backpack_connected',
                 'required' => ['user', 'externalbackpack'],
                 'switchids' => ['user' => 'userid', 'externalbackpack' => 'externalbackpackid']
             ],
             'last access times' => [
                 'datagenerator' => 'setup_backpack_connected',
                 'required' => ['user', 'externalbackpack'],
                 'switchids' => ['user' => 'userid', 'externalbackpack' => 'externalbackpackid']
             ],
             'last access times' => [
+                'singular' => 'last access time',
                 'datagenerator' => 'last_access_times',
                 'required' => ['user', 'course', 'lastaccess'],
                 'switchids' => ['user' => 'userid', 'course' => 'courseid'],
             ],
         ];
                 'datagenerator' => 'last_access_times',
                 'required' => ['user', 'course', 'lastaccess'],
                 'switchids' => ['user' => 'userid', 'course' => 'courseid'],
             ],
         ];
+
+        return $entities;
     }
 
     /**
     }
 
     /**
index 107c165..44ea79d 100644 (file)
@@ -171,13 +171,23 @@ abstract class behat_generator_base {
      *
      * @param string    $generatortype The name of the entity to create.
      * @param TableNode $data from the step.
      *
      * @param string    $generatortype The name of the entity to create.
      * @param TableNode $data from the step.
+     * @param bool      $singular Whether there is only one record and it is pivotted
      */
      */
-    public function generate_items(string $generatortype, TableNode $data) {
+    public function generate_items(string $generatortype, TableNode $data, bool $singular = false) {
         // Now that we need them require the data generators.
         require_once(__DIR__ . '/../../testing/generator/lib.php');
 
         $elements = $this->get_creatable_entities();
 
         // Now that we need them require the data generators.
         require_once(__DIR__ . '/../../testing/generator/lib.php');
 
         $elements = $this->get_creatable_entities();
 
+        foreach ($elements as $key => $configuration) {
+            if (array_key_exists('singular', $configuration)) {
+                $singularverb = $configuration['singular'];
+                unset($configuration['singular']);
+                unset($elements[$key]['singular']);
+                $elements[$singularverb] = $configuration;
+            }
+        }
+
         if (!isset($elements[$generatortype])) {
             throw new PendingException($this->name_for_errors($generatortype) .
                     ' is not a known type of entity that can be generated.');
         if (!isset($elements[$generatortype])) {
             throw new PendingException($this->name_for_errors($generatortype) .
                     ' is not a known type of entity that can be generated.');
@@ -193,8 +203,17 @@ abstract class behat_generator_base {
 
         $generatortype = $entityinfo['datagenerator'];
 
 
         $generatortype = $entityinfo['datagenerator'];
 
-        foreach ($data->getHash() as $elementdata) {
+        if ($singular) {
+            // There is only one record to generate, and the table has been pivotted.
+            // The rows each represent a single field.
+            $rows = [$data->getRowsHash()];
+        } else {
+            // There are multiple records to generate.
+            // The rows represent an item to create.
+            $rows = $data->getHash();
+        }
 
 
+        foreach ($rows as $elementdata) {
             // Check if all the required fields are there.
             foreach ($entityinfo['required'] as $requiredfield) {
                 if (!isset($elementdata[$requiredfield])) {
             // Check if all the required fields are there.
             foreach ($entityinfo['required'] as $requiredfield) {
                 if (!isset($elementdata[$requiredfield])) {
index 2b805ed..eb39c03 100644 (file)
@@ -75,7 +75,7 @@ class behat_data_generators extends behat_base {
     ];
 
     /**
     ];
 
     /**
-     * Creates the specified element.
+     * Creates the specified elements.
      *
      * See the class comment for an overview.
      *
      *
      * See the class comment for an overview.
      *
@@ -92,6 +92,24 @@ class behat_data_generators extends behat_base {
         $this->get_instance_for_component($component)->generate_items($entity, $data);
     }
 
         $this->get_instance_for_component($component)->generate_items($entity, $data);
     }
 
+    /**
+     * Creates the specified element.
+     *
+     * See the class comment for an overview.
+     *
+     * @Given the following :entitytype exists:
+     *
+     * @param string    $entitytype The name of the type entity to add
+     * @param TableNode $data
+     */
+    public function the_following_entity_exists($entitytype, TableNode $data) {
+        if (isset($this->movedentitytypes[$entitytype])) {
+            $entitytype = $this->movedentitytypes[$entitytype];
+        }
+        list($component, $entity) = $this->parse_entity_type($entitytype);
+        $this->get_instance_for_component($component)->generate_items($entity, $data, true);
+    }
+
     /**
      * Parse a full entity type like 'users' or 'mod_forum > subscription'.
      *
     /**
      * Parse a full entity type like 'users' or 'mod_forum > subscription'.
      *
index 08e19a3..40077b4 100644 (file)
@@ -41,6 +41,7 @@ class behat_quizaccess_seb_generator extends behat_generator_base {
     protected function get_creatable_entities(): array {
         return [
             'seb templates' => [
     protected function get_creatable_entities(): array {
         return [
             'seb templates' => [
+                'singular' => 'seb template',
                 'datagenerator' => 'template',
                 'required' => ['name'],
             ],
                 'datagenerator' => 'template',
                 'required' => ['name'],
             ],
index 55a8145..fc9342d 100644 (file)
@@ -37,11 +37,13 @@ class behat_mod_quiz_generator extends behat_generator_base {
     protected function get_creatable_entities(): array {
         return [
             'group overrides' => [
     protected function get_creatable_entities(): array {
         return [
             'group overrides' => [
+                'singular' => 'group override',
                 'datagenerator' => 'override',
                 'required' => ['quiz', 'group'],
                 'switchids' => ['quiz' => 'quiz', 'group' => 'groupid'],
             ],
             'user overrides' => [
                 'datagenerator' => 'override',
                 'required' => ['quiz', 'group'],
                 'switchids' => ['quiz' => 'quiz', 'group' => 'groupid'],
             ],
             'user overrides' => [
+                'singular' => 'user override',
                 'datagenerator' => 'override',
                 'required' => ['quiz', 'user'],
                 'switchids' => ['quiz' => 'quiz', 'user' => 'userid'],
                 'datagenerator' => 'override',
                 'required' => ['quiz', 'user'],
                 'switchids' => ['quiz' => 'quiz', 'user' => 'userid'],
index 0dbd430..3a0eced 100644 (file)
@@ -36,6 +36,7 @@ class behat_core_question_generator extends behat_generator_base {
         // are generated by behat_core_generator.
         return [
             'Tags' => [
         // are generated by behat_core_generator.
         return [
             'Tags' => [
+                'singular' => 'Tag',
                 'datagenerator' => 'question_tag',
                 'required' => ['question', 'tag'],
                 'switchids' => ['question' => 'questionid'],
                 'datagenerator' => 'question_tag',
                 'required' => ['question', 'tag'],
                 'switchids' => ['question' => 'questionid'],