[m-rev.] diff: extend testing of the ranges module

Julien Fischer jfischer at opturion.com
Fri Jan 10 17:10:37 AEDT 2025


Extend testing of the ranges module.

Document some exception conditions in the ranges module.

library/ranges.m:
    Document the when insert and delete will throw an exception.

tests/test_ranges.{m,ex}:
    Test that attempting to construct a ranges value containing min_int
    results in an exception being thrown. To do this without hardcoding
    machine-specific values in the expected value, extend the code used
    to print ranges to output symbolic names for {min,max}_int.

    Fix spelling.

Julien.

diff --git a/library/ranges.m b/library/ranges.m
index 8db69f6..c1da8c2 100644
--- a/library/ranges.m
+++ b/library/ranges.m
@@ -116,6 +116,7 @@

     % insert(X, Set0, Set) is true iff Set is the union of Set0 and
     % the set containing only X.
+    % Throws an exception if X = min_int.
     %
 :- func insert(int, ranges) = ranges.
 :- pred insert(int::in, ranges::in, ranges::out) is det.
@@ -129,6 +130,7 @@
     % delete(X, Set0, Set) is true iff Set is the relative complement
     % of Set0 and the set containing only X, i.e. if Set is the set
     % which contains all the elements of Set0 except X.
+    % Throws an exception if X = min_int.
     %
 :- func delete(int, ranges) = ranges.
 :- pred delete(int::in, ranges::in, ranges::out) is det.
diff --git a/tests/hard_coded/test_ranges.exp b/tests/hard_coded/test_ranges.exp
index 00df04b..af12761 100644
--- a/tests/hard_coded/test_ranges.exp
+++ b/tests/hard_coded/test_ranges.exp
@@ -13,11 +13,12 @@ make_singleton_set(-1) = [[-1]]
 make_singleton_set(0) = [[0]]
 make_singleton_set(1) = [[1]]
 make_singleton_set(min_int) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
+make_singleton_set(max_int) = [[max_int]]

 *** Test universe/0 ***

 PASS: ranges.universe is empty.
-PASS: ranges.univere is continguous
+PASS: ranges.universe is contiguous
 PASS: ranges.universe lower bound is min_int + 1.
 PASS: ranges.universe upper bound is max_int.

@@ -241,105 +242,153 @@ nondet_member([[-1], [1], [3], [5], [7], [9]])
===> [-1, 1, 3, 5, 7, 9]

 *** Test insert/2 ***

+insert(min_int, []) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, []) = [[-1]]
 insert(0, []) = [[0]]
 insert(1, []) = [[1]]
 insert(10, []) = [[10]]
+insert(max_int, []) = [[max_int]]
+insert(min_int, [[-1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-1]]) = [[-1]]
 insert(0, [[-1]]) = [[-1, 0]]
 insert(1, [[-1]]) = [[-1], [1]]
 insert(10, [[-1]]) = [[-1], [10]]
+insert(max_int, [[-1]]) = [[-1], [max_int]]
+insert(min_int, [[0]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[0]]) = [[-1, 0]]
 insert(0, [[0]]) = [[0]]
 insert(1, [[0]]) = [[0, 1]]
 insert(10, [[0]]) = [[0], [10]]
+insert(max_int, [[0]]) = [[0], [max_int]]
+insert(min_int, [[1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[1]]) = [[-1], [1]]
 insert(0, [[1]]) = [[0, 1]]
 insert(1, [[1]]) = [[1]]
 insert(10, [[1]]) = [[1], [10]]
+insert(max_int, [[1]]) = [[1], [max_int]]
+insert(min_int, [[-3 .. -1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-3 .. -1]]) = [[-3 .. -1]]
 insert(0, [[-3 .. -1]]) = [[-3 .. 0]]
 insert(1, [[-3 .. -1]]) = [[-3 .. -1], [1]]
 insert(10, [[-3 .. -1]]) = [[-3 .. -1], [10]]
+insert(max_int, [[-3 .. -1]]) = [[-3 .. -1], [max_int]]
+insert(min_int, [[-1 .. 1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-1 .. 1]]) = [[-1 .. 1]]
 insert(0, [[-1 .. 1]]) = [[-1 .. 1]]
 insert(1, [[-1 .. 1]]) = [[-1 .. 1]]
 insert(10, [[-1 .. 1]]) = [[-1 .. 1], [10]]
+insert(max_int, [[-1 .. 1]]) = [[-1 .. 1], [max_int]]
+insert(min_int, [[1 .. 3]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[1 .. 3]]) = [[-1], [1 .. 3]]
 insert(0, [[1 .. 3]]) = [[0 .. 3]]
 insert(1, [[1 .. 3]]) = [[1 .. 3]]
 insert(10, [[1 .. 3]]) = [[1 .. 3], [10]]
+insert(max_int, [[1 .. 3]]) = [[1 .. 3], [max_int]]
+insert(min_int, [[-10 .. -7], [-3 .. -1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1]]
 insert(0, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. 0]]
 insert(1, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1], [1]]
 insert(10, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1], [10]]
+insert(max_int, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 ..
-1], [max_int]]
+insert(min_int, [[1 .. 3], [7 .. 10]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[1 .. 3], [7 .. 10]]) = [[-1], [1 .. 3], [7 .. 10]]
 insert(0, [[1 .. 3], [7 .. 10]]) = [[0 .. 3], [7 .. 10]]
 insert(1, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 10]]
 insert(10, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 10]]
+insert(max_int, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 10], [max_int]]
+insert(min_int, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = <<exception:
function `ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1
.. 1], [7 .. 10]]
 insert(0, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1 ..
1], [7 .. 10]]
 insert(1, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1 ..
1], [7 .. 10]]
 insert(10, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1
.. 1], [7 .. 10]]
+insert(max_int, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7],
[-1 .. 1], [7 .. 10], [max_int]]
+insert(min_int, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = <<exception:
function `ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1 ..
1], [3 .. 6]]
 insert(0, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1 ..
1], [3 .. 6]]
 insert(1, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1 ..
1], [3 .. 6]]
 insert(10, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1 ..
1], [3 .. 6], [10]]
+insert(max_int, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1
.. 1], [3 .. 6], [max_int]]
+insert(min_int, [[-1], [1], [3], [5], [7], [9]]) = <<exception:
function `ranges.make_singleton_set'/1: cannot represent min_int>>
 insert(-1, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3], [5], [7], [9]]
 insert(0, [[-1], [1], [3], [5], [7], [9]]) = [[-1 .. 1], [3], [5], [7], [9]]
 insert(1, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3], [5], [7], [9]]
 insert(10, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3], [5],
[7], [9, 10]]
+insert(max_int, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3],
[5], [7], [9], [max_int]]

 *** Test delete/2 ***

+delete(min_int, []) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, []) = []
 delete(0, []) = []
 delete(1, []) = []
 delete(10, []) = []
+delete(max_int, []) = []
+delete(min_int, [[-1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-1]]) = []
 delete(0, [[-1]]) = [[-1]]
 delete(1, [[-1]]) = [[-1]]
 delete(10, [[-1]]) = [[-1]]
+delete(max_int, [[-1]]) = [[-1]]
+delete(min_int, [[0]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[0]]) = [[0]]
 delete(0, [[0]]) = []
 delete(1, [[0]]) = [[0]]
 delete(10, [[0]]) = [[0]]
+delete(max_int, [[0]]) = [[0]]
+delete(min_int, [[1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[1]]) = [[1]]
 delete(0, [[1]]) = [[1]]
 delete(1, [[1]]) = []
 delete(10, [[1]]) = [[1]]
+delete(max_int, [[1]]) = [[1]]
+delete(min_int, [[-3 .. -1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-3 .. -1]]) = [[-3, -2]]
 delete(0, [[-3 .. -1]]) = [[-3 .. -1]]
 delete(1, [[-3 .. -1]]) = [[-3 .. -1]]
 delete(10, [[-3 .. -1]]) = [[-3 .. -1]]
+delete(max_int, [[-3 .. -1]]) = [[-3 .. -1]]
+delete(min_int, [[-1 .. 1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-1 .. 1]]) = [[0, 1]]
 delete(0, [[-1 .. 1]]) = [[-1], [1]]
 delete(1, [[-1 .. 1]]) = [[-1, 0]]
 delete(10, [[-1 .. 1]]) = [[-1 .. 1]]
+delete(max_int, [[-1 .. 1]]) = [[-1 .. 1]]
+delete(min_int, [[1 .. 3]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[1 .. 3]]) = [[1 .. 3]]
 delete(0, [[1 .. 3]]) = [[1 .. 3]]
 delete(1, [[1 .. 3]]) = [[2, 3]]
 delete(10, [[1 .. 3]]) = [[1 .. 3]]
+delete(max_int, [[1 .. 3]]) = [[1 .. 3]]
+delete(min_int, [[-10 .. -7], [-3 .. -1]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3, -2]]
 delete(0, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1]]
 delete(1, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1]]
 delete(10, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1]]
+delete(max_int, [[-10 .. -7], [-3 .. -1]]) = [[-10 .. -7], [-3 .. -1]]
+delete(min_int, [[1 .. 3], [7 .. 10]]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 10]]
 delete(0, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 10]]
 delete(1, [[1 .. 3], [7 .. 10]]) = [[2, 3], [7 .. 10]]
 delete(10, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 9]]
+delete(max_int, [[1 .. 3], [7 .. 10]]) = [[1 .. 3], [7 .. 10]]
+delete(min_int, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = <<exception:
function `ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [0,
1], [7 .. 10]]
 delete(0, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1],
[1], [7 .. 10]]
 delete(1, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1,
0], [7 .. 10]]
 delete(10, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7], [-1
.. 1], [7 .. 9]]
+delete(max_int, [[-10 .. -7], [-1 .. 1], [7 .. 10]]) = [[-10 .. -7],
[-1 .. 1], [7 .. 10]]
+delete(min_int, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = <<exception:
function `ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [0, 1], [3 .. 6]]
 delete(0, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1],
[1], [3 .. 6]]
 delete(1, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1, 0], [3 .. 6]]
 delete(10, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1 ..
1], [3 .. 6]]
+delete(max_int, [[-6 .. -3], [-1 .. 1], [3 .. 6]]) = [[-6 .. -3], [-1
.. 1], [3 .. 6]]
+delete(min_int, [[-1], [1], [3], [5], [7], [9]]) = <<exception:
function `ranges.make_singleton_set'/1: cannot represent min_int>>
 delete(-1, [[-1], [1], [3], [5], [7], [9]]) = [[1], [3], [5], [7], [9]]
 delete(0, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3], [5], [7], [9]]
 delete(1, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [3], [5], [7], [9]]
 delete(10, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3], [5], [7], [9]]
+delete(max_int, [[-1], [1], [3], [5], [7], [9]]) = [[-1], [1], [3],
[5], [7], [9]]

 *** Test subset/2 ***

@@ -1220,6 +1269,7 @@ prune_to_prev_non_member([[-1], [1], [3], [5],
[7], [9]], [[-1], [1], [3]], 5, 4
 *** Test from_list/1 ***

 from_list([]) = []
+from_list([min_int]) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
 from_list([-1]) = [[-1]]
 from_list([0]) = [[0]]
 from_list([1]) = [[1]]
@@ -1231,13 +1281,14 @@ from_list([1, 2, 3, 4, 5, 561, -1]) = [[-1],
[1 .. 5], [561]]

 *** Test from_set/1 ***

-from_set(sol([])) = []
-from_set(sol([-1])) = [[-1]]
-from_set(sol([0])) = [[0]]
-from_set(sol([1])) = [[1]]
-from_set(sol([1, 2, 3])) = [[1 .. 3]]
-from_set(sol([-10, 1, 2, 3, 10])) = [[-10], [1 .. 3], [10]]
-from_set(sol([-1, 1, 2, 3, 4, 5, 561])) = [[-1], [1 .. 5], [561]]
+from_set(set([])) = []
+from_set(set([min_int])) = <<exception: function
`ranges.make_singleton_set'/1: cannot represent min_int>>
+from_set(set([-1])) = [[-1]]
+from_set(set([0])) = [[0]]
+from_set(set([1])) = [[1]]
+from_set(set([1, 2, 3])) = [[1 .. 3]]
+from_set(set([-10, 1, 2, 3, 10])) = [[-10], [1 .. 3], [10]]
+from_set(set([-1, 1, 2, 3, 4, 5, 561])) = [[-1], [1 .. 5], [561]]

 *** Test to_sorted_list/1 ***

diff --git a/tests/hard_coded/test_ranges.m b/tests/hard_coded/test_ranges.m
index 34a65a9..8cb2a7a 100644
--- a/tests/hard_coded/test_ranges.m
+++ b/tests/hard_coded/test_ranges.m
@@ -145,7 +145,7 @@ test_make_singleton_set(!IO) :-
     io.format("make_singleton_set(-1) = %s\n",
[r(make_singleton_set(-1))], !IO),
     io.format("make_singleton_set(0) = %s\n", [r(make_singleton_set(0))], !IO),
     io.format("make_singleton_set(1) = %s\n", [r(make_singleton_set(1))], !IO),
-    % Check that we cannot construct a singeleton set containg min_int.
+    % Check that we cannot construct a singleton set containing min_int.
     io.write_string("make_singleton_set(min_int) = ", !IO),
     ( try []
         Range = make_singleton_set(min_int)
@@ -157,6 +157,8 @@ test_make_singleton_set(!IO) :-
     catch_any Other ->
         throw(Other)
     ),
+    io.format("make_singleton_set(max_int) = %s\n",
+        [r(make_singleton_set(max_int))], !IO),
     io.nl(!IO).

 %---------------------------------------------------------------------------%
@@ -174,7 +176,7 @@ test_universe(!IO) :-
         io.write_string("PASS: ranges.universe is empty.\n", !IO)
     ),
     ( if is_contiguous(Universe, Lo, Hi) then
-        io.write_string("PASS: ranges.univere is continguous\n", !IO),
+        io.write_string("PASS: ranges.universe is contiguous\n", !IO),
         ( if Lo = int.min_int + 1 then
             io.write_string(
                 "PASS: ranges.universe lower bound is min_int + 1.\n", !IO)
@@ -457,28 +459,37 @@ test_nondet_member(Ranges, !IO) :-
 %---------------------------------------------------------------------------%

 :- pred test_insert_and_delete((func(int, ranges) = ranges)::in, string::in,
-    io::di, io::uo) is det.
+    io::di, io::uo) is cc_multi.

 test_insert_and_delete(Op, OpDesc, !IO) :-
     io.format("*** Test %s/2 ***\n\n", [s(OpDesc)], !IO),
-    Values = [-1, 0, 1, 10],
+    Values = [min_int, -1, 0, 1, 10, max_int],
     list.foldl(do_test_insert_and_delete(Op, OpDesc, Values),
         test_ranges, !IO),
     io.nl(!IO).

 :-  pred do_test_insert_and_delete((func(int, ranges) = ranges)::in,
-    string::in, list(int)::in, ranges::in, io::di, io::uo) is det.
+    string::in, list(int)::in, ranges::in, io::di, io::uo) is cc_multi.

 do_test_insert_and_delete(Op, OpDesc, Values, Ranges, !IO) :-
     list.foldl(do_test_insert_and_delete_2(Op, OpDesc, Ranges), Values, !IO).

 :-  pred do_test_insert_and_delete_2((func(int, ranges) = ranges)::in,
-    string::in, ranges::in, int::in, io::di, io::uo) is det.
+    string::in, ranges::in, int::in, io::di, io::uo) is cc_multi.

 do_test_insert_and_delete_2(Op, OpDesc, Ranges, Value, !IO) :-
-    Result = Op(Value, Ranges),
-    io.format("%s(%d, %s) = %s\n",
-        [s(OpDesc), i(Value), r(Ranges), r(Result)], !IO).
+    io.format("%s(%s, %s) = ",
+        [s(OpDesc), n(Value), r(Ranges)], !IO),
+    ( try []
+        Result = Op(Value, Ranges)
+    then
+        io.format("%s\n", [r(Result)], !IO)
+    catch S ->
+        S = software_error(Msg),
+        io.format("<<exception: %s>>\n", [s(Msg)], !IO)
+    catch_any Other ->
+        throw(Other)
+    ).

 %---------------------------------------------------------------------------%

@@ -559,7 +570,8 @@ do_test_restrict_range_2(Ranges, {Min, Max}, !IO) :-

 test_binary_test_op(Pred, PredName, !IO) :-
     io.format("*** Test %s/2 ***\n\n", [s(PredName)], !IO),
-    list.foldl(do_binary_test_op_1(Pred, PredName, test_ranges),
test_ranges, !IO),
+    list.foldl(do_binary_test_op_1(Pred, PredName, test_ranges), test_ranges,
+        !IO),
     io.nl(!IO).

 :- pred do_binary_test_op_1(pred(ranges, ranges)::in(pred(in, in) is semidet),
@@ -656,12 +668,13 @@ do_test_prune_2(Pred, PredDesc, Ranges, Value, !IO) :-

 %---------------------------------------------------------------------------%

-:- pred test_from_list(io::di, io::uo) is det.
+:- pred test_from_list(io::di, io::uo) is cc_multi.

 test_from_list(!IO) :-
     io.write_string("*** Test from_list/1 ***\n\n", !IO),
     TestLists = [
         [],
+        [min_int],
         [-1],
         [0],
         [1],
@@ -674,18 +687,28 @@ test_from_list(!IO) :-
     list.foldl(do_test_from_list, TestLists, !IO),
     io.nl(!IO).

-:- pred do_test_from_list(list(int)::in, io::di, io::uo) is det.
+:- pred do_test_from_list(list(int)::in, io::di, io::uo) is cc_multi.

 do_test_from_list(List, !IO) :-
-    Ranges = ranges.from_list(List),
-    io.format("from_list(%s) = %s\n", [s(string(List)), r(Ranges)], !IO).
+    io.format("from_list(%s) = ", [li(List)], !IO),
+    ( try []
+        Ranges = ranges.from_list(List)
+    then
+        io.format("%s\n", [r(Ranges)], !IO)
+    catch S ->
+        S = software_error(Msg),
+        io.format("<<exception: %s>>\n", [s(Msg)], !IO)
+    catch_any Other ->
+        throw(Other)
+    ).

-:- pred test_from_set(io::di, io::uo) is det.
+:- pred test_from_set(io::di, io::uo) is cc_multi.

 test_from_set(!IO) :-
     io.write_string("*** Test from_set/1 ***\n\n", !IO),
     TestSets = [
         set.from_list([]),
+        set.from_list([min_int]),
         set.from_list([-1]),
         set.from_list([0]),
         set.from_list([1]),
@@ -696,11 +719,20 @@ test_from_set(!IO) :-
     list.foldl(do_test_from_set, TestSets, !IO),
     io.nl(!IO).

-:- pred do_test_from_set(set(int)::in, io::di, io::uo) is det.
+:- pred do_test_from_set(set(int)::in, io::di, io::uo) is cc_multi.

-do_test_from_set(List, !IO) :-
-    Ranges = ranges.from_set(List),
-    io.format("from_set(%s) = %s\n", [s(string(List)), r(Ranges)], !IO).
+do_test_from_set(Set, !IO) :-
+    io.format("from_set(%s) = ", [si(Set)], !IO),
+    ( try []
+        Ranges = ranges.from_set(Set)
+    then
+        io.format("%s\n", [r(Ranges)], !IO)
+    catch S ->
+        S = software_error(Msg),
+        io.format("<<exception: %s>>\n", [s(Msg)], !IO)
+    catch_any Other ->
+        throw(Other)
+    ).

 %---------------------------------------------------------------------------%

@@ -935,14 +967,46 @@ ranges_to_desc(Ranges) = Desc :-

 range_to_desc(Lo, Hi, !Descs) :-
     ( if Lo = Hi then
-        Desc = string.format("[%d]", [i(Lo)])
+        Desc = string.format("[%s]", [n(Lo)])
     else if Lo + 1 = Hi then
-        Desc = string.format("[%d, %d]", [i(Lo), i(Hi)])
+        Desc = string.format("[%s, %s]", [n(Lo), n(Hi)])
     else
-        Desc = string.format("[%d .. %d]", [i(Lo), i(Hi)])
+        Desc = string.format("[%s .. %s]", [n(Lo), n(Hi)])
     ),
     !:Descs = [Desc | !.Descs].

+    % Format an integer, returning a symbolic representation for {min,max}_int.
+    %
+:- func n(int) = poly_type.
+
+n(N) = s(int_to_maybe_symbolic_string(N)).
+
+    % Format a list of integers, returning symbolic representations for
+    % {min,max}_int.
+    %
+:- func li(list(int)) = poly_type.
+
+li(List) = s(ListStr) :-
+    ListStrs = list.map(int_to_maybe_symbolic_string, List),
+    ListStr = "[" ++ string.join_list(", ", ListStrs) ++ "]".
+
+:- func si(set(int)) = poly_type.
+
+si(Set) = s(SetStr) :-
+    ElemStrs = list.map(int_to_maybe_symbolic_string, to_sorted_list(Set)),
+    SetStr = "set([" ++ string.join_list(", ", ElemStrs) ++ "])".
+
+:- func int_to_maybe_symbolic_string(int) = string.
+
+int_to_maybe_symbolic_string(N) = Str :-
+    ( if N = min_int then
+        Str = "min_int"
+    else if N = max_int then
+        Str = "max_int"
+    else
+        string.int_to_string(N, Str)
+    ).
+
 %---------------------------------------------------------------------------%

 :- func test_ranges = list(ranges).


More information about the reviews mailing list