Completed
Push — master ( 9821e6...398a65 )
by Jasper
8s
created

AddTests   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 175
Duplicated Lines 10.29 %

Importance

Changes 5
Bugs 0 Features 2
Metric Value
c 5
b 0
f 2
dl 18
loc 175
rs 8.3396
wmc 44

28 Methods

Rating   Name   Duplication   Size   Complexity  
A assertNotCalledWith() 0 3 2
A locAt() 0 4 1
A test_If_file_not_version_but_series_and_not_in_there_yet() 8 9 1
A test_Found_copy_set_as_parent_inherits_and_flags_and_informs_listener() 0 10 1
A test_accepts_optional_provenance() 0 3 1
A test_Adds_uid() 0 5 2
A testIfInspectedAndReturnEptyList() 0 3 1
A test_Adds_timestamp() 0 3 1
A test_For_nonexisting_transient_file_behaves_normal() 0 3 1
A test_If_dryrun_doesnt_talk_to_repo_and_status_is_test() 0 6 4
A test_If_inspect_raises_exceptions_tells_listener_and_doesnt_save() 0 7 3
A test_If_file_is_version_but_not_series() 0 7 1
A test_If_file_is_version_and_series() 0 8 1
A test_copiesOf_not_called_if_parent_available() 0 3 2
A test_copiesOf_not_called_before_inspect() 0 6 2
A test_Sets_transient_flag_if_provided() 0 3 1
A test_getSeries_not_called_before_inspect() 0 3 2
A test_Calls_inspect() 0 3 1
A setUp() 0 15 2
A test_If_file_doesnt_exists_raises_error() 0 4 1
A add() 0 4 2
A test_If_config_attach_set_calls_attach_on_file() 0 10 3
A test_If_file_unknown_adds_it() 0 5 1
A test_Doesnt_inspect_transient_files() 0 3 2
A test_Creates_ImageFile_object_with_factory() 0 3 1
A test_If_file_not_version_but_series_has_file() 8 9 2
A test_If_only_copy_is_same_location_ignores_it() 0 8 3
A test_Returns_provenance_and_informs_listener() 0 5 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AddTests often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import unittest, os
2
from mock import Mock, patch, call, sentinel
3
from tests.ditest import DependencyInjectionTestBase
4
5
6
class AddTests(DependencyInjectionTestBase):
7
8
    def setUp(self):
9
        super(AddTests, self).setUp()
10
        self.config.dryrun = False
11
        self.repo.byLocation.return_value = None
12
        self.query.copiesOf.return_value = []
13
        self.img = Mock()
14
        self.lastProvenance = None
15
        def locAt(loc, provenance):
16
            self.lastProvenance = provenance
17
            self.lastPath = loc
18
            return self.img
19
        self.fileFactory.locatedAt.side_effect = locAt
20
        patcher = patch('niprov.adding.datetime')
21
        self.datetime = patcher.start()
22
        self.addCleanup(patcher.stop)
23
24
    def add(self, path, **kwargs):
25
        from niprov.adding import add
26
        with patch('niprov.adding.inheritFrom') as self.inheritFrom:
27
            return add(path, dependencies=self.dependencies, **kwargs)
28
29
    def assertNotCalledWith(self, m, *args, **kwargs):
30
        c = call(*args, **kwargs)
31
        assert c not in m.call_args_list, "Unexpectedly found call: "+str(c)
32
33
    def test_Returns_provenance_and_informs_listener(self):
34
        new = '/p/f2'
35
        image = self.add(new)
36
        self.listener.fileAdded.assert_called_with(self.img)
37
        self.assertEqual(image, self.img)
38
39
    def test_Sets_transient_flag_if_provided(self):
40
        image = self.add('/p/f1', transient=True)
41
        self.assertEqual(self.lastProvenance['transient'],True)
42
43
    def test_Creates_ImageFile_object_with_factory(self):
44
        image = self.add('p/afile.f')
45
        self.assertIs(self.img, image)
46
47
    def test_Calls_inspect(self):
48
        image = self.add('p/afile.f')
49
        self.img.inspect.assert_called_with()
50
51
    def test_If_inspect_raises_exceptions_tells_listener_and_doesnt_save(self):
52
        self.img.inspect.side_effect = IOError
53
        image = self.add('p/afile.f')
54
        assert not self.repo.add.called
55
        assert not self.repo.update.called
56
        self.listener.fileError.assert_called_with(self.img.path)
57
        self.assertEqual(self.img.status, 'failed')
58
59
    def test_If_dryrun_doesnt_talk_to_repo_and_status_is_test(self):
60
        self.config.dryrun = True
61
        image = self.add('p/afile.f')
62
        assert not self.repo.add.called
63
        assert not self.repo.update.called
64
        assert not self.img.inspect.called
65
66
    def test_accepts_optional_provenance(self):
67
        image = self.add('p/afile.f', provenance={'fob':'bez'})
68
        self.assertEqual(self.lastProvenance['fob'],'bez')
69
70
    def test_If_file_doesnt_exists_raises_error(self):
71
        self.filesys.fileExists.return_value = False
72
        self.assertRaises(IOError, self.add, self.img.location.path)
73
        self.filesys.fileExists.assert_called_with(self.img.location.path)
74
75
    def test_For_nonexisting_transient_file_behaves_normal(self):
76
        self.filesys.fileExists.return_value = False
77
        self.add('p/afile.f', transient=True)
78
79
    def test_Doesnt_inspect_transient_files(self):
80
        self.add('p/afile.f', transient=True)
81
        assert not self.img.inspect.called
82
83
    def test_Adds_timestamp(self):
84
        image = self.add('p/afile.f')
85
        self.assertEqual(self.lastProvenance['added'],self.datetime.now())
86
87
    def test_Adds_uid(self):
88
        with patch('niprov.adding.shortuuid') as shortuuid:
89
            shortuuid.uuid.return_value = 'abcdefghijklmn'
90
            image = self.add('p/afile.f')
91
            self.assertEqual(self.lastProvenance['id'],'abcdef')
92
93
    def test_If_config_attach_set_calls_attach_on_file(self):
94
        self.config.attach = False
95
        self.add('p/afile.f')
96
        assert not self.img.attach.called, "Shouldnt attach if not configured."
97
        self.config.attach = True
98
        self.config.attach_format = 'abracadabra'
99
        self.add('p/afile.f', transient=True)
100
        assert not self.img.attach.called, "Shouldnt attach to transient file."
101
        self.add('p/afile.f')
102
        self.img.attach.assert_called_with('abracadabra')
103
104
    def test_If_file_unknown_adds_it(self):                             # A
105
        self.repo.byLocation.return_value = None
106
        self.repo.getSeries.return_value = None
107
        image = self.add('p/afile.f')
108
        self.repo.add.assert_any_call(self.img)
109
110
    def test_If_file_is_version_but_not_series(self):                    # B
111
        previousVersion = Mock()
112
        self.repo.byLocation.return_value = previousVersion
113
        self.repo.getSeries.return_value = None
114
        img = self.add('p/afile.f')
115
        self.img.keepVersionsFromPrevious.assert_called_with(previousVersion)
116
        self.repo.update.assert_any_call(self.img)
117
118
    def test_If_file_is_version_and_series(self):                        # C
119
        previousVersion = Mock()
120
        series = Mock()
121
        self.repo.byLocation.return_value = previousVersion
122
        self.repo.getSeries.return_value = series
123
        image = self.add('p/afile.f')
124
        self.img.keepVersionsFromPrevious.assert_called_with(previousVersion)
125
        self.repo.update.assert_any_call(self.img)
126 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
127
    def test_If_file_not_version_but_series_and_not_in_there_yet(self):   # D1
128
        series = Mock()
129
        series.hasFile.return_value = False
130
        series.mergeWith.return_value = series
131
        self.repo.byLocation.return_value = None
132
        self.repo.getSeries.return_value = series
133
        image = self.add('p/afile.f')
134
        series.mergeWith.assert_called_with(self.img)
135
        self.repo.update.assert_any_call(series)
136 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
137
    def test_If_file_not_version_but_series_has_file(self):               # D2
138
        series = Mock()
139
        series.hasFile.return_value = True
140
        self.repo.byLocation.return_value = None
141
        self.repo.getSeries.return_value = series
142
        image = self.add('p/afile.f')
143
        assert not series.mergeWith.called
144
        self.img.keepVersionsFromPrevious.assert_called_with(series)
145
        self.repo.update.assert_any_call(self.img)
146
147
    def test_copiesOf_not_called_before_inspect(self):
148
        def testIfInspectedAndReturnEptyList(img):
149
            img.inspect.assert_called_with()
150
            return []
151
        self.query.copiesOf.side_effect = testIfInspectedAndReturnEptyList
152
        image = self.add('p/afile.f')
153
154
    def test_getSeries_not_called_before_inspect(self):
155
        self.repo.getSeries.side_effect = lambda img: img.inspect.assert_called_with()
156
        image = self.add('p/afile.f')
157
158
    def test_copiesOf_not_called_if_parent_available(self):
159
        image = self.add('p/afile.f', provenance={'parents':[sentinel.parent]})
160
        assert not self.query.copiesOf.called
161
162
    def test_Found_copy_set_as_parent_inherits_and_flags_and_informs_listener(self):
163
        self.img.provenance = {}
164
        copy = Mock()
165
        copy.provenance = {'location':'copy-location'}
166
        self.query.copiesOf.return_value = [self.img, copy]
167
        out = self.add('p/afile.f')
168
        self.inheritFrom.assert_called_with(self.img.provenance, copy.provenance)
169
        self.listener.usingCopyAsParent.assert_called_with(copy)
170
        self.assertEqual(copy.location.toString(), out.provenance['parents'][0])
171
        self.assertEqual(True, out.provenance['copy-as-parent'])
172
173
    def test_If_only_copy_is_same_location_ignores_it(self):
174
        self.img.provenance = {}
175
        self.query.copiesOf.return_value = [self.img]
176
        out = self.add('p/afile.f')
177
        assert not self.inheritFrom.called
178
        assert not self.listener.usingCopyAsParent.called
179
        self.assertNotIn('parents', out.provenance)
180
        self.assertNotIn('copy-as-parent', out.provenance)
181
182
        
183
184