@@ -261,12 +261,9 @@ defmodule ExUnit.DocTest do
261
261
file = Path . relative_to_cwd ( file )
262
262
tags = [ doctest: file ] ++ Keyword . get ( opts , :tags , [ ] )
263
263
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 ) }
270
267
end )
271
268
end
272
269
@@ -336,8 +333,8 @@ defmodule ExUnit.DocTest do
336
333
## Compilation of extracted tests
337
334
338
335
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 ) }
341
338
end
342
339
343
340
defp test_name ( % { fun_arity: :moduledoc } , m , n ) do
@@ -369,6 +366,10 @@ defmodule ExUnit.DocTest do
369
366
{ :__block__ , [ ] , test_import ( module , do_import ) ++ tests }
370
367
end
371
368
369
+ defp test_tags ( test , tags ) do
370
+ [ doctest_line: test . line ] ++ tags
371
+ end
372
+
372
373
defp multiple_exceptions? ( exprs ) do
373
374
Enum . count ( exprs , fn
374
375
{ _ , { :error , _ , _ } , _ } -> true
@@ -575,9 +576,7 @@ defmodule ExUnit.DocTest do
575
576
do: "The documentation chunk in the module is invalid"
576
577
577
578
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 )
581
580
end
582
581
583
582
defp extract_from_moduledoc ( _ , _doc , _module ) , do: [ ]
@@ -588,10 +587,7 @@ defmodule ExUnit.DocTest do
588
587
589
588
defp extract_from_doc ( { { _ , name , arity } , annotation , _ , % { "en" => doc } , _ } , module ) do
590
589
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 } )
595
591
end
596
592
597
593
defp extract_from_doc ( _doc , _module ) ,
@@ -648,7 +644,7 @@ defmodule ExUnit.DocTest do
648
644
"""
649
645
end
650
646
651
- adjusted_lines = [ { stripped_line , line_no } | adjusted_lines ]
647
+ adjusted_lines = [ { adjust_prompt ( stripped_line , line_no , module ) , line_no } | adjusted_lines ]
652
648
653
649
next =
654
650
cond do
@@ -694,210 +690,118 @@ defmodule ExUnit.DocTest do
694
690
end
695
691
end
696
692
697
- @ fences [ "```" , "~~~" ]
693
+ defp adjust_prompt ( "iex(" <> rest = line , line_no , module ) ,
694
+ do: "iex>" <> skip_iex_number ( rest , line_no , module , line )
698
695
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 )
704
698
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
706
701
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
710
706
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)>}"
714
710
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
719
713
end
720
714
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
748
724
end
749
725
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
762
728
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
776
736
end
777
737
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 ) )
854
744
end
855
745
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 }
859
749
end
860
750
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 )
872
753
end
873
754
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 )
876
765
end
877
766
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 )
880
778
end
881
779
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 )
887
791
end
888
792
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 )
891
796
end
892
797
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 ] ]
896
800
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
898
802
expected = IO . iodata_to_binary ( expected_lines )
899
803
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 ]
901
805
end
902
806
903
807
defp tag_expected ( expected ) do
0 commit comments