Skip to content

Commit c83520d

Browse files
committed
Allow parameterizing list type
1 parent 6ba8258 commit c83520d

File tree

9 files changed

+221
-7
lines changed

9 files changed

+221
-7
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,32 @@ A sequence of values.
131131
Because string is used as a data type for passing inputs to actions, a separator string has to be
132132
specified as well. This is usually a new line or a comma.
133133

134-
Example:
134+
Lists can contain values of any primitive or enum type.
135+
136+
Examples:
135137

136138
```yaml
137139
...
138140
inputs:
139141
input-files:
140142
type: list
141143
separator: ','
144+
listItem:
145+
type: string
146+
...
147+
```
148+
149+
```yaml
150+
...
151+
inputs:
152+
granted-scopes:
153+
type: list
154+
separator: ','
155+
listItem:
156+
type: enum
157+
allowedValues:
158+
- read
159+
- write
142160
...
143161
```
144162

src/main/kotlin/it/krzeminski/githubactionstyping/parsing/ManifestParsing.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ data class ApiItem(
1616
val type: String? = null,
1717
val allowedValues: List<String>? = null,
1818
val separator: String? = null,
19+
val listItem: ApiItem? = null,
1920
)
2021

2122
private val myYaml = Yaml(

src/main/kotlin/it/krzeminski/githubactionstyping/validation/types/Boolean.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ fun ApiItem.validateBoolean(): ItemValidationResult {
1010
if (this.separator != null) {
1111
return ItemValidationResult.Invalid("'separator' is not allowed for this type.")
1212
}
13+
if (this.listItem != null) {
14+
return ItemValidationResult.Invalid("'listItem' is not allowed for this type.")
15+
}
1316

1417
return ItemValidationResult.Valid
1518
}

src/main/kotlin/it/krzeminski/githubactionstyping/validation/types/Enum.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ fun ApiItem.validateEnum(): ItemValidationResult {
1010
if (this.separator != null) {
1111
return ItemValidationResult.Invalid("'separator' is not allowed for this type.")
1212
}
13+
if (this.listItem != null) {
14+
return ItemValidationResult.Invalid("'listItem' is not allowed for this type.")
15+
}
1316
if (this.allowedValues.size < 2) {
1417
return ItemValidationResult.Invalid("There must be at least two allowed values.")
1518
}

src/main/kotlin/it/krzeminski/githubactionstyping/validation/types/Float.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ fun ApiItem.validateFloat(): ItemValidationResult {
1010
if (this.separator != null) {
1111
return ItemValidationResult.Invalid("'separator' is not allowed for this type.")
1212
}
13+
if (this.listItem != null) {
14+
return ItemValidationResult.Invalid("'listItem' is not allowed for this type.")
15+
}
1316

1417
return ItemValidationResult.Valid
1518
}

src/main/kotlin/it/krzeminski/githubactionstyping/validation/types/Integer.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ fun ApiItem.validateInteger(): ItemValidationResult {
1010
if (this.separator != null) {
1111
return ItemValidationResult.Invalid("'separator' is not allowed for this type.")
1212
}
13+
if (this.listItem != null) {
14+
return ItemValidationResult.Invalid("'listItem' is not allowed for this type.")
15+
}
1316

1417
return ItemValidationResult.Valid
1518
}

src/main/kotlin/it/krzeminski/githubactionstyping/validation/types/List.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,30 @@ package it.krzeminski.githubactionstyping.validation.types
22

33
import it.krzeminski.githubactionstyping.parsing.ApiItem
44
import it.krzeminski.githubactionstyping.validation.ItemValidationResult
5+
import it.krzeminski.githubactionstyping.validation.validate
56

67
fun ApiItem.validateList(): ItemValidationResult {
8+
if (this.listItem == null) {
9+
return ItemValidationResult.Invalid("List item information must be specified.")
10+
}
711
if (this.separator == null) {
812
return ItemValidationResult.Invalid("Separator must be specified.")
913
}
1014
if (this.allowedValues != null) {
1115
return ItemValidationResult.Invalid("'allowedValues' is not allowed for this type.")
1216
}
13-
14-
return ItemValidationResult.Valid
17+
return when (this.listItem.type) {
18+
"string" -> this.listItem.validateString()
19+
"boolean" -> this.listItem.validateBoolean()
20+
"integer" -> this.listItem.validateInteger()
21+
"float" -> this.listItem.validateFloat()
22+
"enum" -> this.listItem.validateEnum()
23+
"list" -> ItemValidationResult.Invalid("List can be parameterized only with a primitive or enum type.")
24+
else -> ItemValidationResult.Invalid("Unknown type: '${this.listItem.type}'.")
25+
}.let {
26+
when (it) {
27+
is ItemValidationResult.Invalid -> it.copy(message = "List item type: ${it.message}")
28+
ItemValidationResult.Valid -> it
29+
}
30+
}
1531
}

src/main/kotlin/it/krzeminski/githubactionstyping/validation/types/String.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ fun ApiItem.validateString(): ItemValidationResult {
1010
if (this.separator != null) {
1111
return ItemValidationResult.Invalid("'separator' is not allowed for this type.")
1212
}
13+
if (this.listItem != null) {
14+
return ItemValidationResult.Invalid("'listItem' is not allowed for this type.")
15+
}
1316

1417
return ItemValidationResult.Valid
1518
}

src/test/kotlin/it/krzeminski/githubactionstyping/validation/ManifestValidationTest.kt

Lines changed: 168 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,34 @@ class ManifestValidationTest : FunSpec({
6060
val manifest = Manifest(
6161
typingSpec = expectedTypingSpec,
6262
inputs = mapOf(
63-
"list-input" to ApiItem(type = "list", separator = "\n"),
63+
"list-of-strings-input" to ApiItem(
64+
type = "list",
65+
separator = "\n",
66+
listItem = ApiItem(type = "string"),
67+
),
68+
"list-of-booleans-input" to ApiItem(
69+
type = "list",
70+
separator = "\n",
71+
listItem = ApiItem(type = "boolean"),
72+
),
73+
"list-of-integers-input" to ApiItem(
74+
type = "list",
75+
separator = "\n",
76+
listItem = ApiItem(type = "integer"),
77+
),
78+
"list-of-floats-input" to ApiItem(
79+
type = "list",
80+
separator = "\n",
81+
listItem = ApiItem(type = "float"),
82+
),
83+
"list-of-enums-input" to ApiItem(
84+
type = "list",
85+
separator = "\n",
86+
listItem = ApiItem(
87+
type = "enum",
88+
allowedValues = listOf("foo", "bar")
89+
),
90+
),
6491
),
6592
)
6693

@@ -71,7 +98,11 @@ class ManifestValidationTest : FunSpec({
7198
result shouldBe ActionValidationResult(
7299
overallResult = ItemValidationResult.Valid,
73100
inputs = mapOf(
74-
"list-input" to ItemValidationResult.Valid,
101+
"list-of-strings-input" to ItemValidationResult.Valid,
102+
"list-of-booleans-input" to ItemValidationResult.Valid,
103+
"list-of-integers-input" to ItemValidationResult.Valid,
104+
"list-of-floats-input" to ItemValidationResult.Valid,
105+
"list-of-enums-input" to ItemValidationResult.Valid,
75106
),
76107
)
77108
}
@@ -229,6 +260,39 @@ class ManifestValidationTest : FunSpec({
229260
)
230261
}
231262

263+
test("non-list types with 'listItem' attribute") {
264+
// given
265+
val manifest = Manifest(
266+
typingSpec = expectedTypingSpec,
267+
inputs = mapOf(
268+
"string-input" to ApiItem(type = "string", listItem = ApiItem(type = "string")),
269+
"boolean-input" to ApiItem(type = "boolean", listItem = ApiItem(type = "string")),
270+
"integer-input" to ApiItem(type = "integer", listItem = ApiItem(type = "string")),
271+
"float-input" to ApiItem(type = "float", listItem = ApiItem(type = "string")),
272+
"enum-input" to ApiItem(
273+
type = "enum",
274+
allowedValues = listOf("foo", "bar"),
275+
listItem = ApiItem(type = "string"),
276+
),
277+
),
278+
)
279+
280+
// when
281+
val result = manifest.validate()
282+
283+
// then
284+
result shouldBe ActionValidationResult(
285+
overallResult = ItemValidationResult.Invalid("Some typing is invalid."),
286+
inputs = mapOf(
287+
"string-input" to ItemValidationResult.Invalid("'listItem' is not allowed for this type."),
288+
"boolean-input" to ItemValidationResult.Invalid("'listItem' is not allowed for this type."),
289+
"integer-input" to ItemValidationResult.Invalid("'listItem' is not allowed for this type."),
290+
"float-input" to ItemValidationResult.Invalid("'listItem' is not allowed for this type."),
291+
"enum-input" to ItemValidationResult.Invalid("'listItem' is not allowed for this type."),
292+
),
293+
)
294+
}
295+
232296
test("enum type with 'separator' attribute") {
233297
// given
234298
val manifest = Manifest(
@@ -292,12 +356,33 @@ class ManifestValidationTest : FunSpec({
292356
)
293357
}
294358

359+
test("list type without 'listItem' attribute") {
360+
// given
361+
val manifest = Manifest(
362+
typingSpec = expectedTypingSpec,
363+
inputs = mapOf(
364+
"list-input" to ApiItem(type = "list", separator = ","),
365+
),
366+
)
367+
368+
// when
369+
val result = manifest.validate()
370+
371+
// then
372+
result shouldBe ActionValidationResult(
373+
overallResult = ItemValidationResult.Invalid("Some typing is invalid."),
374+
inputs = mapOf(
375+
"list-input" to ItemValidationResult.Invalid("List item information must be specified."),
376+
),
377+
)
378+
}
379+
295380
test("list type without 'separator' attribute") {
296381
// given
297382
val manifest = Manifest(
298383
typingSpec = expectedTypingSpec,
299384
inputs = mapOf(
300-
"list-input" to ApiItem(type = "list"),
385+
"list-input" to ApiItem(type = "list", listItem = ApiItem(type = "string")),
301386
),
302387
)
303388

@@ -318,7 +403,12 @@ class ManifestValidationTest : FunSpec({
318403
val manifest = Manifest(
319404
typingSpec = expectedTypingSpec,
320405
inputs = mapOf(
321-
"list-input" to ApiItem(type = "list", separator = "\n", allowedValues = listOf("foo", "bar")),
406+
"list-input" to ApiItem(
407+
type = "list",
408+
separator = "\n",
409+
allowedValues = listOf("foo", "bar"),
410+
listItem = ApiItem(type = "string"),
411+
),
322412
),
323413
)
324414

@@ -333,5 +423,79 @@ class ManifestValidationTest : FunSpec({
333423
),
334424
)
335425
}
426+
427+
test("list type with forbidden list item type") {
428+
// given
429+
val manifest = Manifest(
430+
typingSpec = expectedTypingSpec,
431+
inputs = mapOf(
432+
"list-of-lists-input" to ApiItem(
433+
type = "list",
434+
separator = "\n",
435+
listItem = ApiItem(
436+
type = "list",
437+
separator = ",",
438+
listItem = ApiItem(type = "string"),
439+
),
440+
),
441+
),
442+
)
443+
444+
// when
445+
val result = manifest.validate()
446+
447+
// then
448+
result shouldBe ActionValidationResult(
449+
overallResult = ItemValidationResult.Invalid("Some typing is invalid."),
450+
inputs = mapOf(
451+
"list-of-lists-input" to ItemValidationResult.Invalid(
452+
"List item type: List can be parameterized only with a primitive or enum type.",
453+
),
454+
),
455+
)
456+
}
457+
458+
test("list type with list item type with incorrect attributes") {
459+
// given
460+
val manifest = Manifest(
461+
typingSpec = expectedTypingSpec,
462+
inputs = mapOf(
463+
"list-of-enums-without-allowed-values-input" to ApiItem(
464+
type = "list",
465+
separator = "\n",
466+
listItem = ApiItem(type = "enum"),
467+
),
468+
"list-of-integers-with-allowed-values-input" to ApiItem(
469+
type = "list",
470+
separator = "\n",
471+
listItem = ApiItem(type = "integer", allowedValues = listOf("foo", "bar")),
472+
),
473+
"list-of-unknown-type-input" to ApiItem(
474+
type = "list",
475+
separator = "\n",
476+
listItem = ApiItem(type = "for-sure-unknown-type"),
477+
),
478+
),
479+
)
480+
481+
// when
482+
val result = manifest.validate()
483+
484+
// then
485+
result shouldBe ActionValidationResult(
486+
overallResult = ItemValidationResult.Invalid("Some typing is invalid."),
487+
inputs = mapOf(
488+
"list-of-enums-without-allowed-values-input" to ItemValidationResult.Invalid(
489+
"List item type: Allowed values must be specified.",
490+
),
491+
"list-of-integers-with-allowed-values-input" to ItemValidationResult.Invalid(
492+
"List item type: 'allowedValues' is not allowed for this type."
493+
),
494+
"list-of-unknown-type-input" to ItemValidationResult.Invalid(
495+
"List item type: Unknown type: 'for-sure-unknown-type'."
496+
)
497+
),
498+
)
499+
}
336500
}
337501
})

0 commit comments

Comments
 (0)