aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/test/all_SUITE_data/ei_runner.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/erl_interface/test/all_SUITE_data/ei_runner.c')
-rw-r--r--lib/erl_interface/test/all_SUITE_data/ei_runner.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.c b/lib/erl_interface/test/all_SUITE_data/ei_runner.c
new file mode 100644
index 0000000000..205f911e38
--- /dev/null
+++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.c
@@ -0,0 +1,400 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifndef __WIN32__
+#include <unistd.h>
+#endif
+#include <stdarg.h>
+
+#include "ei_runner.h"
+
+#ifndef __WIN32__
+#define _O_BINARY 0
+#define _setmode(fd, mode)
+#endif
+
+#define HEADER_SIZE 4
+
+static char* progname; /* Name of this program (from argv[0]). */
+static int fd_from_erl; /* File descriptor from Erlang. */
+static int fd_to_erl; /* File descriptor to Erlang. */
+
+static int packet_loop();
+static void ensure_buf_big_enough();
+static int readn();
+static void reply(char* buf, unsigned size);
+static void dump();
+
+void
+run_tests(char* argv0, TestCase test_cases[], unsigned number)
+{
+ int i;
+ int n;
+ char* packet;
+
+ progname = argv0;
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+ fd_from_erl = 0;
+ fd_to_erl = 1;
+
+ packet = read_packet(&n);
+
+ /*
+ * Dispatch to the appropriate test function.
+ */
+
+ i = packet[0] * 256 + packet[1];
+ if (i >= number) {
+ fprintf(stderr, "%s: bad test case number %d",
+ progname, i);
+ free(packet);
+ exit(1);
+ } else {
+ (*test_cases[i])();
+ free(packet);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * R e a d i n g p a c k e t s
+ *
+ ************************************************************************/
+
+/*
+ * Reads an Erlang term.
+ *
+ * Only accepts 't' (term) or 'e' (end of test),
+ * exits program on error
+ * returns 1 on 'e', 0 on 't'
+ */
+int get_bin_term(ei_x_buff* x, ei_term* term)
+{
+ int len, version;
+
+ ei_x_free(x);
+ x->buff = read_packet(&len);
+ x->buffsz = len;
+ x->index = 0;
+ switch (x->buff[x->index++]) {
+ case 'e':
+ return 1;
+ case 't':
+ if (ei_decode_version(x->buff, &x->index, &version) < 0
+ || ei_decode_ei_term(x->buff, &x->index, term) < 0) {
+ fail("Failed to decode term");
+ exit(0);
+ }
+ return 0;
+ default:
+ fprintf(stderr, "Garbage received: ");
+ dump(x->buff, len, 16);
+ putc('\n', stderr);
+ fail("C program received garbage");
+ exit(1);
+ }
+}
+
+
+/*
+ * Reads a packet from Erlang. The packet must be a standard {packet, 2}
+ * packet. This function aborts if any error is detected (including EOF).
+ *
+ * Returns: The number of bytes in the packet.
+ */
+
+char *read_packet(int *len)
+{
+
+ unsigned char* io_buf = NULL; /* Buffer for file i/o. */
+ int i;
+ unsigned char header[HEADER_SIZE];
+ unsigned packet_length; /* Length of current packet. */
+ int bytes_read;
+
+ /*
+ * Read the packet header.
+ */
+
+ bytes_read = readn(fd_from_erl, header, HEADER_SIZE);
+
+ if (bytes_read == 0) {
+ fprintf(stderr, "%s: Unexpected end of file\n", progname);
+ exit(1);
+ }
+ if (bytes_read != HEADER_SIZE) {
+ fprintf(stderr, "%s: Failed to read packet header\n", progname);
+ exit(1);
+ }
+
+ /*
+ * Get the length of this packet.
+ */
+
+ packet_length = 0;
+
+ for (i = 0; i < HEADER_SIZE; i++)
+ packet_length = (packet_length << 8) | header[i];
+
+ if (len) *len=packet_length; /* report length only if caller requested it */
+
+ if ((io_buf = (char *) malloc(packet_length)) == NULL) {
+ fprintf(stderr, "%s: insufficient memory for i/o buffer of size %d\n",
+ progname, packet_length);
+ exit(1);
+ }
+
+ /*
+ * Read the packet itself.
+ */
+
+ bytes_read = readn(fd_from_erl, io_buf, packet_length);
+ if (bytes_read != packet_length) {
+ fprintf(stderr, "%s: couldn't read packet of length %d\r\n",
+ progname, packet_length);
+ free(io_buf);
+ exit(1);
+ }
+
+ return io_buf;
+}
+
+
+/***********************************************************************
+ * S e n d i n g r e p l i e s
+ *
+ * The functions below send various types of replies back to Erlang.
+ * Each reply start with a letter indicating the type of reply.
+ *
+ * Reply Translated to on Erlang side
+ * ----- ----------------------------
+ * [$b|Bytes] {bytes, Bytes}
+ * [$e] eot
+ * [$f] test_server:fail()
+ * [$f|Reason] test_server:fail(Reason)
+ * [$t|EncodedTerm] {term, Term}
+ * [$N] 'NULL'
+ * [$m|Message] io:format("~s", [Message]) (otherwise ignored)
+ *
+ ***********************************************************************/
+
+/*
+ * This function reports the outcome of a test fail. It is useful if
+ * you implement a test case entirely in C code.
+ *
+ * If the ok argument is zero, a [$f] reply will be sent to the
+ * Erlang side (causing test_server:fail() to be called); otherwise,
+ * the atom 'eot' will be sent to Erlang.
+ *
+ * If you need to provide more details on a failure, use the fail() function.
+ */
+
+void
+do_report(file, line, ok)
+ char* file;
+ int line;
+ int ok; /* Zero if failed; non-zero otherwise. */
+{
+ char reason;
+ /*unsigned long ab;
+ unsigned long fb;*/
+
+ reason = ok ? 'e' : 'f';
+
+ if (!ok) {
+ do_fail(file, line, "Generic failure");
+ } else {
+ /* release all unallocated blocks */
+ /*erl_eterm_release();*/
+ /* check mem usage stats */
+ /*erl_eterm_statistics(&ab, &fb);*/
+ /*if ((ab == 0) && (fb == 0) ) {*/
+ reply(&reason, 1);
+ /*}
+ else {
+ char sbuf[128];
+
+ sprintf(sbuf, "still %lu terms allocated,"
+ " %lu on freelist at end of test", ab, fb);
+ do_fail(file, line, sbuf);
+ }*/
+ }
+}
+
+
+/*
+ * This function causes a call to test_server:fail(Reason) on the
+ * Erlang side.
+ */
+
+void do_fail(char* file, int line, char* reason)
+{
+ char sbuf[2048];
+
+ sbuf[0] = 'f';
+ sprintf(sbuf+1, "%s, line %d: %s", file, line, reason);
+ reply(sbuf, 1+strlen(sbuf+1));
+}
+
+/*
+ * This function sends a message to the Erlang side.
+ * The message will be written to the test servers log file,
+ * but will otherwise be completly ignored.
+ */
+
+void message(char* format, ...)
+{
+ va_list ap;
+ char sbuf[1024];
+
+ sbuf[0] = 'm';
+ va_start(ap, format);
+ vsprintf(sbuf+1, format, ap);
+ va_end(ap);
+
+ reply(sbuf, 1+strlen(sbuf+1));
+}
+
+/*
+ * This function sends the given binary term to the Erlang side,
+ * where it will be received as {term, Term} (prefix 't').
+ */
+void send_bin_term(ei_x_buff* x)
+{
+ ei_x_buff x2;
+ ei_x_new(&x2);
+ x2.buff[x2.index++] = 't';
+ ei_x_append(&x2, x);
+ reply(x2.buff, x2.index);
+ ei_x_free(&x2);
+}
+
+/*
+ * This function sends a raw buffer of data to the
+ * Erlang side, where it will be received as {bytes, Bytes} (prefix 'b').
+ */
+void send_buffer(char* buf, int size)
+{
+ char* send_buf;
+
+ send_buf = (char *) malloc(size+1);
+ send_buf[0] = 'b';
+ memcpy(send_buf+1, buf, size);
+ reply(send_buf, size+1);
+ free(send_buf);
+}
+
+/***********************************************************************
+ *
+ * P r i v a t e h e l p e r s
+ *
+ ***********************************************************************/
+
+/*
+ * Sends a packet back to Erlang.
+ */
+static void reply(char* reply_buf, unsigned size)
+{
+ int n; /* Temporary to hold size. */
+ int i; /* Loop counter. */
+ char* buf;
+
+
+ buf = (char *) malloc(size+HEADER_SIZE);
+ memcpy(buf+HEADER_SIZE, reply_buf, size);
+
+ /*
+ * Fill the header starting with the least significant byte.
+ */
+ n = size;
+ for (i = HEADER_SIZE-1; i >= 0; i--) {
+ buf[i] = (char) n; /* Store least significant byte. */
+ n = n >> 8;
+ }
+
+ size += HEADER_SIZE;
+ write(fd_to_erl, buf, size);
+ free(buf);
+}
+
+
+/*
+ * Reads len number of bytes.
+ */
+
+static int
+readn(fd, buf, len)
+ int fd; /* File descriptor to read from. */
+ unsigned char *buf; /* Store in this buffer. */
+ int len; /* Number of bytes to read. */
+{
+ int n; /* Byte count in last read call. */
+ int sofar = 0; /* Bytes read so far. */
+
+ do {
+ if ((n = read(fd, buf+sofar, len-sofar)) <= 0)
+ /* error or EOF in read */
+ return(n);
+ sofar += n;
+ } while (sofar < len);
+ return sofar;
+}
+
+void
+dump(buf, sz, max)
+ unsigned char* buf;
+ int sz;
+ int max;
+{
+ int i, imax;
+ char comma[5] = ",";
+
+ if (!sz)
+ return;
+ if (sz > max)
+ imax = max;
+ else
+ imax = sz;
+
+ for (i=0; i<imax; i++) {
+ if (i == imax-1) {
+ if (sz > max)
+ strcpy(comma, ",...");
+ else
+ comma[0] = 0;
+ }
+ if (isdigit(buf[i]))
+ fprintf(stderr, "%u%s", (int)(buf[i]), comma);
+ else {
+ if (isalpha(buf[i])) {
+ fprintf(stderr, "%c%s", buf[i], comma);
+ }
+ else
+ fprintf(stderr, "%u%s", (int)(buf[i]), comma);
+ }
+ }
+}
+