11/*
2- * Copyright 2022-2025 Björn Kautler
2+ * Copyright 2022-2026 Björn Kautler
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -51,6 +51,8 @@ class SlashCommandBuilderProducerTest extends Specification {
5151
5252 SlashCommandJavacord command7 = Stub ()
5353
54+ SlashCommandJavacord command8 = Stub ()
55+
5456 @WeldSetup
5557 def weld = WeldInitiator
5658 .from(SlashCommandBuilderProducer )
@@ -89,6 +91,11 @@ class SlashCommandBuilderProducerTest extends Specification {
8991 .scope(ApplicationScoped )
9092 .types(SlashCommandJavacord )
9193 .creating(command7)
94+ .build(),
95+ MockBean . builder()
96+ .scope(ApplicationScoped )
97+ .types(SlashCommandJavacord )
98+ .creating(command8)
9299 .build()
93100 )
94101 .inject(this )
@@ -100,34 +107,39 @@ class SlashCommandBuilderProducerTest extends Specification {
100107 def prepareCommands () {
101108 command1. with {
102109 it. aliases >> [' foo/bar1/test1' ]
103- it. description >> [ ' The command foo/bar1/test1' ]
110+ it. description >> Optional . of( ' The command foo/bar1/test1' )
104111 it. options >> [createStringOption(' foo-bar1-test1-option' , ' The foo/bar1/test1 option' , false )]
105112 }
106113 command2. with {
107114 it. aliases >> [' foo/bar1/test2' ]
108- it. description >> [ ' The command foo/bar1/test2' ]
115+ it. description >> Optional . of( ' The command foo/bar1/test2' )
109116 }
110117 command3. with {
111118 it. aliases >> [' foo/bar2/test1' ]
112- it. description >> [ ' The command foo/bar2/test1' ]
119+ it. description >> Optional . of( ' The command foo/bar2/test1' )
113120 }
114121 command4. with {
115122 it. aliases >> [' foo/bar2/test2' ]
116- it. description >> [ ' The command foo/bar2/test2' ]
123+ it. description >> Optional . of( ' The command foo/bar2/test2' )
117124 }
118125 command5. with {
119126 it. aliases >> [' foo/test1' ]
120- it. description >> [ ' The command foo/test1' ]
127+ it. description >> Optional . of( ' The command foo/test1' )
121128 it. options >> [createStringOption(' foo-test1-option' , ' The foo/test1 option' , true )]
122129 }
123130 command6. with {
124131 it. aliases >> [' foo/test2' ]
125- it. description >> [ ' The command foo/test2' ]
132+ it. description >> Optional . of( ' The command foo/test2' )
126133 }
127134 command7. with {
128- it. aliases >> [' bar' ]
129- it. description >> [' The command bar' ]
130- it. options >> [createStringOption(' bar-option' , ' The bar option' , false )]
135+ it. aliases >> [' bar/baz' ]
136+ it. description >> Optional . of(' The command bar/baz' )
137+ it. options >> [createStringOption(' bar-baz-option' , ' The bar/baz option' , false )]
138+ }
139+ command8. with {
140+ it. aliases >> [' bam' ]
141+ it. description >> Optional . of(' The command bam' )
142+ it. options >> [createStringOption(' bam-option' , ' The bam option' , false )]
131143 }
132144 }
133145
@@ -139,8 +151,8 @@ class SlashCommandBuilderProducerTest extends Specification {
139151 def slashCommandBuilders = slashCommandBuilders. get()
140152
141153 then :
142- slashCommandBuilders. size() == 2
143- slashCommandBuilders* . delegate* . name ==~ [' bar' , ' foo' ]
154+ slashCommandBuilders. size() == 3
155+ slashCommandBuilders* . delegate* . name ==~ [' bar' , ' bam ' , ' foo' ]
144156 with(slashCommandBuilders. find { it. delegate. name == ' foo' }) {
145157 with(it. delegate) {
146158 it. options. size() == 4
@@ -199,11 +211,27 @@ class SlashCommandBuilderProducerTest extends Specification {
199211 }
200212 with(slashCommandBuilders. find { it. delegate. name == ' bar' }) {
201213 with(it. delegate) {
202- it. description == ' The command bar'
214+ it. options. size() == 1
215+ it. options* . name == [' baz' ]
216+ with(it. options. find { it. name == ' baz' }) {
217+ it. type == SUB_COMMAND
218+ it. description == ' The command bar/baz'
219+ it. options. size() == 1
220+ with(it. options. first()) {
221+ it. name == ' bar-baz-option'
222+ it. description == ' The bar/baz option'
223+ ! it. required
224+ }
225+ }
226+ }
227+ }
228+ with(slashCommandBuilders. find { it. delegate. name == ' bam' }) {
229+ with(it. delegate) {
230+ it. description == ' The command bam'
203231 it. options. size() == 1
204232 with(it. options. first()) {
205- it. name == ' bar -option'
206- it. description == ' The bar option'
233+ it. name == ' bam -option'
234+ it. description == ' The bam option'
207235 ! it. required
208236 }
209237 }
@@ -232,7 +260,8 @@ class SlashCommandBuilderProducerTest extends Specification {
232260 ' command4' | ''' subcommand 'foo/bar2/test2\' '''
233261 ' command5' | ''' subcommand 'foo/test1\' '''
234262 ' command6' | ''' subcommand 'foo/test2\' '''
235- ' command7' | ''' command 'bar\' '''
263+ ' command7' | ''' subcommand 'bar/baz\' '''
264+ ' command8' | ''' command 'bam\' '''
236265 }
237266
238267 @Use (ContextualInstanceCategory )
@@ -249,4 +278,18 @@ class SlashCommandBuilderProducerTest extends Specification {
249278 ise. message == ' Alias must be one, two, or three slash-separated parts for command, ' +
250279 ''' subcommand group and subcommand, but alias 'a/b/c/d' has 4 parts'''
251280 }
281+
282+ @Use (ContextualInstanceCategory )
283+ def ' should throw exception if top-level command has also subcommands' () {
284+ given :
285+ command8. aliases >> [' bar' ]
286+ prepareCommands()
287+
288+ when :
289+ slashCommandBuilders. get(). ci()
290+
291+ then :
292+ IllegalStateException ise = thrown()
293+ ise. message == ''' Top-level command 'bar' cannot have subcommands / subcommand groups'''
294+ }
252295}
0 commit comments