PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/megaco/test/megaco_codec_test_lib.erl

https://github.com/bsmr-erlang/otp
Erlang | 1025 lines | 760 code | 109 blank | 156 comment | 4 complexity | b377abf809d395fe7f0f15a622ffd241 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. %%
  2. %% %CopyrightBegin%
  3. %%
  4. %% Copyright Ericsson AB 2004-2016. All Rights Reserved.
  5. %%
  6. %% Licensed under the Apache License, Version 2.0 (the "License");
  7. %% you may not use this file except in compliance with the License.
  8. %% You may obtain a copy of the License at
  9. %%
  10. %% http://www.apache.org/licenses/LICENSE-2.0
  11. %%
  12. %% Unless required by applicable law or agreed to in writing, software
  13. %% distributed under the License is distributed on an "AS IS" BASIS,
  14. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. %% See the License for the specific language governing permissions and
  16. %% limitations under the License.
  17. %%
  18. %% %CopyrightEnd%
  19. %%
  20. %%
  21. %%----------------------------------------------------------------------
  22. %% Purpose: Test library module for Megaco/H.248 encode/decode
  23. %%----------------------------------------------------------------------
  24. -module(megaco_codec_test_lib).
  25. %% ----
  26. -include_lib("megaco/include/megaco.hrl").
  27. -include_lib("megaco/include/megaco_message_v1.hrl").
  28. -include("megaco_test_lib.hrl").
  29. %% ----
  30. -export([
  31. skip/1,
  32. display_text_messages/2, display_text_messages/3,
  33. generate_text_messages/4,
  34. test_msgs/6,
  35. plain_decode_encode/5,
  36. plain_encode_decode/5,
  37. trans_first_encode_decode/5,
  38. actions_first_encode_decode/5,
  39. action_first_encode_decode/5,
  40. encode_message/4,
  41. decode_message/5, decode_message/6,
  42. expect_instruction/3,
  43. expect_encode/3,
  44. expect_encode_only/3,
  45. expect_encode_decode/4,
  46. expect_encode_decode_only/4,
  47. expect_decode/3,
  48. expect_decode_only/3,
  49. expect_decode_encode/4,
  50. expect_decode_encode_only/4,
  51. expect_exec/2
  52. ]).
  53. -record(expect_instruction,
  54. {
  55. %% Short description of what this instruction does
  56. description, % string()
  57. %% The actual instruction
  58. command, % function(Data) -> term()
  59. %% Verification function of the instruction
  60. verify % function(Res, Data) -> {ok, NewData} | {error, Reason}
  61. }
  62. ).
  63. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  64. display_text_messages(V, Msgs) ->
  65. display_text_messages(V, [], Msgs).
  66. display_text_messages(_, _, []) ->
  67. ok;
  68. display_text_messages(V, EC, [{Name, Msg, _ED, _Conf}|Msgs]) ->
  69. (catch display_text_message(Name, EC, Msg, V)),
  70. display_text_messages(V, EC, Msgs).
  71. display_text_message(Name, EC, Msg, V) when is_tuple(Msg) ->
  72. io:format("~n(Erlang) message ~p:~n~p~n", [Name, Msg]),
  73. case (catch megaco_pretty_text_encoder:encode_message(EC,V,Msg)) of
  74. {'EXIT', _R} ->
  75. io:format("~nPretty encoded: failed (exit)~n", []);
  76. {error, {{deprecated, PWhat}, _}} ->
  77. io:format("~nPretty encoded: deprecated~n~p~n", [PWhat]),
  78. throw(continue);
  79. {error, PReason} ->
  80. io:format("~nPretty encoded: failed (error)~n~p~n", [PReason]),
  81. throw(continue);
  82. {ok, Pretty} ->
  83. io:format("~nPretty encoded:~n~s~n", [binary_to_list(Pretty)])
  84. end,
  85. case (catch megaco_compact_text_encoder:encode_message(EC,V,Msg)) of
  86. {'EXIT', _} ->
  87. io:format("~nCompact encoded: failed~n", []);
  88. {error, {{deprecated, CWhat}, _}} ->
  89. io:format("~nPretty encoded: deprecated~n~p~n", [CWhat]);
  90. {ok, Compact} ->
  91. io:format("~nCompact encoded:~n~s~n", [binary_to_list(Compact)])
  92. end;
  93. display_text_message(_, _, _, _) ->
  94. skipping.
  95. generate_text_messages(DirName, V, EC, Msgs) when is_atom(DirName) ->
  96. generate_text_messages(atom_to_list(DirName), V, EC, Msgs);
  97. generate_text_messages(DirName, V, EC, Msgs) when is_list(DirName) ->
  98. DirPath = filename:join(["/tmp", DirName]),
  99. case file:make_dir(DirPath) of
  100. ok ->
  101. generate_text_messages2(DirPath, V, EC, Msgs);
  102. {error, eexist} ->
  103. generate_text_messages2(DirPath, V, EC, Msgs);
  104. {error, Reason} ->
  105. io:format("Failed creating directory ~s: ~p~n", [DirPath, Reason]),
  106. ok
  107. end.
  108. generate_text_messages2(_, _, _, []) ->
  109. ok;
  110. generate_text_messages2(Dir, V, EC, [{Name, Msg, _ED, _Conf}|Msgs]) ->
  111. (catch generate_text_message(Dir, Name, EC, Msg, V)),
  112. generate_text_messages2(Dir, V, EC, Msgs).
  113. generate_text_message(Dir, Name, EC, Msg, V) ->
  114. io:format("~p: ", [Name]),
  115. case (catch megaco_pretty_text_encoder:encode_message(EC,V,Msg)) of
  116. {'EXIT', EReason} ->
  117. io:format("failed encoding [exit]: ~n~p~n", [EReason]),
  118. throw(continue);
  119. {error, {{deprecated, PWhat}, _}} ->
  120. io:format("failed encoding [deprecated]: ~n~p~n", [PWhat]),
  121. throw(continue);
  122. {error, PReason} ->
  123. io:format("failed encoding [error]: ~n~p~n", [PReason]),
  124. throw(continue);
  125. {ok, Pretty} ->
  126. io:format("encoded", []),
  127. FName = filename:flatten([Name, ".txt"]),
  128. Filename = filename:join([Dir, FName]),
  129. case (catch file:open(Filename, [write])) of
  130. {ok, Fd} ->
  131. io:format(Fd, "~s", [binary_to_list(Pretty)]),
  132. io:format(" - written to disk~n", []),
  133. (catch file:close(Fd)),
  134. ok;
  135. {error, OReason} ->
  136. io:format(" - failed writing to disk: "
  137. "~n~p~n~s~n",
  138. [OReason, binary_to_list(Pretty)]),
  139. throw(continue)
  140. end
  141. end.
  142. test_msgs(Codec, DynamicDecode, Ver, EC, Check, Msgs)
  143. when is_function(Check) andalso is_list(Msgs) ->
  144. io:format("~n", []),
  145. test_msgs(Codec, DynamicDecode, Ver, EC, Check, Msgs, []).
  146. test_msgs(_Codec, _DD, _Ver, _EC, _Check, [], []) ->
  147. ok;
  148. test_msgs(_Codec, _DD, _Ver, _EC, _Check, [], Errs) ->
  149. ?ERROR(lists:reverse(Errs));
  150. test_msgs(Codec, DD, Ver, EC, Check,
  151. [{Name, {error, Error}, _ED, _Conf}|Msgs], Acc) ->
  152. io:format("error~n", []),
  153. test_msgs(Codec, DD, Ver, EC, Check, Msgs, [{Name, Error}|Acc]);
  154. test_msgs(Codec, DD, Ver, EC, Check,
  155. [{Name, Msg, ED, Conf}|Msgs], Acc) ->
  156. Dbg = test_msgs_debug(Conf),
  157. put(dbg, Dbg),
  158. io:format("~-16w ", [Name]),
  159. case (catch encode_decode(ED, Check, Codec, DD, Ver, EC, Msg)) of
  160. ok ->
  161. io:format("ok~n", []),
  162. erase(dbg),
  163. test_msgs(Codec, DD, Ver, EC, Check, Msgs, Acc);
  164. Error ->
  165. io:format("error~n", []),
  166. erase(dbg),
  167. test_msgs(Codec, DD, Ver, EC, Check, Msgs, [{Name, Error}|Acc])
  168. end.
  169. test_msgs_debug(Conf) ->
  170. case lists:keysearch(dbg, 1, Conf) of
  171. {value, {dbg, true}} ->
  172. true;
  173. _ ->
  174. false
  175. end.
  176. encode_decode(Func, Check, Codec, DynamicDecode, Ver, EC, Msg1)
  177. when is_function(Func) ->
  178. d("encode_decode -> entry with"
  179. "~n Func: ~p"
  180. "~n Check: ~p"
  181. "~n Codec: ~p"
  182. "~n DynamicDecode: ~p"
  183. "~n Ver: ~p"
  184. "~n EC: ~p",
  185. [Func, Check, Codec, DynamicDecode, Ver, EC]),
  186. case (catch Func(Codec, DynamicDecode, Ver, EC, Msg1)) of
  187. {ok, Msg1} ->
  188. d("encode_decode -> expected result"),
  189. ok;
  190. {ok, Msg2} ->
  191. d("encode_decode -> unexpected result - check"),
  192. case (catch Check(Msg1, Msg2)) of
  193. ok ->
  194. d("encode_decode -> check - ok"),
  195. ok;
  196. {error, Reason} ->
  197. d("encode_decode -> check - error: "
  198. "~n Reason: ~p", [Reason]),
  199. {error, {Reason, Msg1, Msg2}};
  200. Else ->
  201. d("encode_decode -> check - failed: "
  202. "~n Else: ~p", [Else]),
  203. {error, {invalid_check_result, Else}}
  204. end;
  205. Else ->
  206. d("encode_decode -> failed: "
  207. "~n Else: ~p", [Else]),
  208. Else
  209. end.
  210. %% *** plain_encode_decode ***
  211. plain_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
  212. d("plain_encode_decode -> entry with"
  213. "~n Codec: ~p"
  214. "~n DynamicDecode: ~p"
  215. "~n Ver: ~p"
  216. "~n EC: ~p", [Codec, DynamicDecode, Ver, EC]),
  217. case (catch encode_message(Codec, Ver, EC, M1)) of
  218. {ok, Bin} ->
  219. d("plain_encode_decode -> encode - ok"),
  220. decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
  221. Error ->
  222. d("plain_encode_decode -> encode - failed: "
  223. "~n Error: ~p", [Error]),
  224. Error
  225. end.
  226. %% *** plain_decode_encode ***
  227. plain_decode_encode(Codec, DynamicDecode, Ver, EC, M) when is_list(M) ->
  228. Bin = list_to_binary(M),
  229. plain_decode_encode(Codec, DynamicDecode, Ver, EC, Bin);
  230. plain_decode_encode(Codec, DynamicDecode, Ver, EC, B) when is_binary(B) ->
  231. case (catch decode_message(Codec, DynamicDecode, Ver, EC, B, true)) of
  232. {ok, M} ->
  233. encode_message(Codec, Ver, EC, M);
  234. Error ->
  235. Error
  236. end.
  237. %% *** trans_first_encode_decode ***
  238. trans_first_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
  239. d("trans_first_encode_decode -> entry"),
  240. case (catch trans_first_encode_message(Codec, Ver, EC, M1)) of
  241. {ok, Bin} ->
  242. decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
  243. Error ->
  244. Error
  245. end.
  246. trans_first_encode_message(Codec, Ver, EC, M1) ->
  247. d("trans_first_encode_message -> entry"),
  248. Mess1 = M1#'MegacoMessage'.mess,
  249. {transactions, Trans1} = Mess1#'Message'.messageBody,
  250. Trans2 = encode_transactions(Codec, Ver, EC, Trans1),
  251. Mess2 = Mess1#'Message'{messageBody = {transactions, Trans2}},
  252. M2 = M1#'MegacoMessage'{mess = Mess2},
  253. encode_message(Codec, Ver, EC, M2).
  254. encode_transactions(Codec, Ver, EC, Trans) when is_list(Trans) ->
  255. d("encode_transactions -> entry"),
  256. [encode_transaction(Codec, Ver, EC, T) || T <- Trans].
  257. encode_transaction(Codec, Ver, EC, T) ->
  258. d("encode_transaction -> entry"),
  259. case (catch Codec:encode_transaction(EC, Ver, T)) of
  260. {ok, EncodecTransactions} ->
  261. EncodecTransactions;
  262. Error ->
  263. throw({error, {transaction_encode_failed, Error, T}})
  264. end.
  265. %% *** actions_first_encode_decode ***
  266. actions_first_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
  267. d("actions_first_encode_decode -> entry"),
  268. case (catch actions_first_encode_message(Codec, Ver, EC, M1)) of
  269. {ok, Bin} ->
  270. decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
  271. Error ->
  272. Error
  273. end.
  274. actions_first_encode_message(Codec, Ver, EC, M1) ->
  275. d("actions_first_encode_message -> entry"),
  276. Mess1 = M1#'MegacoMessage'.mess,
  277. {transactions, Trans1} = Mess1#'Message'.messageBody,
  278. Trans2 = encode_actions(Codec, Ver, EC, Trans1),
  279. Mess2 = Mess1#'Message'{messageBody = {transactions, Trans2}},
  280. M2 = M1#'MegacoMessage'{mess = Mess2},
  281. encode_message(Codec, Ver, EC, M2).
  282. encode_actions(Codec, Ver, EC, Trans) when is_list(Trans) ->
  283. d("encode_actions -> entry"),
  284. [encode_actions1(Codec, Ver, EC, T) || T <- Trans].
  285. encode_actions1(Codec, Ver, EC, {transactionRequest, TR1}) ->
  286. d("encode_actions1 -> entry"),
  287. #'TransactionRequest'{actions = ARs} = TR1,
  288. case (catch encode_action_requests(Codec, Ver, EC, ARs)) of
  289. {ok, EncodedARs} ->
  290. TR2 = TR1#'TransactionRequest'{actions = EncodedARs},
  291. {transactionRequest, TR2};
  292. Error ->
  293. throw({error, {actions_encode_failed, Error, TR1}})
  294. end.
  295. encode_action_requests(Codec, Ver, EC, ARs) ->
  296. d("encode_action_requests -> entry"),
  297. Codec:encode_action_requests(EC, Ver, ARs).
  298. %% *** action_first_encode_decode ***
  299. action_first_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
  300. d("action_first_encode_decode -> entry"),
  301. case (catch action_first_encode_message(Codec, Ver, EC, M1)) of
  302. {ok, Bin} ->
  303. decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
  304. Error ->
  305. Error
  306. end.
  307. action_first_encode_message(Codec, Ver, EC, M1) ->
  308. d("action_first_encode_message -> entry"),
  309. Mess1 = M1#'MegacoMessage'.mess,
  310. {transactions, Trans1} = Mess1#'Message'.messageBody,
  311. Trans2 = encode_action(Codec, Ver, EC, Trans1),
  312. Mess2 = Mess1#'Message'{messageBody = {transactions, Trans2}},
  313. M2 = M1#'MegacoMessage'{mess = Mess2},
  314. encode_message(Codec, Ver, EC, M2).
  315. encode_action(Codec, Ver, EC, Trans) when is_list(Trans) ->
  316. d("encode_action -> entry"),
  317. [encode_action1(Codec, Ver, EC, T) || T <- Trans].
  318. encode_action1(Codec, Ver, EC, {transactionRequest, TR1}) ->
  319. d("encode_action1 -> entry"),
  320. #'TransactionRequest'{actions = ARs1} = TR1,
  321. ARs2 = [encode_action_request(Codec, Ver, EC, AR) || AR <- ARs1],
  322. TR2 = TR1#'TransactionRequest'{actions = ARs2},
  323. {transactionRequest, TR2}.
  324. encode_action_request(Codec, Ver, EC, AR) ->
  325. d("encode_action_request -> entry"),
  326. case (catch Codec:encode_action_request(EC, Ver, AR)) of
  327. {ok, Bin} ->
  328. Bin;
  329. Error ->
  330. throw({error, {encode_action_request_failed, Error, AR}})
  331. end.
  332. encode_message(Codec, Ver, EC, M) ->
  333. d("encode_message -> entry with"
  334. "~n Codec: ~p"
  335. "~n Ver: ~p"
  336. "~n EC: ~p"
  337. "~n M: ~p", [Codec, Ver, EC, M]),
  338. %% case (catch Codec:encode_message(EC, Ver, M)) of
  339. %% {ok, Bin} ->
  340. %% d("encode_message -> encode - ok: "
  341. %% "~n~s", [binary_to_list(Bin)]),
  342. %% {ok, Bin};
  343. %% Error ->
  344. %% d("encode_message -> encode - failed"),
  345. %% throw({error, {message_encode_failed, Error, M}})
  346. %% end.
  347. case (catch timer:tc(Codec, encode_message, [EC, Ver, M])) of
  348. {Time, {ok, Bin}} ->
  349. d("encode_message -> encode - ok after ~p: "
  350. "~n~s", [Time, binary_to_list(Bin)]),
  351. {ok, Bin};
  352. {_Time, Error} ->
  353. d("encode_message -> encode - failed"),
  354. throw({error, {message_encode_failed, Error, M}})
  355. end.
  356. decode_message(Codec, Dynamic, Ver, EC, M) ->
  357. decode_message(Codec, Dynamic, Ver, EC, M, false).
  358. decode_message(Codec, true, _Ver, EC, M, _Timed) ->
  359. d("decode_message -> entry - when using dynamic"),
  360. Codec:decode_message(EC, dynamic, M);
  361. decode_message(Codec, _, Ver, EC, M, false) ->
  362. d("decode_message -> entry with"
  363. "~n Codec: ~p"
  364. "~n Ver: ~p"
  365. "~n EC: ~p", [Codec, Ver, EC]),
  366. Codec:decode_message(EC, Ver, M);
  367. decode_message(Codec, _, Ver, EC, M, true) ->
  368. d("decode_message -> entry with"
  369. "~n Codec: ~p"
  370. "~n Ver: ~p"
  371. "~n EC: ~p", [Codec, Ver, EC]),
  372. {Time, Result} = timer:tc(Codec, decode_message, [EC, Ver, M]),
  373. io:format("~-8w", [Time]),
  374. Result.
  375. %% =======================================================================
  376. %% ------------------------------------------------------------------
  377. %% Create an instruction record
  378. %% ------------------------------------------------------------------
  379. expect_instruction(Desc, Cmd, Verify)
  380. when is_list(Desc) andalso is_function(Cmd) andalso is_function(Verify) ->
  381. #expect_instruction{description = Desc,
  382. command = Cmd,
  383. verify = Verify}.
  384. %% ------------------------------------------------------------------
  385. %% Function: expect_encode
  386. %% Parameters: Msg -> MegacoMessage
  387. %% Encode -> function/1
  388. %% Check -> function/1
  389. %% Description: This function simply encodes, with the Encode fun,
  390. %% and expects this to fail. The failure reason is
  391. %% checked with the Check fun.
  392. %% ------------------------------------------------------------------
  393. expect_encode(InitialData, Encode, Check)
  394. when is_function(Encode) andalso is_function(Check) ->
  395. Instructions =
  396. [
  397. %% Initial encode
  398. expect_instruction(
  399. "Encode (initial) message",
  400. fun(Msg) when is_record(Msg, 'MegacoMessage') ->
  401. (catch Encode(Msg));
  402. (Bad) ->
  403. {error, {invalid_data, Bad}}
  404. end,
  405. fun({error, Reason}, _) ->
  406. io:format("check error reason ", []),
  407. case (catch Check(Reason)) of
  408. ok ->
  409. {ok, done};
  410. Error ->
  411. Error
  412. end;
  413. ({ok, Bin}, Msg) when is_binary(Bin) ->
  414. M = binary_to_list(Bin),
  415. {error, {unexpected_encode_success, {M, Msg}}};
  416. (Crap, _) ->
  417. {error, {unexpected_encode_result, Crap}}
  418. end)
  419. ],
  420. expect_exec(Instructions, InitialData).
  421. %% ------------------------------------------------------------------
  422. %% Function: expect_encode_only
  423. %% Parameters: InitialData -> list() | binary()
  424. %% Encode -> function/1
  425. %% Check -> function/1
  426. %% Description: This function simply encodes, with the Encode fun,
  427. %% and expects it to succeed, which is checked by
  428. %% calling the Check fun with the resulting message.
  429. %% ------------------------------------------------------------------
  430. expect_encode_only(InitialData, Encode, Check)
  431. when is_function(Encode) andalso is_function(Check) ->
  432. Instructions =
  433. [
  434. %% Initial encode
  435. expect_instruction(
  436. "Encode (initial) message",
  437. fun(Msg) when is_record(Msg, 'MegacoMessage') ->
  438. (catch Encode(Msg));
  439. (Bad) ->
  440. {error, {invalid_data, Bad}}
  441. end,
  442. fun({ok, Bin}, _Msg) when is_binary(Bin) ->
  443. case (catch Check(Bin)) of
  444. ok ->
  445. {ok, done};
  446. Error ->
  447. Error
  448. end;
  449. (Crap, _) ->
  450. {error, {unexpected_encode_result, Crap}}
  451. end)
  452. ],
  453. expect_exec(Instructions, InitialData).
  454. %% ------------------------------------------------------------------
  455. %% Function: expect_encode_decode
  456. %% Parameters: InitialData -> MegacoMessage
  457. %% Encode -> function/1
  458. %% Decode -> function/1
  459. %% Check -> function/2
  460. %% Description: This function simply encodes, with the Encode fun, and
  461. %% then decodes, with the Decode fun, the megaco message.
  462. %% The resulting message should be identical, but if it
  463. %% is not, the messages are checked, with the Check fun.
  464. %% ------------------------------------------------------------------
  465. expect_encode_decode(InitialData, Encode, Decode, Check)
  466. when is_function(Encode) andalso
  467. is_function(Decode) andalso
  468. is_function(Check) ->
  469. Instructions =
  470. [
  471. %% Initial encode
  472. expect_instruction(
  473. "Encode (initial) message",
  474. fun(M) when is_record(M, 'MegacoMessage') ->
  475. (catch Encode(M));
  476. (Bad) ->
  477. {error, {invalid_data, Bad}}
  478. end,
  479. fun({ok, Bin}, M) when is_binary(Bin) ->
  480. {ok, {Bin, M}};
  481. ({error, Reason}, _) ->
  482. {error, {unexpected_encode_failure, Reason}};
  483. (Crap, _) ->
  484. {error, {unexpected_encode_result, Crap}}
  485. end),
  486. %% Decode the (encoded) message
  487. expect_instruction(
  488. "Decode message",
  489. fun({Bin, _}) when is_binary(Bin) ->
  490. (catch Decode(Bin));
  491. (Bad) ->
  492. {error, {invalid_data, Bad}}
  493. end,
  494. fun({ok, Msg1}, {_Bin, Msg1})
  495. when is_record(Msg1, 'MegacoMessage') ->
  496. io:format("messages identical - done ", []),
  497. {ok, done};
  498. ({ok, Msg2}, {_Bin, Msg1}) ->
  499. io:format("messages not identical - check - ", []),
  500. case (catch Check(Msg1, Msg2)) of
  501. ok ->
  502. io:format("equal ", []),
  503. {ok, done};
  504. Error ->
  505. io:format("not equal ", []),
  506. io:format("~nError: ~p~n", [Error]),
  507. Error
  508. end;
  509. (Crap, _) ->
  510. {error, {unexpected_decode_result, Crap}}
  511. end)
  512. ],
  513. expect_exec(Instructions, InitialData).
  514. %% ------------------------------------------------------------------
  515. %% Function: expect_encode_decode_only
  516. %% Parameters: InitialData -> MegacoMessage
  517. %% Encode -> function/1
  518. %% Decode -> function/1
  519. %% Check -> function/2
  520. %% Description: This function simply encodes, with the Encode fun,
  521. %% and then decodes, with the Decode fun, the megaco
  522. %% message and expects it to succeed. The resulting
  523. %% message is checked by calling the Check fun with the
  524. %% resulting message.
  525. %% ------------------------------------------------------------------
  526. expect_encode_decode_only(InitialData, Encode, Decode, Check)
  527. when is_function(Encode) andalso
  528. is_function(Decode) andalso
  529. is_function(Check) ->
  530. Instructions =
  531. [
  532. %% Initial encode
  533. expect_instruction(
  534. "Encode (initial) message",
  535. fun(M) when is_record(M, 'MegacoMessage') ->
  536. (catch Encode(M));
  537. (Bad) ->
  538. {error, {invalid_data, Bad}}
  539. end,
  540. fun({ok, Bin}, M) when is_binary(Bin) ->
  541. {ok, {Bin, M}};
  542. ({error, Reason}, _) ->
  543. {error, {unexpected_encode_failure, Reason}};
  544. (Crap, _) ->
  545. {error, {unexpected_encode_result, Crap}}
  546. end),
  547. %% Decode the (encoded) message
  548. expect_instruction(
  549. "Decode message",
  550. fun({Bin, _}) when is_binary(Bin) ->
  551. (catch Decode(Bin));
  552. (Bad) ->
  553. {error, {invalid_data, Bad}}
  554. end,
  555. fun({ok, Msg}, _B) when is_record(Msg, 'MegacoMessage') ->
  556. io:format("decoded - now check ", []),
  557. case (catch Check(Msg)) of
  558. ok ->
  559. {ok, done};
  560. Error ->
  561. Error
  562. end;
  563. ({error, R}, _) ->
  564. {Line, Mod, Reason} =
  565. case lists:keysearch(reason, 1, R) of
  566. {value, {reason, {L, M, Raw}}}
  567. when is_list(Raw) ->
  568. {L, M, lists:flatten(Raw)};
  569. {value, {reason, {L, M, Raw}}} ->
  570. {L, M, Raw};
  571. _ ->
  572. {-1, undefined, R}
  573. end,
  574. Tokens =
  575. case lists:keysearch(token, 1, R) of
  576. {value, {token, T}} ->
  577. T;
  578. _ ->
  579. undefined
  580. end,
  581. {error, {unexpected_decode_failure,
  582. {Mod, Line, Reason, Tokens}}};
  583. (Crap, _) ->
  584. {error, {unexpected_decode_result, Crap}}
  585. end)
  586. ],
  587. expect_exec(Instructions, InitialData).
  588. %% ------------------------------------------------------------------
  589. %% Function: expect_decode
  590. %% Parameters: InitialData -> list() | binary()
  591. %% Decode -> function/1
  592. %% Check -> function/1
  593. %% Description: This function simply decodes, with the Decode fun,
  594. %% and expects this to fail. The failure reason is
  595. %% checked with the Check fun.
  596. %% ------------------------------------------------------------------
  597. expect_decode(InitialData, Decode, Check)
  598. when is_list(InitialData) ->
  599. expect_decode(list_to_binary(InitialData), Decode, Check);
  600. expect_decode(InitialData, Decode, Check)
  601. when is_function(Decode) andalso is_function(Check) ->
  602. Instructions =
  603. [
  604. %% Initial decode
  605. expect_instruction(
  606. "Decode (initial) message",
  607. fun(Bin) when is_binary(Bin) ->
  608. (catch Decode(Bin));
  609. (Bad) ->
  610. {error, {invalid_data, Bad}}
  611. end,
  612. fun({error, Reason}, _) ->
  613. io:format("check error reason - ", []),
  614. case (catch Check(Reason)) of
  615. ok ->
  616. {ok, done};
  617. Error ->
  618. Error
  619. end;
  620. ({ok, Msg}, Bin) ->
  621. io:format("unexpected decode success - ", []),
  622. M = binary_to_list(Bin),
  623. {error, {unexpected_decode_success, {Msg, M}}};
  624. (Crap, _) ->
  625. {error, {unexpected_decode_result, Crap}}
  626. end)
  627. ],
  628. expect_exec(Instructions, InitialData).
  629. %% ------------------------------------------------------------------
  630. %% Function: expect_decode_only
  631. %% Parameters: InitialData -> list() | binary()
  632. %% Decode -> function/1
  633. %% Check -> function/2
  634. %% Description: This function simply decodes, with the Decode fun,
  635. %% and expects it to succeed, which is checked by
  636. %% calling the Check fun with the resulting message.
  637. %% ------------------------------------------------------------------
  638. expect_decode_only(InitialData, Decode, Check)
  639. when is_list(InitialData) ->
  640. expect_decode_only(list_to_binary(InitialData), Decode, Check);
  641. expect_decode_only(InitialData, Decode, Check)
  642. when is_function(Decode) andalso is_function(Check) ->
  643. Instructions =
  644. [
  645. %% Initial decode
  646. expect_instruction(
  647. "Decode (initial) message",
  648. fun(B) when is_binary(B) ->
  649. (catch Decode(B));
  650. (Bad) ->
  651. {error, {invalid_data, Bad}}
  652. end,
  653. fun({ok, Msg}, _B) when is_record(Msg, 'MegacoMessage') ->
  654. case (catch Check(Msg)) of
  655. ok ->
  656. {ok, done};
  657. Error ->
  658. Error
  659. end;
  660. ({error, R}, _) ->
  661. {Line, Mod, Reason} =
  662. case lists:keysearch(reason, 1, R) of
  663. {value, {reason, {L, M, Raw}}}
  664. when is_list(Raw) ->
  665. {L, M, lists:flatten(Raw)};
  666. {value, {reason, {L, M, Raw}}} ->
  667. {L, M, Raw};
  668. _ ->
  669. {-1, undefined, R}
  670. end,
  671. Tokens =
  672. case lists:keysearch(token, 1, R) of
  673. {value, {token, T}} ->
  674. T;
  675. _ ->
  676. undefined
  677. end,
  678. {error, {unexpected_decode_failure,
  679. {Mod, Line, Reason, Tokens}}};
  680. (Crap, _) ->
  681. {error, {unexpected_decode_result, Crap}}
  682. end)
  683. ],
  684. expect_exec(Instructions, InitialData).
  685. %% ------------------------------------------------------------------
  686. %% Function: expect_decode_encode
  687. %% Parameters: InitialData -> list() | binary()
  688. %% Decode -> function/1
  689. %% Encode -> function/1
  690. %% Check -> function/2
  691. %% Description: This function simply decodes, with the Decode fun,
  692. %% and then encodes, with the Encode fun, the megaco
  693. %% message. The resulting binary message should be
  694. %% identical, but if it is not, the messages are
  695. %% decoded again and then if necessary checked, with
  696. %% the Check fun.
  697. %% ------------------------------------------------------------------
  698. expect_decode_encode(InitialData, Decode, Encode, Check)
  699. when is_list(InitialData) ->
  700. expect_decode_encode(list_to_binary(InitialData), Decode, Encode, Check);
  701. expect_decode_encode(InitialData, Decode, Encode, Check)
  702. when is_function(Decode) andalso
  703. is_function(Encode) andalso
  704. is_function(Check) ->
  705. Instructions =
  706. [
  707. %% Initial decode
  708. expect_instruction(
  709. "Decode (initial) message",
  710. fun(B) when is_binary(B) ->
  711. (catch Decode(B));
  712. (Bad) ->
  713. {error, {invalid_data, Bad}}
  714. end,
  715. fun({ok, Msg}, B) when is_record(Msg, 'MegacoMessage') ->
  716. {ok, {Msg, B}};
  717. ({error, R}, _) ->
  718. {Line, Mod, Reason} =
  719. case lists:keysearch(reason, 1, R) of
  720. {value, {reason, {L, M, Raw}}}
  721. when is_list(Raw) ->
  722. {L, M, lists:flatten(Raw)};
  723. {value, {reason, {L, M, Raw}}} ->
  724. {L, M, Raw};
  725. _ ->
  726. {-1, undefined, R}
  727. end,
  728. Tokens =
  729. case lists:keysearch(token, 1, R) of
  730. {value, {token, T}} ->
  731. T;
  732. _ ->
  733. undefined
  734. end,
  735. {error, {unexpected_decode_failure,
  736. {Mod, Line, Reason, Tokens}}};
  737. (Crap, _) ->
  738. {error, {unexpected_decode_result, Crap}}
  739. end),
  740. %% Encode the (decoded) message
  741. expect_instruction(
  742. "Encode message",
  743. fun({Msg, _Bin}) when is_record(Msg, 'MegacoMessage') ->
  744. (catch Encode(Msg));
  745. (Bad) ->
  746. {error, {invalid_data, Bad}}
  747. end,
  748. fun({ok, B}, {_, B}) ->
  749. io:format("binaries equal - done ", []),
  750. {ok, done};
  751. ({ok, B}, {Msg, _}) ->
  752. {ok, {Msg, B}};
  753. ({error, Reason}, _) ->
  754. {error, {unexpected_encode_failure, Reason}};
  755. (Crap, _) ->
  756. {error, {unexpected_encode_result, Crap}}
  757. end),
  758. %% Fallback instruction in case encode produced
  759. %% a binary not equal to the initial
  760. expect_instruction(
  761. "Decode message (if binaries not equal)",
  762. fun(done) ->
  763. done;
  764. ({_Msg, B}) when is_binary(B) ->
  765. (catch Decode(B));
  766. (Bad) ->
  767. {error, {invalid_data, Bad}}
  768. end,
  769. fun({ok, Msg}, {Msg, _Bin}) when is_record(Msg, 'MegacoMessage') ->
  770. io:format("messages identical - done ", []),
  771. {ok, done};
  772. (done, _) ->
  773. io:format("done ", []),
  774. {ok, done};
  775. ({ok, Msg2}, {Msg1, _}) ->
  776. io:format("messages not identical - check - ", []),
  777. case (catch Check(Msg1, Msg2)) of
  778. ok ->
  779. io:format("equal ", []),
  780. {ok, done};
  781. Error ->
  782. io:format("not equal ", []),
  783. Error
  784. end;
  785. ({error, Reason}, _) ->
  786. {error, {unexpected_decode_failure, Reason}};
  787. (Crap, _) ->
  788. {error, {unexpected_decode_result, Crap}}
  789. end)
  790. ],
  791. expect_exec(Instructions, InitialData).
  792. %% ------------------------------------------------------------------
  793. %% Function: expect_decode_encode_only
  794. %% Parameters: InitialData -> list() | binary()
  795. %% Decode -> function/1
  796. %% Encode -> function/1
  797. %% Check -> function/2
  798. %% Description: This function simply decodes, with the Decode fun,
  799. %% and then encodes, with the Encode fun, the megaco
  800. %% message. The resulting binary message is then checked
  801. %% with the Check fun.
  802. %% ------------------------------------------------------------------
  803. expect_decode_encode_only(InitialData, Decode, Encode, Check)
  804. when is_list(InitialData) ->
  805. expect_decode_encode_only(list_to_binary(InitialData),
  806. Decode, Encode, Check);
  807. expect_decode_encode_only(InitialData, Decode, Encode, Check)
  808. when is_function(Decode) andalso
  809. is_function(Encode) andalso
  810. is_function(Check) ->
  811. Instructions =
  812. [
  813. %% Initial decode
  814. expect_instruction(
  815. "Decode (initial) message",
  816. fun(B) when is_binary(B) ->
  817. (catch Decode(B));
  818. (Bad) ->
  819. {error, {invalid_data, Bad}}
  820. end,
  821. fun({ok, Msg}, B) when is_record(Msg, 'MegacoMessage') ->
  822. {ok, {Msg, B}};
  823. ({error, R}, _) ->
  824. {Line, Mod, Reason} =
  825. case lists:keysearch(reason, 1, R) of
  826. {value, {reason, {L, M, Raw}}}
  827. when is_list(Raw) ->
  828. {L, M, lists:flatten(Raw)};
  829. {value, {reason, {L, M, Raw}}} ->
  830. {L, M, Raw};
  831. _ ->
  832. {-1, undefined, R}
  833. end,
  834. Tokens =
  835. case lists:keysearch(token, 1, R) of
  836. {value, {token, T}} ->
  837. T;
  838. _ ->
  839. undefined
  840. end,
  841. {error, {unexpected_decode_failure,
  842. {Mod, Line, Reason, Tokens}}};
  843. (Crap, _) ->
  844. {error, {unexpected_decode_result, Crap}}
  845. end),
  846. %% Encode the (decoded) message
  847. expect_instruction(
  848. "Encode message",
  849. fun({Msg, _Bin}) when is_record(Msg, 'MegacoMessage') ->
  850. (catch Encode(Msg));
  851. (Bad) ->
  852. {error, {invalid_data, Bad}}
  853. end,
  854. fun({ok, B2}, {_, B1}) ->
  855. io:format("encode ok - check bins - ", []),
  856. case (catch Check(B1, B2)) of
  857. ok ->
  858. {ok, done};
  859. Crap ->
  860. {error, {unexpected_encode_check_result, Crap}}
  861. end;
  862. ({error, Reason}, _) ->
  863. {error, {unexpected_encode_failure, Reason}};
  864. (Crap, _) ->
  865. {error, {unexpected_encode_result, Crap}}
  866. end)
  867. ],
  868. expect_exec(Instructions, InitialData).
  869. %% ------------------------------------------------------------------
  870. %% Function: expect_exec
  871. %% Parameters: Instructions -> [instruction()]
  872. %% InitialData -> term()
  873. %% Description: This function is the engine in the codec test
  874. %% cases. It executes each instruction in turn.
  875. %% ------------------------------------------------------------------
  876. expect_exec(Instructions, InitialData) ->
  877. expect_exec(Instructions, InitialData, 1).
  878. expect_exec([], _, _) ->
  879. io:format("~n", []),
  880. ok;
  881. expect_exec([#expect_instruction{description = Desc,
  882. command = Cmd,
  883. verify = Verify}|T], Data, Num) ->
  884. io:format("~n Exec command ~w: ~s => ", [Num, Desc]),
  885. case Verify((catch Cmd(Data)), Data) of
  886. {ok, NewData} ->
  887. io:format("ok", []),
  888. expect_exec(T, NewData, Num+1);
  889. {error, Reason} ->
  890. io:format("error", []),
  891. {error, {Num, Desc, Reason}}
  892. end.
  893. %% =======================================================================
  894. skip({What, Why}) when is_atom(What) andalso is_list(Why) ->
  895. Reason = lists:flatten(io_lib:format("~p: ~s", [What, Why])),
  896. exit({skipped, Reason});
  897. skip({What, Why}) ->
  898. Reason = lists:flatten(io_lib:format("~p: ~p", [What, Why])),
  899. exit({skipped, Reason});
  900. skip(Reason) when is_list(Reason) ->
  901. exit({skipped, Reason});
  902. skip(Reason1) ->
  903. Reason2 = lists:flatten(io_lib:format("~p", [Reason1])),
  904. exit({skipped, Reason2}).
  905. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  906. %% ------------------------------------------------------------------
  907. %% Internal functions
  908. %% ------------------------------------------------------------------
  909. d(F) ->
  910. d(F, []).
  911. d(F, A) ->
  912. d(get(dbg), F, A).
  913. d(true, F, A) ->
  914. io:format("DBG:~w:" ++ F ++ "~n", [?MODULE|A]);
  915. d(_, _, _) ->
  916. ok.