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