Imported Upstream version 0.7.2
[platform/upstream/libsolv.git] / ext / testcase.c
index 26acefa..b815c56 100644 (file)
@@ -15,6 +15,7 @@
 #include "pool.h"
 #include "poolarch.h"
 #include "poolvendor.h"
+#include "evr.h"
 #include "repo.h"
 #include "repo_solv.h"
 #include "solver.h"
@@ -85,6 +86,8 @@ static struct resultflags2str {
   { TESTCASE_RESULT_RULES,             "rules" },
   { TESTCASE_RESULT_GENID,             "genid" },
   { TESTCASE_RESULT_REASON,            "reason" },
+  { TESTCASE_RESULT_CLEANDEPS,         "cleandeps" },
+  { TESTCASE_RESULT_JOBS,              "jobs" },
   { 0, 0 }
 };
 
@@ -119,6 +122,7 @@ static struct solverflags2str {
   { SOLVER_FLAG_FOCUS_BEST,                 "focusbest", 0 },
   { SOLVER_FLAG_STRONG_RECOMMENDS,          "strongrecommends", 0 },
   { SOLVER_FLAG_INSTALL_ALSO_UPDATES,       "installalsoupdates", 0 },
+  { SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED, "onlynamespacerecommended", 0 },
   { 0, 0, 0 }
 };
 
@@ -168,6 +172,13 @@ static struct selflags2str {
   { SELECTION_NOCASE, "nocase" },
   { SELECTION_SOURCE_ONLY, "sourceonly" },
   { SELECTION_WITH_SOURCE, "withsource" },
+  { SELECTION_SKIP_KIND, "skipkind" },
+  { SELECTION_MATCH_DEPSTR, "depstr" },
+  { SELECTION_WITH_DISABLED, "withdisabled" },
+  { SELECTION_WITH_BADARCH, "withbadarch" },
+  { SELECTION_ADD, "add" },
+  { SELECTION_SUBTRACT, "subtract" },
+  { SELECTION_FILTER, "filter" },
   { 0, 0 }
 };
 
@@ -383,6 +394,7 @@ struct oplist {
   { REL_AND,   "&" },
   { REL_OR ,   "|" },
   { REL_WITH , "+" },
+  { REL_WITHOUT , "-" },
   { REL_NAMESPACE , "<NAMESPACE>" },
   { REL_ARCH,       "." },
   { REL_MULTIARCH,  "<MULTIARCH>" },
@@ -392,6 +404,7 @@ struct oplist {
   { REL_KIND,  "<KIND>" },
   { REL_ELSE, "<ELSE>" },
   { REL_ERROR, "<ERROR>" },
+  { REL_UNLESS, "<UNLESS>" },
   { REL_LT, "<" },
   { 0, 0 }
 };
@@ -923,7 +936,7 @@ str2selflags(Pool *pool, char *s)   /* modifies the string! */
            break;
          }
       if (!selflags2str[i].str)
-       pool_debug(pool, SOLV_ERROR, "str2job: unknown selection flag '%s'\n", s);
+       pool_error(pool, 0, "str2job: unknown selection flag '%s'", s);
       s = se;
     }
   return selflags;
@@ -945,7 +958,7 @@ str2jobflags(Pool *pool, char *s)   /* modifies the string */
            break;
          }
       if (!jobflags2str[i].str)
-       pool_debug(pool, SOLV_ERROR, "str2job: unknown job flag '%s'\n", s);
+       pool_error(pool, 0, "str2job: unknown job flag '%s'", s);
       s = se;
     }
   return jobflags;
@@ -980,7 +993,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
     }
   if (npieces < 3)
     {
-      pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
+      pool_error(pool, -1, "str2job: bad line '%s'", str);
       solv_free(pieces);
       return -1;
     }
@@ -990,7 +1003,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
       break;
   if (!job2str[i].str)
     {
-      pool_debug(pool, SOLV_ERROR, "str2job: unknown job '%s'\n", str);
+      pool_error(pool, -1, "str2job: unknown job '%s'", str);
       solv_free(pieces);
       return -1;
     }
@@ -1011,7 +1024,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
     {
       if (npieces != 3)
        {
-         pool_debug(pool, SOLV_ERROR, "str2job: bad pkg selector in '%s'\n", str);
+         pool_error(pool, -1, "str2job: bad pkg selector in '%s'", str);
          solv_free(pieces);
          return -1;
        }
@@ -1019,7 +1032,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
       what = testcase_str2solvid(pool, pieces[2]);
       if (!what)
        {
-         pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[2]);
+         pool_error(pool, -1, "str2job: unknown package '%s'", pieces[2]);
          solv_free(pieces);
          return -1;
        }
@@ -1060,14 +1073,14 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
       Queue q;
       job |= SOLVER_SOLVABLE_ONE_OF;
       queue_init(&q);
-      if (npieces > 3 && strcmp(pieces[2], "nothing") != 0)
+      if (npieces > 2 && strcmp(pieces[2], "nothing") != 0)
        {
          for (i = 2; i < npieces; i++)
            {
              Id p = testcase_str2solvid(pool, pieces[i]);
              if (!p)
                {
-                 pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[i]);
+                 pool_error(pool, -1, "str2job: unknown package '%s'", pieces[i]);
                  queue_free(&q);
                  solv_free(pieces);
                  return -1;
@@ -1083,14 +1096,14 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
       Repo *repo;
       if (npieces != 3)
        {
-         pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
+         pool_error(pool, -1, "str2job: bad line '%s'", str);
          solv_free(pieces);
          return -1;
        }
       repo = testcase_str2repo(pool, pieces[2]);
       if (!repo)
        {
-         pool_debug(pool, SOLV_ERROR, "str2job: unknown repo '%s'\n", pieces[2]);
+         pool_error(pool, -1, "str2job: unknown repo '%s'", pieces[2]);
          solv_free(pieces);
          return -1;
        }
@@ -1101,7 +1114,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
     {
       if (npieces != 3 && strcmp(pieces[2], "packages") != 0)
        {
-         pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
+         pool_error(pool, -1, "str2job: bad line '%s'", str);
          solv_free(pieces);
          return -1;
        }
@@ -1110,7 +1123,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
     }
   else
     {
-      pool_debug(pool, SOLV_ERROR, "str2job: unknown selection in '%s'\n", str);
+      pool_error(pool, -1, "str2job: unknown selection in '%s'", str);
       solv_free(pieces);
       return -1;
     }
@@ -1119,22 +1132,24 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
   return job;
 }
 
+#define SELECTIONJOB_MATCHDEPS         1
+#define SELECTIONJOB_MATCHDEPID                2
+#define SELECTIONJOB_MATCHSOLVABLE     3
+
 static int
-addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue)
+addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int type, int keyname)
 {
   Id job;
-  int i, r;
+  int i, r = 0;
   int selflags;
   Queue sel;
+  char *sp;
 
   for (i = 0; job2str[i].str; i++)
     if (!strcmp(pieces[0], job2str[i].str))
       break;
   if (!job2str[i].str)
-    {
-      pool_debug(pool, SOLV_ERROR, "selstr2job: unknown job '%s'\n", pieces[0]);
-      return -1;
-    }
+    return pool_error(pool, -1, "selstr2job: unknown job '%s'", pieces[0]);
   job = job2str[i].job;
   if (npieces > 3)
     {
@@ -1148,13 +1163,27 @@ addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue)
        }
     }
   if (npieces < 4)
-    {
-      pool_debug(pool, SOLV_ERROR, "selstr2job: no selection flags\n");
-      return -1;
-    }
-  selflags = str2selflags(pool, pieces[3]);
+    return pool_error(pool, -1, "selstr2job: no selection flags");
+  selflags = str2selflags(pool, pieces[npieces - 1]);
+  /* re-join pieces */
+  for (sp = pieces[2]; sp < pieces[npieces - 2]; sp++)
+    if (*sp == 0)
+      *sp = ' ';
   queue_init(&sel);
-  r = selection_make(pool, &sel, pieces[2], selflags);
+  if (selflags & (SELECTION_ADD | SELECTION_SUBTRACT | SELECTION_FILTER))
+    {
+      for (i = 0; i < jobqueue->count; i += 2)
+       queue_push2(&sel, jobqueue->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK), jobqueue->elements[i + 1]);
+      queue_empty(jobqueue);
+    }
+  if (!type)
+    r = selection_make(pool, &sel, pieces[2], selflags);
+  else if (type == SELECTIONJOB_MATCHDEPS)
+    r = selection_make_matchdeps(pool, &sel, pieces[2], selflags, keyname, 0);
+  else if (type == SELECTIONJOB_MATCHDEPID)
+    r = selection_make_matchdepid(pool, &sel, testcase_str2dep(pool, pieces[2]), selflags, keyname, 0);
+  else if (type == SELECTIONJOB_MATCHSOLVABLE)
+    r = selection_make_matchsolvable(pool, &sel, testcase_str2solvid(pool, pieces[2]), selflags, keyname, 0);
   for (i = 0; i < sel.count; i += 2)
     queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]);
   queue_free(&sel);
@@ -1369,12 +1398,13 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags)
       if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':')
        continue;
       tag = line[1] << 16 | line[2] << 8 | line[3];
+      /* tags that do not need a solvable */
       switch(tag)
-        {
+       {
        case 'V' << 16 | 'e' << 8 | 'r':
          tagsversion = atoi(line + 6);
          addselfprovides = tagsversion < 3 || strstr(line + 6, "addselfprovides") != 0;
-         break;
+         continue;
        case 'P' << 16 | 'k' << 8 | 'g':
          if (s)
            {
@@ -1393,7 +1423,15 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags)
            sp[2][-1] = '-';
          s->evr = makeevr(pool, sp[1]);
          s->arch = pool_str2id(pool, sp[3], 1);
+         continue;
+       default:
          break;
+       }
+      if (!s)
+       continue;
+      /* tags that need a solvable */
+      switch(tag)
+       {
        case 'S' << 16 | 'u' << 8 | 'm':
          repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6);
          break;
@@ -1532,10 +1570,7 @@ testcase_setpoolflags(Pool *pool, const char *str)
        if (!strncmp(poolflags2str[i].str, s, p - s) && poolflags2str[i].str[p - s] == 0)
          break;
       if (!poolflags2str[i].str)
-       {
-         pool_debug(pool, SOLV_ERROR, "setpoolflags: unknown flag '%.*s'\n", (int)(p - s), s);
-         return 0;
-       }
+        return pool_error(pool, 0, "setpoolflags: unknown flag '%.*s'", (int)(p - s), s);
       pool_set_flag(pool, poolflags2str[i].flag, v);
     }
   return 1;
@@ -1589,15 +1624,9 @@ testcase_setsolverflags(Solver *solv, const char *str)
        if (!strncmp(solverflags2str[i].str, s, p - s) && solverflags2str[i].str[p - s] == 0)
          break;
       if (!solverflags2str[i].str)
-       {
-         pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unknown flag '%.*s'\n", (int)(p - s), s);
-         return 0;
-       }
+       return pool_error(solv->pool, 0, "setsolverflags: unknown flag '%.*s'", (int)(p - s), s);
       if (solver_set_flag(solv, solverflags2str[i].flag, v) == -1)
-       {
-         pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unsupported flag '%s'\n", solverflags2str[i].str);
-         return 0;
-       }
+        return pool_error(solv->pool, 0, "setsolverflags: unsupported flag '%s'", solverflags2str[i].str);
     }
   return 1;
 }
@@ -2119,6 +2148,28 @@ testcase_solverresult(Solver *solv, int resultflags)
        }
       queue_free(&whyq);
     }
+  if ((resultflags & TESTCASE_RESULT_CLEANDEPS) != 0)
+    {
+      Queue q;
+
+      queue_init(&q);
+      solver_get_cleandeps(solv, &q);
+      for (i = 0; i < q.count; i++)
+       {
+         s = pool_tmpjoin(pool, "cleandeps ", testcase_solvid2str(pool, q.elements[i]), 0);
+         strqueue_push(&sq, s);
+       }
+      queue_free(&q);
+    }
+  if ((resultflags & TESTCASE_RESULT_JOBS) != 0)
+    {
+      for (i = 0; i < solv->job.count; i += 2)
+       {
+         s = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]);
+         s = pool_tmpjoin(pool, "job ", s, 0);
+         strqueue_push(&sq, s);
+       }
+    }
   strqueue_sort(&sq);
   result = strqueue_join(&sq);
   strqueue_free(&sq);
@@ -2145,10 +2196,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
     resultname = "solver.result";
 
   if (mkdir(dir, 0777) && errno != EEXIST)
-    {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not create directory '%s'\n", dir);
-      return 0;
-    }
+    return pool_error(solv->pool, 0, "testcase_write: could not create directory '%s'", dir);
   strqueue_init(&sq);
   FOR_REPOS(repoid, repo)
     {
@@ -2169,14 +2217,14 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
       out = pool_tmpjoin(pool, dir, "/", out);
       if (!(fp = solv_xfopen(out, "w")))
        {
-         pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out);
+         pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
          strqueue_free(&sq);
          return 0;
        }
       testcase_write_testtags(repo, fp);
       if (fclose(fp))
        {
-         pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
+         pool_error(solv->pool, 0, "testcase_write: write error");
          strqueue_free(&sq);
          return 0;
        }
@@ -2301,14 +2349,14 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
          out = pool_tmpjoin(pool, dir, "/", resultname);
          if (!(fp = fopen(out, "w")))
            {
-             pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out);
+             pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
              solv_free(result);
              strqueue_free(&sq);
              return 0;
            }
          if (result && *result && fwrite(result, strlen(result), 1, fp) != 1)
            {
-             pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
+             pool_error(solv->pool, 0, "testcase_write: write error");
              solv_free(result);
              strqueue_free(&sq);
              fclose(fp);
@@ -2316,7 +2364,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
            }
          if (fclose(fp))
            {
-             pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
+             pool_error(solv->pool, 0, "testcase_write: write error");
              strqueue_free(&sq);
              return 0;
            }
@@ -2328,20 +2376,20 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
   out = pool_tmpjoin(pool, dir, "/", testcasename);
   if (!(fp = fopen(out, "w")))
     {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out);
+      pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
       strqueue_free(&sq);
       return 0;
     }
   if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1)
     {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
+      pool_error(solv->pool, 0, "testcase_write: write error");
       strqueue_free(&sq);
       fclose(fp);
       return 0;
     }
   if (fclose(fp))
     {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
+      pool_error(solv->pool, 0, "testcase_write: write error");
       strqueue_free(&sq);
       return 0;
     }
@@ -2495,7 +2543,7 @@ str2resultflags(Pool *pool, char *s)      /* modifies the string! */
            break;
          }
       if (!resultflags2str[i].str)
-       pool_debug(pool, SOLV_ERROR, "result: unknown flag '%s'\n", s);
+       pool_error(pool, 0, "result: unknown flag '%s'", s);
       s = se;
     }
   return resultflags;
@@ -2525,7 +2573,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
     *resultflagsp = 0;
   if (!fp && !(fp = fopen(testcase, "r")))
     {
-      pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", testcase);
+      pool_error(pool, 0, "testcase_read: could not open '%s'", testcase);
       return 0;
     }
   testcasedir = solv_strdup(testcase);
@@ -2615,7 +2663,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
                }
              if (!rfp)
                {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata);
+                 pool_error(pool, 0, "testcase_read: could not open '%s'", rdata);
                }
              else if (!strcmp(repotype, "testtags"))
                {
@@ -2637,7 +2685,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
              else
                {
                  fclose(rfp);
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: unknown repo type for repo '%s'\n", repo->name);
+                 pool_error(pool, 0, "testcase_read: unknown repo type for repo '%s'", repo->name);
                }
            }
        }
@@ -2673,7 +2721,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
                }
              if (!(dp && *dp))
                {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: system: could not change disttype to '%s'\n", pieces[2]);
+                 pool_error(pool, 0, "testcase_read: system: could not change disttype to '%s'", pieces[2]);
                  missing_features = 1;
                }
            }
@@ -2687,7 +2735,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            {
              Repo *repo = testcase_str2repo(pool, pieces[3]);
              if (!repo)
-               pool_debug(pool, SOLV_ERROR, "testcase_read: system: unknown repo '%s'\n", pieces[3]);
+               pool_error(pool, 0, "testcase_read: system: unknown repo '%s'", pieces[3]);
              else
                pool_set_installed(pool, repo);
            }
@@ -2704,7 +2752,25 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            }
          if (npieces >= 3 && !strcmp(pieces[2], "selection"))
            {
-             addselectionjob(pool, pieces + 1, npieces - 1, job);
+             addselectionjob(pool, pieces + 1, npieces - 1, job, 0, 0);
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdeps"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPS, pool_str2id(pool, pieces[3], 1));
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdepid"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPID, pool_str2id(pool, pieces[3], 1));
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchsolvable"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHSOLVABLE, pool_str2id(pool, pieces[3], 1));
              continue;
            }
          /* rejoin */
@@ -2725,7 +2791,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
          s = strchr(pieces[1], '(');
          if (!s && pieces[1][i - 1] != ')')
            {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: bad namespace '%s'\n", pieces[1]);
+             pool_error(pool, 0, "testcase_read: bad namespace '%s'", pieces[1]);
            }
          else
            {
@@ -2788,7 +2854,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
                {
                  FILE *rfp = fopen(rdata, "r");
                  if (!rfp)
-                   pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata);
+                   pool_error(pool, 0, "testcase_read: could not open '%s'", rdata);
                  else
                    {
                      result = read_file(rfp);
@@ -2814,7 +2880,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
          Id p;
          if (strcmp(pieces[1], "pkg"))
            {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: bad disable type '%s'\n", pieces[1]);
+             pool_error(pool, 0, "testcase_read: bad disable type '%s'", pieces[1]);
              continue;
            }
          if (!prepared)
@@ -2830,7 +2896,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
          if (p)
            MAPCLR(pool->considered, p);
          else
-           pool_debug(pool, SOLV_ERROR, "disable: unknown package '%s'\n", pieces[2]);
+           pool_error(pool, 0, "disable: unknown package '%s'", pieces[2]);
        }
       else if (!strcmp(pieces[0], "feature"))
        {
@@ -2842,7 +2908,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
                  break;
              if (!features[j])
                {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: missing feature '%s'\n", pieces[i]);
+                 pool_error(pool, 0, "testcase_read: missing feature '%s'", pieces[i]);
                  missing_features++;
                }
            }
@@ -2869,12 +2935,12 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
                  break;
              if (!op->flags)
                {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown op '%s'\n", pieces[2]);
+                 pool_error(pool, 0, "testcase_read: genid: unknown op '%s'", pieces[2]);
                  break;
                }
              if (ngenid < 2)
                {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: genid: out of stack\n");
+                 pool_error(pool, 0, "testcase_read: genid: out of stack");
                  break;
                }
              ngenid -= 2;
@@ -2888,7 +2954,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            id = testcase_str2dep(pool, pieces[2]);
          else
            {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown command '%s'\n", pieces[1]);
+             pool_error(pool, 0, "testcase_read: genid: unknown command '%s'", pieces[1]);
              break;
            }
          genid[ngenid++] = id;
@@ -2897,14 +2963,22 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
        {
          if (strcmp(pieces[1], "name"))
            {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: autoinst: illegal mode\n");
+             pool_error(pool, 0, "testcase_read: autoinst: illegal mode");
              break;
            }
          queue_push(&autoinstq, pool_str2id(pool, pieces[2], 1));
        }
+      else if (!strcmp(pieces[0], "evrcmp") && npieces == 3)
+       {
+         Id evr1 = pool_str2id(pool, pieces[1], 1);
+         Id evr2 = pool_str2id(pool, pieces[2], 1);
+         int r = pool_evrcmp(pool, evr1, evr2, EVRCMP_COMPARE);
+         r = r < 0 ? REL_LT : r > 0 ? REL_GT : REL_EQ;
+         queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, evr1, evr2, r, 1));
+       }
       else
        {
-         pool_debug(pool, SOLV_ERROR, "testcase_read: cannot parse command '%s'\n", pieces[0]);
+         pool_error(pool, 0, "testcase_read: cannot parse command '%s'", pieces[0]);
        }
     }
   while (job && ngenid > 0)