-
-
Notifications
You must be signed in to change notification settings - Fork 766
/
CliArgsSpec.kt
334 lines (277 loc) · 14.3 KB
/
CliArgsSpec.kt
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
package io.gitlab.arturbosch.detekt.cli
import io.github.detekt.test.utils.resourceAsPath
import io.github.detekt.tooling.api.spec.RulesSpec.FailurePolicy.FailOnSeverity
import io.github.detekt.tooling.api.spec.RulesSpec.FailurePolicy.NeverFail
import io.gitlab.arturbosch.detekt.api.Severity
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.condition.DisabledOnOs
import org.junit.jupiter.api.condition.EnabledOnOs
import org.junit.jupiter.api.condition.OS
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.EnumSource
import org.junit.jupiter.params.provider.ValueSource
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.absolute
internal class CliArgsSpec {
@Nested
inner class `Parsing the input path` {
private val pathBuildGradle = Path("build.gradle.kts").absolute()
private val pathCliArgs = Path("src/main/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgs.kt").absolute()
private val pathCliArgsSpec = Path("src/test/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgsSpec.kt").absolute()
private val pathAnalyzer =
Path("../detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/AnalyzerSpec.kt").absolute()
.normalize()
@Test
fun `the current working directory is used if parameter is not set`() {
val spec = parseArguments(emptyArray()).toSpec()
val workingDir = Path("").absolute()
assertThat(spec.projectSpec.inputPaths).allSatisfy { it.absolute().startsWith(workingDir) }
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgsSpec)
}
@ParameterizedTest
@ValueSource(
strings = [
"src/main,../detekt-core/src/test,build.gradle.kts",
"src/main;../detekt-core/src/test;build.gradle.kts",
"src/main,../detekt-core/src/test;build.gradle.kts",
]
)
fun `when the input is defined it is passed to the spec`(param: String) {
val spec = parseArguments(arrayOf("--input", param)).toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathCliArgsSpec)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
@DisabledOnOs(OS.WINDOWS)
fun `reports an error if the input path does not exist (non-Windows OS)`() {
val params = arrayOf("--input", "nonExistent ")
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(params) }
.withMessage("Input path does not exist: 'nonExistent '")
}
@Test
@EnabledOnOs(OS.WINDOWS)
fun `reports an error if the input path does not exist (Windows OS)`() {
val params = arrayOf("--input", "nonExistent ")
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(params) }
.withMessage(""""--input": couldn't convert "nonExistent " to a path""")
}
@Nested
inner class FilterInput {
private val input = arrayOf("--input", "src/main/../main/,../detekt-core/src/test,build.gradle.kts")
private val pathMain = Path("src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Main.kt").absolute()
@Test
fun `no filters`() {
val spec = parseArguments(input).toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
fun `excludes in path`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/test/**")).toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathAnalyzer)
}
@Test
fun `includes in path`() {
val spec = parseArguments(input + arrayOf("--includes", "**/test/**")).toSpec()
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
fun `excludes and includes in path`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/test/**", "--includes", "**/test/**"))
.toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
fun `excludes in path normalized`() {
val spec = parseArguments(input + arrayOf("--excludes", "src/main/kotlin/**")).toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
fun `doesn't take into account absolute path`() {
val spec = parseArguments(input + arrayOf("--excludes", "/home/**,/Users/**")).toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
fun `excludes main but includes one file`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/main/**", "--includes", "**/CliArgs.kt"))
.toSpec()
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}
@Test
fun `parse excludes correctly`() {
val paths: List<Collection<Path>> = listOf(
"**/main/**,**/detekt-core/**,**/build.gradle.kts",
"**/main/**;**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**, **/build.gradle.kts",
"**/main/** ;**/detekt-core/**; **/build.gradle.kts",
"**/main/**,**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**; **/build.gradle.kts",
" ,,**/main/**,**/detekt-core/**,**/build.gradle.kts",
).map {
val spec = parseArguments(input + arrayOf("--excludes", it)).toSpec()
spec.projectSpec.inputPaths
}
assertThat(paths.distinct()).hasSize(1)
}
@Test
fun `parse includes correctly`() {
val paths: List<Collection<Path>> = listOf(
"**/main/**,**/detekt-core/**,**/build.gradle.kts",
"**/main/**;**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**, **/build.gradle.kts",
"**/main/** ;**/detekt-core/**; **/build.gradle.kts",
"**/main/**,**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**; **/build.gradle.kts",
" ,,**/main/**,**/detekt-core/**,**/build.gradle.kts",
).map {
val spec = parseArguments(input + arrayOf("--includes", it)).toSpec()
spec.projectSpec.inputPaths
}
assertThat(paths.distinct()).hasSize(1)
}
}
}
@Nested
inner class `parsing config parameters` {
@Test
fun `should fail on invalid config value`() {
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(arrayOf("--config", "sfsjfsdkfsd")).toSpec() }
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(arrayOf("--config", "./i.do.not.exist.yml")).toSpec() }
}
}
@Nested
inner class `Valid combination of options` {
@Nested
inner class `Baseline feature` {
@Test
fun `reports an error when using --create-baseline without a --baseline file`() {
assertThatCode { parseArguments(arrayOf("--create-baseline")) }
.isInstanceOf(HandledArgumentViolation::class.java)
.hasMessage("Creating a baseline.xml requires the --baseline parameter to specify a path.")
}
@Test
fun `reports an error when using --baseline file does not exist`() {
assertThatCode { parseArguments(arrayOf("--baseline", "nonExistent")) }
.isInstanceOf(HandledArgumentViolation::class.java)
.hasMessage("The file specified by --baseline should exist 'nonExistent'.")
}
@Test
fun `reports an error when using --baseline file which is not a file`() {
val directory = resourceAsPath("/cases").toString()
assertThatCode { parseArguments(arrayOf("--baseline", directory)) }
.isInstanceOf(HandledArgumentViolation::class.java)
.hasMessage("The path specified by --baseline should be a file '$directory'.")
}
}
@Test
fun `throws HelpRequest on --help`() {
assertThatExceptionOfType(HelpRequest::class.java)
.isThrownBy { parseArguments(arrayOf("--help")) }
}
@Test
fun `throws HandledArgumentViolation on wrong options`() {
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(arrayOf("--unknown-to-us-all")) }
}
}
@Test
fun `--all-rules lead to all rules being activated`() {
val spec = parseArguments(arrayOf("--all-rules")).toSpec()
assertThat(spec.rulesSpec.activateAllRules).isTrue()
}
@Nested
inner class `type resolution parameters are accepted` {
@Test
fun `--jvm-target is accepted`() {
val spec = parseArguments(arrayOf("--jvm-target", "11")).toSpec()
assertThat(spec.compilerSpec.jvmTarget).isEqualTo("11")
}
@Test
fun `--jvm-target with decimal is accepted`() {
val spec = parseArguments(arrayOf("--jvm-target", "1.8")).toSpec()
assertThat(spec.compilerSpec.jvmTarget).isEqualTo("1.8")
}
@Test
fun `--language-version is accepted`() {
val spec = parseArguments(arrayOf("--language-version", "1.6")).toSpec()
assertThat(spec.compilerSpec.languageVersion).isEqualTo("1.6")
}
}
@Nested
inner class `Configuration of FailurePolicy` {
@Test
fun `not specified results in default value`() {
val args = emptyArray<String>()
val actual = parseArguments(args)
assertThat(actual.failurePolicy).isEqualTo(FailOnSeverity(Severity.Error))
}
@Test
fun `--fail-on-severity never specified results in never fail policy`() {
val args = arrayOf("--fail-on-severity", "never")
val actual = parseArguments(args)
assertThat(actual.failurePolicy).isEqualTo(NeverFail)
}
@ParameterizedTest(name = "{0}")
@EnumSource(value = FailureSeverity::class, names = ["Never"], mode = EnumSource.Mode.EXCLUDE)
fun `--fail-on-severity`(severity: FailureSeverity) {
val args = arrayOf("--fail-on-severity", severity.name.lowercase())
val actual = parseArguments(args)
assertThat(actual.failurePolicy).isInstanceOf(FailOnSeverity::class.java)
assertThat((actual.failurePolicy as FailOnSeverity).minSeverity.name)
.isEqualToIgnoringCase(severity.name)
}
@Test
fun `invalid --fail-on-severity parameter`() {
val args = arrayOf("--fail-on-severity", "foo")
assertThatThrownBy {
parseArguments(args)
}.isInstanceOf(IllegalArgumentException::class.java)
}
}
@Test
fun `base-path with a non existent directory`() {
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(arrayOf("--base-path", "nonExistent")) }
.withMessage("Value passed to --base-path must be a directory.")
}
@Test
fun `jdk-home with a non existent directory`() {
assertThatExceptionOfType(HandledArgumentViolation::class.java)
.isThrownBy { parseArguments(arrayOf("--jdk-home", "nonExistent")) }
.withMessage("Value passed to --jdk-home must be a directory.")
}
}