:- module(test_jpl,
	  [ run_tests/0,
	    run_tests/1
	  ]).
% ensure we get the local copies

:- asserta(user:file_search_path(foreign, '.')).
:- asserta(user:file_search_path(jpl_examples, 'examples/prolog')).
:- asserta(user:file_search_path(jar, '.')).
:- asserta(user:file_search_path(library, '.')).
:- asserta(user:file_search_path(library, '../plunit')).

:- use_module(library(jpl)).
:- use_module(library(plunit)).

:- jpl:add_search_path('CLASSPATH', 'jpltest.jar').

:- begin_tests(jpl).

test(
	ancestor_types_1,
	[	true(
			Ts == [class([jpl],['Compound']),class([jpl],['Term']),class([java,lang],['Object'])]
		)
	]
) :-
	jpl:jpl_type_to_ancestor_types( class([jpl],['Atom']), Ts).

test(
	call_array_equals_1,
	[	setup((
			jpl_new( array(byte), [4,5,6], A1),
			jpl_new( array(byte), [4,5,6], A2)
		))
	]
) :-
	jpl_call( A1, equals, [A2], @(false)).

test(
	call_array_equals_2,
	[	setup((
			jpl_new( array(byte), [4,5,6], A1)
		))
	]
) :-
	jpl_call( A1, equals, [A1], @(true)).

test(
	call_array_hashcode_1,
	[	setup((
			jpl_new( array(byte), [4,5,6], A)
		)),
		true((
			integer( H)
		))
	]
) :-
	jpl_call( A, hashCode, [], H).

test(
	call_array_hashcode_2,
	[	setup((
			jpl_new( array(byte), [4,5,6], A1),
			jpl_new( array(byte), [4,5,6], A2)
		)),
		true((
			H1 \== H2
		))
	]
) :-
	jpl_call( A1, hashCode, [], H1),
	jpl_call( A2, hashCode, [], H2).

test(
	call_array_to_string_1,
	[	setup((
			jpl_new( array(byte), [4,5,6], A)
		)),
		true((
			atom_codes( S, [0'[, 0'B | _])
		))
	]
) :-
	jpl_call( A, toString, [], S).

test(
	call_instance_param_cyclic_term_1,
	[	setup((
			T = f(T),
			jpl_new( 'jpl.test.Test', [], Test)
		)),
		throws(
			error(type_error(acyclic,T),context(jpl_call/4,_))
		)
	]
) :-
	jpl_call( Test, methodInstanceTerm, [{T}], @(true)).

testX(
	call_instance_param_cyclic_term_2,
	[	setup((
			T = f(T),
			jpl_new( 'jpl.test.Test', [], Test)
		)),
		throws(
			error(type_error(acyclic,_),context(jpl_call/4,_))
		)
	]
) :-
	jpl_call( Test, methodInstanceTerm, [{T}], @(true)).

test(
	call_method_static_array_1,
	[	setup((
			jpl_new( array(int), [3,4,5], IntArray)
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticArray, [IntArray], 'int[]').

test(
	call_method_static_array_2,
	[	setup((
			jpl_new( array(byte), [3,4,5], ByteArray)
		)),
		throws(
			error(
				type_error(method_params,[ByteArray]),
				context(jpl_call/4,_)
			)
		)
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticArray, [ByteArray], _).

test(
	call_static_param_cyclic_term_1,
	[	setup((
			T = f(T)
		)),
		throws(
			error(type_error(acyclic,T),context(jpl_call/4,_))
		)
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticTerm, [{T}], @(true)).

test(
	call_class_get_name_1,
	[	setup((
			ClassName = 'java.lang.Integer',
			jpl_classname_to_class( ClassName, ClassObject)
		)),
		true((
			ClassName == ClassName2
		))
	]
) :-
	jpl_call( ClassObject, getName, [], ClassName2).

test(
	call_get_array_bad_field_name_1,
	[	setup((
			jpl_new( array(byte), 5, A),
			FieldName = colour
		)),
		throws(
			error(domain_error(array_field_name,FieldName),context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, FieldName, _).

test(
	call_get_array_bad_fspec_1,
	[	setup((
			jpl_new( array(byte), 5, A),
			Fspec = poo(77)
		)),
		throws(
			error(type_error(array_lookup_spec,Fspec),context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, Fspec, _).

test(
	call_get_array_bad_index_range_1,
	[	setup((
			jpl_new( array(byte), 5, A)
		)),
		throws(
			error(domain_error(array_index_range,(-1)-2),context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, (-1)-2, _).

test(
	call_get_array_bad_index_range_2,
	[	setup((
			jpl_new( array(byte), 5, A)
		)),
		throws(
			error(domain_error(array_index_range,10-12),context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, 10-12, _).

test(
	call_get_array_bad_index_range_3,
	[	setup((
			jpl_new( array(byte), 5, A)
		)),
		throws(
			error(domain_error(array_index_range,3-33),context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, 3-33, _).

test(
	call_get_array_bad_index_range_4,
	[	setup((
			jpl_new( array(byte), 5, A)
		)),
		throws(
			error(type_error(array_index_range,this-that),context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, this-that, _).

test(
	get_array_element_1,
	[	setup((
			jpl_new( array(byte), [4,5,6,7,8], A)
		)),
		true((
			7 == V
		))
	]
) :-
	jpl_get( A, 3, V). % should bind V = 7 i.e. a[3] i.e. the fourth array element counting from zero

test(
	get_array_elements_1,
	[	setup((
			jpl_new( array(byte), [4,5,6,7,8], A)
		)),
		true((
			[5,6] == V
		))
	]
) :-
	jpl_get( A, 1-2, V). % should bind V = [5,6] i.e. a[1-2] i.e. the 2nd to 3rd array elements counting from zero

test(
	get_array_length_1,
	[	setup((
			Len1 is 5,
			jpl_new( array(byte), Len1, A)
		)),
		true((
			Len1 == Len2
		))
	]
) :-
	jpl_get( A, length, Len2). % should bind Len2 to the (integer) value of Len1

test(
	get_array_negative_index_1,
	[	setup((
			BadIndex is -1,
			jpl_new( array(byte), 5, A)
		)),
		throws(
			error(domain_error(array_index,BadIndex), context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, BadIndex, _).

test(
	get_array_unbound_fspec_1,
	[	setup((
			jpl_new( array(byte), 5, A)
		)),
		throws(
			error(instantiation_error,context(jpl_get/3,_))
		)
	]
) :-
	jpl_get( A, _, _).

test(
	get_field_static_boolean_1,
	[	true((
			V == @(false)
		))
	]
) :-
	jpl_get( 'jpl.test.Test', fieldStaticBoolean1, V).

test(
	get_field_static_boolean_2,
	[	true((
			V == @(true)
		))
	]
) :-
	jpl_get( 'jpl.test.Test', fieldStaticBoolean2, V).

test(
	get_field_static_char_1,
	[	true((
			V == 0
		))
	]
) :-
	jpl_get( 'jpl.test.Test', fieldStaticChar1, V).

test(
	get_field_static_char_2,
	[	true((
			V == 65535
		))
	]
) :-
	jpl_get( 'jpl.test.Test', fieldStaticChar2, V).

test(
	get_field_instance_byte_2,
	[	setup((
			jpl_new( 'jpl.test.Test', [], Test)
		)),
		true((
			V == -1
		))
	]
) :-
	jpl_get( Test, fieldInstanceByte2, V).

test(
	list_to_array_1,
	[	true((
			Type == array(byte)
		))
	]
) :-
	jpl_list_to_array( [1,2,3], A),
	jpl_object_to_type( A, Type).

test(
	method_static_byte_1,
	[	throws(
			error(
				type_error(method_params,[-129]),
				context(jpl_call/4,_)
			)
		)
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoByte, [-129], _).

test(
	method_static_echo_boolean_1,
	[	setup((
			jpl_false( V1)
		)),
		true((
			V1 == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoBoolean, [V1], V2).

test(
	method_static_echo_boolean_2,
	[	setup((
			jpl_true( V1)
		)),
		true((
			V1 == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoBoolean, [V1], V2).

test(
	method_static_echo_char_1,
	[	setup((
			V1 = 0
		)),
		true((
			V1 == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoChar, [V1], V2).

test(
	method_static_echo_char_2,
	[	setup((
			V1 = 65535
		)),
		true((
			V1 == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoChar, [V1], V2).

test(
	method_static_char_3,
	[	setup((
			V1 = -1
		)),
		throws(
			error(
				type_error(method_params,[V1]),
				context(jpl_call/4,_)
			)
		)
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoChar, [V1], _).

test(
	method_static_char_4,
	[	setup((
			V1 = 1.0
		)),
		throws(
			error(
				type_error(method_params,[V1]),
				context(jpl_call/4,_)
			)
		)
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoChar, [V1], _).

test(
	method_static_char_5,
	[	setup((
			V1 = a
		)),
		throws(
			error(
				type_error(method_params,[V1]),
				context(jpl_call/4,_)
			)
		)
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoChar, [V1], _).

test(
	method_static_echo_double_1,
	[	setup((
			V1 = 1.5
		)),
		true((
			V1 == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoDouble, [V1], V2).

test(
	method_static_echo_double_2,
	[	setup((
			V1 = 2
		)),
		true((
			V2 =:= float(V1)
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoDouble, [V1], V2).

test(
	method_static_echo_double_3,
	[	setup((
			(   current_prolog_flag( bounded, true)
		    ->  current_prolog_flag( max_integer, V1)
		    ;   V1 is 2**63-1
		    ),
			V2b is float(V1)
		)),
		true((
			V2 == V2b
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoDouble, [V1], V2).

test(
	method_static_echo_float_1,
	[	setup((
			V1 = 1.5
		)),
		true((
			V1 == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoFloat, [V1], V2).

test(
	method_static_echo_float_2,
	[	setup((
			V1 is 2,
			V2b is float(V1)
		)),
		true((
			V2 == V2b
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoFloat, [V1], V2).

test(
	method_static_echo_float_3,
	[	setup((
			(   current_prolog_flag( bounded, true)
		    ->  current_prolog_flag( max_integer, V1)
		    ;   V1 is 2**63-1 % was 2**99
		    ),
			V2b is float(V1)
		)),
		true((
			V2 == V2b
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoFloat, [V1], V2).

test(
	method_static_echo_float_4,
	[	blocked('we do not yet widen unbounded integers to floats or doubles'),
		setup((
			(   current_prolog_flag( bounded, true)
		    ->  current_prolog_flag( max_integer, V1)
		    ;   V1 is 2**99		% an unbounded integer
		    ),
			V2b is float(V1)
		)),
		true((
			V2 == V2b
		))
	]
) :-
	jpl_call( 'jpl.test.Test', methodStaticEchoFloat, [V1], V2).

test(
	new_abstract_class_1,
	[	setup((
			Classname = 'java.util.Dictionary'
		)),
		throws(
			error(
				type_error(concrete_class,Classname),
				context(jpl_new/3,_)
			)
		)
	]
) :-
	jpl_new( Classname, [], _).

test(
	new_array_boolean_from_val_1,
	[	setup((
			jpl_false( V)
		)),
		true((
			V == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', newArrayBooleanFromValue, [V], A),
	jpl_get( A, 0, V2).

test(
	new_array_double_from_val_1,
	[	setup((
			V is 1.5
		)),
		true((
			V == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', newArrayDoubleFromValue, [V], A),
	jpl_get( A, 0, V2).

test(
	new_array_float_from_val_1,
	[	setup((
			V is 1.5
		)),
		true((
			V == V2
		))
	]
) :-
	jpl_call( 'jpl.test.Test', newArrayFloatFromValue, [V], A),
	jpl_get( A, 0, V2).

test(
	new_interface_1,
	[	setup((
			Classname = 'java.util.Enumeration'
		)),
		throws(
			error(
				type_error(concrete_class,Classname),
				context(jpl_new/3,_)
			)
		)
	]
) :-
	jpl_new( Classname, [], _).

test(
	new_param_cyclic_term_1,
	[	setup((
			T = f(T)
		)),
		throws(
			error(
				type_error(acyclic,T),
				context(jpl_new/3,_)
			)
		)
	]
) :-
	jpl_new( 'jpl.test.Test', [{T}], _).

test(
	prolog_calls_java_calls_prolog_1,
	[	true((
			V == @(true)
		))
	]
) :-
	jpl_new( 'jpl.Query', ['4 is 2+2'], Q),
	jpl_call( Q, hasSolution, [], V).

test(
	set_array_element_cyclic_term_1,
	[	setup((
			T = f(T),
			jpl_new( array(class([jpl,test],['Test'])), 5, A)
		)),
		throws(
			error(
				type_error(acyclic,T),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( A, 0, {T}).

test(
	set_array_elements_bad_type_1,
	[	setup((
			jpl_new( array(byte), 3, A)
		)),
		throws(
			error(
				type_error(array(byte),[128]),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( A, 0, 128).

test(
	set_array_length_1,
	[	setup((
			jpl_new( array(byte), 6, A)
		)),
		throws(
			error(
				permission_error(modify,final_field,length),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( A, length, 13).

test(
	set_field_bad_field_spec_1,
	[	setup((
			BadFieldName = 3.7
		)),
		throws(
			error(
				type_error(field_name,BadFieldName),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', BadFieldName, a).

test(
	set_field_instance_cyclic_term_1,
	[	setup((
			T = f(T),
			jpl_new( 'jpl.test.Test', [], Test)
		)),
		throws(
			error(
				type_error(acyclic,T),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( Test, instanceTerm, {T}).

test(
	set_field_long_array_1,
	[	setup((
			jpl_new( array(long), [1,2,3], LongArray)
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticLongArray, LongArray).

test(
	set_field_long_array_2,
	[	setup((
			jpl_new( array(int), [1,2,3], IntArray)
		)),
		throws(
			error(
				type_error('[J',IntArray),	% NB '[J' is *not* how the type was specified in the failing goal
				context(
					jpl_set/3,
					'the value is not assignable to the named field of the class'
				)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticLongArray, IntArray).

test(
	set_field_object_array_1,
	[	setup((
			jpl_new( 'java.util.Date', [], Date),
			jpl_new( array(class([java,lang],['Object'])), [Date,Date], ObjArray)
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticObjectArray, ObjArray).

test(
	set_field_static_bad_type_1,
	[	setup((
			BadVal = 27
		)),
		throws(
			error(
				type_error(boolean,BadVal),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticBoolean, BadVal).

test(
	set_field_static_boolean_1,
	[	setup((
			jpl_true( V)
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticBoolean, V).

test(
	set_field_static_boolean_2,
	[	setup((
			jpl_false( V)
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticBoolean, V).

test(
	set_field_static_boolean_bad_1,
	[	setup((
			BadVal = foo(bar)
		)),
		throws(
			error(
				type_error(field_value,BadVal),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticBoolean, BadVal).

test(
	set_field_static_cyclic_term_1,
	[	setup((
			T = f(T)
		)),
		throws(
			error(
				type_error(acyclic,T),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', staticTerm, {T}).

test(
	set_field_static_final_int_1,
	[	setup((
			FieldName = fieldStaticFinalInt,
			Value = 6
		)),
		throws(
			error(
				permission_error(modify,final_field,FieldName),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', FieldName, Value).

test(
	set_field_static_shadow_1,
	[	blocked('we do not yet resolve same-named shadowed fields')
	]
) :-
	jpl_set( 'jpl.test.ShadowB', fieldStaticInt, 3).

test(
	set_field_static_term_1,
	[	setup((
			T1 = foo(bar,33),
			T2 = bar(77,bing)
		)),
		true((
			T1 == T1a,
			T2 == T2a
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticTerm, {T1}),
	jpl_get( 'jpl.test.Test', fieldStaticTerm, {T1a}),
	jpl_set( 'jpl.test.Test', fieldStaticTerm, {T2}),
	jpl_get( 'jpl.test.Test', fieldStaticTerm, {T2a}).

test(
	set_field_static_term_2,
	[	setup((
			T1 = foo(bar,33),
			T2 = bar(77,bing)
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticTerm, {T1}),
	jpl_get( 'jpl.test.Test', fieldStaticTerm, {T1}),
	jpl_set( 'jpl.test.Test', fieldStaticTerm, {T2}),
	jpl_get( 'jpl.test.Test', fieldStaticTerm, {T2}).

test(
	set_get_array_element_boolean_1,
	[	setup((
			jpl_new( array(boolean), 3, A),
			V = @(false)
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_boolean_2,
	[	setup((
			jpl_new( array(boolean), 3, A),
			V = @(true)
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_boolean_3,
	[	setup((
			jpl_new( array(boolean), 3, A),
			V = bogus
		)),
		throws(
			error(
				type_error(array(boolean),[V]),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( A, 2, V).

test(
	set_get_array_element_byte_1,
	[	setup((
			jpl_new( array(byte), 3, A),
			V = 33
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_byte_2,
	[	setup((
			jpl_new( array(byte), 3, A),
			V = 128
		)),
		throws(
			error(
				type_error(array(byte),[V]),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( A, 2, V).

test(
	set_get_array_element_char_1,
	[	setup((
			jpl_new( array(char), 3, A),
			V = 65535
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_double_1,
	[	setup((
			jpl_new( array(double), 3, A),
			V = 2.5
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_float_1,
	[	setup((
			jpl_new( array(float), 3, A),
			V = 7.5
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_float_2,
	[	setup((
			jpl_new( array(float), 3, A),
			V is 2,
			VrX is float(V)
		)),
		true((
			VrX == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_float_3,
	[	setup((
			jpl_new( array(float), 3, A),
			(	current_prolog_flag( bounded, true)
			->	current_prolog_flag( max_integer, Imax)
			;	Imax is 2**63-1
			),
			VrX is float(Imax)
		)),
		true((
			VrX == Vr
		))
	]
) :-
	jpl_set( A, 2, Imax),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_long_1,
	[	setup((
			jpl_new( array(long), 3, A),
			(	current_prolog_flag( bounded, true)
			->	current_prolog_flag( max_integer, V)
			;	V is 2**63-1
			)
		)),
		true((
			V == Vr
		))
	]
) :-
	jpl_set( A, 2, V),
	jpl_get( A, 2, Vr).

test(
	set_get_array_element_long_2,
	[	setup((
			jpl_new( array(long), 3, A),
			(	current_prolog_flag( bounded, true)
			->	current_prolog_flag( max_integer, V)
			;	V is 2**63
			)
		)),
		throws(
			error(
				type_error(array(long),[V]),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( A, 2, V).

test(
	set_get_array_elements_boolean_1,
	[	setup((
			jpl_new( array(boolean), 3, A),
			Vf = @(false),
			Vt = @(true)
		)),
		true((
			Vf+Vt+Vf == Vr0+Vr1+Vr2
		))
	]
) :-
	jpl_set( A, 0, Vf),
	jpl_set( A, 1, Vt),
	jpl_set( A, 2, Vf),
	jpl_get( A, 0, Vr0),
	jpl_get( A, 1, Vr1),
	jpl_get( A, 2, Vr2).

test(
	set_get_field_static_long_1,
	[	setup((
			(   current_prolog_flag( bounded, true)
		    ->  current_prolog_flag( max_integer, V)
		    ;   V is 2**63-1
		    )
		)),
		true((
			V == V2
		))
	]
) :-
	jpl_set( 'jpl.test.Test', fieldStaticLong, V),
	jpl_get( 'jpl.test.Test', fieldStaticLong, V2).

test(
	set_non_accessible_field_1,
	[	throws(
			error(
				existence_error(field,gagaga),
				context(jpl_set/3,_)
			)
		)
	]
) :-
	jpl_set( 'jpl.test.Test', gagaga, 4).

test(
	terms_to_array_1,
	[]
) :-
	jpl_terms_to_array( [foo(bar)], A),
	jpl_object_to_type( A, array(class([jpl],['Term']))),
	jpl_get( A, length, 1),
	jpl_get( A, 0, T),
	jpl_call( T, toString, [], 'foo(bar)').

test(
	throw_java_exception_1,
	[	blocked('part of the error term is nondeterministic: we need to match with _'),
		throws(
			error(
				java_exception(@(_)),
				'java.lang.NumberFormatException'
			)
		)
	]
) :-
	jpl_call( 'java.lang.Integer', decode, [q], _).

test(
	versions_1,
	[	true((
			Vpl == Vc,
			Vc == Vjava
		))
	]
) :-
	jpl_pl_lib_version(Vpl),
	jpl_c_lib_version(Vc),
	jpl_call( 'jpl.JPL', version_string, [], Vjava).

%	JW: Mutual recursion check.  Moved from jpl.pl to here.  As the
%	callback is in module user, we define it there.

user:jpl_test_fac( N, F) :-
	(	N == 1
	->	F = 1
	;	N > 1
	->	N2 is N-1,
		jpl_call( 'jpl.test.Test', fac, [N2], F2),	% call its Java counterpart, which does vice versa
		F is N*F2
	;	F = 0
	).

test(fac10,
     [ true(N==3628800)
     ]) :-
     user:jpl_test_fac(10, N).

test(threads1,
	[	true((
			thread_create(jpl_call('java.lang.System', currentTimeMillis, [], _), ThreadId, []),
			thread_join(ThreadId, true)
		))
	]
) :-
	jpl_call('java.lang.System', currentTimeMillis, [], _).

test(threads2, true(X==true)) :-
	jpl_call('java.lang.System', currentTimeMillis, [], _),
	thread_create(jpl_call('java.lang.System', currentTimeMillis, [], _), ThreadId, []),
	thread_join(ThreadId, X).

test(threads3,
	[	true((
			length(Ss, 1000),
			sort(Ss, [true])
		))
	]
) :-
	jpl_call('java.lang.System', currentTimeMillis, [], _),
	findall(
		Status,
		(	between(1, 1000, _),
			thread_create(jpl_call('java.lang.System', currentTimeMillis, [], _), ThreadId, []),
			thread_join(ThreadId, Status)
		),
		Ss
	).

test(jref1,
	[	true((
			Term1 \== Term2,
			Term1 =@= Term2
		))
	]
) :-
	length(Term1, 5),
	jpl:jni_term_to_jref(Term1, JRef),
	jpl:jni_jref_to_term(JRef, Term2).

:- end_tests(jpl).