blob: 8b4044dfc93820f57b4efeb09353d3bd75fb4479 [file] [log] [blame]
/**
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you under the Apache License, Version 2.0 (the
*"License"); you may not use this file except in compliance
*with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an
*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
*specific language governing permissions and limitations
*under the License.
*/
#include <CppUTest/TestHarness.h>
#include <float.h>
#include <assert.h>
#include "CppUTest/CommandLineTestRunner.h"
extern "C" {
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <ffi.h>
#include "dyn_common.h"
#include "dyn_type.h"
#include "json_serializer.h"
#include "json_rpc.h"
static void stdLog(void *handle, int level, const char *file, int line, const char *msg, ...) {
va_list ap;
const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"};
fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line);
va_start(ap, msg);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
}
void prepareTest(void) {
dyn_function_type *dynFunc = NULL;
int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", NULL, &dynFunc);
CHECK_EQUAL(0, rc);
char *result = NULL;
void *handle = NULL;
double arg1 = 1.0;
double arg2 = 2.0;
void *args[4];
args[0] = &handle;
args[1] = &arg1;
args[2] = &arg2;
rc = jsonRpc_prepareInvokeRequest(dynFunc, "add", args, &result);
CHECK_EQUAL(0, rc);
//printf("result is %s\n", result);
STRCMP_CONTAINS("\"add\"", result);
STRCMP_CONTAINS("1.0", result);
STRCMP_CONTAINS("2.0", result);
free(result);
dynFunction_destroy(dynFunc);
}
void handleTestPre(void) {
dyn_function_type *dynFunc = NULL;
int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", NULL, &dynFunc);
CHECK_EQUAL(0, rc);
const char *reply = "{\"r\":2.2}";
double result = -1.0;
double *out = &result;
void *args[4];
args[3] = &out;
rc = jsonRpc_handleReply(dynFunc, reply, args);
CHECK_EQUAL(0, rc);
//CHECK_EQUAL(2.2, result);
dynFunction_destroy(dynFunc);
}
int add(void *handle, double a, double b, double *result) {
*result = a + b;
return 0;
}
int getName_example4(void *handle, char** result) {
*result = strdup("allocatedInFunction");
return 0;
}
struct tst_seq {
uint32_t cap;
uint32_t len;
double *buf;
};
//StatsResult={DDD[D average min max input}
struct tst_StatsResult {
double average;
double min;
double max;
struct tst_seq input;
};
int stats(void *handle, struct tst_seq input, struct tst_StatsResult **out) {
assert(out != NULL);
assert(*out == NULL);
double total = 0.0;
unsigned int count = 0;
double max = DBL_MIN;
double min = DBL_MAX;
unsigned int i;
for (i = 0; i<input.len; i += 1) {
total += input.buf[i];
count += 1;
if (input.buf[i] > max) {
max = input.buf[i];
}
if (input.buf[i] < min) {
min = input.buf[i];
}
}
struct tst_StatsResult *result = (struct tst_StatsResult *) calloc(1, sizeof(*result));
result->average = total / count;
result->min = min;
result->max = max;
double *buf = (double *)calloc(input.len, sizeof(double));
memcpy(buf, input.buf, input.len * sizeof(double));
result->input.len = input.len;
result->input.cap = input.len;
result->input.buf = buf;
*out = result;
return 0;
}
struct item {
double a;
double b;
};
struct item_seq {
uint32_t cap;
uint32_t len;
struct item **buf;
};
struct tst_serv {
void *handle;
int (*add)(void *, double, double, double *);
int (*sub)(void *, double, double, double *);
int (*sqrt)(void *, double, double *);
int (*stats)(void *, struct tst_seq, struct tst_StatsResult **);
};
struct tst_serv_example4 {
void *handle;
int (*getName_example4)(void *, char** name);
};
void callTestPreAllocated(void) {
dyn_interface_type *intf = NULL;
FILE *desc = fopen("descriptors/example1.descriptor", "r");
CHECK(desc != NULL);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
char *result = NULL;
struct tst_serv serv;
serv.handle = NULL;
serv.add = add;
rc = jsonRpc_call(intf, &serv, "{\"m\":\"add(DD)D\", \"a\": [1.0,2.0]}", &result);
CHECK_EQUAL(0, rc);
STRCMP_CONTAINS("3.0", result);
free(result);
dynInterface_destroy(intf);
}
void callTestOutput(void) {
dyn_interface_type *intf = NULL;
FILE *desc = fopen("descriptors/example1.descriptor", "r");
CHECK(desc != NULL);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
char *result = NULL;
struct tst_serv serv;
serv.handle = NULL;
serv.stats = stats;
rc = jsonRpc_call(intf, &serv, "{\"m\":\"stats([D)LStatsResult;\", \"a\": [[1.0,2.0]]}", &result);
CHECK_EQUAL(0, rc);
STRCMP_CONTAINS("1.5", result); //avg
free(result);
dynInterface_destroy(intf);
}
void handleTestOut(void) {
dyn_interface_type *intf = NULL;
FILE *desc = fopen("descriptors/example1.descriptor", "r");
CHECK(desc != NULL);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
struct methods_head *head;
dynInterface_methods(intf, &head);
dyn_function_type *func = NULL;
struct method_entry *entry = NULL;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(entry->name, "stats") == 0) {
func = entry->dynFunc;
break;
}
}
CHECK(func != NULL);
const char *reply = "{\"r\":{\"input\":[1.0,2.0],\"max\":2.0,\"average\":1.5,\"min\":1.0}}";
void *args[3];
args[0] = NULL;
args[1] = NULL;
args[2] = NULL;
struct tst_StatsResult *result = NULL;
void *out = &result;
args[2] = &out;
rc = jsonRpc_handleReply(func, reply, args);
CHECK_EQUAL(0, rc);
CHECK_EQUAL(1.5, result->average);
free(result->input.buf);
free(result);
dynInterface_destroy(intf);
}
static void handleTestOutputSequence(void) {
dyn_interface_type *intf = NULL;
FILE *desc = fopen("descriptors/example2.descriptor", "r");
CHECK(desc != NULL);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
struct methods_head *head;
dynInterface_methods(intf, &head);
dyn_function_type *func = NULL;
struct method_entry *entry = NULL;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(entry->name, "example1") == 0) {
func = entry->dynFunc;
break;
}
}
CHECK(func != NULL);
//dyn_type *arg = dynFunction_argumentTypeForIndex(func, 1);
//dynType_print(arg, stdout);
const char *reply = "{\"r\":[{\"a\":1.0,\"b\":1.5},{\"a\":2.0,\"b\":2.5}]}";
void *args[2];
args[0] = NULL;
args[1] = NULL;
struct item_seq *result = NULL;
void *out = &result;
args[1] = &out;
rc = jsonRpc_handleReply(func, reply, args);
CHECK_EQUAL(0, rc);
CHECK_EQUAL(2, result->len);
CHECK_EQUAL(1.0, result->buf[0]->a);
CHECK_EQUAL(1.5, result->buf[0]->b);
CHECK_EQUAL(2.0, result->buf[1]->a);
CHECK_EQUAL(2.5, result->buf[1]->b);
unsigned int i;
for (i = 0; i < result->len; i +=1 ) {
free(result->buf[i]);
}
free(result->buf);
free(result);
dynInterface_destroy(intf);
}
void callTestOutChar(void) {
dyn_interface_type *intf = NULL;
FILE *desc = fopen("descriptors/example4.descriptor", "r");
CHECK(desc != NULL);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
char *result = NULL;
struct tst_serv_example4 serv;
serv.handle = NULL;
serv.getName_example4 = getName_example4;
rc = jsonRpc_call(intf, &serv, "{\"m\":\"getName(V)t\", \"a\": []}", &result);
CHECK_EQUAL(0, rc);
STRCMP_CONTAINS("allocatedInFunction", result);
free(result);
dynInterface_destroy(intf);
}
void handleTestOutChar(void) {
dyn_interface_type *intf = NULL;
FILE *desc = fopen("descriptors/example4.descriptor", "r");
CHECK(desc != NULL);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
struct methods_head *head;
dynInterface_methods(intf, &head);
dyn_function_type *func = NULL;
struct method_entry *entry = NULL;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(entry->name, "getName") == 0) {
func = entry->dynFunc;
break;
}
}
CHECK(func != NULL);
const char *reply = "{\"r\": \"this is a test string\" }";
char *result = NULL;
void *out = &result;
void *args[2];
args[0] = NULL;
args[1] = &out;
rc = jsonRpc_handleReply(func, reply, args);
STRCMP_EQUAL("this is a test string", result);
free(result);
dynInterface_destroy(intf);
}
}
TEST_GROUP(JsonRpcTests) {
void setup() {
int lvl = 1;
dynCommon_logSetup(stdLog, NULL, lvl);
dynType_logSetup(stdLog, NULL,lvl);
dynFunction_logSetup(stdLog, NULL,lvl);
dynInterface_logSetup(stdLog, NULL,lvl);
jsonSerializer_logSetup(stdLog, NULL, lvl);
jsonRpc_logSetup(stdLog, NULL, lvl);
}
};
TEST(JsonRpcTests, prepareTest) {
prepareTest();
}
TEST(JsonRpcTests, handleTestPre) {
handleTestPre();
}
TEST(JsonRpcTests, handleTestOut) {
handleTestOut();
}
TEST(JsonRpcTests, callPre) {
callTestPreAllocated();
}
TEST(JsonRpcTests, callOut) {
callTestOutput();
}
TEST(JsonRpcTests, handleOutSeq) {
handleTestOutputSequence();
}
TEST(JsonRpcTests, callTestOutChar) {
callTestOutChar();
}
TEST(JsonRpcTests, handleOutChar) {
handleTestOutChar();
}