]> sigrok.org Git - libsigrokdecode.git/blobdiff - tests/runtc.c
runtc: Update to the new libsigrok session API.
[libsigrokdecode.git] / tests / runtc.c
index c3d0725ecb6d2712d0a5b1b38211cb5de8ea3b7c..11ae560dbea4766c63872d09018dbf9b333a6e66 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <Python.h>
 #include "../libsigrokdecode.h"
 #include <libsigrok/libsigrok.h>
 #include <stdlib.h>
 #ifdef __LINUX__
 #include <sched.h>
 #endif
-#include "../config.h"
+#include "config.h"
 
 int debug = FALSE;
 int statistics = FALSE;
 char *coverage_report;
 
-struct probe {
+struct channel {
        char *name;
-       int probe;
+       int channel;
 };
 
 struct option {
        char *key;
-       char *value;
+       GVariant *value;
 };
 
 struct pd {
        char *name;
-       GSList *probes;
+       GSList *channels;
        GSList *options;
 };
 
@@ -67,12 +68,17 @@ struct output {
 };
 
 struct cvg {
-       int lines;
-       int missed;
+       int num_lines;
+       int num_missed;
+       float coverage;
+       GSList *missed_lines;
 };
 
 
 struct cvg *get_mod_cov(PyObject *py_cov, char *module_name);
+void cvg_add(struct cvg *dst, struct cvg *src);
+struct cvg *cvg_new(void);
+gboolean find_missed_line(struct cvg *cvg, char *linespec);
 
 
 static void logmsg(char *prefix, FILE *out, const char *format, va_list args)
@@ -135,8 +141,8 @@ static void usage(char *msg)
        printf("Usage: runtc [-dPpoiOf]\n");
        printf("  -d  Debug\n");
        printf("  -P  <protocol decoder>\n");
-       printf("  -p  <probename=probenum> (optional)\n");
-       printf("  -o  <probeoption=value> (optional)\n");
+       printf("  -p  <channelname=channelnum> (optional)\n");
+       printf("  -o  <channeloption=value> (optional)\n");
        printf("  -i <input file>\n");
        printf("  -O <output-pd:output-type[:output-class]>\n");
        printf("  -f <output file> (optional)\n");
@@ -322,16 +328,17 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
        struct srd_session *sess;
        struct srd_decoder *dec;
        struct srd_decoder_inst *di, *prev_di;
-       srd_pd_output_callback_t cb;
+       srd_pd_output_callback cb;
        struct pd *pd;
-       struct probe *probe;
+       struct channel *channel;
        struct option *option;
        GVariant *gvar;
-       GHashTable *probes, *opts;
+       GHashTable *channels, *opts;
        GSList *pdl, *l;
        int idx;
-       int max_probe;
+       int max_channel;
        char **decoder_class;
+       struct sr_session *sr_sess;
 
        if (op->outfile) {
                if ((op->outfd = open(op->outfile, O_CREAT|O_WRONLY, 0600)) == -1) {
@@ -341,12 +348,12 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
                }
        }
 
-       if (sr_session_load(infile) != SR_OK)
+       if (sr_session_load(infile, &sr_sess) != SR_OK)
                return FALSE;
 
        if (srd_session_new(&sess) != SRD_OK)
                return FALSE;
-       sr_session_datafeed_callback_add(sr_cb, sess);
+       sr_session_datafeed_callback_add(sr_sess, sr_cb, sess);
        switch (op->type) {
        case SRD_OUTPUT_ANN:
                cb = srd_cb_ann;
@@ -380,23 +387,23 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
                        return FALSE;
                g_hash_table_destroy(opts);
 
-               /* Map probes. */
-               if (pd->probes) {
-                       probes = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+               /* Map channels. */
+               if (pd->channels) {
+                       channels = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                        (GDestroyNotify)g_variant_unref);
-                       max_probe = 0;
-                       for (l = pd->probes; l; l = l->next) {
-                               probe = l->data;
-                               if (probe->probe > max_probe)
-                                       max_probe = probe->probe;
-                               gvar = g_variant_new_int32(probe->probe);
+                       max_channel = 0;
+                       for (l = pd->channels; l; l = l->next) {
+                               channel = l->data;
+                               if (channel->channel > max_channel)
+                                       max_channel = channel->channel;
+                               gvar = g_variant_new_int32(channel->channel);
                                g_variant_ref_sink(gvar);
-                               g_hash_table_insert(probes, probe->name, gvar);
+                               g_hash_table_insert(channels, channel->name, gvar);
                        }
-                       if (srd_inst_probe_set_all(di, probes,
-                                       (max_probe + 8) / 8) != SRD_OK)
+                       if (srd_inst_channel_set_all(di, channels,
+                                       (max_channel + 8) / 8) != SRD_OK)
                                return FALSE;
-                       g_hash_table_destroy(probes);
+                       g_hash_table_destroy(channels);
                }
 
                /* If this is not the first decoder in the list, stack it
@@ -438,9 +445,9 @@ static int run_testcase(char *infile, GSList *pdlist, struct output *op)
                        DBG("Class %s index is %d", op->class, op->class_idx);
        }
 
-       sr_session_start();
-       sr_session_run();
-       sr_session_stop();
+       sr_session_start(sr_sess);
+       sr_session_run(sr_sess);
+       sr_session_stop(sr_sess);
 
        srd_session_destroy(sess);
 
@@ -490,12 +497,13 @@ static PyObject *start_coverage(GSList *pdlist)
 
 struct cvg *get_mod_cov(PyObject *py_cov, char *module_name)
 {
-       PyObject *py_mod, *py_pathlist, *py_path, *py_func, *py_pd, *py_result;
+       PyObject *py_mod, *py_pathlist, *py_path, *py_func, *py_pd;
+       PyObject *py_result, *py_missed, *py_item;
        DIR *d;
        struct dirent *de;
        struct cvg *cvg_mod;
-       int lines, missed, i;
-       char *path;
+       int num_lines, num_missed, linenum, i, j;
+       char *path, *linespec;
 
        if (!(py_mod = PyImport_ImportModule(module_name)))
                return NULL;
@@ -504,7 +512,8 @@ struct cvg *get_mod_cov(PyObject *py_cov, char *module_name)
        py_pathlist = PyObject_GetAttrString(py_mod, "__path__");
        for (i = 0; i < PyList_Size(py_pathlist); i++) {
                py_path = PyList_GetItem(py_pathlist, i);
-               path = PyUnicode_AsUTF8AndSize(py_path, NULL);
+        PyUnicode_FSConverter(PyList_GetItem(py_pathlist, i), &py_path);
+               path = PyBytes_AS_STRING(py_path);
                if (!(d = opendir(path))) {
                        ERR("Invalid module path '%s'", path);
                        return NULL;
@@ -523,51 +532,114 @@ struct cvg *get_mod_cov(PyObject *py_cov, char *module_name)
                        Py_DecRef(py_func);
 
                        if (!cvg_mod)
-                               cvg_mod = calloc(1, sizeof(struct cvg));
+                               cvg_mod = cvg_new();
                        if (PyTuple_Size(py_result) != 5) {
                                ERR("Invalid result from coverage of '%s/%s'", path, de->d_name);
                                return NULL;
                        }
-                       lines = PyList_Size(PyTuple_GetItem(py_result, 1));
-                       missed = PyList_Size(PyTuple_GetItem(py_result, 3));
-                       DBG("Coverage for %s/%s: %d lines, %d missed.", module_name, de->d_name, lines, missed);
-                       cvg_mod->lines += lines;
-                       cvg_mod->missed += missed;
+                       num_lines = PyList_Size(PyTuple_GetItem(py_result, 1));
+                       py_missed = PyTuple_GetItem(py_result, 3);
+                       num_missed = PyList_Size(py_missed);
+                       cvg_mod->num_lines += num_lines;
+                       cvg_mod->num_missed += num_missed;
+                       for (j = 0; j < num_missed; j++) {
+                               py_item = PyList_GetItem(py_missed, j);
+                               linenum = PyLong_AsLong(py_item);
+                               linespec = g_strdup_printf("%s/%s:%d", module_name,
+                                               de->d_name, linenum);
+                               cvg_mod->missed_lines = g_slist_append(cvg_mod->missed_lines, linespec);
+                       }
+                       DBG("Coverage for %s/%s: %d lines, %d missed.",
+                                       module_name, de->d_name, num_lines, num_missed);
                        Py_DecRef(py_result);
                }
        }
+       if (cvg_mod->num_lines)
+               cvg_mod->coverage = 100 - ((float)cvg_mod->num_missed / (float)cvg_mod->num_lines * 100);
 
        Py_DecRef(py_mod);
+    Py_DecRef(py_path);
 
        return cvg_mod;
 }
 
+struct cvg *cvg_new(void)
+{
+       struct cvg *cvg;
+
+       cvg = calloc(1, sizeof(struct cvg));
+
+       return cvg;
+}
+
+gboolean find_missed_line(struct cvg *cvg, char *linespec)
+{
+       GSList *l;
+
+       for (l = cvg->missed_lines; l; l = l->next)
+               if (!strcmp(l->data, linespec))
+                       return TRUE;
+
+       return FALSE;
+}
+
+void cvg_add(struct cvg *dst, struct cvg *src)
+{
+       GSList *l;
+       char *linespec;
+
+
+       dst->num_lines += src->num_lines;
+       dst->num_missed += src->num_missed;
+       for (l = src->missed_lines; l; l = l->next) {
+               linespec = l->data;
+               if (!find_missed_line(dst, linespec))
+                       dst->missed_lines = g_slist_append(dst->missed_lines, linespec);
+       }
+
+}
+
 static int report_coverage(PyObject *py_cov, GSList *pdlist)
 {
        PyObject *py_func, *py_mod, *py_args, *py_kwargs, *py_outfile, *py_pct;
-       GSList *l;
+       GSList *l, *ml;
        struct pd *pd;
        struct cvg *cvg_mod, *cvg_all;
-       float total;
+       float total_coverage;
+       int lines, missed, cnt;
 
        DBG("Making coverage report.");
 
        /* Get coverage for each module in the stack. */
-       cvg_all = calloc(1, sizeof(struct cvg));
-       for (l = pdlist; l; l = l->next) {
+       lines = missed = 0;
+       cvg_all = cvg_new();
+       for (cnt = 0, l = pdlist; l; l = l->next, cnt++) {
                pd = l->data;
                if (!(cvg_mod = get_mod_cov(py_cov, pd->name)))
                        return FALSE;
-               cvg_all->lines += cvg_mod->lines;
-               cvg_all->missed += cvg_mod->missed;
+               printf("coverage: scope=%s coverage=%.0f%% lines=%d missed=%d "
+                               "missed_lines=", pd->name, cvg_mod->coverage,
+                               cvg_mod->num_lines, cvg_mod->num_missed);
+               for (ml = cvg_mod->missed_lines; ml; ml = ml->next) {
+                       if (ml != cvg_mod->missed_lines)
+                               printf(",");
+                       printf("%s", (char *)ml->data);
+               }
+               printf("\n");
+               lines += cvg_mod->num_lines;
+               missed += cvg_mod->num_missed;
+               cvg_add(cvg_all, cvg_mod);
                DBG("Coverage for module %s: %d lines, %d missed", pd->name,
-                               cvg_mod->lines, cvg_mod->missed);
+                               cvg_mod->num_lines, cvg_mod->num_missed);
        }
+       lines /= cnt;
+       missed /= cnt;
+       total_coverage = 100 - ((float)missed / (float)lines * 100);
 
        /* Machine-readable stats on stdout. */
-       total = 100 - ((float)cvg_all->missed / (float)cvg_all->lines * 100);
-       printf("coverage: lines=%d missed=%d coverage=%.0f%%\n",
-                       cvg_all->lines, cvg_all->missed, total);
+       printf("coverage: scope=all coverage=%.0f%% lines=%d missed=%d\n",
+                       total_coverage, cvg_all->num_lines, cvg_all->num_missed);
+
 
        /* Write text report to file. */
        /* io.open(coverage_report, "w") */
@@ -615,11 +687,11 @@ int main(int argc, char **argv)
        PyObject *coverage;
        GSList *pdlist;
        struct pd *pd;
-       struct probe *probe;
+       struct channel *channel;
        struct option *option;
        struct output *op;
-       int ret;
-       char c, *opt_infile, **kv, **opstr;
+       int ret, c;
+       char *opt_infile, **kv, **opstr;
 
        op = malloc(sizeof(struct output));
        op->pd = NULL;
@@ -640,7 +712,7 @@ int main(int argc, char **argv)
                case 'P':
                        pd = g_malloc(sizeof(struct pd));
                        pd->name = g_strdup(optarg);
-                       pd->probes = pd->options = NULL;
+                       pd->channels = pd->options = NULL;
                        pdlist = g_slist_append(pdlist, pd);
                        break;
                case 'p':
@@ -658,15 +730,16 @@ int main(int argc, char **argv)
                                usage(NULL);
                        }
                        if (c == 'p') {
-                               probe = malloc(sizeof(struct probe));
-                               probe->name = g_strdup(kv[0]);
-                               probe->probe = strtoul(kv[1], 0, 10);
+                               channel = malloc(sizeof(struct channel));
+                               channel->name = g_strdup(kv[0]);
+                               channel->channel = strtoul(kv[1], 0, 10);
                                /* Apply to last PD. */
-                               pd->probes = g_slist_append(pd->probes, probe);
+                               pd->channels = g_slist_append(pd->channels, channel);
                        } else {
                                option = malloc(sizeof(struct option));
                                option->key = g_strdup(kv[0]);
-                               option->value = g_strdup(kv[1]);
+                               option->value = g_variant_new_string(kv[1]);
+                g_variant_ref_sink(option->value);
                                /* Apply to last PD. */
                                pd->options = g_slist_append(pd->options, option);
                        }
@@ -689,6 +762,9 @@ int main(int argc, char **argv)
                                op->type = SRD_OUTPUT_BINARY;
                        else if (!strcmp(opstr[1], "python"))
                                op->type = SRD_OUTPUT_PYTHON;
+                       else if (!strcmp(opstr[1], "exception"))
+                /* Doesn't matter, we just need it to bomb out. */
+                               op->type = SRD_OUTPUT_PYTHON;
                        else {
                                ERR("Unknown output type '%s'", opstr[1]);
                                g_strfreev(opstr);