Time for test cases!
:- begin_tests(sub_string). test(find_single_bravo,[true(T),nondet]) :- % bbbbbb55555aaaaaaaa Str = "alpha bravo charlie", sub_string(Str, Before, Length, After, "bravo"), T = ([Before,Length,After] == [6,5,8]). test(find_multiple_bravo,[true(T)]) :- Str = "alpha bravo charlie bravo delta", bagof([Before,Length,After],sub_string(Str, Before, Length, After, "bravo"), Bag), T = (Bag == [[6,5,20],[20,5,6]]). test(fail_finding_micron,[fail]) :- Str = "alpha bravo charlie bravo delta", sub_string(Str, _Before, _Length, _After, "micron"). test(zero_is_the_first_char,[true(Extract="a")]) :- sub_string("axxxx", 0, 1, _, Extract). test(negative_pos_is_not_allowed,[error(domain_error(not_less_than_zero,_))]) :- sub_string("axxxx",-1, 1, _, _). % edge case which actually succeeds test(there_is_zero_chars_past_the_end,[true(T)]) :- Str = "alpha bravo", string_length(Str,StrLen), sub_string(Str, StrLen, 0, After, Extract), T = ([After,Extract] == [0,""]). test(getting_the_last_char,[true(T)]) :- Str = "alpha bravo", string_length(Str,StrLen), succ(Pos,StrLen), sub_string(Str, Pos, 1, After, Extract), T = ([After,Extract] == [0,"o"]). test(cannot_get_more_chars_than_there_are,[fail]) :- Str = "alpha bravo", string_length(Str,StrLen), succ(Pos,StrLen), sub_string(Str, Pos, 2, _, _). test(there_is_nothing_beyond_past_the_end_not_even_zero_chars,[fail]) :- Str = "alpha bravo", string_length(Str,StrLen), succ(StrLen,BeyondStrLen), sub_string(Str, BeyondStrLen, 0, _, _). % so one has to be careful! test(extract_at_most_5_chars,[true(T)]) :- Str = "alpha bravo charlie", Want = 5, bagof([CurPos,FixedCurPos,CanHave,After,Extract], solution(Str,Want,CurPos,FixedCurPos,CanHave,After,Extract),Bag), T = (Bag == [[-5, 0,0,19,"" ], [-4, 0,1,18,"a" ], [-3, 0,2,17,"al" ], [-2, 0,3,16,"alp" ], [-1, 0,4,15,"alph" ], [ 0, 0,5,14,"alpha"], [ 1, 1,5,13,"lpha "], [ 2, 2,5,12,"pha b"], [ 3, 3,5,11,"ha br"], [ 4, 4,5,10,"a bra"], [ 5, 5,5, 9," brav"], [ 6, 6,5, 8,"bravo"], [ 7, 7,5, 7,"ravo "], [ 8, 8,5, 6,"avo c"], [ 9, 9,5, 5,"vo ch"], [10,10,5, 4,"o cha"], [11,11,5, 3," char"], [12,12,5, 2,"charl"], [13,13,5, 1,"harli"], [14,14,5, 0,"arlie"], [15,15,4, 0, "rlie"], [16,16,3, 0, "lie"], [17,17,2, 0, "ie"], [18,18,1, 0, "e"], [19,19,0, 0, ""]]). solution(Str,Want,CurPos,FixedCurPos,CanHave,After,Extract) :- string_length(Str,StrLen), StartPos is -Want, between(StartPos,StrLen,CurPos), CanHave is min(CurPos+Want,min(Want,StrLen-CurPos)), FixedCurPos is max(0,CurPos), sub_string(Str,FixedCurPos,CanHave,After,Extract). :- end_tests(sub_string).