### ----------------------------------------------------
### -- Cro::RPC::JSON
### -- Licenses: Artistic-2.0
### -- Authors: Vadim Belman <vrurg@lflat.org>
### -- File: t/050-request.rakutest
### ----------------------------------------------------
use lib $?FILE.IO.parent(1).add('lib');
use lib $?FILE.IO.parent(2).add('lib');
use Test;
use Test::JRPC;
use Cro::HTTP::Test;
use Cro::HTTP::Router;
use Cro::RPC::JSON:api<2>;
use Cro::RPC::JSON::Exception;
use Cro::RPC::JSON::MethodResponse:api<2>;
use JSON::Fast;
use Test-Data;

plan 2;

subtest "Basics", {
    use Basic-JRPC;
    my @basics = ['Sync', &Basic-JRPC::routes], ['Async', &Basic-JRPC::async-routes];

    for @basics -> ($title, &r) {
        subtest $title => {
            plan 5;

            test-service &r(), {

                test post('api', content-type => "application/notjson"),
                     status => 415,
                     ;

                test post('api', json => { jsonrpc=>"2.0", id=>123, method => "oops", params => [1,2,3] }),
                     status => 200,
                     json => { jsonrpc => "2.0", id => 123, result => { a => 1, b => 2 } },
                     ;

                test post('api', json => { jsonrpc=>"2.0", id=> "stringy-id-124", method => "oops", params => [1,2,3] }),
                     status => 200,
                     json => { jsonrpc => "2.0", id => "stringy-id-124", result => { a => 1, b => 2 } },
                     ;

                test post(
                         'api',
                         content-type => 'application/json',
                         body => to-json( [
                             { jsonrpc => "2.0", id => 321, method => "go", params => <a b c> },
                             { jsonrpc => "2.0", method => "go-notify", params => <a b c> },
                             { jsonrpc => "2.0", id => 322, method => "do", params => <d e f> },
                             { method  => "go", id => 323, params => "aaa" },
                             { jsonrpc => "1.0", id => 324, method => "do-1", },
                             { jsonrpc => "2.0", id => 325, method => "rpc.method", },
                         ] ),
                                                    ),
                     status => 200,
                     json => [
                         { jsonrpc => "2.0", id => 321, result => { a=>1, b=>2 } },
                         { jsonrpc => "2.0", id => 322, result => { a=>1, b=>2 } },
                         {
                             jsonrpc => "2.0",
                             error   => {
                                 code    => JRPCInvalidRequest,
                                 message => "Missing required 'jsonrpc' key",
                             },
                         },
                         {
                             jsonrpc => "2.0",
                             id      => 324,
                             error   => {
                                 code    => JRPCInvalidRequest,
                                 message => "Invalid jsonrpc version: 1.0",
                             },
                         },
                         { jsonrpc => "2.0", id => 325, result => { a=>1, b=>2 } },
                     ],
                     ;

                test get( '/api' ),
                     status => 500,
                     content-type => "text/plain",
                     body-text => /"JSON-RPC is only supported for POST method"/,
                     ;
            }
        }
    }
}

subtest "Actor Class" => {
    plan 2;
    use JRPC-Actor;

    sub test-actor(Mu \actor, Str:D $message) {
        subtest $message => {
            plan @Test-Data::jrpc-requests.elems;
            sub routes {
                route {
                    my $actor = actor.new;
                    post -> "api" {
                        json-rpc $actor;
                    }
                }
            }

            my $id = 123;
            test-service routes, {
                test-given '/api', {
                    my $*expected-jrpc-protocol = 'HTTP';
                    my $*expected-jrpc-method = 'POST';
                    for @Test-Data::jrpc-requests -> %req-data {
                        my $id = next-id;
                        my ( %json, %expect );
                        given %req-data {
                            %json = jsonrpc => "2.0",
                                    :$id,
                                    method => .<method>,
                                    |( params => $_ with .<params> );
                            %expect = status => .<status>,
                                      json => {
                                          deep-compare $_,
                                                       {
                                                           jsonrpc => "2.0",
                                                           :$id,
                                                           |( <result error>.map(-> $k { $k =>
                                                                                         $_ with %req-data{$k} }) )
                                                       }
                                      },
                                      ;
                        }

                        subtest %req-data<subtest>, {
                            test post(:%json, content-type => "application/json; charset=UTF-8"), |%expect;
                        }
                    }
                }
            };
        }
    }

    test-actor(JRPC-Actor, "An Actor Class");

    my class Actor-Child is JRPC-Actor { };
    test-actor(Actor-Child, "A Child Of Actor Class");
}

done-testing;

# vim: ft=perl6


