Skip to content

Commit

Permalink
Perform more strict checking on interface method.
Browse files Browse the repository at this point in the history
1. The first method argument must be of handle type.
2. Only one output argument (either am=pre or am=out) is allowed.
3. Output argument (if any) must be the last argument.
  • Loading branch information
PengZheng committed Jan 26, 2024
1 parent aebe975 commit 28db6c3
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ version=1.0.0
:annotations
classname=org.example.Calculator
:methods
add(DD)D=add(#am=invalid;PDD#am=pre;*D)N
add(DD)D=add(#am=handle;P#am=invalid;PDD#am=pre;*D)N
13 changes: 13 additions & 0 deletions libs/dfi/gtest/descriptors/invalids/methodMissingHandle.descriptor
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:header
type=interface
name=calculator
version=1.0.0
:annotations
classname=org.example.Calculator
:types
StatsResult={DDD[D average min max input}
:methods
add(DD)D=add(DD#am=pre;*D)N
sub(DD)D=sub(#am=handle;PDD*#am=pre;D)N
sqrt(D)D=sqrt(#am=handle;PD*#am=pre;D)N
stats([D)LStatsResult;=stats(#am=handle;P[D#am=out;*LStatsResult;)N
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:header
type=interface
name=calculator
version=1.0.0
:annotations
classname=org.example.Calculator
:types
StatsResult={DDD[D average min max input}
:methods
add(DD)D=add()N
sub(DD)D=sub(#am=handle;PDD*#am=pre;D)N
sqrt(D)D=sqrt(#am=handle;PD*#am=pre;D)N
stats([D)LStatsResult;=stats(#am=handle;P[D#am=out;*LStatsResult;)N
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ version=1.0.0
:annotations
:types
:methods
multiPreOut(V)Di=multiPreOut(#am=handle;P#am=pre;*D#am=pre;*i)N
multiOut(V)Di=multiOut(#am=handle;P#am=out;**D#am=out;**i)N
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
:header
type=interface
name=example5
version=1.0.0
:annotations
:types
:methods
multiPreOut(V)Di=multiPreOut(#am=handle;P#am=pre;*D#am=pre;*i)N
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
:header
type=interface
name=example5
version=1.0.0
:annotations
:types
:methods
outWrongPos(V)Di=outWrongPos(#am=handle;P#am=out;**i**D)N
69 changes: 69 additions & 0 deletions libs/dfi/gtest/src/dyn_interface_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern "C" {

#include "dyn_common.h"
#include "dyn_interface.h"
#include "celix_err.h"
#include "celix_version.h"

static void checkInterfaceVersion(dyn_interface_type* dynIntf, const char* v) {
Expand Down Expand Up @@ -100,111 +101,174 @@ extern "C" {
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of a space at the end of the name
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid header */
desc = fopen("descriptors/invalids/invalidHeader.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing name value
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Header without Version */
desc = fopen("descriptors/invalids/noVersion.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing version field in header section
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Header without Type */
desc = fopen("descriptors/invalids/noType.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing type field in header section
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Header without Name */
desc = fopen("descriptors/invalids/noName.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing name field in header section
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid Annotations Section */
desc = fopen("descriptors/invalids/invalidInterfaceAnnotations.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing name field in annotations section
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid section */
desc = fopen("descriptors/invalids/invalidSection.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of unknown section type
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid return type */
desc = fopen("descriptors/invalids/invalidMethodReturnType.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of invalid return type (D instead of N)
EXPECT_STREQ("Parse Error. Got return type 'D' rather than 'N' (native int) for method add(DD)D (0)", celix_err_popLastError());
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Method without arguments */
desc = fopen("descriptors/invalids/methodWithoutArguments.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_NE(0, status);
EXPECT_STREQ("Parse Error. The first argument must be handle for method add(DD)D (0)", celix_err_popLastError());
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Method missing handle */
desc = fopen("descriptors/invalids/methodMissingHandle.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_NE(0, status);
EXPECT_STREQ("Parse Error. The first argument must be handle for method add(DD)D (0)", celix_err_popLastError());
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Method with multiple PreOut arguments */
desc = fopen("descriptors/invalids/multiPreOutArgs.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_NE(0, status);
EXPECT_STREQ("Parse Error. Only one output argument is allowed for method multiPreOut(V)Di (0)", celix_err_popLastError());
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Method with multiple Out arguments */
desc = fopen("descriptors/invalids/multiOutArgs.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_NE(0, status);
EXPECT_STREQ("Parse Error. Only one output argument is allowed for method multiOut(V)Di (0)", celix_err_popLastError());
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Method with an Out argument at wrong position */
desc = fopen("descriptors/invalids/outArgAtWrongPosition.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_NE(0, status);
EXPECT_STREQ("Parse Error. Output argument is only allowed as the last argument for method outWrongPos(V)Di (0)",
celix_err_popLastError());
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid method section */
desc = fopen("descriptors/invalids/invalidMethod.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of space at the end of the method
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid method section missing method id */
desc = fopen("descriptors/invalids/invalidMethodMissingId.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid method section missing equality */
desc = fopen("descriptors/invalids/invalidMethodMissingEquality.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid method section missing function name */
desc = fopen("descriptors/invalids/invalidMethodMissingFunctionName.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid type */
desc = fopen("descriptors/invalids/invalidType.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of space at the end of the type
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid types section missing type name */
desc = fopen("descriptors/invalids/noTypeName.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing type name
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid types section missing equality */
desc = fopen("descriptors/invalids/invalidTypeMissingEquality.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status); //Test fails because of missing equality
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid types section with unrecognized simple type */
desc = fopen("descriptors/invalids/invalidTypeUnrecognizedSimpleType.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_NE(0, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* Invalid metatype in method description */
desc = fopen("descriptors/invalids/invalidMetaType.descriptor", "r");
Expand All @@ -213,27 +277,31 @@ extern "C" {
dynInterface_destroy(dynIntf);
ASSERT_EQ(0, status); //Invalid meta type doesn't generate errors, just warnings
fclose(desc); desc=NULL; dynIntf=NULL;
celix_err_resetErrors();

/* Invalid version section */
desc = fopen("descriptors/invalids/invalidVersion.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* garbage descriptor */
desc = fopen("descriptors/invalids/garbage.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();

/* invalid extra section */
desc = fopen("descriptors/invalids/invalidExtraSection.descriptor", "r");
assert(desc != NULL);
status = dynInterface_parse(desc, &dynIntf);
ASSERT_EQ(1, status);
fclose(desc); desc=NULL;
celix_err_resetErrors();
}
}

Expand All @@ -242,6 +310,7 @@ class DynInterfaceTests : public ::testing::Test {
DynInterfaceTests() {
}
~DynInterfaceTests() override {
celix_err_resetErrors();
}

};
Expand Down
95 changes: 0 additions & 95 deletions libs/dfi/gtest/src/json_rpc_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,93 +584,6 @@ extern "C" {
dynInterface_destroy(intf);
}

//Current only support one out argument
void handleTestMultiPreOut(void) {
dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/invalids/multiOutArgs.descriptor", "r");
ASSERT_TRUE(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
ASSERT_EQ(0, rc);
fclose(desc);

const struct methods_head* head = dynInterface_methods(intf);
dyn_function_type *func = nullptr;
struct method_entry *entry = nullptr;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(dynFunction_getName(entry->dynFunc), "multiPreOut") == 0) {
func = entry->dynFunc;
break;
}
}
ASSERT_TRUE(func != nullptr);

const char *reply = R"({"r":2.0})";

void *args[3];
args[0] = nullptr;
args[1] = nullptr;
args[2] = nullptr;

double result1 = 0;
void *out = &result1;
args[1] = &out;
int result2 = 0;
void *out2 = &result2;
args[2] = &out2;

int rsErrno = 0;
rc = jsonRpc_handleReply(func, reply, args, &rsErrno);
ASSERT_NE(0, rc);
celix_err_printErrors(stderr, nullptr, nullptr);

dynInterface_destroy(intf);
}

//Current only support one out argument
void handleTestMultiOut(void) {
dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/invalids/multiOutArgs.descriptor", "r");
ASSERT_TRUE(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
ASSERT_EQ(0, rc);
fclose(desc);

const struct methods_head* head = dynInterface_methods(intf);
dyn_function_type *func = nullptr;
struct method_entry *entry = nullptr;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(dynFunction_getName(entry->dynFunc), "multiOut") == 0) {
func = entry->dynFunc;
break;
}
}
ASSERT_TRUE(func != nullptr);

const char *reply = R"({"r":2.0})";

void *args[3];
args[0] = nullptr;
args[1] = nullptr;
args[2] = nullptr;

double *result1 = nullptr;
void *out = &result1;
args[1] = &out;
int *result2 = nullptr;
void *out2 = &result2;
args[2] = &out2;

int rsErrno = 0;
rc = jsonRpc_handleReply(func, reply, args, &rsErrno);
ASSERT_NE(0, rc);
celix_err_printErrors(stderr, nullptr, nullptr);

dynInterface_destroy(intf);
}




void callTestOutChar(void) {
dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example4.descriptor", "r");
Expand Down Expand Up @@ -897,14 +810,6 @@ TEST_F(JsonRpcTests, handleTestAction) {
handleTestAction();
}

TEST_F(JsonRpcTests, handleTestMultiPreOut) {
handleTestMultiPreOut();
}

TEST_F(JsonRpcTests, handleTestMultiOut) {
handleTestMultiOut();
}

TEST_F(JsonRpcTests, callTestChar) {
callTestChar();
}
Expand Down
Loading

0 comments on commit 28db6c3

Please sign in to comment.