PL-Unit problem with JSON terms

Hi,

I’ve been struggling for a while with using JSON inside unit tests (or at least that seems to me to be the problem). I am new to Prolog, so I have been trying to study the SWI-Prolog documentation in detail, but something must have escaped my attention. Please forgive any inexact terms I may use.

The problem is that I receive the error “‘json_term’ expected, found … (a compound)” when I try to introduce a JSON object inside the test block (I also tried using a dict object). I have tested the same JSON object outside plunit, and it seems to be correct.

I will include the test results and code to reproduce the problem.

Any help would be greatly appreciated.

Best,

Mikko Tiihonen

Welcome to SWI-Prolog (threaded, 64 bits, version 8.0.3)
?- load_test_files([make(all)]).
**true.**
?- run_tests.
% PL-Unit: test_server
% Started server at http://localhost:50001/
**ERROR: …/test/test_server.plt:8:**
**test server: assertion failed**
**Assertion: _10130==foo**
**ERROR: …/test/test_server.plt:8:**
**test server: received error: Type error: `json_term' expected, found `param1=foo' (a compound)**
done
% 1 assertion failed
% 1 test failed
% 0 tests passed
**false.**

test_server.pl:

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/json)).
:- use_module(library(http/http_json)).

server(Port) :-
	http_server(http_dispatch,
	[ port(Port)
	]).
	
:- http_handler(root(.), entry_page, []).

entry_page(Request) :-
	reply(Request).
	
reply(Request) :-
	member(method(post), Request), !,
	http_read_json(Request, DataDict, [json_object(dict)]),
	get_dict(param1, DataDict, ReplyDict),
	reply_json_dict(ReplyDict).

test_server.plt:

:- use_module(library(http/http_client)).
:- use_module(library(http/json)).

:- include(test_server).

:- begin_tests(test_server).

test(server) :-
	setup_call_cleanup(
		server(50001),
		http_post('http://localhost:50001', json([param1='foo', param2='bar']), In, []),
		(assertion(In == 'foo'), http_stop_server(50001, []))).

:- end_tests(test_server).

I have not done more than read your post and noticed that you are having problems using an SWI-Prolog HTTP server to handle JSON. Instead of trying to find and fix your bug, I saw that Simple Prolog server with JavaScript clien is also using JSON and might be a better starting point for what you seek.

Also, again without running any code, in test_server.plt noticed that

:- use_module(library(http/http_client)).
:- use_module(library(http/json)).

:- include(test_server).

is before

:- begin_tests(test_server).

When I see

:- begin_tests(test_server).

I think

module('test_server',[]).

In other words you are wanting the to use modules but you have asked for them outside of the test module.

I would try this:

:- begin_tests(test_server).

:- use_module(library(http/http_client)).
:- use_module(library(http/json)).

Not sure about what to do with

:- include(test_server).

but thinking the test_server should be put into a module and then also added with use_module/1

HTH

Thank you for your kind suggestions, Eric. use_module/1 is certainly more elegant and I also tried wrapping everything in the test module. I will also have a look at the Simple Prolog Server,

However, the original problem remains despite these changes. It seems to me that for some reason JSON objects are parsed as Prolog compounds when inside the test block (but of course I may be mistaken).

I think you have to wrap your JSON object once more in json/1, i.e.,

json(json([Name=Value, ...]))

The first tells http_post/4 that the data is JSON and the second specifies the JSON data itself. Note that you can also have json("Hello world").

Thanks a lot, Jan! That solved my problem.

It is really great to have such helpful experts here. Prolog seems to have quite some intricacies, while being a very powerful language. The community spirit here is admirable.

Best,

Mikko