@@ -261,12 +261,9 @@ defmodule ExUnit.DocTest do
261261 file = Path . relative_to_cwd ( file )
262262 tags = [ doctest: file ] ++ Keyword . get ( opts , :tags , [ ] )
263263
264- extract_tests ( 1 , doc , module )
265- |> Stream . map ( & normalize_test ( & 1 , :moduledoc ) )
266- |> Stream . with_index ( 1 )
267- |> Enum . map ( fn { test , acc } ->
268- tags = [ doctest_line: test . line ] ++ tags
269- { "#{ file } (#{ acc } )" , test_content ( test , module , false , file ) , tags }
264+ extract_tests ( 1 , doc , module , :moduledoc )
265+ |> Enum . with_index ( fn test , acc ->
266+ { "#{ file } (#{ acc + 1 } )" , test_content ( test , module , false , file ) , test_tags ( test , tags ) }
270267 end )
271268 end
272269
@@ -336,8 +333,8 @@ defmodule ExUnit.DocTest do
336333 ## Compilation of extracted tests
337334
338335 defp compile_test ( test , module , do_import , n , file , tags ) do
339- tags = [ doctest_line: test . line ] ++ tags
340- { test_name ( test , module , n ) , test_content ( test , module , do_import , file ) , tags }
336+ { test_name ( test , module , n ) , test_content ( test , module , do_import , file ) ,
337+ test_tags ( test , tags ) }
341338 end
342339
343340 defp test_name ( % { fun_arity: :moduledoc } , m , n ) do
@@ -369,6 +366,10 @@ defmodule ExUnit.DocTest do
369366 { :__block__ , [ ] , test_import ( module , do_import ) ++ tests }
370367 end
371368
369+ defp test_tags ( test , tags ) do
370+ [ doctest_line: test . line ] ++ tags
371+ end
372+
372373 defp multiple_exceptions? ( exprs ) do
373374 Enum . count ( exprs , fn
374375 { _ , { :error , _ , _ } , _ } -> true
@@ -575,9 +576,7 @@ defmodule ExUnit.DocTest do
575576 do: "The documentation chunk in the module is invalid"
576577
577578 defp extract_from_moduledoc ( annotation , % { "en" => doc } , module ) do
578- for test <- extract_tests ( :erl_anno . line ( annotation ) , doc , module ) do
579- normalize_test ( test , :moduledoc )
580- end
579+ extract_tests ( :erl_anno . line ( annotation ) , doc , module , :moduledoc )
581580 end
582581
583582 defp extract_from_moduledoc ( _ , _doc , _module ) , do: [ ]
@@ -588,10 +587,7 @@ defmodule ExUnit.DocTest do
588587
589588 defp extract_from_doc ( { { _ , name , arity } , annotation , _ , % { "en" => doc } , _ } , module ) do
590589 line = :erl_anno . line ( annotation )
591-
592- for test <- extract_tests ( line , doc , module ) do
593- normalize_test ( test , { name , arity } )
594- end
590+ extract_tests ( line , doc , module , { name , arity } )
595591 end
596592
597593 defp extract_from_doc ( _doc , _module ) ,
@@ -648,7 +644,7 @@ defmodule ExUnit.DocTest do
648644 """
649645 end
650646
651- adjusted_lines = [ { stripped_line , line_no } | adjusted_lines ]
647+ adjusted_lines = [ { adjust_prompt ( stripped_line , line_no , module ) , line_no } | adjusted_lines ]
652648
653649 next =
654650 cond do
@@ -694,210 +690,118 @@ defmodule ExUnit.DocTest do
694690 end
695691 end
696692
697- @ fences [ "```" , "~~~" ]
693+ defp adjust_prompt ( "iex(" <> rest = line , line_no , module ) ,
694+ do: "iex>" <> skip_iex_number ( rest , line_no , module , line )
698695
699- defp extract_tests ( line_no , doc , module ) do
700- all_lines = String . split ( doc , [ "\r \n " , "\n " ] , trim: false )
701- lines = adjust_indent ( all_lines , line_no + 1 , module )
702- extract_tests ( lines , [ ] , [ ] , [ ] , true , module , [ ] )
703- end
696+ defp adjust_prompt ( "...(" <> rest = line , line_no , module ) ,
697+ do: "...>" <> skip_iex_number ( rest , line_no , module , line )
704698
705- defp extract_tests ( lines , expr_acc , expected_acc , acc , new_test , module , formatted )
699+ defp adjust_prompt ( line , _line_no , _module ) ,
700+ do: line
706701
707- defp extract_tests ( [ ] , [ ] , [ ] , [ ] , _ , _ , _ ) do
708- [ ]
709- end
702+ defp skip_iex_number ( string , line_no , module , line ) do
703+ case :binary . split ( string , ")>" ) do
704+ [ _pre , post ] ->
705+ post
710706
711- defp extract_tests ( [ ] , [ ] , [ ] , acc , _ , _ , _ ) do
712- Enum . reverse ( acc )
713- end
707+ [ _ ] ->
708+ message =
709+ "unknown IEx prompt: #{ inspect ( line ) } . \n Accepted formats are: iex>, iex(1)>, ...>, ...(1)>}"
714710
715- # End of input and we've still got a test pending.
716- defp extract_tests ( [ ] , expr_acc , expected_acc , [ test | rest ] , _ , _ , formatted ) do
717- test = add_expr ( test , expr_acc , expected_acc , formatted )
718- Enum . reverse ( [ test | rest ] )
711+ raise Error , line: line_no , module: module , message: message
712+ end
719713 end
720714
721- # We've encountered the next test on an adjacent line. Put them into one group.
722- defp extract_tests (
723- [ { "iex>" <> _ , _ } | _ ] = list ,
724- expr_acc ,
725- expected_acc ,
726- [ test | rest ] ,
727- new_test ,
728- module ,
729- formatted
730- )
731- when expr_acc != [ ] and expected_acc != [ ] do
732- test = add_expr ( test , expr_acc , expected_acc , formatted )
733- extract_tests ( list , [ ] , [ ] , [ test | rest ] , new_test , module , [ ] )
734- end
735-
736- # Store expr_acc and start a new test case.
737- defp extract_tests (
738- [ { "iex>" <> string = line , line_no } | lines ] ,
739- [ ] ,
740- expected_acc ,
741- acc ,
742- true ,
743- module ,
744- _
745- ) do
746- test = % { line: line_no , fun_arity: nil , exprs: [ ] }
747- extract_tests ( lines , [ string ] , expected_acc , [ test | acc ] , false , module , line )
715+ defp chunk_tests ( lines , acc ) do
716+ case lines
717+ |> Enum . drop_while ( & ( not test_started? ( & 1 ) ) )
718+ |> Enum . split_while ( & ( not test_finished? ( & 1 ) ) ) do
719+ { [ ] , [ ] } -> Enum . reverse ( acc )
720+ { test , [ ] } -> Enum . reverse ( [ test | acc ] )
721+ { [ ] , [ _empty_line | lines ] } -> chunk_tests ( lines , acc )
722+ { test , [ _empty_line | lines ] } -> chunk_tests ( lines , [ test | acc ] )
723+ end
748724 end
749725
750- # Store expr_acc.
751- defp extract_tests (
752- [ { "iex>" <> string = line , _ } | lines ] ,
753- [ ] ,
754- expected_acc ,
755- acc ,
756- false ,
757- module ,
758- _
759- ) do
760- extract_tests ( lines , [ string ] , expected_acc , acc , false , module , line )
761- end
726+ defp test_started? ( { "iex>" <> _ , _ } ) , do: true
727+ defp test_started? ( _ ) , do: false
762728
763- # Still gathering expr_acc. Synonym for the next clause.
764- defp extract_tests (
765- [ { "iex>" <> string = line , _ } | lines ] ,
766- expr_acc ,
767- expected_acc ,
768- acc ,
769- new_test ,
770- module ,
771- formatted
772- ) do
773- expr_acc = add_line ( expr_acc , string )
774- formatted = add_line ( formatted , line )
775- extract_tests ( lines , expr_acc , expected_acc , acc , new_test , module , formatted )
729+ defp test_finished? ( { line , _ } ) do
730+ case line do
731+ "" -> true
732+ "```" <> _ -> true
733+ "~~~" <> _ -> true
734+ _ -> false
735+ end
776736 end
777737
778- # Still gathering expr_acc. Synonym for the previous clause.
779- defp extract_tests (
780- [ { "...>" <> string = line , _ } | lines ] ,
781- expr_acc ,
782- expected_acc ,
783- acc ,
784- new_test ,
785- module ,
786- formatted
787- )
788- when expr_acc != [ ] do
789- expr_acc = add_line ( expr_acc , string )
790- formatted = add_line ( formatted , line )
791- extract_tests ( lines , expr_acc , expected_acc , acc , new_test , module , formatted )
792- end
793-
794- # Expression numbers are simply skipped.
795- defp extract_tests (
796- [ { << "iex(" , _ >> <> string = line , line_no } | lines ] ,
797- expr_acc ,
798- expected_acc ,
799- acc ,
800- new_test ,
801- module ,
802- formatted
803- ) do
804- new_line = { "iex" <> skip_iex_number ( string , module , line_no , line ) , line_no }
805- extract_tests ( [ new_line | lines ] , expr_acc , expected_acc , acc , new_test , module , formatted )
806- end
807-
808- # Expression numbers are simply skipped redux.
809- defp extract_tests (
810- [ { << "...(" , _ >> <> string , line_no } = line | lines ] ,
811- expr_acc ,
812- expected_acc ,
813- acc ,
814- new_test ,
815- module ,
816- formatted
817- ) do
818- new_line = { "..." <> skip_iex_number ( string , module , line_no , line ) , line_no }
819- extract_tests ( [ new_line | lines ] , expr_acc , expected_acc , acc , new_test , module , formatted )
820- end
821-
822- # Skip empty or documentation line.
823- defp extract_tests ( [ _ | lines ] , [ ] , [ ] , acc , _ , module , _formatted ) do
824- extract_tests ( lines , [ ] , [ ] , acc , true , module , [ ] )
825- end
826-
827- # Encountered end of fenced code block, store pending test
828- defp extract_tests (
829- [ { << fence :: 3 - bytes >> <> _ , _ } | lines ] ,
830- expr_acc ,
831- expected_acc ,
832- [ test | rest ] ,
833- _new_test ,
834- module ,
835- formatted
836- )
837- when fence in @ fences and expr_acc != [ ] do
838- test = add_expr ( test , expr_acc , expected_acc , formatted )
839- extract_tests ( lines , [ ] , [ ] , [ test | rest ] , true , module , [ ] )
840- end
841-
842- # Encountered an empty line, store pending test
843- defp extract_tests (
844- [ { "" , _ } | lines ] ,
845- expr_acc ,
846- expected_acc ,
847- [ test | rest ] ,
848- _new_test ,
849- module ,
850- formatted
851- ) do
852- test = add_expr ( test , expr_acc , expected_acc , formatted )
853- extract_tests ( lines , [ ] , [ ] , [ test | rest ] , true , module , [ ] )
738+ defp extract_tests ( line_no , doc , module , fun_arity ) do
739+ doc
740+ |> String . split ( [ "\r \n " , "\n " ] , trim: false )
741+ |> adjust_indent ( line_no + 1 , module )
742+ |> chunk_tests ( [ ] )
743+ |> Enum . map ( & build_test ( & 1 , fun_arity ) )
854744 end
855745
856- # Finally, parse expected_acc.
857- defp extract_tests ( [ { expected , _ } | lines ] , expr_acc , [ ] , acc , new_test , module , formatted ) do
858- extract_tests ( lines , expr_acc , expected , acc , new_test , module , formatted )
746+ defp build_test ( [ { _ , line_no } | _ ] = lines , fun_arity ) do
747+ exprs = build_test ( lines , [ ] , [ ] , [ ] , [ ] )
748+ % { line: line_no , exprs: Enum . reverse ( exprs ) , fun_arity: fun_arity }
859749 end
860750
861- defp extract_tests (
862- [ { expected , _ } | lines ] ,
863- expr_acc ,
864- expected_acc ,
865- acc ,
866- new_test ,
867- module ,
868- formatted
869- ) do
870- expected_acc = add_line ( expected_acc , expected )
871- extract_tests ( lines , expr_acc , expected_acc , acc , new_test , module , formatted )
751+ defp build_test ( [ ] , [ _ | _ ] = expr , expected , formatted , acc ) do
752+ add_expr ( acc , expr , expected , formatted )
872753 end
873754
874- defp add_line ( acc , line ) do
875- [ acc , [ ?\n , line ] ]
755+ # Tidy up the previous expression before starting a new one.
756+ defp build_test (
757+ [ { "iex>" <> _ , _ } | _ ] = list ,
758+ [ _ | _ ] = expr ,
759+ [ _ | _ ] = expected ,
760+ formatted ,
761+ acc
762+ ) do
763+ acc = add_expr ( acc , expr , expected , formatted )
764+ build_test ( list , [ ] , [ ] , [ ] , acc )
876765 end
877766
878- defp skip_iex_number ( ")>" <> string , _module , _line_no , _line ) do
879- ">" <> string
767+ # We start a new expression.
768+ defp build_test (
769+ [ { "iex>" <> string = line , _ } | lines ] ,
770+ expr ,
771+ expected ,
772+ formatted ,
773+ acc
774+ ) do
775+ expr = add_line ( expr , string )
776+ formatted = add_line ( formatted , line )
777+ build_test ( lines , expr , expected , formatted , acc )
880778 end
881779
882- defp skip_iex_number ( "" , module , line_no , line ) do
883- message =
884- "unknown IEx prompt: #{ inspect ( line ) } .\n Accepted formats are: iex>, iex(1)>, ...>, ...(1)>}"
885-
886- raise Error , line: line_no , module: module , message: message
780+ # Continuation of an expression.
781+ defp build_test (
782+ [ { "...>" <> string = line , _ } | lines ] ,
783+ expr ,
784+ expected ,
785+ formatted ,
786+ acc
787+ ) do
788+ expr = add_line ( expr , string )
789+ formatted = add_line ( formatted , line )
790+ build_test ( lines , expr , expected , formatted , acc )
887791 end
888792
889- defp skip_iex_number ( << _ >> <> string , module , line_no , line ) do
890- skip_iex_number ( string , module , line_no , line )
793+ # Otherwise, it is expected lines.
794+ defp build_test ( [ { line , _ } | lines ] , expr , expected , formatted , acc ) do
795+ build_test ( lines , expr , add_line ( expected , line ) , formatted , acc )
891796 end
892797
893- defp normalize_test ( % { exprs: exprs } = test , fa ) do
894- % { test | fun_arity: fa , exprs: Enum . reverse ( exprs ) }
895- end
798+ defp add_line ( [ ] , line ) , do: [ line ]
799+ defp add_line ( acc , line ) , do: [ acc , [ ?\n , line ] ]
896800
897- defp add_expr ( % { exprs: exprs } = test , expr_lines , expected_lines , formatted_lines ) do
801+ defp add_expr ( exprs , expr_lines , expected_lines , formatted_lines ) do
898802 expected = IO . iodata_to_binary ( expected_lines )
899803 doctest = IO . iodata_to_binary ( [ ?\n , formatted_lines , ?\n , expected ] )
900- % { test | exprs: [ { expr_lines , tag_expected ( expected ) , doctest } | exprs ] }
804+ [ { expr_lines , tag_expected ( expected ) , doctest } | exprs ]
901805 end
902806
903807 defp tag_expected ( expected ) do
0 commit comments