{"action":"created","comment":{"url":"https://api.github.com/repos/open-craft/problem-builder/pulls/comments/36503497","id":36503497,"diff_hunk":"@@ -0,0 +1,226 @@\n+\"\"\"\n+Unit tests for Instructor Tool block\n+\"\"\"\n+import random\n+import unittest\n+from mock import Mock\n+from xblock.field_data import DictFieldData\n+from problem_builder import instructor_tool, InstructorToolBlock\n+\n+\n+class TestInstructorToolBlock(unittest.TestCase):\n+    \"\"\"\n+    Test InstructorToolBlock with some mocked data.\n+    \"\"\"\n+\n+    def _get_block(self, block_info):\n+        # Build spec\n+        spec = ['scope_ids', 'runtime', 'has_children', 'children']\n+        for attr in block_info.get('attrs', []):\n+            spec.append(attr)\n+        # Assemble block\n+        block = Mock(spec=spec)\n+        scope_ids_mock = Mock()\n+        scope_ids_mock.usage_id = block_info.get('usage_id')\n+        block.scope_ids = scope_ids_mock\n+        block.runtime = self.runtime_mock\n+        block.children = []\n+        for attr, val in block_info.get('attrs', {}).items():\n+            setattr(block, attr, val)\n+        return block\n+\n+    def setUp(self):\n+        self.runtime_mock = Mock()\n+        self.runtime_mock.get_block = self._get_block\n+        scope_ids_mock = Mock()\n+        scope_ids_mock.usage_id = u'0'\n+        self.block = InstructorToolBlock(\n+            self.runtime_mock, field_data=DictFieldData({}), scope_ids=scope_ids_mock\n+        )\n+        self.block.children = [\n+            # No attributes: Prefer usage_id\n+            {'usage_id': u'1'},\n+            # Single attribute: Prefer attribute that's present\n+            {'usage_id': u'2', 'preferred_attr': 'question', 'attrs': {'question': 'question'}},\n+            {'usage_id': u'3', 'preferred_attr': 'name', 'attrs': {'name': 'name'}},\n+            {'usage_id': u'4', 'preferred_attr': 'display_name', 'attrs': {'display_name': 'display_name'}},\n+            # Two attributes (question, name): Prefer question\n+            {\n+                'usage_id': u'5',\n+                'preferred_attr':\n+                'question', 'attrs': {'question': 'question', 'name': 'name'}\n+            },\n+            # Two attributes (question, display_name): Prefer question\n+            {\n+                'usage_id': u'6',\n+                'preferred_attr': 'question',\n+                'attrs': {'question': 'question', 'display_name': 'display_name'}\n+            },\n+            # Two attributes (name, display_name): Prefer name\n+            {\n+                'usage_id': u'7',\n+                'preferred_attr': 'name',\n+                'attrs': {'name': 'name', 'display_name': 'display_name'}\n+            },\n+            # All attributes: Prefer question\n+            {\n+                'usage_id': u'8',\n+                'preferred_attr': 'question',\n+                'attrs': {'question': 'question', 'name': 'name', 'display_name': 'display_name'}\n+            },\n+        ]\n+\n+    def test_student_view_block_tree_names(self):\n+        \"\"\"\n+        Check if `student_view` method uses preferred block attributes\n+        when building block tree for render context.\n+\n+        Each entry of a block tree is a dictionary that must contain\n+        an `id` key and a `name` key.\n+\n+        - `id` must be set to the ID\n+          (usage_id or block_id) of the corresponding block.\n+\n+        - `name` must be set to the value of one of the following\n+          attributes of the corresponding block:\n+\n+          - question\n+          - name (question ID)\n+          - display_name (question title)\n+          - block ID\n+\n+          Note that the attributes are listed in order of preference;\n+          i.e., if `block.question` has a meaningful value, that value\n+          should be used for `name` (irrespective of what the values\n+          of the other attributes might be).\n+        \"\"\"\n+        instructor_tool.loader = Mock()\n+        instructor_tool.loader.render_template.return_value = u''\n+\n+        self.block.student_view(context={})\n+        block_tree = instructor_tool.loader.render_template.call_args[0][1]['block_tree']\n+\n+        # Check size of block_tree\n+        num_blocks = len(self.block.children) + 1\n+        self.assertEqual(len(block_tree), num_blocks)\n+\n+        # Check block_tree for root entry\n+        # - Does block_tree contain single entry whose `id` matches usage_id of instructor block?\n+        matching_blocks = [block for block in block_tree if block['id'] == self.block.scope_ids.usage_id]\n+        self.assertEqual(len(matching_blocks), 1)\n+        # # - Is `name` of that entry set to \"All\"?\n+        matching_block = matching_blocks.pop()\n+        self.assertEqual(matching_block['name'], 'All')\n+\n+        # Check block_tree for children\n+        for child in self.block.children:\n+            usage_id = child.get('usage_id')\n+            attrs = child.get('attrs', {})\n+            # - Does block_tree contain single entry whose `id` matches usage_id of current child?\n+            matching_blocks = [block for block in block_tree if block['id'] == usage_id]\n+            self.assertEqual(len(matching_blocks), 1)\n+            # - Is `name` of that entry set to value of current child's preferred_attr?\n+            matching_block = matching_blocks.pop()\n+            if not attrs:\n+                self.assertEqual(matching_block['name'], usage_id)\n+            else:\n+                preferred_attr = child.get('preferred_attr')\n+                self.assertEqual(matching_block['name'], attrs[preferred_attr])\n+\n+    def test_student_view_block_tree_choice_blocks_excluded(self):\n+        \"\"\"\n+        Check if `student_view` method excludes 'pb-choice' blocks when\n+        building block tree for render context.\n+        \"\"\"\n+        # Pretend that all blocks in self.block.children are of type 'pb-choice:\n+        self.block.runtime.id_reader = Mock()\n+        self.block.runtime.id_reader.get_block_type.return_value = 'pb-choice'\n+\n+        instructor_tool.loader = Mock()\n+        instructor_tool.loader.render_template.return_value = u''\n+\n+        self.block.student_view(context={})\n+        block_tree = instructor_tool.loader.render_template.call_args[0][1]['block_tree']\n+\n+        # Check size of block_tree: Should only include root block\n+        self.assertEqual(len(block_tree), 1)\n+\n+    def test_student_view_block_tree_eligible(self):\n+        \"\"\"\n+        Check if `student_view` method correctly marks MCQ, Rating, and\n+        Answer blocks as eligible when building tree for render\n+        context.\n+\n+        A block is eligible if its type is one of {'pb-mcq', 'pb-rating', 'pb-answer'}.\n+        \"\"\"\n+        # Pretend that all blocks in self.block.children are eligible:\n+        self.block.runtime.id_reader = Mock()\n+        self.block.runtime.id_reader.get_block_type.return_value = random.choice(['pb-mcq', 'pb-rating', 'pb-answer'])","path":"problem_builder/tests/unit/test_instructor_tool.py","position":158,"original_position":158,"commit_id":"bb3c01cd7c61cfc39b3fa594e521988c4f36ea33","original_commit_id":"bb3c01cd7c61cfc39b3fa594e521988c4f36ea33","user":{"login":"e-kolpakov","id":3330048,"avatar_url":"https://avatars.githubusercontent.com/u/3330048?v=3","gravatar_id":"","url":"https://api.github.com/users/e-kolpakov","html_url":"https://github.com/e-kolpakov","followers_url":"https://api.github.com/users/e-kolpakov/followers","following_url":"https://api.github.com/users/e-kolpakov/following{/other_user}","gists_url":"https://api.github.com/users/e-kolpakov/gists{/gist_id}","starred_url":"https://api.github.com/users/e-kolpakov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/e-kolpakov/subscriptions","organizations_url":"https://api.github.com/users/e-kolpakov/orgs","repos_url":"https://api.github.com/users/e-kolpakov/repos","events_url":"https://api.github.com/users/e-kolpakov/events{/privacy}","received_events_url":"https://api.github.com/users/e-kolpakov/received_events","type":"User","site_admin":false},"body":"@itsjeyd this only tests for one of `('pb-mcq', 'pb-rating', 'pb-answer')` at a time. Better approach would be to use `ddt` and parameterized test:\r\n\r\n    @ddt.data('pb-mcq', 'pb-rating', 'pb-answer')\r\n    def test_student_view_block_tree_eligible(self, block_type):\r\n        ...\r\n        self.block.runtime.id_reader.get_block_type.return_value = block_type\r\n        ...","created_at":"2015-08-07T09:23:22Z","updated_at":"2015-08-07T09:23:22Z","html_url":"https://github.com/open-craft/problem-builder/pull/50#discussion_r36503497","pull_request_url":"https://api.github.com/repos/open-craft/problem-builder/pulls/50","_links":{"self":{"href":"https://api.github.com/repos/open-craft/problem-builder/pulls/comments/36503497"},"html":{"href":"https://github.com/open-craft/problem-builder/pull/50#discussion_r36503497"},"pull_request":{"href":"https://api.github.com/repos/open-craft/problem-builder/pulls/50"}}},"pull_request":{"url":"https://api.github.com/repos/open-craft/problem-builder/pulls/50","id":40615328,"html_url":"https://github.com/open-craft/problem-builder/pull/50","diff_url":"https://github.com/open-craft/problem-builder/pull/50.diff","patch_url":"https://github.com/open-craft/problem-builder/pull/50.patch","issue_url":"https://api.github.com/repos/open-craft/problem-builder/issues/50","number":50,"state":"open","locked":false,"title":"(WIP) Add unit tests for instructor tool","user":{"login":"itsjeyd","id":961441,"avatar_url":"https://avatars.githubusercontent.com/u/961441?v=3","gravatar_id":"","url":"https://api.github.com/users/itsjeyd","html_url":"https://github.com/itsjeyd","followers_url":"https://api.github.com/users/itsjeyd/followers","following_url":"https://api.github.com/users/itsjeyd/following{/other_user}","gists_url":"https://api.github.com/users/itsjeyd/gists{/gist_id}","starred_url":"https://api.github.com/users/itsjeyd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/itsjeyd/subscriptions","organizations_url":"https://api.github.com/users/itsjeyd/orgs","repos_url":"https://api.github.com/users/itsjeyd/repos","events_url":"https://api.github.com/users/itsjeyd/events{/privacy}","received_events_url":"https://api.github.com/users/itsjeyd/received_events","type":"User","site_admin":false},"body":"This PR aims to extend unit test coverage for problem-builder by introducing unit tests for the Instructor Tool block.\r\n\r\nIt follows up on #47.\r\n","created_at":"2015-07-22T21:43:44Z","updated_at":"2015-08-07T09:23:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5e0bfb06cab096bd6b0919ecec21a5764eb0bb9f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/open-craft/problem-builder/pulls/50/commits","review_comments_url":"https://api.github.com/repos/open-craft/problem-builder/pulls/50/comments","review_comment_url":"https://api.github.com/repos/open-craft/problem-builder/pulls/comments{/number}","comments_url":"https://api.github.com/repos/open-craft/problem-builder/issues/50/comments","statuses_url":"https://api.github.com/repos/open-craft/problem-builder/statuses/bb3c01cd7c61cfc39b3fa594e521988c4f36ea33","head":{"label":"open-craft:instructor-tool-unit-tests","ref":"instructor-tool-unit-tests","sha":"bb3c01cd7c61cfc39b3fa594e521988c4f36ea33","user":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"repo":{"id":33264452,"name":"problem-builder","full_name":"open-craft/problem-builder","owner":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-craft/problem-builder","description":"An XBlock for posing questions to students","fork":false,"url":"https://api.github.com/repos/open-craft/problem-builder","forks_url":"https://api.github.com/repos/open-craft/problem-builder/forks","keys_url":"https://api.github.com/repos/open-craft/problem-builder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-craft/problem-builder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-craft/problem-builder/teams","hooks_url":"https://api.github.com/repos/open-craft/problem-builder/hooks","issue_events_url":"https://api.github.com/repos/open-craft/problem-builder/issues/events{/number}","events_url":"https://api.github.com/repos/open-craft/problem-builder/events","assignees_url":"https://api.github.com/repos/open-craft/problem-builder/assignees{/user}","branches_url":"https://api.github.com/repos/open-craft/problem-builder/branches{/branch}","tags_url":"https://api.github.com/repos/open-craft/problem-builder/tags","blobs_url":"https://api.github.com/repos/open-craft/problem-builder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-craft/problem-builder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-craft/problem-builder/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-craft/problem-builder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-craft/problem-builder/statuses/{sha}","languages_url":"https://api.github.com/repos/open-craft/problem-builder/languages","stargazers_url":"https://api.github.com/repos/open-craft/problem-builder/stargazers","contributors_url":"https://api.github.com/repos/open-craft/problem-builder/contributors","subscribers_url":"https://api.github.com/repos/open-craft/problem-builder/subscribers","subscription_url":"https://api.github.com/repos/open-craft/problem-builder/subscription","commits_url":"https://api.github.com/repos/open-craft/problem-builder/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-craft/problem-builder/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-craft/problem-builder/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-craft/problem-builder/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-craft/problem-builder/contents/{+path}","compare_url":"https://api.github.com/repos/open-craft/problem-builder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-craft/problem-builder/merges","archive_url":"https://api.github.com/repos/open-craft/problem-builder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-craft/problem-builder/downloads","issues_url":"https://api.github.com/repos/open-craft/problem-builder/issues{/number}","pulls_url":"https://api.github.com/repos/open-craft/problem-builder/pulls{/number}","milestones_url":"https://api.github.com/repos/open-craft/problem-builder/milestones{/number}","notifications_url":"https://api.github.com/repos/open-craft/problem-builder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-craft/problem-builder/labels{/name}","releases_url":"https://api.github.com/repos/open-craft/problem-builder/releases{/id}","created_at":"2015-04-01T18:18:42Z","updated_at":"2015-05-14T03:28:29Z","pushed_at":"2015-08-07T07:49:08Z","git_url":"git://github.com/open-craft/problem-builder.git","ssh_url":"git@github.com:open-craft/problem-builder.git","clone_url":"https://github.com/open-craft/problem-builder.git","svn_url":"https://github.com/open-craft/problem-builder","homepage":null,"size":4836,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":2,"default_branch":"master"}},"base":{"label":"open-craft:master","ref":"master","sha":"36cd10b93228caa9d8a9cc17c38fda782e48f101","user":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"repo":{"id":33264452,"name":"problem-builder","full_name":"open-craft/problem-builder","owner":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-craft/problem-builder","description":"An XBlock for posing questions to students","fork":false,"url":"https://api.github.com/repos/open-craft/problem-builder","forks_url":"https://api.github.com/repos/open-craft/problem-builder/forks","keys_url":"https://api.github.com/repos/open-craft/problem-builder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-craft/problem-builder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-craft/problem-builder/teams","hooks_url":"https://api.github.com/repos/open-craft/problem-builder/hooks","issue_events_url":"https://api.github.com/repos/open-craft/problem-builder/issues/events{/number}","events_url":"https://api.github.com/repos/open-craft/problem-builder/events","assignees_url":"https://api.github.com/repos/open-craft/problem-builder/assignees{/user}","branches_url":"https://api.github.com/repos/open-craft/problem-builder/branches{/branch}","tags_url":"https://api.github.com/repos/open-craft/problem-builder/tags","blobs_url":"https://api.github.com/repos/open-craft/problem-builder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-craft/problem-builder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-craft/problem-builder/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-craft/problem-builder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-craft/problem-builder/statuses/{sha}","languages_url":"https://api.github.com/repos/open-craft/problem-builder/languages","stargazers_url":"https://api.github.com/repos/open-craft/problem-builder/stargazers","contributors_url":"https://api.github.com/repos/open-craft/problem-builder/contributors","subscribers_url":"https://api.github.com/repos/open-craft/problem-builder/subscribers","subscription_url":"https://api.github.com/repos/open-craft/problem-builder/subscription","commits_url":"https://api.github.com/repos/open-craft/problem-builder/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-craft/problem-builder/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-craft/problem-builder/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-craft/problem-builder/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-craft/problem-builder/contents/{+path}","compare_url":"https://api.github.com/repos/open-craft/problem-builder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-craft/problem-builder/merges","archive_url":"https://api.github.com/repos/open-craft/problem-builder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-craft/problem-builder/downloads","issues_url":"https://api.github.com/repos/open-craft/problem-builder/issues{/number}","pulls_url":"https://api.github.com/repos/open-craft/problem-builder/pulls{/number}","milestones_url":"https://api.github.com/repos/open-craft/problem-builder/milestones{/number}","notifications_url":"https://api.github.com/repos/open-craft/problem-builder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-craft/problem-builder/labels{/name}","releases_url":"https://api.github.com/repos/open-craft/problem-builder/releases{/id}","created_at":"2015-04-01T18:18:42Z","updated_at":"2015-05-14T03:28:29Z","pushed_at":"2015-08-07T07:49:08Z","git_url":"git://github.com/open-craft/problem-builder.git","ssh_url":"git@github.com:open-craft/problem-builder.git","clone_url":"https://github.com/open-craft/problem-builder.git","svn_url":"https://github.com/open-craft/problem-builder","homepage":null,"size":4836,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/open-craft/problem-builder/pulls/50"},"html":{"href":"https://github.com/open-craft/problem-builder/pull/50"},"issue":{"href":"https://api.github.com/repos/open-craft/problem-builder/issues/50"},"comments":{"href":"https://api.github.com/repos/open-craft/problem-builder/issues/50/comments"},"review_comments":{"href":"https://api.github.com/repos/open-craft/problem-builder/pulls/50/comments"},"review_comment":{"href":"https://api.github.com/repos/open-craft/problem-builder/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/open-craft/problem-builder/pulls/50/commits"},"statuses":{"href":"https://api.github.com/repos/open-craft/problem-builder/statuses/bb3c01cd7c61cfc39b3fa594e521988c4f36ea33"}}}}