commit:     199e4f62b4ede5f2319ef6795a15737ac0882d09
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sun Apr  7 20:06:20 2019 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Sun Apr  7 20:14:35 2019 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=199e4f62

atoms: add proper support for blockers and USE dependencies

- ignore SLOT in atom_compare when not set on both sides
- parse USE-dependencies, properly removing it from PV
- parse blockers (! and !!) separate from version ranges, such that the
  original meaning can be restored and differentiated from

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/atom.c                      | 250 ++++++++++++++++++++++++++++-----------
 libq/atom.h                      |  66 ++++++++---
 man/qatom.1                      |   5 +-
 qatom.c                          |  40 +++++--
 tests/atom_compare/static.good   |   4 +-
 tests/atom_compare/static.q.good |   2 +-
 tests/atom_compare/static.tests  |   4 +-
 tests/qatom/dotest               |  22 ++++
 8 files changed, 298 insertions(+), 95 deletions(-)

diff --git a/libq/atom.c b/libq/atom.c
index 60a37ce..4c06c1a 100644
--- a/libq/atom.c
+++ b/libq/atom.c
@@ -16,16 +16,28 @@
 #include <ctype.h>
 #include <xalloc.h>
 
-const char * const booga[] = {"!!!", "!=", "==", ">", "<"};
-
 const char * const atom_suffixes_str[] = {
        "_alpha", "_beta", "_pre", "_rc", "_/*bogus*/", "_p"
 };
 
+const char * const atom_slotdep_str[] = {
+       "", "=", "*"
+};
+
+const char * const atom_usecond_str[] = {
+       "", "!", "-", "?", "=", "(+)", "(-)"
+};
+
+const char * const atom_blocker_str[] = {
+       "", "!", "!!"
+};
+
 const char * const atom_op_str[] = {
-       "", ">", ">=", "=", "<=", "<", "~", "!", "!!", "*"
+       "", "=", ">", ">=", "<", "<=", "~", "*"
 };
 
+const char * const booga[] = {"!!!", "!=", "==", ">", "<"};
+
 #ifdef EBUG
 void
 atom_print(const depend_atom *atom)
@@ -52,7 +64,10 @@ atom_explode(const char *atom)
 {
        depend_atom *ret;
        char *ptr;
-       size_t len, slen, idx, sidx;
+       size_t len;
+       size_t slen;
+       size_t idx;
+       size_t sidx;
 
        /* we allocate mem for atom struct and two strings (strlen(atom)).
         * the first string is for CAT/PN/PV while the second is for PVR.
@@ -76,61 +91,37 @@ atom_explode(const char *atom)
        ret->PVR = ret->P + slen + 1;
        ret->CATEGORY = ret->PVR + slen + 1 + 3;
 
+       /* check for blocker operators */
+       ret->blocker = ATOM_BL_NONE;
+       if (*atom == '!') {
+               ret->blocker++;
+               atom++;
+       }
+       if (*atom == '!') {
+               ret->blocker++;
+               atom++;
+       }
+
        /* eat any prefix operators */
-       switch (atom[0]) {
+       ret->pfx_op = ATOM_OP_NONE;
+       switch (*atom) {
        case '>':
-               ++atom;
-               if (atom[0] == '=') {
-                       ++atom;
-                       ret->pfx_op = ATOM_OP_NEWER_EQUAL;
-               } else
-                       ret->pfx_op = ATOM_OP_NEWER;
-               break;
-       case '=':
-               ++atom;
-               ret->pfx_op = ATOM_OP_EQUAL;
+               ret->pfx_op = ATOM_OP_NEWER;
+               atom++;
                break;
        case '<':
-               ++atom;
-               if (atom[0] == '=') {
-                       ++atom;
-                       ret->pfx_op = ATOM_OP_OLDER_EQUAL;
-               } else
-                       ret->pfx_op = ATOM_OP_OLDER;
+               ret->pfx_op = ATOM_OP_OLDER;
+               atom++;
                break;
        case '~':
-               ++atom;
                ret->pfx_op = ATOM_OP_PV_EQUAL;
-               break;
-       case '!':
-               ++atom;
-               switch (atom[0]) {
-               case '!':
-                       ++atom;
-                       ret->pfx_op = ATOM_OP_BLOCK_HARD;
-                       break;
-               case '>':
-                       ++atom;
-                       if (atom[0] == '=') {
-                               ++atom;
-                               ret->pfx_op = ATOM_OP_OLDER;
-                       } else
-                               ret->pfx_op = ATOM_OP_OLDER_EQUAL;
-                       break;
-               case '<':
-                       ++atom;
-                       if (atom[0] == '=') {
-                               ++atom;
-                               ret->pfx_op = ATOM_OP_NEWER;
-                       } else
-                               ret->pfx_op = ATOM_OP_NEWER_EQUAL;
-                       break;
-               default:
-                       ret->pfx_op = ATOM_OP_BLOCK;
-                       break;
-               }
+               atom++;
                break;
        }
+       if (*atom == '=') {
+               ret->pfx_op += ATOM_OP_EQUAL;
+               atom++;
+       }
        strcpy(ret->CATEGORY, atom);
 
        /* eat file name crap when given an (autocompleted) path */
@@ -145,21 +136,24 @@ atom_explode(const char *atom)
 
        /* chip off the trailing [:SLOT] as needed */
        if ((ptr = strrchr(ret->CATEGORY, ':')) != NULL) {
-               ret->SLOT = ptr + 1;
-               *ptr = '\0';
+               *ptr++ = '\0';
+               ret->SLOT = ptr;
 
-               /* ignore slots that are about package matching */
-               if (ret->SLOT[0] == '=' || ret->SLOT[0] == '*')
-                       ret->SLOT = NULL;
+               /* deal with slot operators */
+               if ((ptr = strrchr(ret->SLOT, '=')) != NULL && ptr[1] == '\0') {
+                       ret->slotdep = ATOM_SD_ANY_REBUILD;
+                       *ptr = '\0';
+               }
+               if ((ptr = strrchr(ret->SLOT, '*')) != NULL && ptr[1] == '\0') {
+                       ret->slotdep = ATOM_SD_ANY_IGNORE;
+                       *ptr = '\0';
+               }
        }
 
        /* see if we have any suffix operators */
-       if ((ptr = strrchr(ret->CATEGORY, '*')) != NULL) {
-               /* make sure it's the last byte */
-               if (ptr[1] == '\0') {
-                       ret->sfx_op = ATOM_OP_STAR;
-                       *ptr = '\0';
-               }
+       if ((ptr = strrchr(ret->CATEGORY, '*')) != NULL && ptr[1] == '\0') {
+               ret->sfx_op = ATOM_OP_STAR;
+               *ptr = '\0';
        }
 
        /* break up the CATEGORY and PVR */
@@ -167,7 +161,8 @@ atom_explode(const char *atom)
                ret->PN = ptr + 1;
                *ptr = '\0';
                /* eat extra crap in case it exists, this is a feature to allow
-                * /path/to/pkg.ebuild */
+                * /path/to/pkg.ebuild, doesn't work with prefix operators
+                * though */
                if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL)
                        ret->CATEGORY = ptr + 1;
        } else {
@@ -175,6 +170,68 @@ atom_explode(const char *atom)
                ret->CATEGORY = NULL;
        }
 
+       /* hunt down build with USE dependencies */
+       if ((ptr = strrchr(ret->PN, ']')) != NULL && ptr[1] == '\0' &&
+                       (ptr = strrchr(ret->PN, '[')) != NULL)
+       {
+               atom_usedep *w = NULL;
+               do {
+                       if (ret->usedeps == NULL) {
+                               ret->usedeps = w = xmalloc(sizeof(atom_usedep));
+                       } else {
+                               w = w->next = xmalloc(sizeof(atom_usedep));
+                       }
+                       w->next = NULL;
+                       *ptr++ = '\0';
+                       w->pfx_cond = w->sfx_cond = ATOM_UC_NONE;
+                       switch (*ptr) {
+                               case '-':
+                                       w->pfx_cond = ATOM_UC_NEG;
+                                       ptr++;
+                                       break;
+                               case '!':
+                                       w->pfx_cond = ATOM_UC_NOT;
+                                       ptr++;
+                                       break;
+                       }
+                       w->use = ptr;
+                       while (*ptr != '\0') {
+                               switch (*ptr) {
+                                       case '?':
+                                               w->sfx_cond = ATOM_UC_COND;
+                                               *ptr++ = '\0';
+                                               break;
+                                       case '=':
+                                               w->sfx_cond = ATOM_UC_EQUAL;
+                                               *ptr++ = '\0';
+                                               break;
+                                       case '(':
+                                               if (strncmp(ptr, "(+)", 3) == 
0) {
+                                                       w->sfx_cond = 
ATOM_UC_PREV_ENABLED;
+                                                       *ptr = '\0';
+                                                       ptr += 3;
+                                               } else if (strncmp(ptr, "(-)", 
3) == 0) {
+                                                       w->sfx_cond = 
ATOM_UC_PREV_ENABLED;
+                                                       *ptr = '\0';
+                                                       ptr += 3;
+                                               } else {
+                                                       ptr++;
+                                               }
+                                               break;
+                                       case ',':
+                                       case ']':
+                                               *ptr = ']';
+                                               break;
+                                       default:
+                                               ptr++;
+                               }
+                               if (*ptr == ']')
+                                       break;
+                       }
+               } while (ptr[1] != '\0');
+               *ptr++ = '\0';
+       }
+
        /* CATEGORY should be all set here, PN contains everything up to
         * SLOT, REPO or '*'
         * PN must not end in a hyphen followed by anything matching version
@@ -202,7 +259,7 @@ atom_explode(const char *atom)
                        /* allow for 1 optional suffix letter */
                        if (*ptr >= 'a' && *ptr <= 'z')
                                ret->letter = *ptr++;
-                       if (*ptr == '_' || *ptr == '\0' || *ptr == '-') {
+                       if (*ptr == '_' || *ptr == '-' || *ptr == '\0') {
                                lastpv = pv;
                                continue;  /* valid, keep searching */
                        }
@@ -333,12 +390,35 @@ atom_compare(const depend_atom *a1, const depend_atom *a2)
        atom_operator pfx_op = a2->pfx_op;
        atom_operator sfx_op = a2->sfx_op;
 
-       /* check slot */
-       if (a1->SLOT || a2->SLOT) {
-               if (!a1->SLOT || !a2->SLOT || strcmp(a1->SLOT, a2->SLOT))
-                       return NOT_EQUAL;
+       /* handle the inversing effect of blockers */
+       if (a2->blocker != ATOM_BL_NONE) {
+               switch (pfx_op) {
+                       case ATOM_OP_NEWER:
+                               pfx_op = ATOM_OP_OLDER_EQUAL;
+                               break;
+                       case ATOM_OP_NEWER_EQUAL:
+                               pfx_op = ATOM_OP_OLDER;
+                               break;
+                       case ATOM_OP_OLDER:
+                               pfx_op = ATOM_OP_NEWER_EQUAL;
+                               break;
+                       case ATOM_OP_OLDER_EQUAL:
+                               pfx_op = ATOM_OP_NEWER;
+                               break;
+                       case ATOM_OP_EQUAL:
+                       case ATOM_OP_PV_EQUAL:
+                       default:
+                               pfx_op = ATOM_OP_NEQUAL;
+                               break;
+               }
        }
 
+       /* check slot only when both sides have it */
+       if (a1->SLOT && a2->SLOT &&
+                       a1->SLOT[0] != '\0' && a2->SLOT[0] != '\0' &&
+                       strcmp(a1->SLOT, a2->SLOT) != 0)
+               return NOT_EQUAL;
+
        /* check repo */
        if (a1->REPO || a2->REPO) {
                if (!a1->REPO || !a2->REPO || strcmp(a1->REPO, a2->REPO))
@@ -489,3 +569,39 @@ implode_a1_ret:
        atom_implode(a1);
        return ret;
 }
+
+static char _atom_buf[BUFSIZ];
+char *
+atom_to_string(depend_atom *a)
+{
+       char *buf = _atom_buf;
+       size_t buflen = sizeof(_atom_buf);
+       size_t off = 0;
+       atom_usedep *ud;
+
+       off += snprintf(buf + off, buflen - off, "%s%s",
+                       atom_blocker_str[a->blocker], atom_op_str[a->pfx_op]);
+       if (a->CATEGORY != NULL)
+               off += snprintf(buf + off, buflen - off, "%s/", a->CATEGORY);
+       if (a->PN != NULL)
+               off += snprintf(buf + off, buflen - off, "%s", a->PN);
+       if (a->PV != NULL)
+               off += snprintf(buf + off, buflen - off, "-%s", a->PV);
+       if (a->PR_int > 0)
+               off += snprintf(buf + off, buflen - off, "-r%d", a->PR_int);
+       off += snprintf(buf + off, buflen - off, "%s", atom_op_str[a->sfx_op]);
+       for (ud = a->usedeps; ud != NULL; ud = ud->next)
+               off += snprintf(buf + off, buflen - off, "%s%s%s%s%s",
+                               ud == a->usedeps ? "[" : "",
+                               atom_usecond_str[ud->pfx_cond],
+                               ud->use,
+                               atom_usecond_str[ud->sfx_cond],
+                               ud->next == NULL ? "]" : ",");
+       if (a->SLOT != NULL)
+               off += snprintf(buf + off, buflen - off, ":%s%s",
+                               a->SLOT, atom_slotdep_str[a->slotdep]);
+       if (a->REPO != NULL)
+               off += snprintf(buf + off, buflen - off, "::%s", a->REPO);
+
+       return buf;
+}

diff --git a/libq/atom.h b/libq/atom.h
index c8e900f..c9a1ddb 100644
--- a/libq/atom.h
+++ b/libq/atom.h
@@ -4,6 +4,7 @@
  *
  * Copyright 2005-2008 Ned Ludd        - <so...@gentoo.org>
  * Copyright 2005-2016 Mike Frysinger  - <vap...@gentoo.org>
+ * Copyright 2019-     Fabian Groffen  - <grob...@gentoo.org>
  */
 
 #ifndef _ATOM_COMPARE_H
@@ -12,39 +13,75 @@
 typedef enum {
        VER_ALPHA=0, VER_BETA, VER_PRE, VER_RC, VER_NORM, VER_P
 } atom_suffixes;
-
 extern const char * const atom_suffixes_str[];
 
-typedef struct {
-       atom_suffixes suffix;
-       uint64_t sint;
-} atom_suffix;
+/* slotdeps, := :* :SLOT= */
+typedef enum {
+       /*   */ ATOM_SD_NONE = 0,
+       /* = */ ATOM_SD_ANY_REBUILD,
+       /* * */ ATOM_SD_ANY_IGNORE
+} atom_slotdep;
+extern const char * const atom_slotdep_str[];
 
-extern const char * const atom_op_str[];
+typedef enum {
+       /*     */ ATOM_UC_NONE = 0,
+       /* !   */ ATOM_UC_NOT,
+       /* -   */ ATOM_UC_NEG,
+       /* ?   */ ATOM_UC_COND,
+       /* =   */ ATOM_UC_EQUAL,
+       /* (+) */ ATOM_UC_PREV_ENABLED,
+       /* (-) */ ATOM_UC_PREV_DISABLED,
+} atom_usecond;
+extern const char * const atom_usecond_str[];
+
+typedef enum {
+       /*    */ ATOM_BL_NONE = 0,
+       /* !  */ ATOM_BL_BLOCK,
+       /* !! */ ATOM_BL_BLOCK_HARD,
+} atom_blocker;
+extern const char * const atom_blocker_str[];
 
 typedef enum {
        /*    */ ATOM_OP_NONE = 0,
+       /* =  */ ATOM_OP_EQUAL,
        /* >  */ ATOM_OP_NEWER,
        /* >= */ ATOM_OP_NEWER_EQUAL,
-       /* =  */ ATOM_OP_EQUAL,
-       /* <= */ ATOM_OP_OLDER_EQUAL,
        /* <  */ ATOM_OP_OLDER,
+       /* <= */ ATOM_OP_OLDER_EQUAL,
        /* ~  */ ATOM_OP_PV_EQUAL,
-       /* !  */ ATOM_OP_BLOCK,
-       /* !! */ ATOM_OP_BLOCK_HARD,
        /* *  */ ATOM_OP_STAR,
+       /*    */ ATOM_OP_NEQUAL,
 } atom_operator;
+extern const char * const atom_op_str[];
+
+typedef struct {
+       atom_suffixes suffix;
+       uint64_t sint;
+} atom_suffix;
+
+typedef struct _atom_usedep {
+       struct _atom_usedep *next;
+       char *use;
+       atom_usecond pfx_cond;
+       atom_usecond sfx_cond;
+} atom_usedep;
 
 typedef struct {
-       /* XXX: we don't provide PF ... */
-       atom_operator pfx_op, sfx_op;
+       atom_blocker blocker;
+       atom_operator pfx_op;
+       atom_operator sfx_op;
        char *CATEGORY;
        char *PN;
+       char *PV;
        unsigned int PR_int;
        char letter;
        atom_suffix *suffixes;
-       char *PV, *PVR;
-       char *P, *SLOT, *REPO;
+       char *PVR;
+       char *P;
+       atom_usedep *usedeps;
+       char *SLOT;
+       atom_slotdep slotdep;
+       char *REPO;
 } depend_atom;
 
 extern const char * const booga[];
@@ -54,5 +91,6 @@ depend_atom *atom_explode(const char *atom);
 void atom_implode(depend_atom *atom);
 int atom_compare(const depend_atom *a1, const depend_atom *a2);
 int atom_compare_str(const char * const s1, const char * const s2);
+char *atom_to_string(depend_atom *a);
 
 #endif

diff --git a/man/qatom.1 b/man/qatom.1
index 4860957..046b89e 100644
--- a/man/qatom.1
+++ b/man/qatom.1
@@ -1,5 +1,5 @@
 .\" generated by mkman.py, please do NOT edit!
-.TH qatom "1" "Feb 2019" "Gentoo Foundation" "qatom"
+.TH qatom "1" "Apr 2019" "Gentoo Foundation" "qatom"
 .SH NAME
 qatom \- split atom strings
 .SH SYNOPSIS
@@ -67,6 +67,9 @@ The package suffices, currently that is just the asterisk.
 \fB\-c\fR, \fB\-\-compare\fR
 Compare two atoms.
 .TP
+\fB\-p\fR, \fB\-\-print\fR
+Print reconstructed atom.
+.TP
 \fB\-\-root\fR \fI<arg>\fR
 Set the ROOT env var.
 .TP

diff --git a/qatom.c b/qatom.c
index c1af10d..20e2dcb 100644
--- a/qatom.c
+++ b/qatom.c
@@ -16,15 +16,17 @@
 
 #define QATOM_FORMAT "%{CATEGORY} %{PN} %{PV} %[PR] %[SLOT] %[pfx] %[sfx]"
 
-#define QATOM_FLAGS "F:c" COMMON_FLAGS
+#define QATOM_FLAGS "F:cp" COMMON_FLAGS
 static struct option const qatom_long_opts[] = {
        {"format",     a_argument, NULL, 'F'},
        {"compare",   no_argument, NULL, 'c'},
+       {"print",     no_argument, NULL, 'p'},
        COMMON_LONG_OPTS
 };
 static const char * const qatom_opts_help[] = {
        "Custom output format (default: " QATOM_FORMAT ")",
        "Compare two atoms",
+       "Print reconstructed atom",
        COMMON_OPTS_HELP
 };
 #define qatom_usage(ret) usage(ret, QATOM_FLAGS, qatom_long_opts, 
qatom_opts_help, NULL, lookup_applet_idx("qatom"))
@@ -92,7 +94,9 @@ qatom_printf(const char *format, const depend_atom *atom, int 
pverbose)
                                                printf("r%i", atom->PR_int);
                                } else if (!strncmp("SLOT", fmt, len)) {
                                        if (showit || atom->SLOT)
-                                               printf(":%s", atom->SLOT ? 
atom->SLOT : "-");
+                                               printf(":%s%s",
+                                                               atom->SLOT ? 
atom->SLOT : "-",
+                                                               
atom_slotdep_str[atom->slotdep]);
                                } else if (!strncmp("REPO", fmt, len)) {
                                        if (showit || atom->REPO)
                                                printf("::%s", HN(atom->REPO));
@@ -117,15 +121,17 @@ qatom_printf(const char *format, const depend_atom *atom, 
int pverbose)
 
 int qatom_main(int argc, char **argv)
 {
-       enum qatom_atom { _EXPLODE=0, _COMPARE } action = _EXPLODE;
+       enum qatom_atom { _EXPLODE=0, _COMPARE, _PRINT } action = _EXPLODE;
        const char *format = QATOM_FORMAT;
        depend_atom *atom;
+       depend_atom *atomc;
        int i;
 
        while ((i = GETOPT_LONG(QATOM, qatom, "")) != -1) {
                switch (i) {
                case 'F': format = optarg; break;
                case 'c': action = _COMPARE; break;
+               case 'p': action = _PRINT; break;
                COMMON_GETOPTS_CASES(qatom)
                }
        }
@@ -137,19 +143,37 @@ int qatom_main(int argc, char **argv)
                err("compare needs even number of arguments");
 
        for (i = optind; i < argc; ++i) {
+               atom = atom_explode(argv[i]);
+               if (atom == NULL) {
+                       warnf("invalid atom: %s\n", argv[i]);
+                       continue;
+               }
+
                switch (action) {
                case _COMPARE:
-                       printf("%s %s %s\n", argv[i],
-                                       booga[atom_compare_str(argv[i], 
argv[i+1])], argv[i+1]);
-                       ++i;
+                       i++;
+                       atomc = atom_explode(argv[i]);
+                       if (atomc == NULL) {
+                               warnf("invalid atom: %s\n", argv[i]);
+                               break;
+                       }
+                       printf("%s %s ",
+                                       atom_to_string(atom),
+                                       booga[atom_compare(atom, atomc)]);
+                       printf("%s\n",
+                                       atom_to_string(atomc));
+                       atom_implode(atomc);
                        break;
                case _EXPLODE:
-                       atom = atom_explode(argv[i]);
                        qatom_printf(format, atom, verbose);
                        putchar('\n');
-                       atom_implode(atom);
+                       break;
+               case _PRINT:
+                       printf("%s\n", atom_to_string(atom));
                        break;
                }
+
+               atom_implode(atom);
        }
 
        return EXIT_SUCCESS;

diff --git a/tests/atom_compare/static.good b/tests/atom_compare/static.good
index 9061ae4..6da5553 100644
--- a/tests/atom_compare/static.good
+++ b/tests/atom_compare/static.good
@@ -10,7 +10,7 @@ a-2.0_pre < a-2.0_rc
 a-2.0_pre < a-2.0_p1234
 a-2.0_rc < a-2.0
 a-1z > a-1b
-a-1-r0 < a-1-r1
+a-1 < a-1-r1
 a-1d_p1-r12 < a-1d_p1-r50
 a-1.034 < a-1.1
 a-1.0.1 < a-1.002
@@ -40,7 +40,7 @@ a-1 == <=a-2
 a-1 != ~a-0
 a-1 == ~a-1
 a-1 != ~a-2
-a-1-r1 == ~a-1-r0
+a-1-r1 == ~a-1
 a-1-r1 == ~a-1-r1
 a-1-r1 == ~a-1-r2
 a-1 == =a-1*

diff --git a/tests/atom_compare/static.q.good b/tests/atom_compare/static.q.good
index 08a6635..621cf0b 100644
--- a/tests/atom_compare/static.q.good
+++ b/tests/atom_compare/static.q.good
@@ -1,7 +1,7 @@
 a/b == b
 a/b-1 == b
 a-1 == =a-1.0*
-a-1:1234 != a-1
+a-1:1234 == a-1
 a-1:0 < a-2:0
 a-1:0 == a-1:0
 a-1_alpha1 != =a-1-r1*

diff --git a/tests/atom_compare/static.tests b/tests/atom_compare/static.tests
index 2f081c8..168f358 100644
--- a/tests/atom_compare/static.tests
+++ b/tests/atom_compare/static.tests
@@ -10,7 +10,7 @@ a-2.0_pre a-2.0_rc
 a-2.0_pre a-2.0_p1234
 a-2.0_rc a-2.0
 a-1z a-1b
-a-1-r0 a-1-r1
+a-1 a-1-r1
 a-1d_p1-r12 a-1d_p1-r50
 a-1.034 a-1.1
 a-1.0.1 a-1.002
@@ -40,7 +40,7 @@ a-1 <=a-2
 a-1 ~a-0
 a-1 ~a-1
 a-1 ~a-2
-a-1-r1 ~a-1-r0
+a-1-r1 ~a-1
 a-1-r1 ~a-1-r1
 a-1-r1 ~a-1-r2
 a-1 =a-1*

diff --git a/tests/qatom/dotest b/tests/qatom/dotest
index c879624..2e16b25 100755
--- a/tests/qatom/dotest
+++ b/tests/qatom/dotest
@@ -55,4 +55,26 @@ test f17 "games-rpg eschalon-book-1-demo 106 r1" \
                       -F '%{CATEGORY} %{PN} %{PV} %{PR}' \
                                        "games-rpg/eschalon-book-1-demo-106-r1"
 
+# Comparison tests
+test c01 "cat/pkg-123-r3 == pkg" \
+       -c 'cat/pkg-123-r3' 'pkg'
+test c02 "cat/pkg-123-r3 == !<cat/pkg-123" \
+       -c 'cat/pkg-123-r3' '!<cat/pkg-123'
+test c03 "cat/pkg-123-r3 != !<cat/pkg-124" \
+       -c 'cat/pkg-123-r3' '!<cat/pkg-124'
+test c04 "cat/pkg-123-r3 < cat/pkg-123-r4" \
+       -c 'cat/pkg-123-r3' 'cat/pkg-123-r4'
+test c05 "cat/pkg-123 > cat/pkg-12.3" \
+       -c 'cat/pkg-123' 'cat/pkg-12.3'
+test c07 "cat/pkg-123 == cat/pkg-123:bar" \
+       -c 'cat/pkg-123' 'cat/pkg-123:bar'              # bug 668418
+test c08 "cat/pkg-123:foo != cat/pkg-123:bar" \
+       -c 'cat/pkg-123:foo' 'cat/pkg-123:bar'
+test c09 "cat/pkg-123:foo == cat/pkg-123:foo=" \
+       -c 'cat/pkg-123:foo' 'cat/pkg-123:foo='
+test c10 "cat/pkg-123:foo == cat/pkg-123:=" \
+       -c 'cat/pkg-123:foo' 'cat/pkg-123:='
+test c11 "cat/pkg-123[!foo,bar(+),baz=] == cat/pkg-123" \
+       -c 'cat/pkg-123[!foo,bar(+),baz=]' 'cat/pkg-123'
+
 end

Reply via email to