-
Notifications
You must be signed in to change notification settings - Fork 226
Expand file tree
/
Copy pathtest_completable.py
More file actions
157 lines (134 loc) · 5.52 KB
/
test_completable.py
File metadata and controls
157 lines (134 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""
Tests of the CompletableXBlockMixin.
"""
import math
from collections import namedtuple
from unittest import TestCase
from unittest import mock
import ddt
from hypothesis import example, given, strategies
from xblock.core import XBlock
from xblock.fields import ScopeIds
from xblock.runtime import Runtime
from xblock.completable import CompletableXBlockMixin, XBlockCompletionMode
from xblock.test.tools import TestKey
@ddt.ddt
class XBlockCompletionModeTest(TestCase):
"""
Tests for XBlockCompletionMode
"""
blocklike = namedtuple('block_like', ['completion_mode'])
@ddt.data(
XBlockCompletionMode.COMPLETABLE,
XBlockCompletionMode.AGGREGATOR,
XBlockCompletionMode.EXCLUDED,
)
def test_explicit_mode(self, mode):
block = self.blocklike(mode)
self.assertEqual(
XBlockCompletionMode.get_mode(block),
mode
)
def test_no_mode(self):
self.assertEqual(
XBlockCompletionMode.get_mode(object()),
XBlockCompletionMode.COMPLETABLE,
)
def test_unknown_mode(self):
block = self.blocklike('somenewmode')
self.assertEqual(
XBlockCompletionMode.get_mode(block),
'somenewmode'
)
class CompletableXBlockMixinTest(TestCase):
"""
Tests for CompletableXBlockMixin.
"""
class TestBuddyXBlock(XBlock, CompletableXBlockMixin):
"""
Simple XBlock extending CompletableXBlockMixin.
"""
class TestIllegalCustomCompletionAttrXBlock(XBlock, CompletableXBlockMixin):
"""
XBlock extending CompletableXBlockMixin using illegal `has_custom_completion` attribute.
"""
has_custom_completion = False
class TestIllegalCompletionMethodAttrXBlock(XBlock, CompletableXBlockMixin):
"""
XBlock extending CompletableXBlockMixin using illegal `completion_mode` attribute.
"""
completion_mode = "something_else"
def _make_block(self, runtime=None, block_type=None):
"""
Creates a test block.
"""
block_type = block_type if block_type else self.TestBuddyXBlock
runtime = runtime if runtime else mock.Mock(spec=Runtime)
test_key = TestKey("test_buddy", "test_id")
scope_ids = ScopeIds("user_id", "test_buddy", test_key, test_key)
return block_type(runtime=runtime, scope_ids=scope_ids)
def test_has_custom_completion_property(self):
"""
Test `has_custom_completion` property is set by mixin.
"""
block = self._make_block()
self.assertTrue(block.has_custom_completion)
self.assertTrue(getattr(block, 'has_custom_completion', False))
def test_completion_mode_property(self):
"""
Test `completion_mode` property is set by mixin.
"""
block = self._make_block()
self.assertEqual(XBlockCompletionMode.get_mode(block), XBlockCompletionMode.COMPLETABLE)
self.assertEqual(block.completion_mode, XBlockCompletionMode.COMPLETABLE)
@given(strategies.floats())
def test_emit_completion_illegal_custom_completion(self, any_completion):
"""
Test `emit_completion` raises exception when called on a XBlock with illegal `has_custom_completion` value.
"""
runtime_mock = mock.Mock(spec=Runtime)
illegal_custom_completion_block = self._make_block(runtime_mock, self.TestIllegalCustomCompletionAttrXBlock)
with self.assertRaises(AttributeError):
illegal_custom_completion_block.emit_completion(any_completion)
@given(strategies.floats())
def test_emit_completion_completion_mode(self, any_completion):
"""
Test `emit_completion` raises exception when called on a XBlock with illegal `completion_mode` value.
"""
runtime_mock = mock.Mock(spec=Runtime)
illegal_completion_mode_block = self._make_block(runtime_mock, self.TestIllegalCompletionMethodAttrXBlock)
with self.assertRaises(AttributeError):
illegal_completion_mode_block.emit_completion(any_completion)
@given(strategies.floats(min_value=0.0, max_value=1.0))
@example(1.0)
@example(0.0)
def test_emit_completion_emits_event(self, valid_completion_percent):
"""
Test `emit_completion` emits completion events when passed a valid argument.
Given a valid completion percent
When emit_completion is called
Then runtime.publish is called with expected arguments
"""
runtime_mock = mock.Mock(spec=Runtime)
block = self._make_block(runtime_mock)
block.emit_completion(valid_completion_percent)
runtime_mock.publish.assert_called_once_with(block, "completion", {"completion": valid_completion_percent})
@given(strategies.floats().filter(lambda x: math.isnan(x) or x < 0.0 or x > 1.0))
@example(None)
@example(float('+inf'))
@example(float('-inf'))
def test_emit_completion_raises_assertion_error_if_invalid(self, invalid_completion_percent):
"""
Test `emit_completion` raises exception when passed an invalid argument.
Given an invalid completion percent
* Less than 0.0
* Greater than 1.0
* Positive or negative infinity
* NaN
When emit_completion is called
Then value error is thrown
"""
runtime_mock = mock.Mock(spec=Runtime)
block = self._make_block(runtime_mock)
with self.assertRaises(ValueError):
self.assertRaises(block.emit_completion(invalid_completion_percent))