1
+ package com.github.monosoul.git.updateindex.extended
2
+
3
+ import com.github.monosoul.git.updateindex.extended.ExtendedUpdateIndexTaskTest.FilesAndCommandArgumentsSource.NoVcsRoot
4
+ import com.github.monosoul.git.updateindex.extended.ExtendedUpdateIndexTaskTest.FilesAndCommandArgumentsSource.WithVcsRoot
5
+ import com.intellij.mock.MockApplication
6
+ import com.intellij.mock.MockProject
7
+ import com.intellij.openapi.application.ApplicationManager.setApplication
8
+ import com.intellij.openapi.progress.ProgressIndicator
9
+ import com.intellij.openapi.util.Disposer.dispose
10
+ import com.intellij.openapi.vcs.ProjectLevelVcsManager
11
+ import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager
12
+ import com.intellij.openapi.vfs.VirtualFile
13
+ import git4idea.commands.Git
14
+ import git4idea.commands.GitCommandResult
15
+ import git4idea.commands.GitLineHandler
16
+ import io.mockk.Called
17
+ import io.mockk.every
18
+ import io.mockk.impl.annotations.MockK
19
+ import io.mockk.junit5.MockKExtension
20
+ import io.mockk.mockk
21
+ import io.mockk.verify
22
+ import io.mockk.verifyAll
23
+ import io.mockk.verifyOrder
24
+ import org.apache.commons.lang3.RandomStringUtils
25
+ import org.apache.commons.lang3.RandomUtils.nextInt
26
+ import org.apache.log4j.Appender
27
+ import org.apache.log4j.Level.ERROR
28
+ import org.junit.jupiter.api.AfterEach
29
+ import org.junit.jupiter.api.BeforeEach
30
+ import org.junit.jupiter.api.extension.ExtendWith
31
+ import org.junit.jupiter.params.ParameterizedTest
32
+ import org.junit.jupiter.params.provider.ArgumentsSource
33
+ import strikt.api.expectThat
34
+ import strikt.assertions.containsExactlyInAnyOrder
35
+ import strikt.assertions.isEqualTo
36
+ import java.util.stream.Stream.generate
37
+ import kotlin.streams.toList
38
+
39
+ @ExtendWith(MockKExtension ::class )
40
+ internal class ExtendedUpdateIndexTaskTest {
41
+
42
+ private lateinit var parent: TestDisposable
43
+ private lateinit var application: MockApplication
44
+ private lateinit var project: MockProject
45
+
46
+ private lateinit var appender: Appender
47
+
48
+ @MockK
49
+ private lateinit var git: Git
50
+
51
+ @MockK
52
+ private lateinit var vcsManager: ProjectLevelVcsManager
53
+
54
+ @MockK(relaxUnitFun = true )
55
+ private lateinit var dirtyScopeManager: VcsDirtyScopeManager
56
+
57
+ @MockK
58
+ private lateinit var gitLineHandlerFactory: GitLineHandlerFactory
59
+
60
+ @MockK
61
+ private lateinit var gitLineHandler: GitLineHandler
62
+
63
+ @MockK
64
+ private lateinit var gitCommandResult: GitCommandResult
65
+
66
+ @BeforeEach
67
+ fun setUp () {
68
+ parent = TestDisposable ()
69
+
70
+ application = MockApplication (parent)
71
+ setApplication(application, parent)
72
+ application.registerService(git, parent)
73
+
74
+ project = MockProject (null , parent)
75
+ project.registerService(vcsManager, parent)
76
+ project.registerService(dirtyScopeManager, parent)
77
+ project.registerService(gitLineHandlerFactory, parent)
78
+
79
+ appender = mockedAppender<ExtendedUpdateIndexTask >()
80
+
81
+ every { gitLineHandlerFactory.invoke(any(), any(), any()) } returns gitLineHandler
82
+ every { git.runCommand(any<GitLineHandler >()) } returns gitCommandResult
83
+ }
84
+
85
+ @AfterEach
86
+ fun tearDown () {
87
+ dispose(parent)
88
+ }
89
+
90
+ @ParameterizedTest
91
+ @ArgumentsSource(NoVcsRoot ::class )
92
+ fun `should do nothing if a file has no VCS root` (
93
+ files : List <VirtualFile >,
94
+ command : ExtendedUpdateIndexCommand ,
95
+ @MockK indicator : ProgressIndicator
96
+ ) {
97
+ every { vcsManager.getVcsRootFor(any<VirtualFile >()) } returns null
98
+
99
+ ExtendedUpdateIndexTask (project, files, command).run (indicator)
100
+
101
+ verifyOrder {
102
+ vcsManager.getVcsRootFor(files[0 ])
103
+ }
104
+ verifyAll {
105
+ git wasNot Called
106
+ gitLineHandlerFactory wasNot Called
107
+ gitLineHandler wasNot Called
108
+ dirtyScopeManager wasNot Called
109
+ }
110
+ }
111
+
112
+ @ParameterizedTest
113
+ @ArgumentsSource(WithVcsRoot ::class )
114
+ internal fun `should execute a command and log nothing if it was successful` (
115
+ files : List <VirtualFile >,
116
+ command : ExtendedUpdateIndexCommand ,
117
+ @MockK indicator : ProgressIndicator
118
+ ) {
119
+ val root = mockk<VirtualFile >()
120
+ every { vcsManager.getVcsRootFor(any<VirtualFile >()) } returns root
121
+
122
+ every { gitCommandResult.success() } returns true
123
+
124
+
125
+ ExtendedUpdateIndexTask (project, files, command).run (indicator)
126
+
127
+ verify(exactly = files.size) {
128
+ vcsManager.getVcsRootFor(any<VirtualFile >())
129
+ }
130
+ verifyOrder {
131
+ gitLineHandlerFactory.invoke(command, root, withArg {
132
+ expectThat(it) containsExactlyInAnyOrder files
133
+ })
134
+ git.runCommand(gitLineHandler)
135
+ gitCommandResult.success()
136
+ }
137
+ verify(exactly = files.size) {
138
+ dirtyScopeManager.fileDirty(any<VirtualFile >())
139
+ }
140
+ }
141
+
142
+ @ParameterizedTest
143
+ @ArgumentsSource(WithVcsRoot ::class )
144
+ internal fun `should execute a command and log errors if it was unsuccessful` (
145
+ files : List <VirtualFile >,
146
+ command : ExtendedUpdateIndexCommand ,
147
+ @MockK indicator : ProgressIndicator
148
+ ) {
149
+ val root = mockk<VirtualFile >()
150
+ every { vcsManager.getVcsRootFor(any<VirtualFile >()) } returns root
151
+
152
+ every { gitCommandResult.success() } returns false
153
+ val error = RandomStringUtils .randomAlphabetic(LIMIT )
154
+ every { gitCommandResult.errorOutput } returns listOf (error)
155
+
156
+ ExtendedUpdateIndexTask (project, files, command).run (indicator)
157
+
158
+ verify(exactly = files.size) {
159
+ vcsManager.getVcsRootFor(any<VirtualFile >())
160
+ }
161
+ verifyOrder {
162
+ gitLineHandlerFactory.invoke(command, root, withArg {
163
+ expectThat(it) containsExactlyInAnyOrder files
164
+ })
165
+ git.runCommand(gitLineHandler)
166
+ gitCommandResult.success()
167
+ gitCommandResult.errorOutput
168
+ appender.doAppend(withArg {
169
+ expectThat(it) {
170
+ get { message } isEqualTo error
171
+ get { getLevel() } isEqualTo ERROR
172
+ }
173
+ })
174
+ }
175
+ verify(exactly = files.size) {
176
+ dirtyScopeManager.fileDirty(any<VirtualFile >())
177
+ }
178
+ }
179
+
180
+ private sealed class FilesAndCommandArgumentsSource (
181
+ vararg generators : () -> Any?
182
+ ) : AbstractMultiArgumentsSource(*generators) {
183
+
184
+ class NoVcsRoot : FilesAndCommandArgumentsSource (
185
+ { listOf(mockk<VirtualFile >()) },
186
+ { randomEnum<ExtendedUpdateIndexCommand >() }
187
+ )
188
+
189
+ class WithVcsRoot : FilesAndCommandArgumentsSource (
190
+ { virtualFileList() },
191
+ { randomEnum<ExtendedUpdateIndexCommand >() }
192
+ )
193
+
194
+ companion object {
195
+ private fun virtualFileList () = generate { mockk<VirtualFile >() }
196
+ .limit(nextInt(1 , LIMIT ))
197
+ .toList()
198
+ }
199
+ }
200
+ }
0 commit comments