@@ -389,6 +389,185 @@ defmodule ElixirLS.LanguageServer.Providers.ExecuteCommand.LlmDocsAggregatorTest
389389 assert String . contains? ( type_result . documentation , "An example type" )
390390 end
391391
392+ test "handles macro documentation with specs" do
393+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_macro/2" ]
394+
395+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
396+
397+ assert Map . has_key? ( result , :results )
398+ assert length ( result . results ) == 1
399+
400+ macro_result = hd ( result . results )
401+ assert macro_result . module == "ElixirSenseExample.ModuleWithDocs"
402+ assert macro_result . function == "some_macro"
403+ assert macro_result . arity == 2
404+ assert macro_result . documentation =~ "An example macro"
405+
406+ # Check that metadata is included (since: "1.1.0")
407+ assert macro_result . documentation =~ "Since"
408+ assert macro_result . documentation =~ "1.1.0"
409+ end
410+
411+ test "handles macro documentation without arity" do
412+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_macro" ]
413+
414+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
415+
416+ assert Map . has_key? ( result , :results )
417+ # Should find at least the some_macro/2 (from the fixture)
418+ assert length ( result . results ) >= 1
419+
420+ macro_result = result . results |> Enum . find ( & ( & 1 . arity == 2 ) )
421+ assert macro_result . module == "ElixirSenseExample.ModuleWithDocs"
422+ assert macro_result . function == "some_macro"
423+ assert macro_result . arity == 2
424+ assert macro_result . documentation =~ "An example macro"
425+ end
426+
427+ test "handles macrocallback documentation with arity" do
428+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_macrocallback/1" ]
429+
430+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
431+
432+ assert Map . has_key? ( result , :results )
433+ assert length ( result . results ) == 1
434+
435+ macrocallback_result = hd ( result . results )
436+ assert macrocallback_result . module == "ElixirSenseExample.ModuleWithDocs"
437+ assert macrocallback_result . callback == "some_macrocallback"
438+ assert macrocallback_result . arity == 1
439+ assert macrocallback_result . documentation =~ "An example callback"
440+
441+ # Check that we got the documentation (metadata may be formatted differently for callbacks)
442+ assert macrocallback_result . documentation
443+ end
444+
445+ test "handles macrocallback documentation without arity" do
446+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_macrocallback" ]
447+
448+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
449+
450+ assert Map . has_key? ( result , :results )
451+ assert length ( result . results ) >= 1
452+
453+ macrocallback_result = result . results |> Enum . find ( & ( & 1 . arity == 1 ) )
454+ assert macrocallback_result . module == "ElixirSenseExample.ModuleWithDocs"
455+ assert macrocallback_result . callback == "some_macrocallback"
456+ assert macrocallback_result . arity == 1
457+ assert macrocallback_result . documentation =~ "An example callback"
458+ end
459+
460+ test "verifies macro and macrocallback specs are included" do
461+ # Test callback spec
462+ assert { :ok , result } = LlmDocsAggregator . execute ( [ [ "ElixirSenseExample.ModuleWithDocs.some_callback/1" ] ] , % { } )
463+ assert Map . has_key? ( result , :results )
464+ assert length ( result . results ) == 1
465+
466+ callback_result = hd ( result . results )
467+ assert Map . has_key? ( callback_result , :spec )
468+ assert Map . has_key? ( callback_result , :kind )
469+ assert Map . has_key? ( callback_result , :metadata )
470+ assert callback_result . spec == "@callback some_callback(integer()) :: atom()"
471+ assert callback_result . kind == :callback
472+ assert callback_result . metadata . since == "1.1.0"
473+
474+ # Test macrocallback spec
475+ assert { :ok , result } = LlmDocsAggregator . execute ( [ [ "ElixirSenseExample.ModuleWithDocs.some_macrocallback/1" ] ] , % { } )
476+ assert Map . has_key? ( result , :results )
477+ assert length ( result . results ) == 1
478+
479+ macrocallback_result = hd ( result . results )
480+ assert Map . has_key? ( macrocallback_result , :spec )
481+ assert Map . has_key? ( macrocallback_result , :kind )
482+ assert Map . has_key? ( macrocallback_result , :metadata )
483+ assert macrocallback_result . spec == "@macrocallback some_macrocallback(integer()) :: atom()"
484+ assert macrocallback_result . kind == :macrocallback
485+ assert macrocallback_result . metadata . since == "1.1.0"
486+ end
487+
488+ test "verifies function documentation contains specs" do
489+ # Test with ElixirSenseExample.ModuleWithDocs.some_fun/2 which has a @spec
490+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_fun/2" ]
491+
492+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
493+
494+ assert Map . has_key? ( result , :results )
495+ assert length ( result . results ) == 1
496+
497+ func_result = hd ( result . results )
498+ assert func_result . module == "ElixirSenseExample.ModuleWithDocs"
499+ assert func_result . function == "some_fun"
500+ assert func_result . arity == 2
501+ assert func_result . documentation =~ "An example fun"
502+
503+ # Verify that specs are included in the documentation
504+ assert func_result . documentation =~ "**Specs:**"
505+ assert func_result . documentation =~ "@spec some_fun"
506+ assert func_result . documentation =~ "```elixir"
507+ assert func_result . documentation =~ "integer()"
508+ end
509+
510+ test "verifies macro documentation contains specs" do
511+ # Test with ElixirSenseExample.ModuleWithDocs.some_macro/2 which has a @spec
512+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_macro/2" ]
513+
514+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
515+
516+ assert Map . has_key? ( result , :results )
517+ assert length ( result . results ) == 1
518+
519+ macro_result = hd ( result . results )
520+ assert macro_result . module == "ElixirSenseExample.ModuleWithDocs"
521+ assert macro_result . function == "some_macro"
522+ assert macro_result . arity == 2
523+ assert macro_result . documentation =~ "An example macro"
524+
525+ # Verify that specs are included in the macro documentation
526+ assert macro_result . documentation =~ "**Specs:**"
527+ assert macro_result . documentation =~ "@spec some_macro"
528+ assert macro_result . documentation =~ "```elixir"
529+ assert macro_result . documentation =~ "Macro.t()"
530+ end
531+
532+ test "verifies function specs are properly formatted" do
533+ # Test function without arity to get all arities
534+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_fun" ]
535+
536+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
537+
538+ assert Map . has_key? ( result , :results )
539+ assert length ( result . results ) >= 1
540+
541+ # Find the result with arity 2 (which has specs)
542+ func_result = Enum . find ( result . results , & ( & 1 . arity == 2 ) )
543+ assert func_result
544+
545+ # Verify spec formatting
546+ assert func_result . documentation =~ "**Specs:**"
547+ assert func_result . documentation =~ "```elixir"
548+ assert func_result . documentation =~ "@spec some_fun(integer(), integer() | nil) :: integer()"
549+ end
550+
551+ test "verifies macro specs are properly formatted" do
552+ # Test macro without arity to get all arities
553+ modules = [ "ElixirSenseExample.ModuleWithDocs.some_macro" ]
554+
555+ assert { :ok , result } = LlmDocsAggregator . execute ( [ modules ] , % { } )
556+
557+ assert Map . has_key? ( result , :results )
558+ assert length ( result . results ) >= 1
559+
560+ # Find the result with arity 2 (which has specs)
561+ macro_result = Enum . find ( result . results , & ( & 1 . arity == 2 ) )
562+ assert macro_result
563+
564+ # Verify spec formatting for macro
565+ assert macro_result . documentation =~ "**Specs:**"
566+ assert macro_result . documentation =~ "```elixir"
567+ assert macro_result . documentation =~ "@spec some_macro(Macro.t(), Macro.t() | nil) :: Macro.t()"
568+ end
569+
570+
392571 test "returns error for invalid arguments" do
393572 # Test with non-list argument
394573 assert { :ok , result } = LlmDocsAggregator . execute ( "String" , % { } )
0 commit comments