単純型の値の場合、スタブ API はそのまますぐに使用できます。上級ユーザーは、選択した複合型に特化してスタブ API を拡張することができます。この作業については 「複合型に対応するための高度な方法」 で説明します。しかし多くの場合には、スタブ本体への名前付きヘルパー引数を利用する 「複合型に対応するための高度な方法」 の方法で十分です。その例を以下に示します。
複合型に対応するための基本方法
以下の構造体定義を例に考えてみましょう。
struct
Point {
int _x;
int _y;
};
スタブは以下の関数宣言のために作成されます。
Point movePoint(Point line, int xoff, int yoff);
関数の戻り値を変更する必要がある場合、スタブ本体に以下の変更を適用しなければなりません。
- 変更する各メンバーのヘルパー変数を宣言します。
- 変数は (テスト ケース コードによって) 外部から変更されます。
- 変更された値をオリジナルの戻り値に代入します。
Point CppTest_Stub_movePoint (Point point) { Point __return = Point(); int __callOrig = 0; int __point_x = __return._x; /* [1] helper variable for complex type member */ int __point_y = __return._y; /* [1] helper variable for complex type member */ CPPTEST_ACTUAL_CALL("movePoint").WithArg("point", &point). WithArg("__return", &__return)).WithArg("__callOrig", ByRef(__callOrig)). /* [2] expose variable for external modification */ WithArg("__point_x", ByRef(__point_x)). /* [b] expose variable for external modification */ WithArg("__point_y", ByRef(__point_y)). End(); __return._x = __point_x; /* [3] update return value with modified value */ __return._y = __point_y; /* [3] update return value with modified value */ if (__callOrig) { Point __return = movePoint(point); CPPTEST_ACTUAL_AFTER_CALL("movePoint"). WithArg("point", &point).WithArg("__return", &__return)). WithArg("__callOrig", ByRef(__callOrig)).End(); return __return; } return __return; }
次に、テスト ケース中で戻り値を以下のように変更できます。
CPPTEST_ON_CALL("movePoint").Arg("__point_x").Assign(1).
Arg("__point_y").Assign(2);
複合型に対応するための高度な方法
スタブ API で複合型を使用するには、複合型のデータ メンバーへのアクセスを容易にするために、型に固有のヘルパー コードを記述する必要があります。型に固有のユーティリティ コードを用意すると、ベース スタブ API の関数を使って複合型のフィールドにアクセスすることができます。
この概念を説明するために、以下の構造体定義を考えてみましょう。
struct
Point {
int _x;
int _y;
};
struct Line {
Point _p1;
Point _p2;
};
スタブは以下の関数宣言のために作成されます。
Line moveLine(Line line, int xoff, int yoff);
この例での目的は、以下の構文によって、複合型の引数とパラメーターのためのスタブの振る舞いを有効にすることです。
CPPTEST_ON_CALL("moveLine").Arg("__return").Field("_p1").Field("_x").Assign(0);
CPPTEST_ON_CALL("moveLine").Arg("__line").Field("_p2").Field("_y").Assign(12);
この目的を達成するには、moveLine() 関数のスタブが定義されているソース ファイルに以下のコードを追加する必要があります。
/** * Field access function for Point structure * / tgr_value CppTest_Tgr_GetField_Point(tgr_value_ptr obj, tgr_value_ptr field_name) { Point *point = (Point *)obj->value.ptr; const char* name = tgr_value_get_string(field_name); if (tgr_strcmp(name, "_x") == 0) { return tgr_int_ref(&point->_x); } else if (tgr_strcmp(name, "_y") == 0) { return tgr_int_ref(&point->_y); } else { return tgr_error(c_tgr_error_wrong_get_field_argument); } } /** * Helper function returning pointer to structure with Point type * specific utilities */ tgr_type_ptr CppTest_Tgr_Type_Data(void) { static struct tgr_class_definition class_definition = {tgr_false}; if (!class_definition.initialized) { tgr_initialize_class_definition(&class_definition); class_definition.vtbl.get_field = CppTest_Tgr_GetField_Data; } return &class_definition.type; } /** * Field access function for Line structure */ tgr_value TRIGGER_CDECL CppTest_Tgr_GetField_Line(tgr_value_ptr obj, tgr_value_ptr field_name) { Line *line = (Line *)obj->value.ptr; const char* name = tgr_value_get_string(field_name); if (tgr_strcmp(name, "_p1") == 0) { return tgr_object(&line->p1, CppTest_Tgr_Type_Point()); } else if (tgr_strcmp(name, "_p2") == 0) { return tgr_object(&line->_p2, CppTest_Tgr_Type_Point()); } else { return tgr_error(c_tgr_error_wrong_get_field_argument); } } /** * Helper function returning pointer to structure with Line type * specific utilities */ tgr_type_ptr CppTest_Tgr_Type_Line(void) { static struct tgr_class_definition class_definition = {tgr_false}; if (!class_definition.initialized) { tgr_initialize_class_definition(&class_definition); class_definition.vtbl.get_field = CppTest_Tgr_GetField_Line; } return &class_definition.type; }
最後に、型に固有の操作コードをスタブ本体に置く必要があります。それには、自動生成スタブの本体を変更し、以下のメソッド呼び出しを新しい呼び出しで置き換える必要があります。
元の呼び出し:
WithArg(const char* name, RValue value)
置き換える呼び出し:
WithArg(const char* name, const volatile void* obj, tgr_type_ptr type)
メソッド呼び出しでは、型に特化したユーティリティを指定できます。変更したスタブ本体は、以下の例に似ているはずです。
Line CppTest_Stub_moveLine (Line line, int xoff, int yoff) { Line __return = Line(); int __callOrig = 0; CPPTEST_ACTUAL_CALL("moveLine "). WithArg("line", &line, CppTest_Tgr_Type_Line()). WithArg("xoff", ByRef(xoff)). WithArg("xoff", ByRef(yoff)). WithArg("__return", &__return, CppTest_Tgr_Type_Line()). WithArg("__callOrig", ByRef(__callOrig)).End(); if (__callOrig) { Line __return = moveLine(line, xoff, yoff); CPPTEST_ACTUAL_AFTER_CALL("moveLine "). WithArg("line", &line, CppTest_Tgr_Type_Line()). WithArg("xoff", ByRef(xoff)). WithArg("xoff", ByRef(yoff)). WithArg("__return", &__return, CppTest_Tgr_Type_Line()). WithArg("__callOrig", ByRef(__callOrig)).End(); return __return; } return __return; }