1# Copyright 2016-2017 Tobias Grosser
2#
3# Use of this software is governed by the MIT license
4#
5# Written by Tobias Grosser, Weststrasse 47, CH-8003, Zurich
6
7import sys
8import isl
9
10# Test that isl objects can be constructed.
11#
12# This tests:
13#  - construction from a string
14#  - construction from an integer
15#  - static constructor without a parameter
16#  - conversion construction
17#
18#  The tests to construct from integers and strings cover functionality that
19#  is also tested in the parameter type tests, but here the presence of
20#  multiple overloaded constructors and overload resolution is tested.
21#
22def test_constructors():
23	zero1 = isl.val("0")
24	assert(zero1.is_zero())
25
26	zero2 = isl.val(0)
27	assert(zero2.is_zero())
28
29	zero3 = isl.val.zero()
30	assert(zero3.is_zero())
31
32	bs = isl.basic_set("{ [1] }")
33	result = isl.set("{ [1] }")
34	s = isl.set(bs)
35	assert(s.is_equal(result))
36
37# Test integer function parameters for a particular integer value.
38#
39def test_int(i):
40	val_int = isl.val(i)
41	val_str = isl.val(str(i))
42	assert(val_int.eq(val_str))
43
44# Test integer function parameters.
45#
46# Verify that extreme values and zero work.
47#
48def test_parameters_int():
49	test_int(sys.maxsize)
50	test_int(-sys.maxsize - 1)
51	test_int(0)
52
53# Test isl objects parameters.
54#
55# Verify that isl objects can be passed as lvalue and rvalue parameters.
56# Also verify that isl object parameters are automatically type converted if
57# there is an inheritance relation. Finally, test function calls without
58# any additional parameters, apart from the isl object on which
59# the method is called.
60#
61def test_parameters_obj():
62	a = isl.set("{ [0] }")
63	b = isl.set("{ [1] }")
64	c = isl.set("{ [2] }")
65	expected = isl.set("{ [i] : 0 <= i <= 2 }")
66
67	tmp = a.union(b)
68	res_lvalue_param = tmp.union(c)
69	assert(res_lvalue_param.is_equal(expected))
70
71	res_rvalue_param = a.union(b).union(c)
72	assert(res_rvalue_param.is_equal(expected))
73
74	a2 = isl.basic_set("{ [0] }")
75	assert(a.is_equal(a2))
76
77	two = isl.val(2)
78	half = isl.val("1/2")
79	res_only_this_param = two.inv()
80	assert(res_only_this_param.eq(half))
81
82# Test different kinds of parameters to be passed to functions.
83#
84# This includes integer and isl object parameters.
85#
86def test_parameters():
87	test_parameters_int()
88	test_parameters_obj()
89
90# Test that isl objects are returned correctly.
91#
92# This only tests that after combining two objects, the result is successfully
93# returned.
94#
95def test_return_obj():
96	one = isl.val("1")
97	two = isl.val("2")
98	three = isl.val("3")
99
100	res = one.add(two)
101
102	assert(res.eq(three))
103
104# Test that integer values are returned correctly.
105#
106def test_return_int():
107	one = isl.val("1")
108	neg_one = isl.val("-1")
109	zero = isl.val("0")
110
111	assert(one.sgn() > 0)
112	assert(neg_one.sgn() < 0)
113	assert(zero.sgn() == 0)
114
115# Test that isl_bool values are returned correctly.
116#
117# In particular, check the conversion to bool in case of true and false.
118#
119def test_return_bool():
120	empty = isl.set("{ : false }")
121	univ = isl.set("{ : }")
122
123	b_true = empty.is_empty()
124	b_false = univ.is_empty()
125
126	assert(b_true)
127	assert(not b_false)
128
129# Test that strings are returned correctly.
130# Do so by calling overloaded isl.ast_build.from_expr methods.
131#
132def test_return_string():
133	context = isl.set("[n] -> { : }")
134	build = isl.ast_build.from_context(context)
135	pw_aff = isl.pw_aff("[n] -> { [n] }")
136	set = isl.set("[n] -> { : n >= 0 }")
137
138	expr = build.expr_from(pw_aff)
139	expected_string = "n"
140	assert(expected_string == expr.to_C_str())
141
142	expr = build.expr_from(set)
143	expected_string = "n >= 0"
144	assert(expected_string == expr.to_C_str())
145
146# Test that return values are handled correctly.
147#
148# Test that isl objects, integers, boolean values, and strings are
149# returned correctly.
150#
151def test_return():
152	test_return_obj()
153	test_return_int()
154	test_return_bool()
155	test_return_string()
156
157# Test that foreach functions are modeled correctly.
158#
159# Verify that closures are correctly called as callback of a 'foreach'
160# function and that variables captured by the closure work correctly. Also
161# check that the foreach function handles exceptions thrown from
162# the closure and that it propagates the exception.
163#
164def test_foreach():
165	s = isl.set("{ [0]; [1]; [2] }")
166
167	list = []
168	def add(bs):
169		list.append(bs)
170	s.foreach_basic_set(add)
171
172	assert(len(list) == 3)
173	assert(list[0].is_subset(s))
174	assert(list[1].is_subset(s))
175	assert(list[2].is_subset(s))
176	assert(not list[0].is_equal(list[1]))
177	assert(not list[0].is_equal(list[2]))
178	assert(not list[1].is_equal(list[2]))
179
180	def fail(bs):
181		raise "fail"
182
183	caught = False
184	try:
185		s.foreach_basic_set(fail)
186	except:
187		caught = True
188	assert(caught)
189
190# Test the isl Python interface
191#
192# This includes:
193#  - Object construction
194#  - Different parameter types
195#  - Different return types
196#  - Foreach functions
197#
198test_constructors()
199test_parameters()
200test_return()
201test_foreach()
202