/* * %CopyrightBegin% * * Copyright Ericsson AB 2004-2018. All Rights Reserved. * * Licensed 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. * * %CopyrightEnd% */ #ifdef VXWORKS #include "reclaim.h" #endif #include "ei_runner.h" /* * Purpose: Read pids, funs and others without real meaning on the C side * and pass it back to Erlang to test that it is still the same. * Author: kent@erix.ericsson.se */ /*#define MESSAGE(FMT,A1,A2) message(FMT,A1,A2)*/ #define MESSAGE(FMT,A1,A2) typedef struct { char name[MAXATOMLEN_UTF8]; erlang_char_encoding enc; }my_atom; struct my_obj { union { erlang_fun fun; erlang_pid pid; erlang_port port; erlang_ref ref; erlang_trace trace; erlang_big big; my_atom atom; int arity; }u; int nterms; /* 0 for non-containers */ char* startp; /* container start position in decode buffer */ }; typedef int decodeFT(const char *buf, int *index, struct my_obj*); typedef int encodeFT(char *buf, int *index, struct my_obj*); typedef int x_encodeFT(ei_x_buff*, struct my_obj*); struct Type { char* name; char* type; decodeFT* ei_decode_fp; encodeFT* ei_encode_fp; x_encodeFT* ei_x_encode_fp; }; struct Type fun_type = { "fun", "erlang_fun", (decodeFT*)ei_decode_fun, (encodeFT*)ei_encode_fun, (x_encodeFT*)ei_x_encode_fun }; struct Type pid_type = { "pid", "erlang_pid", (decodeFT*)ei_decode_pid, (encodeFT*)ei_encode_pid, (x_encodeFT*)ei_x_encode_pid }; struct Type port_type = { "port", "erlang_port", (decodeFT*)ei_decode_port, (encodeFT*)ei_encode_port, (x_encodeFT*)ei_x_encode_port }; struct Type ref_type = { "ref", "erlang_ref", (decodeFT*)ei_decode_ref, (encodeFT*)ei_encode_ref, (x_encodeFT*)ei_x_encode_ref }; struct Type trace_type = { "trace", "erlang_trace", (decodeFT*)ei_decode_trace, (encodeFT*)ei_encode_trace, (x_encodeFT*)ei_x_encode_trace }; struct Type big_type = { "big", "erlang_big", (decodeFT*)ei_decode_big, (encodeFT*)ei_encode_big, (x_encodeFT*)ei_x_encode_big }; int ei_decode_my_atom(const char *buf, int *index, my_atom* a) { return ei_decode_atom_as(buf, index, (a ? a->name : NULL), sizeof(a->name), ERLANG_UTF8, (a ? &a->enc : NULL), NULL); } int ei_encode_my_atom(char *buf, int *index, my_atom* a) { return ei_encode_atom_as(buf, index, a->name, ERLANG_UTF8, a->enc); } int ei_x_encode_my_atom(ei_x_buff* x, my_atom* a) { return ei_x_encode_atom_as(x, a->name, ERLANG_UTF8, a->enc); } struct Type my_atom_type = { "atom", "my_atom", (decodeFT*)ei_decode_my_atom, (encodeFT*)ei_encode_my_atom, (x_encodeFT*)ei_x_encode_my_atom }; int my_decode_tuple_header(const char *buf, int *index, struct my_obj* obj) { int ret = ei_decode_tuple_header(buf, index, &obj->u.arity); if (ret == 0 && obj) obj->nterms = obj->u.arity; return ret; } int my_encode_tuple_header(char *buf, int *index, struct my_obj* obj) { return ei_encode_tuple_header(buf, index, obj->u.arity); } int my_x_encode_tuple_header(ei_x_buff* x, struct my_obj* obj) { return ei_x_encode_tuple_header(x, (long)obj->u.arity); } struct Type tuple_type = { "tuple_header", "arity", my_decode_tuple_header, my_encode_tuple_header, my_x_encode_tuple_header }; int my_decode_list_header(const char *buf, int *index, struct my_obj* obj) { int ret = ei_decode_list_header(buf, index, &obj->u.arity); if (ret == 0 && obj) { obj->nterms = obj->u.arity + 1; } return ret; } int my_encode_list_header(char *buf, int *index, struct my_obj* obj) { return ei_encode_list_header(buf, index, obj->u.arity); } int my_x_encode_list_header(ei_x_buff* x, struct my_obj* obj) { return ei_x_encode_list_header(x, (long)obj->u.arity); } struct Type list_type = { "list_header", "arity", my_decode_list_header, my_encode_list_header, my_x_encode_list_header }; int my_decode_nil(const char *buf, int *index, struct my_obj* dummy) { int type, size, ret; ret = ei_get_type(buf, index, &type, &size); (*index)++; return ret ? ret : !(type == ERL_NIL_EXT); } int my_encode_nil(char *buf, int *index, struct my_obj* dummy) { return ei_encode_empty_list(buf, index); } int my_x_encode_nil(ei_x_buff* x, struct my_obj* dummy) { return ei_x_encode_empty_list(x); } struct Type nil_type = { "empty_list", "nil", my_decode_nil, my_encode_nil, my_x_encode_nil }; int my_decode_map_header(const char *buf, int *index, struct my_obj* obj) { int ret = ei_decode_map_header(buf, index, &obj->u.arity); if (ret == 0 && obj) obj->nterms = obj->u.arity * 2; return ret; } int my_encode_map_header(char *buf, int *index, struct my_obj* obj) { return ei_encode_map_header(buf, index, obj->u.arity); } int my_x_encode_map_header(ei_x_buff* x, struct my_obj* obj) { return ei_x_encode_map_header(x, (long)obj->u.arity); } struct Type map_type = { "map_header", "arity", my_decode_map_header, my_encode_map_header, my_x_encode_map_header }; #define BUFSZ 2000 void decode_encode(struct Type** tv, int nobj) { struct my_obj objv[10]; int oix = 0; char* packet; char* inp; char* outp; char out_buf[BUFSZ]; int size1, size2, size3; int err, i; ei_x_buff arg; packet = read_packet(NULL); inp = packet+1; outp = out_buf; ei_x_new(&arg); for (i=0; iname, t->type); size1 = 0; err = t->ei_decode_fp(inp, &size1, NULL); if (err != 0) { if (err != -1) { fail("decode returned non zero but not -1"); } else { fail1("decode '%s' returned non zero", t->name); } return; } if (size1 < 1) { fail("size is < 1"); return; } if (size1 > BUFSZ) { fail("size is > BUFSZ"); return; } size2 = 0; objv[oix].nterms = 0; objv[oix].startp = inp; err = t->ei_decode_fp(inp, &size2, &objv[oix]); if (err != 0) { if (err != -1) { fail("decode returned non zero but not -1"); } else { fail("decode returned non zero"); } return; } if (size1 != size2) { MESSAGE("size1 = %d, size2 = %d\n",size1,size2); fail("decode sizes differs"); return; } if (!objv[oix].nterms) { size2 = 0; err = ei_skip_term(inp, &size2); if (err != 0) { fail("ei_skip_term returned non zero"); return; } if (size1 != size2) { MESSAGE("size1 = %d, size2 = %d\n",size1,size2); fail("skip size differs"); return; } } MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type); size2 = 0; err = t->ei_encode_fp(NULL, &size2, &objv[oix]); if (err != 0) { if (err != -1) { fail("size calculation returned non zero but not -1"); return; } else { fail("size calculation returned non zero"); return; } } if (size1 != size2) { MESSAGE("size1 = %d, size2 = %d\n",size1,size2); fail("decode and encode size differs when buf is NULL"); return; } MESSAGE("ei_encode_%s, arg is type %s", t->name, t->type); size3 = 0; err = t->ei_encode_fp(outp, &size3, &objv[oix]); if (err != 0) { if (err != -1) { fail("returned non zero but not -1"); } else { fail("returned non zero"); } return; } if (size1 != size3) { MESSAGE("size1 = %d, size2 = %d\n",size1,size3); fail("decode and encode size differs"); return; } MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type); err = t->ei_x_encode_fp(&arg, &objv[oix]); if (err != 0) { if (err != -1) { fail("returned non zero but not -1"); } else { fail("returned non zero"); } ei_x_free(&arg); return; } if (arg.index < 1) { fail("size is < 1"); ei_x_free(&arg); return; } inp += size1; outp += size1; if (objv[oix].nterms) { /* container term */ if (++oix >= sizeof(objv)/sizeof(*objv)) fail("Term too deep"); } else { /* "leaf" term */ while (oix > 0) { if (--(objv[oix - 1].nterms) == 0) { /* last element in container */ --oix; size2 = 0; err = ei_skip_term(objv[oix].startp, &size2); if (err != 0) { fail("ei_skip_term returned non zero"); return; } if (objv[oix].startp + size2 != inp) { MESSAGE("size1 = %d, size2 = %d\n", size1, size2); fail("container skip size differs"); return; } } else break; /* more elements in container */ } } } if (oix > 0) { fail("Container not complete"); } send_buffer(out_buf, outp - out_buf); send_buffer(arg.buff, arg.index); ei_x_free(&arg); free_packet(packet); } void decode_encode_one(struct Type* t) { decode_encode(&t, 1); } void decode_encode_big(struct Type* t) { char *buf; char buf2[2048]; void *p; /* (TYPE*) */ int size1 = 0; int size2 = 0; int size3 = 0; int err, index = 0, len, type; ei_x_buff arg; MESSAGE("ei_decode_%s, arg is type %s", t->name, t->type); buf = read_packet(NULL); ei_get_type(buf+1, &index, &type, &len); p = ei_alloc_big(len); err = t->ei_decode_fp(buf+1, &size1, p); if (err != 0) { if (err != -1) { fail("decode returned non zero but not -1"); } else { fail("decode returned non zero"); } return; } if (size1 < 1) { fail("size is < 1"); return; } MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type); err = t->ei_encode_fp(NULL, &size2, p); if (err != 0) { if (err != -1) { fail("size calculation returned non zero but not -1"); return; } else { fail("size calculation returned non zero"); return; } } if (size1 != size2) { MESSAGE("size1 = %d, size2 = %d\n",size1,size2); fail("decode and encode size differs when buf is NULL"); return; } MESSAGE("ei_encode_%s, arg is type %s", t->name, t->type); err = t->ei_encode_fp(buf2, &size3, p); if (err != 0) { if (err != -1) { fail("returned non zero but not -1"); } else { fail("returned non zero"); } return; } if (size1 != size3) { MESSAGE("size1 = %d, size2 = %d\n",size1,size3); fail("decode and encode size differs"); return; } send_buffer(buf2, size1); MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type); ei_x_new(&arg); err = t->ei_x_encode_fp(&arg, p); if (err != 0) { if (err != -1) { fail("returned non zero but not -1"); } else { fail("returned non zero"); } ei_x_free(&arg); return; } if (arg.index < 1) { fail("size is < 1"); ei_x_free(&arg); return; } send_buffer(arg.buff, arg.index); ei_x_free(&arg); ei_free_big(p); free_packet(buf); } /* ******************************************************************** */ TESTCASE(test_ei_decode_encode) { int i; ei_init(); decode_encode_one(&fun_type); decode_encode_one(&pid_type); decode_encode_one(&port_type); decode_encode_one(&ref_type); decode_encode_one(&trace_type); decode_encode_big(&big_type); decode_encode_big(&big_type); decode_encode_big(&big_type); decode_encode_big(&big_type); decode_encode_big(&big_type); decode_encode_big(&big_type); /* Test large node containers... */ for (i=0; i<6; i++) { decode_encode_one(&pid_type); decode_encode_one(&port_type); decode_encode_one(&ref_type); } /* Unicode atoms */ for (i=0; i<24; i++) { decode_encode_one(&my_atom_type); decode_encode_one(&pid_type); decode_encode_one(&port_type); decode_encode_one(&ref_type); } decode_encode_one(&tuple_type); /* {} */ { struct Type* tpl[] = { &tuple_type, &my_atom_type, &pid_type, &port_type, &ref_type }; decode_encode(tpl, 5); } { struct Type* list[] = { &list_type, &my_atom_type, &pid_type, &port_type, &ref_type, &nil_type }; decode_encode(list, 6); } { struct Type* list[] = { &list_type, &my_atom_type, &fun_type }; decode_encode(list, 3); } decode_encode_one(&map_type); /* #{} */ { /* #{atom => atom}*/ struct Type* map[] = { &map_type, &my_atom_type, &my_atom_type }; decode_encode(map, 3); } { /* #{atom => atom, atom => pid, port => ref }*/ struct Type* map[] = { &map_type, &my_atom_type, &my_atom_type, &my_atom_type, &pid_type, &port_type, &ref_type }; decode_encode(map, 7); } report(1); } /* ******************************************************************** */