@@ -194,5 +194,218 @@ def test_use_consumable_no_consumables_available(
194194 )
195195
196196
197- # TODO: add test for other types of consumables
198- class TestUseConsumableOtherType : ...
197+ class TestUseConsumableWithCards :
198+ """Test use_consumable with cards parameter for consumables that target specific cards."""
199+
200+ @pytest .fixture (autouse = True )
201+ def setup_and_teardown (
202+ self , tcp_client : socket .socket
203+ ) -> Generator [dict , None , None ]:
204+ # Start a run and get to SELECTING_HAND state with a consumable
205+ send_and_receive_api_message (
206+ tcp_client ,
207+ "start_run" ,
208+ {
209+ "deck" : "Red Deck" ,
210+ "stake" : 1 ,
211+ "seed" : "TEST123" ,
212+ },
213+ )
214+ send_and_receive_api_message (
215+ tcp_client , "skip_or_select_blind" , {"action" : "select" }
216+ )
217+
218+ # Play a hand to get to shop
219+ send_and_receive_api_message (
220+ tcp_client ,
221+ "play_hand_or_discard" ,
222+ {"action" : "play_hand" , "cards" : [0 , 1 , 2 , 3 ]},
223+ )
224+ send_and_receive_api_message (tcp_client , "cash_out" , {})
225+
226+ # Buy a consumable
227+ send_and_receive_api_message (
228+ tcp_client ,
229+ "shop" ,
230+ {"action" : "buy_card" , "index" : 2 },
231+ )
232+
233+ # Start next round to get back to SELECTING_HAND state
234+ send_and_receive_api_message (tcp_client , "shop" , {"action" : "next_round" })
235+ game_state = send_and_receive_api_message (
236+ tcp_client , "skip_or_select_blind" , {"action" : "select" }
237+ )
238+
239+ yield game_state
240+ send_and_receive_api_message (tcp_client , "go_to_menu" , {})
241+
242+ def test_use_consumable_with_cards_success (
243+ self , tcp_client : socket .socket , setup_and_teardown
244+ ) -> None :
245+ """Test successfully using a consumable with specific cards selected."""
246+ game_state = setup_and_teardown
247+
248+ # Verify we're in SELECTING_HAND state
249+ assert game_state ["state" ] == State .SELECTING_HAND .value
250+
251+ # Skip test if no consumables available
252+ if len (game_state ["consumables" ]["cards" ]) == 0 :
253+ pytest .skip ("No consumables available in this test run" )
254+
255+ # Use the consumable with specific cards selected
256+ response = send_and_receive_api_message (
257+ tcp_client ,
258+ "use_consumable" ,
259+ {"index" : 0 , "cards" : [0 , 2 , 4 ]}, # Select cards 0, 2, and 4
260+ )
261+
262+ # Verify response is successful
263+ assert "error" not in response
264+
265+ def test_use_consumable_with_invalid_cards (
266+ self , tcp_client : socket .socket , setup_and_teardown
267+ ) -> None :
268+ """Test using consumable with invalid card indices."""
269+ game_state = setup_and_teardown
270+
271+ # Skip test if no consumables available
272+ if len (game_state ["consumables" ]["cards" ]) == 0 :
273+ pytest .skip ("No consumables available in this test run" )
274+
275+ # Try to use consumable with out-of-range card indices
276+ response = send_and_receive_api_message (
277+ tcp_client ,
278+ "use_consumable" ,
279+ {"index" : 0 , "cards" : [99 , 100 ]}, # Invalid card indices
280+ )
281+ assert_error_response (
282+ response ,
283+ "Invalid card index" ,
284+ expected_error_code = ErrorCode .INVALID_CARD_INDEX .value ,
285+ )
286+
287+ def test_use_consumable_with_too_many_cards (
288+ self , tcp_client : socket .socket , setup_and_teardown
289+ ) -> None :
290+ """Test using consumable with more than 5 cards."""
291+ game_state = setup_and_teardown
292+
293+ # Skip test if no consumables available
294+ if len (game_state ["consumables" ]["cards" ]) == 0 :
295+ pytest .skip ("No consumables available in this test run" )
296+
297+ # Try to use consumable with more than 5 cards
298+ response = send_and_receive_api_message (
299+ tcp_client ,
300+ "use_consumable" ,
301+ {"index" : 0 , "cards" : [0 , 1 , 2 , 3 , 4 , 5 ]}, # 6 cards - too many
302+ )
303+ assert_error_response (
304+ response ,
305+ "Invalid number of cards" ,
306+ expected_error_code = ErrorCode .PARAMETER_OUT_OF_RANGE .value ,
307+ )
308+
309+ def test_use_consumable_with_empty_cards (
310+ self , tcp_client : socket .socket , setup_and_teardown
311+ ) -> None :
312+ """Test using consumable with empty cards array."""
313+ game_state = setup_and_teardown
314+
315+ # Skip test if no consumables available
316+ if len (game_state ["consumables" ]["cards" ]) == 0 :
317+ pytest .skip ("No consumables available in this test run" )
318+
319+ # Try to use consumable with empty cards array
320+ response = send_and_receive_api_message (
321+ tcp_client ,
322+ "use_consumable" ,
323+ {"index" : 0 , "cards" : []}, # Empty array
324+ )
325+ assert_error_response (
326+ response ,
327+ "Invalid number of cards" ,
328+ expected_error_code = ErrorCode .PARAMETER_OUT_OF_RANGE .value ,
329+ )
330+
331+ def test_use_consumable_with_invalid_cards_type (
332+ self , tcp_client : socket .socket , setup_and_teardown
333+ ) -> None :
334+ """Test using consumable with non-array cards parameter."""
335+ game_state = setup_and_teardown
336+
337+ # Skip test if no consumables available
338+ if len (game_state ["consumables" ]["cards" ]) == 0 :
339+ pytest .skip ("No consumables available in this test run" )
340+
341+ # Try to use consumable with invalid cards type
342+ response = send_and_receive_api_message (
343+ tcp_client ,
344+ "use_consumable" ,
345+ {"index" : 0 , "cards" : "invalid" }, # Not an array
346+ )
347+ assert_error_response (
348+ response ,
349+ "Invalid parameter type" ,
350+ expected_error_code = ErrorCode .INVALID_PARAMETER .value ,
351+ )
352+
353+ def test_use_planet_without_cards (
354+ self , tcp_client : socket .socket , setup_and_teardown
355+ ) -> None :
356+ """Test that planet consumables still work without cards parameter."""
357+ game_state = setup_and_teardown
358+
359+ # Skip test if no consumables available
360+ if len (game_state ["consumables" ]["cards" ]) == 0 :
361+ pytest .skip ("No consumables available in this test run" )
362+
363+ # Use consumable without cards parameter (original behavior)
364+ response = send_and_receive_api_message (
365+ tcp_client ,
366+ "use_consumable" ,
367+ {"index" : 0 }, # No cards parameter
368+ )
369+
370+ # Should still work for consumables that don't need cards
371+ assert "error" not in response
372+
373+ def test_use_consumable_with_cards_wrong_state (
374+ self , tcp_client : socket .socket
375+ ) -> None :
376+ """Test that using consumable with cards fails in non-SELECTING_HAND states."""
377+ # Start a run and get to shop state
378+ send_and_receive_api_message (
379+ tcp_client ,
380+ "start_run" ,
381+ {"deck" : "Red Deck" , "stake" : 1 , "seed" : "OOOO155" },
382+ )
383+ send_and_receive_api_message (
384+ tcp_client , "skip_or_select_blind" , {"action" : "select" }
385+ )
386+ send_and_receive_api_message (
387+ tcp_client ,
388+ "play_hand_or_discard" ,
389+ {"action" : "play_hand" , "cards" : [0 , 1 , 2 , 3 ]},
390+ )
391+ send_and_receive_api_message (tcp_client , "cash_out" , {})
392+ game_state = send_and_receive_api_message (
393+ tcp_client ,
394+ "shop" ,
395+ {"action" : "buy_card" , "index" : 1 },
396+ )
397+
398+ # Verify we're in SHOP state
399+ assert game_state ["state" ] == State .SHOP .value
400+
401+ # Try to use consumable with cards while in SHOP state (should fail)
402+ response = send_and_receive_api_message (
403+ tcp_client , "use_consumable" , {"index" : 0 , "cards" : [0 , 1 , 2 ]}
404+ )
405+ assert_error_response (
406+ response ,
407+ "Cannot use consumable with cards when not in selecting hand state" ,
408+ expected_error_code = ErrorCode .INVALID_GAME_STATE .value ,
409+ )
410+
411+ send_and_receive_api_message (tcp_client , "go_to_menu" , {})
0 commit comments